Repository: minio/minio-py
Pull request #881 (2020-04-10 04:52:39)

fix formatting as per pep8 in copy_conditions.py


Patch:
diff --git a/minio/api.py b/minio/api.py
index 25a1bf6..bdfc70e 100644
--- a/minio/api.py
+++ b/minio/api.py
@@ -71,11 +71,12 @@ from .helpers import (get_target_url, is_non_empty_string,
                       get_sha256_hexdigest, get_md5_base64digest,
                       optimal_part_info,
                       is_valid_bucket_name, read_full,
-                      get_s3_region_from_endpoint, is_valid_sse_object, is_valid_sse_c_object,
-                      is_valid_source_sse_object,
-                      is_valid_bucket_notification_config, is_valid_policy_type,
-                      mkdir_p, dump_http, amzprefix_user_metadata,
-                      is_supported_header, is_amz_header)
+                      get_s3_region_from_endpoint, is_valid_sse_object,
+                      is_valid_sse_c_object, is_valid_source_sse_object,
+                      is_valid_bucket_notification_config,
+                      is_valid_policy_type, mkdir_p, dump_http,
+                      amzprefix_user_metadata, is_supported_header,
+                      is_amz_header)
 from .helpers import (MAX_PART_SIZE,
                       MAX_POOL_SIZE,
                       MIN_PART_SIZE,
@@ -116,7 +117,7 @@ _DEFAULT_USER_AGENT = 'MinIO {0} {1}'.format(
 
 
 # Duration of 7 days in seconds
-_MAX_EXPIRY_TIME = 604800 # 7 days in seconds
+_MAX_EXPIRY_TIME = 604800  # 7 days in seconds
 
 # Number of parallel workers which upload parts
 _PARALLEL_UPLOADERS = 3
@@ -153,6 +154,7 @@ class Minio(object):
     object in each process, and not share it between processes.
 
     """
+
     def __init__(self, endpoint, access_key=None,
                  secret_key=None,
                  session_token=None,
@@ -165,27 +167,19 @@ class Minio(object):
         is_valid_endpoint(endpoint)
 
         # Validate http client has correct base class.
-        if http_client and not isinstance(http_client, urllib3.poolmanager.PoolManager):
-            raise InvalidArgumentError('HTTP client should be of instance `urllib3.poolmanager.PoolManager`')
-
+        if http_client and not isinstance(
+                http_client,
+                urllib3.poolmanager.PoolManager):
+            raise InvalidArgumentError(
+                'HTTP client should be of instance'
+                ' `urllib3.poolmanager.PoolManager`'
+            )
 
         # Default is a secured connection.
-        endpoint_url = 'https://' + endpoint
-        accelerate_endpoint_url = 'https://s3-accelerate.amazonaws.com'
-        if not secure:
-            endpoint_url = 'http://' + endpoint
-            accelerate_endpoint_url = 'http://s3-accelerate.amazonaws.com'
-
-        # Parse url endpoints.
-        url_components = urlsplit(endpoint_url)
-
-        # Extract region if possible from endpoint.
-        if not region:
-            region = get_s3_region_from_endpoint(endpoint)
-
-        self._region = region
+        scheme = 'https://' if secure else 'http://'
+        self._region = region or get_s3_region_from_endpoint(endpoint)
         self._region_map = dict()
-        self._endpoint_url = url_components.geturl()
+        self._endpoint_url = urlsplit(scheme + endpoint).geturl()
         self._is_ssl = secure
         self._access_key = access_key
         self._secret_key = secret_key
@@ -193,43 +187,31 @@ class Minio(object):
         self._user_agent = _DEFAULT_USER_AGENT
         self._trace_output_stream = None
         self._enable_s3_accelerate = False
-        self._accelerate_endpoint_url = accelerate_endpoint_url
-
-        # Set credentials if possible
-
-        if credentials is not None:
-            self._credentials = credentials
-        else:
-            self._credentials = Credentials(
-                provider= Chain(
-                    providers=[
-                        Static(access_key, secret_key, session_token),
-                        EnvAWS(),
-                        EnvMinio(),
-                        IamEc2MetaData(),
-                    ]
-                )
+        self._accelerate_endpoint_url = scheme + 's3-accelerate.amazonaws.com'
+        self._credentials = credentials or Credentials(
+            provider=Chain(
+                providers=[
+                    Static(access_key, secret_key, session_token),
+                    EnvAWS(),
+                    EnvMinio(),
+                    IamEc2MetaData(),
+                ]
             )
+        )
 
         # Load CA certificates from SSL_CERT_FILE file if set
-        ca_certs = os.environ.get('SSL_CERT_FILE')
-        if not ca_certs:
-            ca_certs = certifi.where()
-
-        if not http_client:
-            self._http = urllib3.PoolManager(
-                timeout=urllib3.Timeout.DEFAULT_TIMEOUT,
-                maxsize=MAX_POOL_SIZE,
-                        cert_reqs='CERT_REQUIRED',
-                        ca_certs=ca_certs,
-                        retries=urllib3.Retry(
-                            total=5,
-                            backoff_factor=0.2,
-                            status_forcelist=[500, 502, 503, 504]
-                        )
+        ca_certs = os.environ.get('SSL_CERT_FILE') or certifi.where()
+        self._http = http_client or urllib3.PoolManager(
+            timeout=urllib3.Timeout.DEFAULT_TIMEOUT,
+            maxsize=MAX_POOL_SIZE,
+            cert_reqs='CERT_REQUIRED',
+            ca_certs=ca_certs,
+            retries=urllib3.Retry(
+                total=5,
+                backoff_factor=0.2,
+                status_forcelist=[500, 502, 503, 504]
             )
-        else:
-            self._http = http_client
+        )
 
     # Set application information.
     def set_app_info(self, app_name, app_version):
@@ -282,8 +264,8 @@ class Minio(object):
 
         # Strip 80/443 ports since curl & browsers do not
         # send them in Host header.
-        if (scheme == 'http' and parsed_url.port == 80) or\
-        (scheme == 'https' and parsed_url.port == 443):
+        if (scheme == 'http' and parsed_url.port == 80) or (
+                scheme == 'https' and parsed_url.port == 443):
             host = parsed_url.hostname
 
         if 's3.amazonaws.com' in host:
@@ -306,10 +288,10 @@ class Minio(object):
         is_non_empty_string(object_name)
 
         content = xml_marshal_select(opts)
-        url_values = dict()
-        url_values["select"] = ""
-        url_values["select-type"] = "2"
-
+        url_values = {
+            "select": "",
+            "select-type": "2",
+        }
         headers = {
             'Content-Length': str(len(content)),
             'Content-Md5': get_md5_base64digest(content)
@@ -348,14 +330,13 @@ class Minio(object):
         is_valid_bucket_name(bucket_name, True)
 
         # Default region for all requests.
-        region = 'us-east-1'
-        if self._region:
-            region = self._region
-            # Validate if caller requested bucket location is same as current region
-            if self._region != location:
-                raise InvalidArgumentError("Configured region {0}, requested"
-                                           " {1}".format(self._region,
-                                                         location))
+        region = self._region or 'us-east-1'
+        # Validate if caller requested bucket location is same as current
+        # region
+        if self._region and self._region != location:
+            raise InvalidArgumentError(
+                "Configured region {0}, requested {1}".format(
+                    self._region, location))
 
         method = 'PUT'
         # Set user agent once before the request.
@@ -365,10 +346,9 @@ class Minio(object):
         if location and location != 'us-east-1':
             content = xml_marshal_bucket_constraint(location)
             headers['Content-Length'] = str(len(content))
+            headers['Content-Md5'] = get_md5_base64digest(content)
 
         content_sha256_hex = get_sha256_hexdigest(content)
-        if content:
-            headers['Content-Md5'] = get_md5_base64digest(content)
 
         # In case of Amazon S3.  The make bucket issued on already
         # existing bucket would fail with 'AuthorizationMalformed'
@@ -413,10 +393,7 @@ class Minio(object):
         headers = {'User-Agent': self._user_agent}
 
         # default for all requests.
-        region = 'us-east-1'
-        # region is set then use the region.
-        if self._region:
-            region = self._region
+        region = self._region or 'us-east-1'
 
         # Get signature headers if any.
         headers = sign_v4(method, url, region,
@@ -437,7 +414,8 @@ class Minio(object):
         try:
             return parse_list_buckets(response.data)
         except InvalidXMLError:
-            if self._endpoint_url.endswith("s3.amazonaws.com") and (not self._access_key or not self._secret_key):
+            if self._endpoint_url.endswith("s3.amazonaws.com") and (
+                    not self._access_key or not self._secret_key):
                 raise AccessDenied(response)
 
     def bucket_exists(self, bucket_name):
@@ -451,7 +429,7 @@ class Minio(object):
 
         try:
             self._url_open('HEAD', bucket_name=bucket_name)
-        # If the bucket has not been created yet, MinIO will return a "NoSuchBucket" error.
+        # If bucket has not been created yet, MinIO returns NoSuchBucket error.
         except NoSuchBucket:
             return False
         except ResponseError:
@@ -485,8 +463,8 @@ class Minio(object):
 
     def delete_bucket_policy(self, bucket_name):
         self._url_open("DELETE",
-                        bucket_name=bucket_name,
-                        query={"policy": ""})
+                       bucket_name=bucket_name,
+                       query={"policy": ""})
 
     def set_bucket_policy(self, bucket_name, policy):
         """
@@ -505,11 +483,11 @@ class Minio(object):
         }
         content_sha256_hex = get_sha256_hexdigest(policy)
         self._url_open("PUT",
-                        bucket_name=bucket_name,
-                        query={"policy": ""},
-                        headers=headers,
-                        body=policy,
-                        content_sha256=content_sha256_hex)
+                       bucket_name=bucket_name,
+                       query={"policy": ""},
+                       headers=headers,
+                       body=policy,
+                       content_sha256=content_sha256_hex)
 
     def get_bucket_notification(self, bucket_name):
         """
@@ -579,38 +557,21 @@ class Minio(object):
             content_sha256=content_sha256_hex
         )
 
-    # put_bucket_encryption sets default encryption configuration on an existing bucket.
+    # put_bucket_encryption sets default encryption configuration on an
+    # existing bucket.
     def put_bucket_encryption(self, bucket_name, enc_config):
         """
         Set default encryption configuration on a given bucket.
 
         :param bucket_name: Bucket name.
-        :param enc_config: Default encryption configuration in dictionary format.
+        :param enc_config: Default encryption configuration in dictionary
+                           format.
         """
         is_valid_bucket_name(bucket_name, False)
 
         # 'Rule' is a list, so we need to go through each one of
         # its key/value pair and collect the encryption values.
         rules = enc_config['ServerSideEncryptionConfiguration']['Rule']
-        rule_list = list()
-        if isinstance(rules, list):
-            for apply_enc in rules:
-                rule_list.append(apply_enc['ApplyServerSideEncryptionByDefault'])
-                # As soon as we get to the first default encryption setting,
-                # we break the loop. That is because, at this point, only
-                # a single 'Rule' entry is allowed/supported. This is a server
-                # side restriction and and it is validated on the server side.
-                break
-        elif isinstance(rules, dict):
-            # This check enables user to provide a single 'Rule' as a
-            # dictionary instead of a list.
-            # This is just an extra convenience.
-            rule_list.append(rules["ApplyServerSideEncryptionByDefault"])
-        else:
-            raise InvalidArgumentError(
-                'Encryption configuration must be a "dict" with a "list" type of "Rule"s'
-            )
-
         enc_config_xml = xml_marshal_bucket_encryption(rules)
 
         headers = {
@@ -619,12 +580,12 @@ class Minio(object):
         }
         content_sha256_hex = get_sha256_hexdigest(enc_config_xml)
         self._url_open("PUT",
-                        bucket_name=bucket_name,
-                        query={"encryption": ""},
-                        headers=headers,
-                        body=enc_config_xml,
-                        content_sha256=content_sha256_hex
-                        )
+                       bucket_name=bucket_name,
+                       query={"encryption": ""},
+                       headers=headers,
+                       body=enc_config_xml,
+                       content_sha256=content_sha256_hex
+                       )
 
     def get_bucket_encryption(self, bucket_name):
         """
@@ -678,12 +639,10 @@ class Minio(object):
         is_valid_bucket_name(bucket_name, False)
 
         # If someone explicitly set prefix to None convert it to empty string.
-        if prefix is None:
-            prefix = ''
+        prefix = prefix or ''
 
         # If someone explicitly set suffix to None convert it to empty string.
-        if suffix is None:
-            suffix = ''
+        suffix = suffix or ''
 
         url_components = urlsplit(self._endpoint_url)
         if url_components.hostname == 's3.amazonaws.com':
@@ -706,7 +665,7 @@ class Minio(object):
                         if hasattr(line, 'decode'):
                             line = line.decode('utf-8')
                         event = json.loads(line)
-                        if event['Records'] is not None:
+                        if event['Records']:
                             yield event
             except JSONDecodeError:
                 response.close()
@@ -740,7 +699,8 @@ class Minio(object):
                                    file_size, content_type, metadata, sse,
                                    progress, part_size)
 
-    def fget_object(self, bucket_name, object_name, file_path, request_headers=None, sse=None):
+    def fget_object(self, bucket_name, object_name, file_path,
+                    request_headers=None, sse=None):
         """
         Retrieves an object from a bucket and writes at file_path.
 
@@ -750,7 +710,8 @@ class Minio(object):
         :param bucket_name: Bucket to read object from.
         :param object_name: Name of the object to read.
         :param file_path: Local file path to save the object.
-        :param request_headers: Any additional headers to be added with GET request.
+        :param request_headers: Any additional headers to be added with GET
+                                request.
         """
         is_valid_bucket_name(bucket_name, False)
         is_non_empty_string(object_name)
@@ -774,11 +735,13 @@ class Minio(object):
             file_statinfo = os.stat(file_part_path)
 
             # Get partial object.
-            response = self._get_partial_object(bucket_name, object_name,
-                                                offset=file_statinfo.st_size,
-                                                length=0,
-                                                request_headers=request_headers,
-                                                sse=sse)
+            response = self._get_partial_object(
+                bucket_name, object_name,
+                offset=file_statinfo.st_size,
+                length=0,
+                request_headers=request_headers,
+                sse=sse
+            )
 
             # Save content_size to verify if we wrote more data.
             content_size = int(response.headers['content-length'])
@@ -794,27 +757,26 @@ class Minio(object):
 
             # Verify if we wrote data properly.
             if total_written < content_size:
-                msg = 'Data written {0} bytes is smaller than the ' \
-                      'specified size {1} bytes'.format(total_written,
-                                                        content_size)
+                msg = ('Data written {0} bytes is smaller than the specified'
+                       ' size {1} bytes').format(total_written, content_size)
                 raise InvalidSizeError(msg)
 
             if total_written > content_size:
-                msg = 'Data written {0} bytes is in excess than the ' \
-                      'specified size {1} bytes'.format(total_written,
-                                                        content_size)
+                msg = ('Data written {0} bytes is in excess than the specified'
+                       ' size {1} bytes').format(total_written, content_size)
                 raise InvalidSizeError(msg)
 
-        #Delete existing file to be compatible with Windows
+        # Delete existing file to be compatible with Windows
         if os.path.exists(file_path):
             os.remove(file_path)
-        #Rename with destination file path
+        # Rename with destination file path
         os.rename(file_part_path, file_path)
 
         # Return the stat
         return stat
 
-    def get_object(self, bucket_name, object_name, request_headers=None, sse=None):
+    def get_object(self, bucket_name, object_name, request_headers=None,
+                   sse=None):
         """
         Retrieves an object from a bucket.
 
@@ -829,7 +791,8 @@ class Minio(object):
 
         :param bucket_name: Bucket to read object from
         :param object_name: Name of object to read
-        :param request_headers: Any additional headers to be added with GET request.
+        :param request_headers: Any additional headers to be added with GET
+                                request.
         :return: :class:`urllib3.response.HTTPResponse` object.
 
         """
@@ -841,7 +804,8 @@ class Minio(object):
                                         request_headers=request_headers,
                                         sse=sse)
 
-    def get_partial_object(self, bucket_name, object_name, offset=0, length=0, request_headers=None, sse=None):
+    def get_partial_object(self, bucket_name, object_name, offset=0, length=0,
+                           request_headers=None, sse=None):
         """
         Retrieves an object from a bucket.
 
@@ -862,7 +826,8 @@ class Minio(object):
            Must be >= 0.
         :param length: Optional number of bytes to retrieve.
            Must be an integer.
-        :param request_headers: Any additional headers to be added with GET request.
+        :param request_headers: Any additional headers to be added with GET
+                                request.
         :return: :class:`urllib3.response.HTTPResponse` object.
 
         """
@@ -899,20 +864,19 @@ class Minio(object):
         headers = {}
 
         # Preserving the user-defined metadata in headers
-        if metadata is not None:
+        if metadata:
             headers = amzprefix_user_metadata(metadata)
             headers["x-amz-metadata-directive"] = "REPLACE"
 
         if conditions:
-            for k, v in conditions.items():
-                headers[k] = v
+            headers.update(conditions)
 
         # Source argument to copy_object can only be of type copy_SSE_C
         if source_sse:
             is_valid_source_sse_object(source_sse)
             headers.update(source_sse.marshal())
 
-        #Destination argument to copy_object cannot be of type copy_SSE_C
+        # Destination argument to copy_object cannot be of type copy_SSE_C
         if sse:
             is_valid_sse_object(sse)
             headers.update(sse.marshal())
@@ -937,7 +901,8 @@ class Minio(object):
         Examples:
          file_stat = os.stat('hello.txt')
          with open('hello.txt', 'rb') as data:
-             minio.put_object('foo', 'bar', data, file_stat.st_size, 'text/plain')
+             minio.put_object('foo', 'bar', data, file_stat.st_size,
+                              'text/plain')
 
         - For length lesser than 5MB put_object automatically
           does single Put operation.
@@ -968,7 +933,8 @@ class Minio(object):
 
         if not callable(getattr(data, 'read')):
             raise ValueError(
-                'Invalid input data does not implement a callable read() method')
+                'Invalid input data does not implement'
+                ' a callable read() method')
 
         if length > (part_size * MAX_MULTIPART_COUNT):
             raise InvalidArgumentError('Part size * max_parts(10000) is '
@@ -986,9 +952,7 @@ class Minio(object):
             metadata = {}
 
         metadata = amzprefix_user_metadata(metadata)
-
-        metadata['Content-Type'] = 'application/octet-stream' if \
-            not content_type else content_type
+        metadata['Content-Type'] = content_type or 'application/octet-stream'
 
         if length > part_size:
             return self._stream_put_object(bucket_name, object_name,
@@ -1047,8 +1011,7 @@ class Minio(object):
         is_valid_bucket_name(bucket_name, False)
 
         # If someone explicitly set prefix to None convert it to empty string.
-        if prefix is None:
-            prefix = ''
+        prefix = prefix or ''
 
         method = 'GET'
 
@@ -1071,12 +1034,15 @@ class Minio(object):
                                       bucket_name=bucket_name,
                                       query=query,
                                       headers=headers)
-            objects, is_truncated, marker = parse_list_objects(response.data,
-                                                               bucket_name=bucket_name)
+            objects, is_truncated, marker = parse_list_objects(
+                response.data,
+                bucket_name=bucket_name
+            )
             for obj in objects:
                 yield obj
 
-    def list_objects_v2(self, bucket_name, prefix='', recursive=False, start_after=''):
+    def list_objects_v2(self, bucket_name, prefix='', recursive=False,
+                        start_after=''):
         """
         List objects in the given bucket using the List objects V2 API.
 
@@ -1123,11 +1089,8 @@ class Minio(object):
         is_valid_bucket_name(bucket_name, False)
 
         # If someone explicitly set prefix to None convert it to empty string.
-        if prefix is None:
-            prefix = ''
-
-        if start_after is None:
-            start_after = ''
+        prefix = prefix or ''
+        start_after = start_after or ''
 
         # Initialize query parameters.
         query = {
@@ -1143,7 +1106,7 @@ class Minio(object):
         continuation_token = None
         is_truncated = True
         while is_truncated:
-            if continuation_token is not None:
+            if continuation_token:
                 query['continuation-token'] = continuation_token
             response = self._url_open(method='GET',
                                       bucket_name=bucket_name,
@@ -1180,7 +1143,7 @@ class Minio(object):
         content_type = response.headers.get('content-type', '')
         last_modified = response.headers.get('last-modified')
 
-        ## Capture only custom metadata.
+        # Capture only custom metadata.
         custom_metadata = dict()
         for k in response.headers:
             if is_supported_header(k) or is_amz_header(k):
@@ -1282,8 +1245,7 @@ class Minio(object):
                 # clear batch for next set of items
                 obj_batch = []
 
-    def list_incomplete_uploads(self, bucket_name, prefix='',
-                                recursive=False):
+    def list_incomplete_uploads(self, bucket_name, prefix='', recursive=False):
         """
         List all in-complete uploads for a given bucket.
 
@@ -1331,18 +1293,19 @@ class Minio(object):
     def _list_incomplete_uploads(self, bucket_name, prefix='',
                                  recursive=False, is_aggregate_size=True):
         """
-        List incomplete uploads list all previously uploaded incomplete multipart objects.
+        List incomplete uploads list all previously uploaded incomplete
+        multipart objects.
 
         :param bucket_name: Bucket name to list uploaded objects.
         :param prefix: String specifying objects returned must begin with.
-        :param recursive: If yes, returns all incomplete objects for a specified prefix.
+        :param recursive: If yes, returns all incomplete objects for a
+                          specified prefix.
         :return: An generator of incomplete uploads in alphabetical order.
         """
         is_valid_bucket_name(bucket_name, False)
 
         # If someone explicitly set prefix to None convert it to empty string.
-        if prefix is None:
-            prefix = ''
+        prefix = prefix or ''
 
         # Initialize query parameters.
         query = {
@@ -1436,9 +1399,8 @@ class Minio(object):
         is_valid_bucket_name(bucket_name, False)
         is_non_empty_string(object_name)
 
-        recursive = True
         uploads = self._list_incomplete_uploads(bucket_name, object_name,
-                                                recursive,
+                                                recursive=True,
                                                 is_aggregate_size=False)
         for upload in uploads:
             if object_name == upload.object_name:
@@ -1446,11 +1408,11 @@ class Minio(object):
                                                upload.upload_id)
 
     def presigned_url(self, method,
-                    bucket_name,
-                    object_name,
-                    expires=timedelta(days=7),
-                    response_headers=None,
-                    request_date=None):
+                      bucket_name,
+                      object_name,
+                      expires=timedelta(days=7),
+                      response_headers=None,
+                      request_date=None):
         """
         Presigns a method on an object and provides a url
 
@@ -1478,11 +1440,11 @@ class Minio(object):
         is_valid_bucket_name(bucket_name, False)
         is_non_empty_string(object_name)
 
-        if expires.total_seconds() < 1 or \
-           expires.total_seconds() > _MAX_EXPIRY_TIME:
-            raise InvalidArgumentError('Expires param valid values'
-                                       ' are between 1 sec to'
-                                       ' {0} secs'.format(_MAX_EXPIRY_TIME))
+        if (expires.total_seconds() < 1 or
+                expires.total_seconds() > _MAX_EXPIRY_TIME):
+            raise InvalidArgumentError(
+                'Expires param valid values are between 1 sec to'
+                ' {0} secs'.format(_MAX_EXPIRY_TIME))
 
         region = self._get_bucket_region(bucket_name)
         endpoint_url = self._endpoint_url
@@ -1495,7 +1457,7 @@ class Minio(object):
                              bucket_region=region)
 
         return presign_v4(method, url,
-                          credentials = self._credentials,
+                          credentials=self._credentials,
                           region=region,
                           expires=int(expires.total_seconds()),
                           response_headers=response_headers,
@@ -1584,8 +1546,8 @@ class Minio(object):
         date = datetime.utcnow()
         iso8601_date = date.strftime("%Y%m%dT%H%M%SZ")
         region = self._get_bucket_region(post_policy.form_data['bucket'])
-        credential_string = generate_credential_string(self._credentials.get().access_key,
-                                                       date, region)
+        credential_string = generate_credential_string(
+            self._credentials.get().access_key, date, region)
 
         policy = [
             ('eq', '$x-amz-date', iso8601_date),
@@ -1617,7 +1579,8 @@ class Minio(object):
 
     # All private functions below.
     def _get_partial_object(self, bucket_name, object_name,
-                            offset=0, length=0, request_headers=None, sse=None):
+                            offset=0, length=0, request_headers=None,
+                            sse=None):
         """Retrieves an object from a bucket.
 
         Optionally takes an offset and length of data to retrieve.
@@ -1647,24 +1610,20 @@ class Minio(object):
         is_valid_bucket_name(bucket_name, False)
         is_non_empty_string(object_name)
 
-        headers = {}
-        if request_headers:
-            headers = request_headers
+        headers = request_headers or {}
 
-        if offset != 0 or length != 0:
-            request_range = '{}-{}'.format(
-                offset, "" if length == 0 else offset + length - 1
-            )
-            headers['Range'] = 'bytes=' + request_range
+        if offset or length:
+            headers['Range'] = 'bytes={}-{}'.format(
+                offset, offset + length - 1 if length else "")
 
         if sse:
             headers.update(sse.marshal())
 
         return self._url_open('GET',
-                               bucket_name=bucket_name,
-                               object_name=object_name,
-                               headers=headers,
-                               preload_content=False)
+                              bucket_name=bucket_name,
+                              object_name=object_name,
+                              headers=headers,
+                              preload_content=False)
 
     def _do_put_object(self, bucket_name, object_name, part_data,
                        part_size, upload_id='', part_number=0,
@@ -1695,10 +1654,9 @@ class Minio(object):
         }
 
         md5_base64 = ''
-        sha256_hex = ''
+        sha256_hex = _UNSIGNED_PAYLOAD
         if self._is_ssl:
             md5_base64 = get_md5_base64digest(part_data)
-            sha256_hex = _UNSIGNED_PAYLOAD
         else:
             sha256_hex = get_sha256_hexdigest(part_data)
 
@@ -1737,8 +1695,8 @@ class Minio(object):
         return response.headers['etag'].replace('"', '')
 
     def _upload_part_routine(self, part_info):
-        bucket_name, object_name, upload_id, \
-                part_number, part_data, sse, progress = part_info
+        (bucket_name, object_name, upload_id, part_number,
+         part_data, sse, progress) = part_info
         # Initiate multipart put.
         etag = self._do_put_object(bucket_name, object_name, part_data,
                                    len(part_data), upload_id,
@@ -1767,7 +1725,9 @@ class Minio(object):
         is_non_empty_string(object_name)
         if not callable(getattr(data, 'read')):
             raise ValueError(
-                'Invalid input data does not implement a callable read() method')
+                'Invalid input data does not implement'
+                ' a callable read() method'
+            )
 
         # get upload id.
         upload_id = self._new_multipart_upload(bucket_name, object_name,
@@ -1794,8 +1754,9 @@ class Minio(object):
                                  else last_part_size)
 
             part_data = read_full(data, current_part_size)
-            pool.add_task(self._upload_part_routine, (bucket_name, object_name, upload_id,
-                                                      part_number, part_data, sse, progress))
+            pool.add_task(self._upload_part_routine, (
+                bucket_name, object_name, upload_id, part_number, part_data,
+                sse, progress))
 
         try:
             upload_result = pool.result()
@@ -1953,19 +1914,10 @@ class Minio(object):
         :return: Region of bucket name.
         """
 
-        # Region set in constructor, return right here.
-        if self._region:
-            return self._region
-
-        # get bucket location for Amazon S3.
-        region = 'us-east-1'  # default to US standard.
-        if bucket_name in self._region_map:
-            region = self._region_map[bucket_name]
-        else:
+        region = self._region or self._region_map.get(bucket_name)
+        if not region:
             region = self._get_bucket_location(bucket_name)
             self._region_map[bucket_name] = region
-
-        # Success.
         return region
 
     def _get_bucket_location(self, bucket_name):
@@ -1975,23 +1927,21 @@ class Minio(object):
         :param bucket_name: Fetches location of the Bucket name.
         :return: location of bucket name is returned.
         """
-        method = 'GET'
-        url = self._endpoint_url + '/' + bucket_name + '?location='
-        headers = {}
-        # default for all requests.
-        region = 'us-east-1'
-
         # Region is set override.
         if self._region:
             return self._region
 
         # For anonymous requests no need to get bucket location.
-        if self._credentials.get().access_key is None or self._credentials.get().secret_key is None:
+        if not (self._credentials.get().access_key and
+                self._credentials.get().secret_key):
             return 'us-east-1'
 
+        method = 'GET'
+        url = self._endpoint_url + '/' + bucket_name + '?location='
+
         # Get signature headers if any.
-        headers = sign_v4(method, url, region,
-                          headers,
+        headers = sign_v4(method, url, "us-east-1",
+                          {},
                           self._credentials,
                           None, datetime.utcnow())
 
@@ -2028,8 +1978,7 @@ class Minio(object):
 
         # Set user agent once before executing the request.
         fold_case_headers['User-Agent'] = self._user_agent
-        for header in headers:
-            fold_case_headers[header] = headers[header]
+        fold_case_headers.update(headers)
 
         # Get bucket region.
         region = self._get_bucket_region(bucket_name)
@@ -2054,8 +2003,7 @@ class Minio(object):
             dump_http(method, url, fold_case_headers, response,
                       self._trace_output_stream)
 
-        if response.status != 200 and response.status != 204 \
-           and response.status != 206:
+        if response.status not in [200, 204, 206]:
             # Upon any response error invalidate the region cache
             # proactively for the bucket name.
             self._delete_bucket_region(bucket_name)
@@ -2065,21 +2013,13 @@ class Minio(object):
             if not preload_content:
                 response.release_conn()
 
-            supported_methods = [
-                'HEAD',
-                'GET',
-                'POST',
-                'PUT',
-                'DELETE'
-            ]
-
-            if method in supported_methods:
+            if method in ['DELETE', 'GET', 'HEAD', 'POST', 'PUT']:
                 raise ResponseError(response,
                                     method,
                                     bucket_name,
                                     object_name).get_exception()
-            else:
-                raise ValueError('Unsupported method returned'
-                                 ' error: {0}'.format(response.status))
+
+            raise ValueError('Unsupported method returned'
+                             ' error: {0}'.format(response.status))
 
         return response
diff --git a/minio/compat.py b/minio/compat.py
index 1743eef..2811d1e 100644
--- a/minio/compat.py
+++ b/minio/compat.py
@@ -40,26 +40,20 @@ if _is_py2:
     from Queue import Empty
     queue_empty = Empty
 
-    from urllib import quote
-    _urlencode = quote
+    from urllib import quote, unquote
 
-    from urllib import unquote
-    urldecode = unquote
+    from urlparse import urlsplit, parse_qs
 
-    import urlparse
-    urlsplit = urlparse.urlsplit
-    parse_qs = urlparse.parse_qs
-
-    ## Create missing types.
+    # Create missing types.
     bytes = str
 
-    ## Update better types.
+    # Update better types.
     builtin_range = range
     range = xrange
     builtin_str = str
     str = unicode
 
-    ## Add missing imports
+    # Add missing imports
     basestring = basestring
 elif _is_py3:
     from queue import Queue
@@ -68,41 +62,37 @@ elif _is_py3:
     from queue import Empty
     queue_empty = Empty
 
-    from urllib.request import quote
-    _urlencode = quote
-
-    from urllib.request import unquote
-    urldecode = unquote
+    from urllib.parse import quote, unquote, urlsplit, parse_qs
+    unquote = unquote  # to get rid of F401
+    urlsplit = urlsplit  # to get rid of F401
+    parse_qs = parse_qs  # to get rid of F401
 
-    import urllib.parse
-    urlsplit = urllib.parse.urlsplit
-    parse_qs = urllib.parse.parse_qs
-
-    ## Create types to compat with py2.
+    # Create types to compat with py2.
     builtin_range = range
     builtin_str = str
 
-    ## Create missing types.
+    # Create missing types.
     basestring = (str, bytes)
     long = int
 
-    ## Add missing imports
+    # Add missing imports
     bytes = bytes
     range = range
     str = str
 
-numeric_types = (int, long, float)
 
-def urlencode(resource):
+# Note earlier versions of minio.compat exposed urllib.quote as urlencode
+def _quote(resource):
     """
-    This implementation of urlencode supports all unicode characters
+    This implementation of urllib.quote supports all unicode characters
 
     :param: resource: Resource value to be url encoded.
     """
     if isinstance(resource, str):
-        return _urlencode(resource.encode('utf-8'))
+        return quote(resource.encode('utf-8'))
+
+    return quote(resource)
 
-    return _urlencode(resource)
 
 def queryencode(query):
     """
@@ -110,4 +100,4 @@ def queryencode(query):
 
     :param: query: Query value to be url encoded.
     """
-    return urlencode(query).replace('/', '%2F')
+    return _quote(query).replace('/', '%2F')
diff --git a/minio/copy_conditions.py b/minio/copy_conditions.py
index 82f1588..6f68b53 100644
--- a/minio/copy_conditions.py
+++ b/minio/copy_conditions.py
@@ -40,6 +40,8 @@ from .helpers import is_non_empty_string
 #      key: "x-amz-copy-if-modified-since",
 #      value: "Tue, 15 Nov 1994 12:45:26 GMT",
 #
+
+
 class CopyConditions(collectionsAbc.MutableMapping):
     """
     A :class:`CopyConditions <CopyConditions>` collection of
@@ -51,9 +53,9 @@ class CopyConditions(collectionsAbc.MutableMapping):
         - x-amz-copy-source-if-modified-since
 
     """
+
     def __init__(self, *args, **kwargs):
-        self._store = dict()
-        self.update(dict(*args, **kwargs))  # use the free update to set keys
+        self._store = dict(*args, **kwargs)
 
     def __getitem__(self, key):
         return self._store[key]
diff --git a/minio/credentials/aws_iam.py b/minio/credentials/aws_iam.py
index 1d26c84..abf5edd 100644
--- a/minio/credentials/aws_iam.py
+++ b/minio/credentials/aws_iam.py
@@ -14,29 +14,28 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import os, json, urllib3, datetime
+import json
+import urllib3
+import datetime
 from .credentials import Provider, Value, Expiry
 from minio.error import ResponseError
 
-class IamEc2MetaData(Provider):
 
+class IamEc2MetaData(Provider):
     iam_security_creds_path = '/latest/meta-data/iam/security-credentials'
-
     default_expiry_window = datetime.timedelta(minutes=5)
 
     def __init__(self, endpoint=None):
         super(Provider, self).__init__()
-        if endpoint == "" or endpoint is None:
-            endpoint = "http://169.254.169.254"
-        self._endpoint = endpoint
+        self._endpoint = endpoint or "http://169.254.169.254"
         self._expiry = Expiry()
         self._http_client = urllib3.PoolManager(
-                retries=urllib3.Retry(
-                    total=5,
-                    backoff_factor=0.2,
-                    status_forcelist=[500, 502, 503, 504]
-                    )
-                )
+            retries=urllib3.Retry(
+                total=5,
+                backoff_factor=0.2,
+                status_forcelist=[500, 502, 503, 504]
+            )
+        )
 
     def request_cred_list(self):
         url = self._endpoint + self.iam_security_creds_path
@@ -68,7 +67,8 @@ class IamEc2MetaData(Provider):
 
         creds_name = role_names[0]
         role_creds = self.request_cred(creds_name)
-        expiration = datetime.datetime.strptime(role_creds['Expiration'], '%Y-%m-%dT%H:%M:%SZ')
+        expiration = datetime.datetime.strptime(
+            role_creds['Expiration'], '%Y-%m-%dT%H:%M:%SZ')
         self._expiry.set_expiration(expiration, self.default_expiry_window)
 
         return Value(
diff --git a/minio/credentials/chain.py b/minio/credentials/chain.py
index c9f7e8a..dbe96c0 100644
--- a/minio/credentials/chain.py
+++ b/minio/credentials/chain.py
@@ -16,6 +16,7 @@
 
 from .credentials import Provider, Value
 
+
 class Chain(Provider):
     def __init__(self, providers):
         super(Provider, self).__init__()
@@ -25,15 +26,11 @@ class Chain(Provider):
     def retrieve(self):
         for provider in self._providers:
             creds = provider.retrieve()
-            if ((creds.access_key is None or creds.access_key == "") and
-                (creds.secret_key is None or creds.secret_key == "")):
-                continue
-            self._current = provider
-            return creds
+            if creds.access_key and creds.secret_key:
+                self._current = provider
+                return creds
         self._current = None
         return Value()
 
     def is_expired(self):
-        if self._current == None:
-            return True
-        return self._current.is_expired()
+        return self._current.is_expired() if self._current else True
diff --git a/minio/credentials/credentials.py b/minio/credentials/credentials.py
index 3063e5c..f20bb9b 100644
--- a/minio/credentials/credentials.py
+++ b/minio/credentials/credentials.py
@@ -15,7 +15,8 @@
 # limitations under the License.
 
 from abc import ABCMeta, abstractmethod
-from datetime import datetime, timedelta
+from datetime import datetime
+
 
 class Value(object):
     def __init__(self, access_key=None, secret_key=None, session_token=None):
@@ -23,8 +24,8 @@ class Value(object):
         self.secret_key = secret_key
         self.session_token = session_token
 
-class Provider(object):
 
+class Provider(object):
     __metaclass__ = ABCMeta
 
     @abstractmethod
@@ -35,19 +36,19 @@ class Provider(object):
     def is_expired(self):
         pass
 
+
 class Expiry(object):
     def __init__(self):
         self._expiration = None
 
     def set_expiration(self, expiration, time_delta=None):
         self._expiration = expiration
-        if time_delta is not None:
+        if time_delta:
             self._expiration = self._expiration + time_delta
 
     def is_expired(self):
-        if self._expiration is None:
-            return True
-        return self._expiration < datetime.now()
+        return self._expiration < datetime.now() if self._expiration else True
+
 
 class Credentials(object):
     def __init__(self, forceRefresh=True, provider=None):
@@ -57,10 +58,7 @@ class Credentials(object):
 
     def get(self):
         if self.is_expired():
-            try:
-                creds = self._provider.retrieve()
-            except:
-                raise
+            creds = self._provider.retrieve()
             self._creds = creds
             self._forceRefresh = False
         return self._creds
diff --git a/minio/credentials/env_aws.py b/minio/credentials/env_aws.py
index 4f09f8c..ccb8af2 100644
--- a/minio/credentials/env_aws.py
+++ b/minio/credentials/env_aws.py
@@ -18,6 +18,7 @@ import os
 
 from .credentials import Provider, Value
 
+
 class EnvAWS(Provider):
     def __init__(self, retrieved=False):
         super(Provider, self).__init__()
@@ -25,15 +26,14 @@ class EnvAWS(Provider):
 
     def retrieve(self):
         self.retrieved = False
-
-        access_key = os.environ.get('AWS_ACCESS_KEY_ID')
-        if access_key == "":
-            access_key = os.environ.get('AWS_ACCESS_KEY')
-
-        secret = os.environ.get('AWS_SECRET_ACCESS_KEY')
-        if secret == "":
-            secret = os.environ.get('AWS_SECRET_KEY')
-
+        access_key = (
+            os.environ.get('AWS_ACCESS_KEY_ID') or
+            os.environ.get('AWS_ACCESS_KEY')
+        )
+        secret = (
+            os.environ.get('AWS_SECRET_ACCESS_KEY') or
+            os.environ.get('AWS_SECRET_KEY')
+        )
         self.retrieved = True
         return Value(
             access_key=access_key,
diff --git a/minio/credentials/env_minio.py b/minio/credentials/env_minio.py
index c285abb..0d06095 100644
--- a/minio/credentials/env_minio.py
+++ b/minio/credentials/env_minio.py
@@ -19,6 +19,7 @@ import os
 
 from .credentials import Provider, Value
 
+
 class EnvMinio(Provider):
     def __init__(self, retrieved=False):
         super(Provider, self).__init__()
@@ -26,15 +27,12 @@ class EnvMinio(Provider):
 
     def retrieve(self):
         self._retrieved = False
-
-        id = os.environ.get('MINIO_ACCESS_KEY')
-
+        access_key = os.environ.get('MINIO_ACCESS_KEY')
         secret = os.environ.get('MINIO_SECRET_KEY')
-
         self._retrieved = True
 
         return Value(
-            access_key=id,
+            access_key=access_key,
             secret_key=secret
         )
 
diff --git a/minio/credentials/file_aws_credentials.py b/minio/credentials/file_aws_credentials.py
index fe1c879..139ba77 100644
--- a/minio/credentials/file_aws_credentials.py
+++ b/minio/credentials/file_aws_credentials.py
@@ -19,26 +19,19 @@ import configparser
 
 from .credentials import Provider, Value
 
+
 class FileAWSCredentials(Provider):
     def __init__(self, filename=None, profile=None, retrieved=False):
         super(Provider, self).__init__()
-        self._filename = filename
-        self._profile = profile
+        self._filename = (
+            filename or
+            os.environ.get('AWS_SHARED_CREDENTIALS_FILE') or
+            os.path.join(os.environ.get('HOME'), '.aws', 'credentials')
+        )
+        self._profile = profile or os.environ.get('AWS_PROFILE') or "default"
         self._retrieved = retrieved
 
     def retrieve(self):
-
-        if self._filename == "" or self._filename is None:
-            self._filename = os.environ.get('AWS_SHARED_CREDENTIALS_FILE')
-            if self._filename == "" or self._filename is None:
-                home_dir = os.environ.get('HOME')
-                self._filename = os.path.join(home_dir, '.aws', 'credentials')
-
-        if self._profile == "" or self._profile is None:
-            self._profile = os.environ.get('AWS_PROFILE')
-            if self._profile == "" or self._profile is None:
-                self._profile = 'default'
-
         self._retrieved = False
         ini_profile = configparser.ConfigParser()
         ini_profile.read(self._filename)
@@ -50,14 +43,15 @@ class FileAWSCredentials(Provider):
         except:
             pass
 
-        if access_key == '' or secret == '':
-            return Value()
+        if access_key and secret:
+            self._retrieved = True
+            return Value(
+                access_key=access_key,
+                secret_key=secret,
+                session_token=session_token)
+
+        return Value()
 
-        self._retrieved = True
-        return Value(
-            access_key=access_key,
-            secret_key=secret,
-            session_token=session_token)
 
     def is_expired(self):
         return not self._retrieved
diff --git a/minio/credentials/file_minio_client.py b/minio/credentials/file_minio_client.py
index 74bd44a..e57bd09 100644
--- a/minio/credentials/file_minio_client.py
+++ b/minio/credentials/file_minio_client.py
@@ -14,30 +14,26 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import configparser
-import os, json
+import os
+import json
 import sys
 
 from .credentials import Provider, Value
 
+
 class FileMinioClient(Provider):
     def __init__(self, filename=None, alias=None, retrieved=False):
         super(Provider, self).__init__()
-        self._filename = filename
-        self._alias = alias
+        self._filename = (
+            filename or
+            os.path.join(os.environ.get('HOME'),
+                         'mc' if sys.platform == 'win32' else '.mc',
+                         'config.json')
+        )
+        self._alias = alias or os.environ.get('MINIO_ALIAS') or "s3"
         self._retrieved = retrieved
 
     def retrieve(self):
-        if self._filename == "" or self._filename is None:
-            home_dir = os.environ.get('HOME')
-            self._filename = os.path.join(home_dir, '.mc', 'config.json')
-            if sys.platform == 'win32':
-                self._filename = os.path.join(home_dir, 'mc', 'config.json')
-        if self._alias == "" or self._alias is None:
-            self._alias = os.environ.get('MINIO_ALIAS')
-            if self._alias == "" or self._alias is None:
-                self._alias = "s3"
-
         self._retrieved = False
 
         config = open(self._filename, 'r')
diff --git a/minio/credentials/static.py b/minio/credentials/static.py
index b37af3d..d71597c 100644
--- a/minio/credentials/static.py
+++ b/minio/credentials/static.py
@@ -16,6 +16,7 @@
 
 from .credentials import Provider, Value
 
+
 class Static(Provider):
     def __init__(self, access_key=None, secret_key=None, token=None):
         super(Static, self).__init__()
@@ -31,4 +32,4 @@ class Static(Provider):
         )
 
     def is_expired(self):
-        return False
\ No newline at end of file
+        return False
diff --git a/minio/fold_case_dict.py b/minio/fold_case_dict.py
index be8699d..1b6ab50 100644
--- a/minio/fold_case_dict.py
+++ b/minio/fold_case_dict.py
@@ -24,39 +24,37 @@ This module implements a case insensitive dictionary.
 
 """
 
+
 class FoldCaseDict(dict):
     def __init__(self, dictionary={}):
         self._data = self.__create(dictionary)
 
     def __create(self, value):
-        if isinstance(value, dict):
-            data = {}
-            for k, v in value.items():
-                if isinstance(v, dict):
-                    data[k.lower()] = FoldCaseDict(self.__create(v))
-                else:
-                    data[k.lower()] = v
-            return data
-        else:
+        if not isinstance(value, dict):
             return value
 
-    def __getitem__(self, item):
-        return self._data[item.lower()]
+        data = {}
+        for k, v in value.items():
+            data[k.lower()] = FoldCaseDict(v) if isinstance(v, dict) else v
+        return data
+
+    def __getitem__(self, key):
+        return self._data.__getitem__(key.lower())
 
-    def __contains__(self, item):
-        return item.lower() in self._data
+    def __contains__(self, key):
+        return self._data.__contains__(key.lower())
 
     def __setitem__(self, key, value):
-        self._data[key.lower()] = self.__create(value)
+        self._data.__setitem__(key.lower(), self.__create(value))
 
     def __delitem__(self, key):
-        del self._data[key.lower()]
+        self._data.__delitem__(key.lower())
 
     def __iter__(self):
-        return (k for k in self._data.keys())
+        return self._data.__iter__()
 
     def __len__(self):
-        return len(self._data)
+        return self._data.__len__()
 
     def __eq__(self, other):
         if isinstance(other, dict):
@@ -66,61 +64,55 @@ class FoldCaseDict(dict):
         else:
             raise NotImplementedError
 
-        # Compare insensitively
-        return self.items() == other.items()
+        return self._data.__eq__(other._data)
 
     def __repr__(self):
-        return str(self._data)
+        return self._data.__repr__()
 
     def get(self, key, default=None):
-        if not key.lower() in self:
-            return default
-        else:
-            return self[key]
+        return self._data.get(key.lower(), default)
 
     def has_key(self, key):
-        return key.lower() in self
+        return self._data.has_key(key.lower())
 
     def items(self):
-        return [(k, v) for k, v in self.iteritems()]
+        return self._data.items()
 
     def keys(self):
-        return [k for k in self.iterkeys()]
+        return self._data.keys()
 
     def values(self):
-        return [v for v in self.itervalues()]
+        return self._data.values()
 
     def iteritems(self):
-        for k, v in self._data.items():
-            yield k, v
+        return self._data.iteritems()
 
     def iterkeys(self):
-        for k, v in self._data.items():
+        for k in self._data.keys():
             yield k
 
     def itervalues(self):
-        for k, v in self._data.items():
+        for v in self._data.values():
             yield v
 
     def update(self, dictionary):
-        if not (isinstance(dictionary, dict) or
-                isinstance(dictionary, FoldCaseDict)):
+        if isinstance(dictionary, dict):
+            dictionary = FoldCaseDict(dictionary)
+        elif isinstance(dictionary, FoldCaseDict):
+            pass
+        else:
             raise TypeError
 
-        for k, v in dictionary.items():
-            self[k] = v
+        self._data.update(dictionary._data)
 
     def copy(self):
-        copy_dict = FoldCaseDict()
-        for k, v in self._data.items():
-            copy_dict[k] = v
-        return copy_dict
+        return FoldCaseDict(self._data.copy())
 
     def clear(self):
         self._data = {}
 
     def pop(self, key):
-        return self._data.pop(key)
+        return self._data.pop(key.lower())
 
     def popitem(self):
         return self._data.popitem()
diff --git a/minio/helpers.py b/minio/helpers.py
index 61e960c..5eb57ad 100644
--- a/minio/helpers.py
+++ b/minio/helpers.py
@@ -42,7 +42,7 @@ import os
 import errno
 import math
 
-from .compat import (urlsplit, urlencode, queryencode,
+from .compat import (urlsplit, _quote, queryencode,
                      str, bytes, basestring, _is_py3, _is_py2)
 from .error import (InvalidBucketError, InvalidEndpointError,
                     InvalidArgumentError)
@@ -599,7 +599,7 @@ def encode_object_name(object_name):
     :return: URL encoded input object name.
     """
     is_non_empty_string(object_name)
-    return urlencode(object_name)
+    return _quote(object_name)
 
 class Hasher(object):
     """
diff --git a/minio/parsers.py b/minio/parsers.py
index ee05fac..a6e5d90 100644
--- a/minio/parsers.py
+++ b/minio/parsers.py
@@ -35,7 +35,7 @@ import pytz
 
 # minio specific.
 from .error import (ETREE_EXCEPTIONS, InvalidXMLError, MultiDeleteError)
-from .compat import urldecode
+from .compat import unquote
 from .definitions import (Object, Bucket, IncompleteUpload,
                           UploadPart, MultipartUploadResult,
                           CopyObjectResult)
@@ -112,7 +112,7 @@ class S3Element(object):
         """
         text = self.get_child_text(name, strict)
         # strictness is already enforced above.
-        return urldecode(text) if text is not None else None
+        return unquote(text) if text is not None else None
 
     def get_etag_elem(self, strict=True):
         """Fetches an 'ETag' child element suitably processed.
diff --git a/minio/post_policy.py b/minio/post_policy.py
index 8241ef2..628e54f 100644
--- a/minio/post_policy.py
+++ b/minio/post_policy.py
@@ -40,6 +40,7 @@ class PostPolicy(object):
     A :class:`PostPolicy <PostPolicy>` object for constructing
        Amazon S3 POST policy JSON string.
     """
+
     def __init__(self):
         self._expiration = None
         self._content_length_range = tuple()
@@ -113,8 +114,7 @@ class PostPolicy(object):
         """
         err_msg = ('Min-length ({}) must be <= Max-length ({}), '
                    'and they must be non-negative.').format(
-                       min_length, max_length
-                   )
+                       min_length, max_length)
         if min_length > max_length or min_length < 0 or max_length < 0:
             raise ValueError(err_msg)
 
@@ -134,11 +134,10 @@ class PostPolicy(object):
                             list(self._content_length_range))
 
         policy_stmt = {
-            "expiration": self._expiration.strftime(
-                "%Y-%m-%dT%H:%M:%S.000Z"),
+            "expiration": self._expiration.strftime("%Y-%m-%dT%H:%M:%S.000Z"),
         }
 
-        if len(policies) > 0:
+        if policies:
             policy_stmt["conditions"] = policies
 
         return json.dumps(policy_stmt)
@@ -157,7 +156,8 @@ class PostPolicy(object):
         Validate for required parameters.
         """
         if not isinstance(self._expiration, datetime.datetime):
-            raise InvalidArgumentError('Expiration datetime must be specified.')
+            raise InvalidArgumentError(
+                'Expiration datetime must be specified.')
 
         if 'key' not in self.form_data:
             raise InvalidArgumentError('object key must be specified.')
diff --git a/minio/select/errors.py b/minio/select/errors.py
index fee9f19..b25867c 100644
--- a/minio/select/errors.py
+++ b/minio/select/errors.py
@@ -25,11 +25,13 @@ This module implements the error classes for SelectObject responses.
 
 """
 
+
 class SelectMessageError(Exception):
     '''
     Raised in case of message type 'error'
     '''
 
+
 class SelectCRCValidationError(Exception):
     '''
     Raised in case of CRC mismatch
diff --git a/minio/select/helpers.py b/minio/select/helpers.py
index c3b6b75..34d9f75 100644
--- a/minio/select/helpers.py
+++ b/minio/select/helpers.py
@@ -32,27 +32,26 @@ SQL = 'SQL'  # Value for ExpressionType
 EVENT_RECORDS = 'Records'  # Event Type is Records
 EVENT_PROGRESS = 'Progress'  # Event Type Progress
 EVENT_STATS = 'Stats'  # Event Type Stats
-EVENT_CONT = 'Cont' # Event Type continue
+EVENT_CONT = 'Cont'  # Event Type continue
 EVENT_END = 'End'  # Event Type is End
-EVENT_CONTENT_TYPE = "text/xml" # Event content xml type
+EVENT_CONTENT_TYPE = "text/xml"  # Event content xml type
 EVENT = 'event'  # Message Type is event
 ERROR = 'error'  # Message Type is error
 
+
 def calculate_crc(value):
     '''
     Returns the CRC using crc32
     '''
     return crc32(value) & 0xffffffff
 
+
 def validate_crc(current_value, expected_value):
     '''
     Validate through CRC check
     '''
-    crc_current = calculate_crc(current_value)
-    crc_expected = byte_int(expected_value)
-    if crc_current == crc_expected:
-        return True
-    return False
+    return calculate_crc(current_value) == byte_int(expected_value)
+
 
 def byte_int(data_bytes):
     '''
diff --git a/minio/select/options.py b/minio/select/options.py
index c85cda7..a12d6e3 100644
--- a/minio/select/options.py
+++ b/minio/select/options.py
@@ -27,10 +27,12 @@ This module implements the SelectOption definition for SelectObject API.
 
 from .helpers import (SQL)
 
+
 class CSVInput:
     """
     CSVInput: Input Format as CSV.
     """
+
     def __init__(self, FileHeaderInfo=None, RecordDelimiter="\n",
                  FieldDelimiter=",", QuoteCharacter='"',
                  QuoteEscapeCharacter='"', Comments="#",
@@ -43,10 +45,12 @@ class CSVInput:
         self.Comments = Comments
         self.AllowQuotedRecordDelimiter = AllowQuotedRecordDelimiter
 
+
 class JSONInput:
     """
     JSONInput: Input format as JSON.
     """
+
     def __init__(self, Type=None):
         self.Type = Type
 
@@ -61,6 +65,7 @@ class InputSerialization:
     """
     InputSerialization: nput Format.
     """
+
     def __init__(self, compression_type="NONE", csv=None, json=None, par=None):
         self.compression_type = compression_type
         self.csv_input = csv
@@ -73,6 +78,7 @@ class CSVOutput:
     CSVOutput: Output as CSV.
 
     """
+
     def __init__(self, QuoteFields="ASNEEDED", RecordDelimiter="\n",
                  FieldDelimiter=",", QuoteCharacter='"',
                  QuoteEscapeCharacter='"'):
@@ -87,6 +93,7 @@ class JsonOutput:
     """
     JsonOutput- Output as JSON.
     """
+
     def __init__(self, RecordDelimiter="\n"):
         self.RecordDelimiter = RecordDelimiter
 
@@ -95,6 +102,7 @@ class OutputSerialization:
     """
     OutputSerialization: Output Format.
     """
+
     def __init__(self,  csv=None, json=None):
         self.csv_output = csv
         self.json_output = json
@@ -104,6 +112,7 @@ class RequestProgress:
     """
     RequestProgress: Sends progress message.
     """
+
     def __init__(self, enabled=False):
         self.enabled = enabled
 
diff --git a/minio/select/reader.py b/minio/select/reader.py
index a1d8292..37ece1f 100644
--- a/minio/select/reader.py
+++ b/minio/select/reader.py
@@ -30,18 +30,15 @@ from __future__ import absolute_import
 import io
 import sys
 
-from binascii import crc32
 from xml.etree import ElementTree
-from xml.etree.ElementTree import ParseError
 
-from .helpers import (EVENT_RECORDS, EVENT_PROGRESS,
-                      EVENT_STATS, EVENT_CONT,
-                      EVENT, EVENT_CONTENT_TYPE,
-                      EVENT_END, ERROR)
+from .helpers import (EVENT_RECORDS, EVENT_STATS,
+                      EVENT, EVENT_CONTENT_TYPE, ERROR)
 
 from .helpers import (validate_crc, calculate_crc, byte_int)
 from .errors import (SelectMessageError, SelectCRCValidationError)
 
+
 def _extract_header(header_bytes):
     """
     populates the header map after reading the header in bytes
@@ -51,26 +48,28 @@ def _extract_header(header_bytes):
     # While loop ends when all the headers present are read
     # header contains multipe headers
     while header_byte_parsed < len(header_bytes):
-        header_name_byte_length = byte_int(header_bytes[header_byte_parsed:header_byte_parsed+1])
+        header_name_byte_length = byte_int(
+            header_bytes[header_byte_parsed:header_byte_parsed+1])
         header_byte_parsed += 1
-        header_name = \
-            header_bytes[header_byte_parsed:
-                         header_byte_parsed+header_name_byte_length]
+        header_name = header_bytes[
+            header_byte_parsed:header_byte_parsed+header_name_byte_length
+        ]
         header_byte_parsed += header_name_byte_length
         # Header Value Type is of 1 bytes and is skipped
         header_byte_parsed += 1
-        value_string_byte_length = \
-            byte_int(header_bytes[header_byte_parsed:
-                                  header_byte_parsed+2])
+        value_string_byte_length = byte_int(
+            header_bytes[header_byte_parsed:header_byte_parsed+2]
+        )
         header_byte_parsed += 2
-        header_value = \
-            header_bytes[header_byte_parsed:
-                         header_byte_parsed+value_string_byte_length]
+        header_value = header_bytes[
+            header_byte_parsed:header_byte_parsed+value_string_byte_length
+        ]
         header_byte_parsed += value_string_byte_length
-        header_map[header_name.decode("utf-8").lstrip(":")] = \
-            header_value.decode("utf-8").lstrip(":")
+        header_map[header_name.decode(
+            "utf-8").lstrip(":")] = header_value.decode("utf-8").lstrip(":")
     return header_map
 
+
 def _parse_stats(stats):
     """
     Parses stats XML and populates the stat dict.
@@ -86,12 +85,14 @@ def _parse_stats(stats):
 
     return stat
 
+
 class SelectObjectReader(object):
     """
     SelectObjectReader returns a Reader that upon read
     returns queried data, but stops when the response ends.
     LimitedRandomReader is compatible with BufferedIOBase.
     """
+
     def __init__(self, response):
         self.response = response
         self.remaining_bytes = bytes()
@@ -121,12 +122,12 @@ class SelectObjectReader(object):
 
         crc_bytes = io.BytesIO()
         total_bytes_len = self.response.read(4)
-        if len(total_bytes_len) == 0:
+        if not total_bytes_len:
             return {}
 
         total_length = byte_int(total_bytes_len)
         header_bytes_len = self.response.read(4)
-        if len(header_bytes_len) == 0:
+        if not header_bytes_len:
             return {}
 
         header_len = byte_int(header_bytes_len)
@@ -145,9 +146,9 @@ class SelectObjectReader(object):
         crc_bytes.write(prelude_bytes_crc)
 
         header_bytes = self.response.read(header_len)
-        if len(header_bytes) == 0:
+        if not header_bytes:
             raise SelectMessageError(
-                "Premature truncation of select message header"+
+                "Premature truncation of select message header" +
                 ", server is sending corrupt message?")
 
         crc_bytes.write(header_bytes)
@@ -156,39 +157,36 @@ class SelectObjectReader(object):
         payload_length = total_length - header_len - int(16)
         payload_bytes = b''
         event_type = header_map["event-type"]
+
         if header_map["message-type"] == ERROR:
             raise SelectMessageError(
-                header_map["error-code"] + ":\"" + \
+                header_map["error-code"] + ":\"" +
                 header_map["error-message"] + "\"")
-        elif header_map["message-type"] == EVENT:
-            if event_type == EVENT_END:
-                pass
-            elif event_type == EVENT_CONT:
-                pass
-            elif event_type == EVENT_STATS:
-                content_type = header_map["content-type"]
-                if content_type != EVENT_CONTENT_TYPE:
-                    raise SelectMessageError(
-                        "Unrecognized content-type {0}".format(content_type))
-                else:
-                    payload_bytes = self.response.read(payload_length)
-                    self.stat = _parse_stats(payload_bytes)
-
-            elif event_type == EVENT_RECORDS:
-                payload_bytes = self.response.read(payload_length)
-        else:
+
+        if header_map["message-type"] != EVENT:
             raise SelectMessageError(
-                "Unrecognized message-type {0}".format(header_map["message-type"])
+                "Unrecognized message-type {0}".format(
+                    header_map["message-type"])
             )
 
+        if event_type == EVENT_STATS:
+            content_type = header_map["content-type"]
+            if content_type != EVENT_CONTENT_TYPE:
+                raise SelectMessageError(
+                    "Unrecognized content-type {0}".format(content_type))
+
+            payload_bytes = self.response.read(payload_length)
+            self.stat = _parse_stats(payload_bytes)
+        elif event_type == EVENT_RECORDS:
+            payload_bytes = self.response.read(payload_length)
+
         crc_bytes.write(payload_bytes)
 
         message_crc = self.response.read(4)
-        if len(message_crc) == 0:
+        if not message_crc:
             return {}
 
-        if not validate_crc(crc_bytes.getvalue(),
-                            message_crc):
+        if not validate_crc(crc_bytes.getvalue(), message_crc):
             raise SelectCRCValidationError(
                 {"Checksum Mismatch, MessageCRC of " +
                  str(calculate_crc(crc_bytes.getvalue())) +
@@ -207,14 +205,13 @@ class SelectObjectReader(object):
         caller should call self.close() to close the stream.
         """
         while not self.response.isclosed():
-            if len(self.remaining_bytes) == 0:
+            if not self.remaining_bytes:
                 message = self.__extract_message()
-                if EVENT_RECORDS in message:
-                    self.remaining_bytes = message.get(EVENT_RECORDS, b'')
-                else:
-                    # For all other events continue
+                if EVENT_RECORDS not in message:
                     continue
 
+                self.remaining_bytes = message.get(EVENT_RECORDS, b'')
+
             result = self.remaining_bytes
             if num_bytes < len(self.remaining_bytes):
                 result = self.remaining_bytes[:num_bytes]
diff --git a/minio/signer.py b/minio/signer.py
index 2dc5a5f..c01bec1 100644
--- a/minio/signer.py
+++ b/minio/signer.py
@@ -42,6 +42,7 @@ _SIGN_V4_ALGORITHM = 'AWS4-HMAC-SHA256'
 # Hardcoded S3 header value for X-Amz-Content-Sha256
 _UNSIGNED_PAYLOAD = u'UNSIGNED-PAYLOAD'
 
+
 def post_presign_signature(date, region, secret_key, policy_str):
     """
     Calculates signature version '4' for POST policy string.
@@ -60,8 +61,8 @@ def post_presign_signature(date, region, secret_key, policy_str):
 
 
 def presign_v4(method, url, credentials,
-               region=None, headers=None, expires=None, response_headers=None,
-               request_date=None):
+               region=None, headers=None, expires=None,
+               response_headers=None, request_date=None):
     """
     Calculates signature version '4' for regular presigned URLs.
 
@@ -80,20 +81,20 @@ def presign_v4(method, url, credentials,
     if not credentials.get().access_key or not credentials.get().secret_key:
         raise InvalidArgumentError('Invalid access_key and secret_key.')
 
-    if region is None:
-        region = 'us-east-1'
-
-    if headers is None:
-        headers = {}
+    region = region or 'us-east-1'
+    headers = headers or {}
+    expires = expires or '604800'
+    request_date = request_date or datetime.utcnow()
 
-    if expires is None:
-        expires = '604800'
-
-    if request_date is None:
-        request_date = datetime.utcnow()
+    # If a sha256sum is known, add to headers to include with signature
+    content_hash_hex = _UNSIGNED_PAYLOAD
+    for k in headers.keys():
+        if k.lower() == 'x-amz-content-sha256':
+            content_hash_hex = headers.get(k, _UNSIGNED_PAYLOAD)
+            del headers[k]
+            break
 
     parsed_url = urlsplit(url)
-    content_hash_hex = _UNSIGNED_PAYLOAD
     host = remove_default_port(parsed_url)
     headers['Host'] = host
     iso8601Date = request_date.strftime("%Y%m%dT%H%M%SZ")
@@ -102,40 +103,33 @@ def presign_v4(method, url, credentials,
     # Construct queries.
     query = {}
     query['X-Amz-Algorithm'] = _SIGN_V4_ALGORITHM
-    query['X-Amz-Credential'] = generate_credential_string(credentials.get().access_key,
-                                                           request_date,
-                                                           region)
+    query['X-Amz-Credential'] = generate_credential_string(
+        credentials.get().access_key, request_date, region)
     query['X-Amz-Date'] = iso8601Date
     query['X-Amz-Expires'] = str(expires)
-    if credentials.get().session_token is not None:
+    if credentials.get().session_token:
         query['X-Amz-Security-Token'] = credentials.get().session_token
 
     signed_headers = get_signed_headers(headers_to_sign)
     query['X-Amz-SignedHeaders'] = ';'.join(signed_headers)
 
-    if response_headers is not None:
+    if response_headers:
         query.update(response_headers)
 
     # URL components.
     url_components = [parsed_url.geturl()]
-    if query is not None:
-        ordered_query = collections.OrderedDict(sorted(query.items()))
-        query_components = []
-        for component_key in ordered_query:
-            single_component = [component_key]
-            if ordered_query[component_key] is not None:
-                single_component.append('=')
-                single_component.append(
-                    queryencode(ordered_query[component_key])
-                )
-            else:
-                single_component.append('=')
-            query_components.append(''.join(single_component))
-
-        query_string = '&'.join(query_components)
-        if query_string:
-            url_components.append('?')
-            url_components.append(query_string)
+    ordered_query = collections.OrderedDict(sorted(query.items()))
+    query_components = []
+    for component_key in ordered_query:
+        single_component = [component_key, '=']
+        if ordered_query[component_key]:
+            single_component.append(queryencode(ordered_query[component_key]))
+        query_components.append(''.join(single_component))
+
+    query_string = '&'.join(query_components)
+    if query_string:
+        url_components.append('?')
+        url_components.append(query_string)
     new_url = ''.join(url_components)
     # new url constructor block ends.
     new_parsed_url = urlsplit(new_url)
@@ -155,17 +149,13 @@ def presign_v4(method, url, credentials,
     return new_parsed_url.geturl()
 
 
-
 def get_signed_headers(headers):
     """
     Get signed headers.
 
     :param headers: input dictionary to be sorted.
     """
-    signed_headers = []
-    for header in headers:
-        signed_headers.append(header.lower().strip())
-    return sorted(signed_headers)
+    return sorted([h.lower().strip() for h in headers])
 
 
 def sign_v4(method, url, region, headers=None,
@@ -179,7 +169,8 @@ def sign_v4(method, url, region, headers=None,
     :param url: Final url which needs to be signed.
     :param region: Region should be set to bucket region.
     :param headers: Optional headers for the method.
-    :param credentials: Optional Credentials object with your AWS s3 account info.
+    :param credentials: Optional Credentials object with your AWS s3 account
+                        info.
     :param content_sha256: Optional body sha256.
     :param request_datetime: Optional request date/time
     """
@@ -188,29 +179,23 @@ def sign_v4(method, url, region, headers=None,
     if not credentials.get().access_key or not credentials.get().secret_key:
         return headers
 
-    if headers is None:
-        headers = FoldCaseDict()
-
-    if region is None:
-        region = 'us-east-1'
+    headers = headers or FoldCaseDict()
+    region = region or 'us-east-1'
 
     parsed_url = urlsplit(url)
     secure = parsed_url.scheme == 'https'
     if secure:
         content_sha256 = _UNSIGNED_PAYLOAD
-    if content_sha256 is None:
-        # with no payload, calculate sha256 for 0 length data.
-        content_sha256 = get_sha256_hexdigest('')
+    content_sha256 = content_sha256 or get_sha256_hexdigest('')
 
     host = remove_default_port(parsed_url)
     headers['Host'] = host
 
-    if request_datetime is None:
-        request_datetime = datetime.utcnow()
+    request_datetime = request_datetime or datetime.utcnow()
 
     headers['X-Amz-Date'] = request_datetime.strftime("%Y%m%dT%H%M%SZ")
     headers['X-Amz-Content-Sha256'] = content_sha256
-    if credentials.get().session_token is not None:
+    if credentials.get().session_token:
         headers['X-Amz-Security-Token'] = credentials.get().session_token
 
     headers_to_sign = headers
@@ -224,21 +209,21 @@ def sign_v4(method, url, region, headers=None,
 
     string_to_sign = generate_string_to_sign(request_datetime, region,
                                              canonical_req)
-    signing_key = generate_signing_key(request_datetime, region, credentials.get().secret_key)
+    signing_key = generate_signing_key(
+        request_datetime, region, credentials.get().secret_key)
     signature = hmac.new(signing_key, string_to_sign.encode('utf-8'),
                          hashlib.sha256).hexdigest()
 
-    authorization_header = generate_authorization_header(credentials.get().access_key,
-                                                         request_datetime,
-                                                         region,
-                                                         signed_headers,
-                                                         signature)
+    authorization_header = generate_authorization_header(
+        credentials.get().access_key, request_datetime, region, signed_headers,
+        signature)
 
     headers['Authorization'] = authorization_header
     return headers
 
 
-def generate_canonical_request(method, parsed_url, headers, signed_headers, content_sha256):
+def generate_canonical_request(method, parsed_url, headers, signed_headers,
+                               content_sha256):
     """
     Generate canonical request.
 
@@ -257,7 +242,7 @@ def generate_canonical_request(method, parsed_url, headers, signed_headers, cont
     for header in signed_headers:
         value = headers[header.title()]
         value = str(value).strip()
-        header_lines.append(header + ':' + str(value))
+        header_lines.append(header + ':' + value)
 
     lines = lines + header_lines
     lines.append('')
@@ -353,6 +338,7 @@ def generate_authorization_header(access_key, date, region,
                    'Signature=' + signature]
     return ' '.join(auth_header)
 
+
 def remove_default_port(parsed_url):
     default_ports = {
         'http': 80,
diff --git a/minio/thread_pool.py b/minio/thread_pool.py
index 5b08112..ac4e28b 100644
--- a/minio/thread_pool.py
+++ b/minio/thread_pool.py
@@ -45,7 +45,7 @@ class Worker(Thread):
         """ Continously receive tasks and execute them """
         while True:
             task = self.tasks_queue.get()
-            if task is None:
+            if not task:
                 self.tasks_queue.task_done()
                 break
             # No exception detected in any thread,
@@ -61,6 +61,7 @@ class Worker(Thread):
             # Mark this task as done, whether an exception happened or not
             self.tasks_queue.task_done()
 
+
 class ThreadPool:
     """ Pool of threads consuming tasks from a queue """
 
@@ -91,4 +92,3 @@ class ThreadPool:
         if not self.exceptions_queue.empty():
             raise self.exceptions_queue.get()
         return self.results_queue
-
diff --git a/minio/xml_marshal.py b/minio/xml_marshal.py
index 53e4747..f7eaa2b 100644
--- a/minio/xml_marshal.py
+++ b/minio/xml_marshal.py
@@ -28,16 +28,37 @@ This module contains the simple wrappers for XML marshaller's.
 from __future__ import absolute_import
 import io
 
-from xml.etree import ElementTree as s3_xml
+import xml.etree.ElementTree as ET
 from collections import defaultdict
 
 _S3_NAMESPACE = 'http://s3.amazonaws.com/doc/2006-03-01/'
 
+
+def Element(tag, with_namespace=False):
+    if with_namespace:
+        return ET.Element(tag, {'xmlns': _S3_NAMESPACE})
+    return ET.Element(tag)
+
+
+def SubElement(parent, tag, text=None):
+    subElement = ET.SubElement(parent, tag)
+    if text is not None:
+        subElement.text = text
+    return subElement
+
+
+def get_xml_data(element):
+    data = io.BytesIO()
+    ET.ElementTree(element).write(data, encoding=None, xml_declaration=False)
+    return data.getvalue()
+
+
 def xml_to_dict(in_xml):
     # Converts xml to dict
-    elem = s3_xml.XML(in_xml)
+    elem = ET.XML(in_xml)
     return etree_to_dict(elem)
 
+
 def etree_to_dict(elem):
     # Converts ElementTree object to dict
     ns = '{' + _S3_NAMESPACE + '}'
@@ -55,7 +76,7 @@ def etree_to_dict(elem):
             for dc in map(etree_to_dict, children):
                 for k, v in dc.items():
                     dd[k].append(v)
-        d = {elem.tag: {k:v[0] if len(v) == 1 else v for k, v in dd.items()}}
+        d = {elem.tag: {k: v[0] if len(v) == 1 else v for k, v in dd.items()}}
     if elem.attrib:
         d[elem.tag].update(('@' + k, v) for k, v in elem.attrib.items())
     if elem.text:
@@ -67,31 +88,25 @@ def etree_to_dict(elem):
             d[elem.tag] = text
     return d
 
+
 def xml_marshal_bucket_encryption(rules):
-    kms_key_val = ''
-    sse_alg_val = 'AES256'
-    root = s3_xml.Element('ServerSideEncryptionConfiguration')
-    for r in rules:
-        rule_xml = s3_xml.SubElement(root, 'Rule')
-        apply_xml = s3_xml.SubElement(rule_xml, 'ApplyServerSideEncryptionByDefault')
-        if 'KMSMasterKeyID' in r['ApplyServerSideEncryptionByDefault'].keys():
-            kms_key_val = r['ApplyServerSideEncryptionByDefault']['KMSMasterKeyID']
-        if 'SSEAlgorithm' in r['ApplyServerSideEncryptionByDefault'].keys():
-            sse_alg_val = r['ApplyServerSideEncryptionByDefault']['SSEAlgorithm']
-        if kms_key_val != '':
-            kms = s3_xml.SubElement(apply_xml, 'KMSMasterKeyID')
-            kms.text = kms_key_val
-        sse = s3_xml.SubElement(apply_xml, 'SSEAlgorithm')
-        sse.text = sse_alg_val
-        # 'break' the loop as soon as the first entry in the list is
-        # processed. That is because, 'Rule" list cannot have more than
-        # one entry for the time-being, even if there are more entries
-        # in the list. This is a server side restriction and it is
-        # validated on the server side.
-        break
-    data = io.BytesIO()
-    s3_xml.ElementTree(root).write(data, encoding=None, xml_declaration=False)
-    return data.getvalue()
+    root = Element('ServerSideEncryptionConfiguration')
+
+    if rules:
+        # As server supports only one rule, the first rule is taken due to
+        # no validation is done at server side.
+        apply_element = SubElement(SubElement(root, 'Rule'),
+                                   'ApplyServerSideEncryptionByDefault')
+        SubElement(apply_element, 'SSEAlgorithm',
+                   rules[0]['ApplyServerSideEncryptionByDefault'].get(
+                       'SSEAlgorithm', 'AES256'))
+        kms_text = rules[0]['ApplyServerSideEncryptionByDefault'].get(
+            'KMSMasterKeyID')
+        if kms_text:
+            SubElement(apply_element, 'KMSMasterKeyID', kms_text)
+
+    return get_xml_data(root)
+
 
 def xml_marshal_bucket_constraint(region):
     """
@@ -100,79 +115,61 @@ def xml_marshal_bucket_constraint(region):
     :param region: Region name of a given bucket.
     :return: Marshalled XML data.
     """
-    root = s3_xml.Element('CreateBucketConfiguration', {'xmlns': _S3_NAMESPACE})
-    location_constraint = s3_xml.SubElement(root, 'LocationConstraint')
-    location_constraint.text = region
-    data = io.BytesIO()
-    s3_xml.ElementTree(root).write(data, encoding=None, xml_declaration=False)
-    return data.getvalue()
+    root = Element('CreateBucketConfiguration', with_namespace=True)
+    SubElement(root, 'LocationConstraint', region)
+    return get_xml_data(root)
 
 
 def xml_marshal_select(opts):
-    root = s3_xml.Element('SelectObjectContentRequest')
-    expression = s3_xml.SubElement(root, 'Expression')
-    expression.text = opts.expression
-    expression_type = s3_xml.SubElement(root, 'ExpressionType')
-    expression_type.text = 'SQL'
-    input_serialization = s3_xml.SubElement(root, 'InputSerialization')
-
-    if opts.in_ser.csv_input is not None:
-        compression_type = s3_xml.SubElement(input_serialization, 'CompressionType')
-        compression_type.text = opts.in_ser.compression_type
-        csv = s3_xml.SubElement(input_serialization, 'CSV')
-        file_header_info = s3_xml.SubElement(csv, 'FileHeaderInfo')
-        file_header_info.text = opts.in_ser.csv_input.FileHeaderInfo
-        record_delimiter = s3_xml.SubElement(csv, 'RecordDelimiter')
-        record_delimiter.text = opts.in_ser.csv_input.RecordDelimiter
-        field_delimiter = s3_xml.SubElement(csv, 'FieldDelimiter')
-        field_delimiter.text = opts.in_ser.csv_input.FieldDelimiter
-        quote_character = s3_xml.SubElement(csv, 'QuoteCharacter')
-        quote_character.text = opts.in_ser.csv_input.QuoteCharacter
-        quote_escape_character = s3_xml.SubElement(csv, 'QuoteEscapeCharacter')
-        quote_escape_character.text = opts.in_ser.csv_input.QuoteEscapeCharacter
-        comments = s3_xml.SubElement(csv, 'Comments')
-        comments.text = opts.in_ser.csv_input.Comments
-        allow_quoted_record_delimiter = s3_xml.SubElement(csv, 'AllowQuotedRecordDelimiter')
-        allow_quoted_record_delimiter.text = opts.in_ser.csv_input.AllowQuotedRecordDelimiter.lower()
-
-    if opts.in_ser.json_input is not None:
-        compression_type = s3_xml.SubElement(input_serialization, 'CompressionType')
-        compression_type.text = opts.in_ser.compression_type
-        json = s3_xml.SubElement(input_serialization, 'JSON')
-        type_input = s3_xml.SubElement(json, 'Type')
-        type_input.text = opts.in_ser.json_input.Type
-
-    if opts.in_ser.parquet_input is not None:
-        compression_type = s3_xml.SubElement(input_serialization, 'CompressionType')
-        compression_type.text = opts.in_ser.compression_type
-        s3_xml.SubElement(input_serialization, 'Parquet')
-
-    output_serialization = s3_xml.SubElement(root, 'OutputSerialization')
-    if opts.out_ser.csv_output is not None:
-        csv = s3_xml.SubElement(output_serialization, 'CSV')
-        quote_field = s3_xml.SubElement(csv, 'QuoteFields')
-        quote_field.text = opts.out_ser.csv_output.QuoteFields
-        record_delimiter = s3_xml.SubElement(csv, 'RecordDelimiter')
-        record_delimiter.text = opts.out_ser.csv_output.RecordDelimiter
-        field_delimiter = s3_xml.SubElement(csv, 'FieldDelimiter')
-        field_delimiter.text = opts.out_ser.csv_output.FieldDelimiter
-        quote_character = s3_xml.SubElement(csv, 'QuoteCharacter')
-        quote_character.text = opts.out_ser.csv_output.QuoteCharacter
-        quote_escape_character = s3_xml.SubElement(csv, 'QuoteEscapeCharacter')
-        quote_escape_character.text = opts.out_ser.csv_output.QuoteEscapeCharacter
-
-    if opts.out_ser.json_output is not None:
-        json = s3_xml.SubElement(output_serialization, 'JSON')
-        record_delimiter = s3_xml.SubElement(json, 'RecordDelimiter')
-        record_delimiter.text = opts.out_ser.json_output.RecordDelimiter
-
-    request_progress = s3_xml.SubElement(root, 'RequestProgress')
-    enabled = s3_xml.SubElement(request_progress, 'Enabled')
-    enabled.text = opts.req_progress.enabled.lower()
-
-    data = io.BytesIO()
-    s3_xml.ElementTree(root).write(data, encoding=None, xml_declaration=False)
-    return data.getvalue()
+    root = Element('SelectObjectContentRequest')
+    SubElement(root, 'Expression', opts.expression)
+    SubElement(root, 'ExpressionType', 'SQL')
+
+    input_serialization = SubElement(root, 'InputSerialization')
+    SubElement(input_serialization, 'CompressionType',
+               opts.in_ser.compression_type)
+
+    if opts.in_ser.csv_input:
+        csv = SubElement(input_serialization, 'CSV')
+        SubElement(csv, 'FileHeaderInfo', opts.in_ser.csv_input.FileHeaderInfo)
+        SubElement(csv, 'RecordDelimiter',
+                   opts.in_ser.csv_input.RecordDelimiter)
+        SubElement(csv, 'FieldDelimiter', opts.in_ser.csv_input.FieldDelimiter)
+        SubElement(csv, 'QuoteCharacter', opts.in_ser.csv_input.QuoteCharacter)
+        SubElement(csv, 'QuoteEscapeCharacter',
+                   opts.in_ser.csv_input.QuoteEscapeCharacter)
+        SubElement(csv, 'Comments', opts.in_ser.csv_input.Comments)
+        SubElement(csv, 'AllowQuotedRecordDelimiter',
+                   opts.in_ser.csv_input.AllowQuotedRecordDelimiter.lower())
+
+    if opts.in_ser.json_input:
+        SubElement(SubElement(input_serialization, 'JSON'), 'Type',
+                   opts.in_ser.json_input.Type)
+
+    if opts.in_ser.parquet_input:
+        SubElement(input_serialization, 'Parquet')
+
+    output_serialization = SubElement(root, 'OutputSerialization')
+    if opts.out_ser.csv_output:
+        csv = SubElement(output_serialization, 'CSV')
+        SubElement(csv, 'QuoteFields', opts.out_ser.csv_output.QuoteFields)
+        SubElement(csv, 'RecordDelimiter',
+                   opts.out_ser.csv_output.RecordDelimiter)
+        SubElement(csv, 'FieldDelimiter',
+                   opts.out_ser.csv_output.FieldDelimiter)
+        SubElement(csv, 'QuoteCharacter',
+                   opts.out_ser.csv_output.QuoteCharacter)
+        SubElement(csv, 'QuoteEscapeCharacter',
+                   opts.out_ser.csv_output.QuoteEscapeCharacter)
+
+    if opts.out_ser.json_output:
+        SubElement(SubElement(output_serialization, 'JSON'), 'RecordDelimiter',
+                   opts.out_ser.json_output.RecordDelimiter)
+
+    SubElement(SubElement(root, 'RequestProgress'), 'Enabled',
+               opts.req_progress.enabled.lower())
+
+    return get_xml_data(root)
 
 
 def xml_marshal_complete_multipart_upload(uploaded_parts):
@@ -182,18 +179,13 @@ def xml_marshal_complete_multipart_upload(uploaded_parts):
     :param uploaded_parts: List of all uploaded parts, ordered by part number.
     :return: Marshalled XML data.
     """
-    root = s3_xml.Element('CompleteMultipartUpload', {'xmlns': _S3_NAMESPACE})
+    root = Element('CompleteMultipartUpload', with_namespace=True)
     for uploaded_part in uploaded_parts:
-        part_number = uploaded_part.part_number
-        part = s3_xml.SubElement(root, 'Part')
-        part_num = s3_xml.SubElement(part, 'PartNumber')
-        part_num.text = str(part_number)
-        etag = s3_xml.SubElement(part, 'ETag')
-        etag.text = '"' + uploaded_part.etag + '"'
-        data = io.BytesIO()
-        s3_xml.ElementTree(root).write(data, encoding=None,
-                                       xml_declaration=False)
-    return data.getvalue()
+        part = SubElement(root, 'Part')
+        SubElement(part, 'PartNumber', str(uploaded_part.part_number))
+        SubElement(part, 'ETag', '"' + uploaded_part.etag + '"')
+
+    return get_xml_data(root)
 
 
 def xml_marshal_bucket_notifications(notifications):
@@ -264,7 +256,7 @@ def xml_marshal_bucket_notifications(notifications):
 
     :return: Marshalled XML data
     """
-    root = s3_xml.Element('NotificationConfiguration', {'xmlns': _S3_NAMESPACE})
+    root = Element('NotificationConfiguration', with_namespace=True)
     _add_notification_config_to_xml(
         root,
         'TopicConfiguration',
@@ -281,9 +273,8 @@ def xml_marshal_bucket_notifications(notifications):
         notifications.get('CloudFunctionConfigurations', [])
     )
 
-    data = io.BytesIO()
-    s3_xml.ElementTree(root).write(data, encoding=None, xml_declaration=False)
-    return data.getvalue()
+    return get_xml_data(root)
+
 
 NOTIFICATIONS_ARN_FIELDNAME_MAP = {
     'TopicConfiguration': 'Topic',
@@ -299,33 +290,25 @@ def _add_notification_config_to_xml(node, element_name, configs):
 
     """
     for config in configs:
-        config_node = s3_xml.SubElement(node, element_name)
+        config_node = SubElement(node, element_name)
 
         if 'Id' in config:
-            id_node = s3_xml.SubElement(config_node, 'Id')
-            id_node.text = config['Id']
+            SubElement(config_node, 'Id', config['Id'])
 
-        arn_node = s3_xml.SubElement(
-            config_node,
-            NOTIFICATIONS_ARN_FIELDNAME_MAP[element_name]
-        )
-        arn_node.text = config['Arn']
+        SubElement(config_node, NOTIFICATIONS_ARN_FIELDNAME_MAP[element_name],
+                   config['Arn'])
 
         for event in config['Events']:
-            event_node = s3_xml.SubElement(config_node, 'Event')
-            event_node.text = event
+            SubElement(config_node, 'Event', event)
 
         filter_rules = config.get('Filter', {}).get(
             'Key', {}).get('FilterRules', [])
         if filter_rules:
-            filter_node = s3_xml.SubElement(config_node, 'Filter')
-            s3key_node = s3_xml.SubElement(filter_node, 'S3Key')
+            s3key_node = SubElement(SubElement(config_node, 'Filter'), 'S3Key')
             for filter_rule in filter_rules:
-                filter_rule_node = s3_xml.SubElement(s3key_node, 'FilterRule')
-                name_node = s3_xml.SubElement(filter_rule_node, 'Name')
-                name_node.text = filter_rule['Name']
-                value_node = s3_xml.SubElement(filter_rule_node, 'Value')
-                value_node.text = filter_rule['Value']
+                filter_rule_node = SubElement(s3key_node, 'FilterRule')
+                SubElement(filter_rule_node, 'Name', filter_rule['Name'])
+                SubElement(filter_rule_node, 'Value', filter_rule['Value'])
     return node
 
 
@@ -336,21 +319,15 @@ def xml_marshal_delete_objects(object_names):
     :param object_names: List of object keys to be deleted.
     :return: Serialized XML string for multi-object delete request body.
     """
-    root = s3_xml.Element('Delete')
+    root = Element('Delete')
 
     # use quiet mode in the request - this causes the S3 Server to
     # limit its response to only object keys that had errors during
     # the delete operation.
-    quiet = s3_xml.SubElement(root, 'Quiet')
-    quiet.text = "true"
+    SubElement(root, 'Quiet', "true")
 
     # add each object to the request.
     for object_name in object_names:
-        object_elt = s3_xml.SubElement(root, 'Object')
-        key_elt = s3_xml.SubElement(object_elt, 'Key')
-        key_elt.text = object_name
+        SubElement(SubElement(root, 'Object'), 'Key', object_name)
 
-    # return the marshalled xml.
-    data = io.BytesIO()
-    s3_xml.ElementTree(root).write(data, encoding=None, xml_declaration=False)
-    return data.getvalue()
+    return get_xml_data(root)


Test patch:
diff --git a/tests/unit/sign_test.py b/tests/unit/sign_test.py
index 8c3ca64..42624c6 100644
--- a/tests/unit/sign_test.py
+++ b/tests/unit/sign_test.py
@@ -24,7 +24,7 @@ from minio.signer import (generate_canonical_request, generate_string_to_sign,
                           generate_signing_key, generate_authorization_header,
                           presign_v4, sign_v4)
 from minio.error import InvalidArgumentError
-from minio.compat import urlsplit, urlencode, queryencode
+from minio.compat import urlsplit, _quote, queryencode
 from minio.fold_case_dict import FoldCaseDict
 from minio.credentials import Credentials, Static
 from minio.helpers import get_target_url
@@ -139,20 +139,20 @@ class SignV4Test(TestCase):
         eq_(hdrs['Authorization'], 'AWS4-HMAC-SHA256 Credential=minio/20150620/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=a2f4546f647981732bd90dfa5a7599c44dca92f44bea48ecc7565df06032c25b')
 
 class UnicodeEncodeTest(TestCase):
-    def test_unicode_urlencode(self):
-        eq_(urlencode('/test/123/汉字'), '/test/123/%E6%B1%89%E5%AD%97')
+    def test_unicode_quote(self):
+        eq_(_quote('/test/123/汉字'), '/test/123/%E6%B1%89%E5%AD%97')
 
     def test_unicode_queryencode(self):
         eq_(queryencode('/test/123/汉字'), '%2Ftest%2F123%2F%E6%B1%89%E5%AD%97')
 
-    def test_unicode_urlencode_u(self):
-        eq_(urlencode(u'/test/123/汉字'), '/test/123/%E6%B1%89%E5%AD%97')
+    def test_unicode_quote_u(self):
+        eq_(_quote(u'/test/123/汉字'), '/test/123/%E6%B1%89%E5%AD%97')
 
     def test_unicode_queryencode_u(self):
         eq_(queryencode(u'/test/123/汉字'), '%2Ftest%2F123%2F%E6%B1%89%E5%AD%97')
 
-    def test_unicode_urlencode_b(self):
-        eq_(urlencode(b'/test/123/\xe6\xb1\x89\xe5\xad\x97'), '/test/123/%E6%B1%89%E5%AD%97')
+    def test_unicode_quote_b(self):
+        eq_(_quote(b'/test/123/\xe6\xb1\x89\xe5\xad\x97'), '/test/123/%E6%B1%89%E5%AD%97')
 
     def test_unicode_queryencode_b(self):
         eq_(queryencode(b'/test/123/\xe6\xb1\x89\xe5\xad\x97'), '%2Ftest%2F123%2F%E6%B1%89%E5%AD%97')