Repository: aws/aws-cli

Issue:
aws s3 commands should not be checking regions
There's currently code in the high level s3 commands that validate that a region is specified (either through a CLI param, env vars, or config file).  However, botocore does not require a region as s3 is marked as a "global" service at the botocore layer.  This makes the region validation inconsistent between `s3` and `s3api`, as `s3api` does not require a region.

We should be able to safely remove `check_region` in this code.



Discussion:

Resolving patch:
diff --git a/awscli/customizations/s3/s3.py b/awscli/customizations/s3/s3.py
--- a/awscli/customizations/s3/s3.py
+++ b/awscli/customizations/s3/s3.py
@@ -753,32 +753,7 @@ def check_region(self, parsed_globals):
         If the region is specified on the command line it takes priority
         over specification via a configuration file or environment variable.
         """
-        configuration = self.session.get_config()
-        env = os.environ.copy()
-        region = None
-        if 'region' in configuration.keys():
-            region = configuration['region']
-        if 'AWS_DEFAULT_REGION' in env.keys():
-            region = env['AWS_DEFAULT_REGION']
-        parsed_region = None
-        if 'region' in parsed_globals:
-            parsed_region = getattr(parsed_globals, 'region')
-        if 'endpoint_url' in parsed_globals:
-            parsed_endpoint_url = getattr(parsed_globals, 'endpoint_url')
-        else:
-            parsed_endpoint_url = None
-        if not region and not parsed_region and parsed_endpoint_url is None:
-            raise Exception("A region must be specified --region or "
-                            "specifying the region\nin a configuration "
-                            "file or as an environment variable.\n"
-                            "Alternately, an endpoint can be specified "
-                            "with --endpoint-url")
-        if parsed_region:
-            self.parameters['region'] = parsed_region
-        elif region:
-            self.parameters['region'] = region
-        else:
-            self.parameters['region'] = None
+        self.parameters['region'] = parsed_globals.region
 
     def check_endpoint_url(self, parsed_globals):
         """
@@ -789,6 +764,7 @@ def check_endpoint_url(self, parsed_globals):
         else:
             self.parameters['endpoint_url'] = None
 
+
 # This is a dictionary useful for automatically adding the different commands,
 # the amount of arguments it takes, and the optional parameters that can appear
 # on the same line as the command.  It also contains descriptions and usage


Test patch:
diff --git a/tests/integration/customizations/s3/test_plugin.py b/tests/integration/customizations/s3/test_plugin.py
--- a/tests/integration/customizations/s3/test_plugin.py
+++ b/tests/integration/customizations/s3/test_plugin.py
@@ -527,6 +527,14 @@ def test_ls_bucket(self):
         p = aws('s3 ls')
         self.assert_no_errors(p)
 
+    def test_ls_with_no_env_vars(self):
+        # By default, the aws() function injects
+        # an AWS_DEFAULT_REGION into the env var of the
+        # process.  We're verifying that a region does *not*
+        # need to be set anywhere.
+        p = aws('s3 ls', env_vars={})
+        self.assert_no_errors(p)
+
     def test_ls_bucket_with_s3_prefix(self):
         p = aws('s3 ls s3://')
         self.assert_no_errors(p)
diff --git a/tests/unit/customizations/s3/test_s3.py b/tests/unit/customizations/s3/test_s3.py
--- a/tests/unit/customizations/s3/test_s3.py
+++ b/tests/unit/customizations/s3/test_s3.py
@@ -369,7 +369,7 @@ def test_check_path_type_pass(self):
 
         for cmd in cmds.keys():
             cmd_param = CommandParameters(self.session, cmd, {})
-            cmd_param.check_region([])
+            cmd_param.check_region(mock.Mock())
             correct_paths = cmds[cmd]
             for path_args in correct_paths:
                 cmd_param.check_path_type(combos[path_args])
@@ -397,7 +397,7 @@ def test_check_path_type_fail(self):
 
         for cmd in cmds.keys():
             cmd_param = CommandParameters(self.session, cmd, {})
-            cmd_param.check_region([])
+            cmd_param.check_region(mock.Mock())
             wrong_paths = cmds[cmd]
             for path_args in wrong_paths:
                 with self.assertRaises(TypeError):
@@ -423,7 +423,7 @@ def test_check_src_path_pass(self):
         for filename in files:
             parameters['dir_op'] = filename[1]
             cmd_parameter = CommandParameters(self.session, 'put', parameters)
-            cmd_parameter.check_region([])
+            cmd_parameter.check_region(mock.Mock())
             cmd_parameter.check_src_path(filename[0])
 
     def test_check_force(self):
@@ -434,23 +434,6 @@ def test_check_force(self):
         cmd_params.parameters['src'] = 's3://mybucket'
         cmd_params.check_force(None)
 
-    def test_region(self):
-        # This tests the ability to specify the region and throw an error
-        # if a region is never specified whether if it is an environment
-        # variable, config file, or parsed global.
-        cmd_params = CommandParameters(self.session, 'mb', {})
-        parser = argparse.ArgumentParser()
-        parser.add_argument('--region', nargs=1)
-        parser.add_argument('--test', action='store_true')
-        parsed_args = parser.parse_args(['--region', 'eu-west-1'])
-        cmd_params.check_region(parsed_args)
-        self.assertEqual(cmd_params.parameters['region'][0], 'eu-west-1')
-
-        cmd_params2 = CommandParameters(self.mock, 'mb', {})
-        parsed_args2 = parser.parse_args(['--test'])
-        with self.assertRaises(Exception):
-            cmd_params2.check_region(parsed_args2)
-
 
 class HelpDocTest(BaseAWSHelpOutputTest):
     def setUp(self):