"""
Utility to upload objects to s3.

Dependencies:
    * boto3

Requires AWS key/secret to be set, for details please see
http://boto3.readthedocs.io/en/latest/guide/configuration.html
"""
import six
if six.PY2:
    from cStringIO import InputType, OutputType, StringIO
    from StringIO import StringIO as StringIOType

    already_stringio = (InputType, OutputType, StringIOType)
else:
    from io import StringIO
    already_stringio = (StringIO,)

from gzip import GzipFile
from io import SEEK_SET

from pandas import DataFrame, Series

try:
    import ujson as json
except ImportError:
    import json


class S3Writer(object):

    _transfer_config = None
    S3_CHUNK_SIZE_BYTES = 16 * 1024 * 1024
    
    @classmethod
    def _get_transfer_config(cls):
        if cls._transfer_config is None:
            import boto3.s3.transfer as transfer
            cls._transfer_config = transfer.TransferConfig(
                    multipart_threshold=cls.S3_CHUNK_SIZE_BYTES,
                    multipart_chunksize=cls.S3_CHUNK_SIZE_BYTES
                    )
        return cls._transfer_config

    @classmethod
    def _serialize_data(cls, data, gzip=False, df_column_names=False,
            gzip_compression_level=6):
        if six.PY3:
            raise Exception("python3 currently not supported for this method! Sorry!")

        # easy, it's already in a stringio ready to go
        if any([isinstance(data, c) for c in already_stringio]):
            # make sure we reset to beginning, just in case, in preparation of read()
            # must be compatible with StringIO and cStringIO, so can't use reset()
            data.seek(SEEK_SET)
            return data
        
        data_io = StringIO()
        if gzip:
            io = GzipFile(fileobj=data_io, mode='w', compresslevel=gzip_compression_level)
        else:
            io = data_io

        if any([isinstance(data, c) for c in (dict, list, str)]):
            io.write(json.dumps(data))
        elif isinstance(data, DataFrame) or isinstance(data, Series):
            data.to_csv(io, index=False, header=df_column_names)
        else:
            io.write(str(data))

        if gzip:
            io.close()

        data_io.seek(SEEK_SET)
        return data_io

    @classmethod
    def upload(cls, data, bucket_name, key_name, aws_access_key_id=None, aws_secret_access_key=None,
            gzip=False, df_column_names=False, gzip_compression_level=6):
        # in here so as not to create a dependency on boto3 for the entire link package
        import boto3
        s3_client = boto3.client(
                's3',
                aws_access_key_id=aws_access_key_id,
                aws_secret_access_key=aws_secret_access_key
            )
        transfer_config = cls._get_transfer_config()

        io = cls._serialize_data(data, gzip=gzip, df_column_names=df_column_names,
                gzip_compression_level=gzip_compression_level)
        s3_client.upload_fileobj(io, Bucket=bucket_name, Key=key_name, Config=transfer_config)


@@ -405,25 +405,34 @@
 ort StringIO
+, BytesIO
 %0A
-
     already_
@@ -1232,115 +1232,8 @@
 =6):
-%0A        if six.PY3:%0A            raise Exception(%22python3 currently not supported for this method! Sorry!%22)
 %0A%0A  
@@ -1580,24 +1580,48 @@
 ta%0A        %0A
+        if six.PY2:%0A    
         data
@@ -1637,16 +1637,63 @@
 ingIO()%0A
+        else:%0A            data_io = BytesIO()%0A%0A
         
@@ -1894,24 +1894,52 @@
 st, str)%5D):%0A
+            if six.PY2:%0A    
             
@@ -1965,16 +1965,90 @@
 (data))%0A
+            else:%0A                io.write(str.encode(json.dumps(data)))%0A%0A
         

add support for python3