Repository: conan-io/conan

Issue:
Print Warning for Python 2 in conan client





Discussion:

Resolving patch:
diff --git a/conans/client/command.py b/conans/client/command.py
--- a/conans/client/command.py
+++ b/conans/client/command.py
@@ -4,6 +4,8 @@
 import sys
 from argparse import ArgumentError
 
+import six
+
 from conans import __version__ as client_version
 from conans.client.conan_api import (Conan, default_manifest_folder)
 from conans.client.conan_command_output import CommandOutputer
@@ -101,6 +103,7 @@ def help(self, *args):
         try:
             commands = self._commands()
             method = commands[args.command]
+            self._warn_python2()
             method(["--help"])
         except KeyError:
             raise ConanException("Unknown command '%s'" % args.command)
@@ -163,6 +166,7 @@ def new(self, *args):
                             help='Define URL of the repository to upload')
 
         args = parser.parse_args(*args)
+        self._warn_python2()
         self._conan.new(args.name, header=args.header, pure_c=args.pure_c, test=args.test,
                         exports_sources=args.sources, bare=args.bare,
                         visual_versions=args.ci_appveyor_win,
@@ -197,6 +201,7 @@ def test(self, *args):
 
         _add_common_install_arguments(parser, build_help=_help_build_policies)
         args = parser.parse_args(*args)
+        self._warn_python2()
         return self._conan.test(args.path, args.reference, args.profile, args.settings,
                                 args.options, args.env, args.remote, args.update,
                                 build_modes=args.build, test_build_folder=args.test_build_folder)
@@ -234,7 +239,7 @@ def create(self, *args):
         _add_common_install_arguments(parser, build_help=_help_build_policies)
 
         args = parser.parse_args(*args)
-
+        self._warn_python2()
         name, version, user, channel = get_reference_fields(args.reference)
 
         if args.test_folder == "None":
@@ -282,6 +287,7 @@ def download(self, *args):
 
         args = parser.parse_args(*args)
 
+        self._warn_python2()
         return self._conan.download(reference=args.reference, package=args.package,
                                     remote_name=args.remote, recipe=args.recipe)
 
@@ -536,6 +542,7 @@ def source(self, *args):
         except ConanException:
             pass
 
+        self._warn_python2()
         return self._conan.source(args.path, args.source_folder, args.install_folder)
 
     def build(self, *args):
@@ -576,6 +583,8 @@ def build(self, *args):
         parser.add_argument("-sf", "--source-folder", action=OnceArgument, help=_SOURCE_FOLDER_HELP)
         args = parser.parse_args(*args)
 
+        self._warn_python2()
+
         if args.build or args.configure or args.install or args.test:
             build, config, install, test = (bool(args.build), bool(args.configure),
                                             bool(args.install), bool(args.test))
@@ -626,6 +635,7 @@ def package(self, *args):
         except ConanException:
             pass
 
+        self._warn_python2()
         return self._conan.package(path=args.path,
                                    build_folder=args.build_folder,
                                    package_folder=args.package_folder,
@@ -662,7 +672,7 @@ def imports(self, *args):
                                           "containing a conanfile.py or conanfile.txt file.")
         except ConanException:
             pass
-
+        self._warn_python2()
         return self._conan.imports(args.path, args.import_folder, args.install_folder)
 
     def export_pkg(self, *args):
@@ -702,8 +712,8 @@ def export_pkg(self, *args):
         parser.add_argument("-sf", "--source-folder", action=OnceArgument, help=_SOURCE_FOLDER_HELP)
 
         args = parser.parse_args(*args)
+        self._warn_python2()
         name, version, user, channel = get_reference_fields(args.reference)
-
         return self._conan.export_pkg(conanfile_path=args.path,
                                       name=name,
                                       version=version,
@@ -732,9 +742,10 @@ def export(self, *args):
                                               "and version are not declared in the conanfile.py")
         parser.add_argument('-k', '-ks', '--keep-source', default=False, action='store_true',
                             help=_KEEP_SOURCE_HELP)
+
         args = parser.parse_args(*args)
+        self._warn_python2()
         name, version, user, channel = get_reference_fields(args.reference)
-
         return self._conan.export(path=args.path,
                                   name=name, version=version, user=user, channel=channel,
                                   keep_source=args.keep_source)
@@ -767,6 +778,8 @@ def remove(self, *args):
                             help="Remove locks")
         args = parser.parse_args(*args)
 
+        self._warn_python2()
+
         # NOTE: returns the expanded pattern (if a pattern was given), and checks
         # that the query parameter wasn't abused
         reference = self._check_query_parameter_and_get_reference(args.pattern_or_reference,
@@ -817,6 +830,8 @@ def copy(self, *args):
         if args.all and args.package:
             raise ConanException("Cannot specify both --all and --package")
 
+        self._warn_python2()
+
         return self._conan.copy(reference=args.reference, user_channel=args.user_channel,
                                 force=args.force, packages=args.package or args.all)
 
@@ -1003,6 +1018,7 @@ def upload(self, *args):
 
         args = parser.parse_args(*args)
 
+
         if args.query and args.package:
             raise ConanException("'-q' and '-p' parameters can't be used at the same time")
 
@@ -1016,6 +1032,9 @@ def upload(self, *args):
         if args.no_overwrite and args.skip_upload:
             raise ConanException("'--skip-upload' argument cannot be used together "
                                  "with '--no-overwrite'")
+
+        self._warn_python2()
+
         if args.force:
             policy = UPLOAD_POLICY_FORCE
         elif args.no_overwrite == "all":
@@ -1219,6 +1238,8 @@ def alias(self, *args):
         parser.add_argument('target', help='Target reference. e.g.: mylib/1.12@user/channel')
         args = parser.parse_args(*args)
 
+        self._warn_python2()
+
         self._conan.export_alias(args.reference, args.target)
 
     def _show_help(self):
@@ -1268,6 +1289,16 @@ def _commands(self):
                     result[method_name] = method
         return result
 
+    def _warn_python2(self):
+        if six.PY2:
+            self._user_io.out.writeln("")
+            self._user_io.out.writeln("Python 2 will soon be deprecated. It is strongly "
+                                      "recommended to use Python 3 with Conan:",
+                                      front=Color.BRIGHT_YELLOW)
+            self._user_io.out.writeln("https://docs.conan.io/en/latest/installation.html"
+                                      "#python-2-deprecation-notice", front=Color.BRIGHT_YELLOW)
+            self._user_io.out.writeln("")
+
     @staticmethod
     def _check_query_parameter_and_get_reference(pattern, query):
         reference = None
@@ -1295,6 +1326,7 @@ def run(self, *args):
                 if command in ["-v", "--version"]:
                     self._user_io.out.success("Conan version %s" % client_version)
                     return False
+                self._warn_python2()
                 self._show_help()
                 if command in ["-h", "--help"]:
                     return False


Test patch:
diff --git a/conans/test/integration/alias_test.py b/conans/test/integration/alias_test.py
--- a/conans/test/integration/alias_test.py
+++ b/conans/test/integration/alias_test.py
@@ -386,7 +386,7 @@ class Pkg(ConanFile):
         client.save({"conanfile.py": dep_conanfile})
         client.run("create . Consumer/0.1@user/testing")
         self.assertIn("Pkg/0.1@user/testing: Already installed!", client.out)
-        self.assertNotIn("latest", client.out)
+        self.assertNotIn("latest@user", client.out)
 
     def repeated_alias_test(self):
         client = TestClient()