Repository: conan-io/conan

Issue:
conan inspect --raw prints status messages
The documentation of `conan inspect --raw` states: "Print just the value of the requested attribute". However, the command prints not only the requested attribute but also status and warning messages like "WARN: Migration: Updating settings.yml" or "my_python_required/0.1@user/channel: Not found in local cache, looking in remotes...". This makes it difficult to use `conan inspect` in automation scripts.

Steps to reproduce (variant A):
```
~/my_package  » conan --version
Conan version 1.18.1
~/my_package » pip3 install conan==1.17.0
~/my_package » conan inspect . --raw name
WARN: Migration: Updating settings.yml
WARN: ****************************************
WARN: settings.yml is locally modified, can't be updated
WARN: The new settings.yml has been stored in: ...
WARN: ****************************************
my_package
```

Steps to reproduce (variant B):
```
~ » conan download -r bincrafters boost_any/1.69.0@bincrafters/stable 
~ » conan remove -f boost_base/1.69.0@bincrafters/stable
~ » conan inspect -r bincrafters --raw name boost_any/1.69.0@bincrafters/stable
boost_base/1.69.0@bincrafters/stable: Retrieving from server 'bincrafters' 
boost_base/1.69.0@bincrafters/stable: Trying with 'bincrafters'...
Downloading conanmanifest.txt: 100%|##########| 103/103 [00:00<00:00, 60.9kB/s]
Downloading conanfile.py: 100%|##########| 10.1k/10.1k [00:00<00:00, 6.13MB/s]
Downloading conan_export.tgz: 100%|##########| 758/758 [00:00<00:00, 616kB/s]
Decompressing conan_export.tgz: 100%|##########| 758/758 [00:00<00:00, 141kB/s]
boost_base/1.69.0@bincrafters/stable: Downloaded recipe revision 0
boost_any
```

Conan version: 1.18.1
Operating system: Ubuntu 18.04.3

- [x] I've read the [CONTRIBUTING guide](https://github.com/conan-io/conan/blob/develop/.github/CONTRIBUTING.md).
- [x] I've specified the Conan version, operating system version and any tool that can be relevant.
- [x] I've explained the steps to reproduce the error or the motivation/use case of the question/suggestion.



Discussion:
Thanks for reporting it. We need to honor `raw` argument.

Resolving patch:
diff --git a/conans/client/command.py b/conans/client/command.py
--- a/conans/client/command.py
+++ b/conans/client/command.py
@@ -250,8 +250,9 @@ def inspect(self, *args):
             raise ConanException("Argument '--raw' is incompatible with '--json'")
 
         attributes = [args.raw, ] if args.raw else args.attribute
+        quiet = bool(args.raw)
 
-        result = self._conan.inspect(args.path_or_reference, attributes, args.remote)
+        result = self._conan.inspect(args.path_or_reference, attributes, args.remote, quiet=quiet)
         Printer(self._out).print_inspect(result, raw=args.raw)
         if args.json:
             json_output = json.dumps(result)
diff --git a/conans/client/conan_api.py b/conans/client/conan_api.py
--- a/conans/client/conan_api.py
+++ b/conans/client/conan_api.py
@@ -2,9 +2,7 @@
 import sys
 from collections import OrderedDict
 
-from conans.client.graph.graph_binaries import GraphBinariesAnalyzer
-from conans.client.manager import deps_install
-from conans.paths.package_layouts.package_cache_layout import PackageCacheLayout
+from six import StringIO
 
 import conans
 from conans import __version__ as client_version
@@ -23,6 +21,7 @@
 from conans.client.cmd.user import user_set, users_clean, users_list, token_present
 from conans.client.conf import ConanClientConfigParser
 from conans.client.graph.graph import RECIPE_EDITABLE
+from conans.client.graph.graph_binaries import GraphBinariesAnalyzer
 from conans.client.graph.graph_manager import GraphManager
 from conans.client.graph.printer import print_graph
 from conans.client.graph.proxy import ConanProxy
@@ -32,6 +31,7 @@
 from conans.client.importer import run_imports, undo_imports
 from conans.client.installer import BinaryInstaller
 from conans.client.loader import ConanFileLoader
+from conans.client.manager import deps_install
 from conans.client.migrations import ClientMigrator
 from conans.client.output import ConanOutput, colorama_initialize
 from conans.client.profile_loader import profile_from_args, read_profile
@@ -57,6 +57,7 @@
 from conans.model.version import Version
 from conans.model.workspace import Workspace
 from conans.paths import BUILD_INFO, CONANINFO, get_conan_user_home
+from conans.paths.package_layouts.package_cache_layout import PackageCacheLayout
 from conans.search.search import search_recipes
 from conans.tools import set_global_instances
 from conans.unicode import get_cwd
@@ -64,20 +65,24 @@
 from conans.util.log import configure_logger
 from conans.util.tracer import log_command, log_exception
 
-
 default_manifest_folder = '.conan_manifests'
 
 
 def api_method(f):
-    def wrapper(*args, **kwargs):
-        api = args[0]
-        api.create_app()
+    def wrapper(api, *args, **kwargs):
+        quiet = kwargs.pop("quiet", False)
+        old_curdir = get_cwd()
+        old_output = api.user_io.out
+        quiet_output = ConanOutput(StringIO(), api.color) if quiet else None
         try:
-            curdir = get_cwd()
+            api.create_app(quiet_output=quiet_output)
             log_command(f.__name__, kwargs)
             with tools.environment_append(api.app.cache.config.env_vars):
-                return f(*args, **kwargs)
+                return f(api, *args, **kwargs)
         except Exception as exc:
+            if quiet_output:
+                old_output.write(quiet_output._stream.getvalue())
+                old_output.flush()
             msg = exception_message_safe(exc)
             try:
                 log_exception(exc, msg)
@@ -85,7 +90,7 @@ def wrapper(*args, **kwargs):
                 pass
             raise
         finally:
-            os.chdir(curdir)
+            os.chdir(old_curdir)
     return wrapper
 
 
@@ -138,15 +143,18 @@ def _get_conanfile_path(path, cwd, py):
 
 
 class ConanApp(object):
-    def __init__(self, cache_folder, user_io, http_requester=None, runner=None):
+    def __init__(self, cache_folder, user_io, http_requester=None, runner=None, quiet_output=None):
         # User IO, interaction and logging
         self.user_io = user_io
         self.out = self.user_io.out
+        if quiet_output:
+            self.user_io.out = quiet_output
+            self.out = quiet_output
+
         self.cache_folder = cache_folder
         self.cache = ClientCache(self.cache_folder, self.out)
         self.config = self.cache.config
-        interactive = not self.config.non_interactive
-        if not interactive:
+        if self.config.non_interactive or quiet_output:
             self.user_io.disable_input()
 
         # Adjust CONAN_LOGGING_LEVEL with the env readed
@@ -202,22 +210,22 @@ def factory(cls):
 
     def __init__(self, cache_folder=None, output=None, user_io=None, http_requester=None,
                  runner=None):
-        color = colorama_initialize()
-        self.out = output or ConanOutput(sys.stdout, sys.stderr, color)
+        self.color = colorama_initialize()
+        self.out = output or ConanOutput(sys.stdout, sys.stderr, self.color)
         self.user_io = user_io or UserIO(out=self.out)
         self.cache_folder = cache_folder or os.path.join(get_conan_user_home(), ".conan")
-        cache = ClientCache(self.cache_folder, self.out)
         self.http_requester = http_requester
         self.runner = runner
         self.app = None  # Api calls will create a new one every call
         # Migration system
-        migrator = ClientMigrator(cache, Version(client_version), self.out)
+        migrator = ClientMigrator(self.cache_folder, Version(client_version), self.out)
         migrator.migrate()
-        # Remove in Conan 2.0
-        sys.path.append(os.path.join(cache.cache_folder, "python"))
+        # FIXME Remove in Conan 2.0
+        sys.path.append(os.path.join(self.cache_folder, "python"))
 
-    def create_app(self):
-        self.app = ConanApp(self.cache_folder, self.user_io, self.http_requester, self.runner)
+    def create_app(self, quiet_output=None):
+        self.app = ConanApp(self.cache_folder, self.user_io, self.http_requester,
+                            self.runner, quiet_output=quiet_output)
 
     @api_method
     def new(self, name, header=False, pure_c=False, test=False, exports_sources=False, bare=False,
@@ -752,7 +760,7 @@ def export(self, path, name, version, user, channel, keep_source=False, cwd=None
     def remove(self, pattern, query=None, packages=None, builds=None, src=False, force=False,
                remote_name=None, outdated=False):
         remotes = self.app.cache.registry.load_remotes()
-        remover = ConanRemover(self.app.cache, self.app.remote_manager, self.user_io, remotes)
+        remover = ConanRemover(self.app.cache, self.app.remote_manager, self.app.user_io, remotes)
         remover.remove(pattern, remote_name, src, builds, packages, force=force,
                        packages_query=query, outdated=outdated)
 
@@ -766,7 +774,7 @@ def copy(self, reference, user_channel, force=False, packages=None):
         # FIXME: conan copy does not support short-paths in Windows
         ref = ConanFileReference.loads(reference)
         cmd_copy(ref, user_channel, packages, self.app.cache,
-                 self.user_io, self.app.remote_manager, self.app.loader, remotes, force=force)
+                 self.app.user_io, self.app.remote_manager, self.app.loader, remotes, force=force)
 
     @api_method
     def authenticate(self, name, password, remote_name, skip_auth=False):
@@ -782,7 +790,7 @@ def authenticate(self, name, password, remote_name, skip_auth=False):
         if skip_auth and token_present(self.app.cache.localdb, remote, name):
             return remote.name, name, name
         if not password:
-            name, password = self.user_io.request_login(remote_name=remote_name, username=name)
+            name, password = self.app.user_io.request_login(remote_name=remote_name, username=name)
 
         _, _, remote_name, prev_user, user = self.app.remote_manager.authenticate(remote, name,
                                                                                   password)
@@ -866,7 +874,7 @@ def upload(self, pattern, package=None, remote_name=None, all_packages=False, co
         """ Uploads a package recipe and the generated binary packages to a specified remote
         """
         upload_recorder = UploadRecorder()
-        uploader = CmdUpload(self.app.cache, self.user_io, self.app.remote_manager,
+        uploader = CmdUpload(self.app.cache, self.app.user_io, self.app.remote_manager,
                              self.app.loader, self.app.hook_manager)
         remotes = self.app.load_remotes(remote_name=remote_name)
         try:
diff --git a/conans/client/migrations.py b/conans/client/migrations.py
--- a/conans/client/migrations.py
+++ b/conans/client/migrations.py
@@ -4,6 +4,7 @@
 from conans import DEFAULT_REVISION_V1
 from conans.client import migrations_settings
 from conans.client.cache.cache import CONAN_CONF, PROFILES_FOLDER
+from conans.client.cache.cache import ClientCache
 from conans.client.cache.remote_registry import migrate_registry_file
 from conans.client.conf.config_installer import _ConfigOrigin, _save_configs
 from conans.client.tools import replace_in_file
@@ -21,9 +22,9 @@
 
 class ClientMigrator(Migrator):
 
-    def __init__(self, cache, current_version, out):
-        self.cache = cache
-        super(ClientMigrator, self).__init__(cache.cache_folder, cache.store,
+    def __init__(self, cache_folder, current_version, out):
+        self.cache = ClientCache(cache_folder, out)
+        super(ClientMigrator, self).__init__(self.cache.cache_folder, self.cache.store,
                                              current_version, out)
 
     def _update_settings_yml(self, old_version):


Test patch:
diff --git a/conans/test/functional/command/quiet_test.py b/conans/test/functional/command/quiet_test.py
new file mode 100644
--- /dev/null
+++ b/conans/test/functional/command/quiet_test.py
@@ -0,0 +1,24 @@
+# coding=utf-8
+
+import unittest
+
+from conans.test.utils.tools import TestClient, GenConanfile
+
+
+class QuietOutputTestCase(unittest.TestCase):
+
+    def test_inspect(self):
+        client = TestClient(default_server_user=True)
+        client.save({"conanfile.py": GenConanfile().with_name("name")})
+        client.run("export . name/version@user/channel")
+        client.run("upload name/version@user/channel --all")
+        client.run("remove * -f")
+
+        # If the recipe exists, it doesn't show extra output
+        client.run("inspect name/version@user/channel --raw name")
+        self.assertEqual(client.out, "name")
+
+        # If the recipe doesn't exist, the output is shown
+        client.run("inspect non-existing/version@user/channel --raw name", assert_error=True)
+        self.assertIn("ERROR: Unable to find 'non-existing/version@user/channel' in remotes",
+                      client.out)