summaryrefslogtreecommitdiff
path: root/boto
diff options
context:
space:
mode:
authorDaniel G. Taylor <danielgtaylor@gmail.com>2014-08-04 15:42:30 -0700
committerDaniel G. Taylor <danielgtaylor@gmail.com>2014-08-04 15:42:30 -0700
commitff3d8159af3c816303785e023a4182aacb6aabf5 (patch)
tree3f9ccb173904eecef829d07f9acbddc6e4b444e5 /boto
parent60603b6514268a76d9f84a8f381fd645271492a8 (diff)
parent8aea0d3381d22d7dc0a58c488db6f5d429083c9c (diff)
downloadboto-ff3d8159af3c816303785e023a4182aacb6aabf5.tar.gz
Merge branch 'release-2.32.1'2.32.1
Conflicts: docs/source/index.rst
Diffstat (limited to 'boto')
-rw-r--r--boto/__init__.py2
-rw-r--r--boto/auth.py6
-rw-r--r--boto/cloudsearch/document.py3
-rw-r--r--boto/compat.py10
-rw-r--r--boto/connection.py7
-rw-r--r--boto/dynamodb/types.py8
-rw-r--r--boto/emr/emrobject.py6
-rw-r--r--boto/fps/connection.py1
-rw-r--r--boto/glacier/concurrent.py2
-rw-r--r--boto/glacier/job.py3
-rw-r--r--boto/glacier/layer1.py27
-rw-r--r--boto/glacier/utils.py13
-rw-r--r--boto/glacier/vault.py2
-rw-r--r--boto/gs/resumable_upload_handler.py5
-rw-r--r--boto/manage/volume.py2
-rw-r--r--boto/mws/connection.py5
-rw-r--r--boto/pyami/config.py14
-rw-r--r--boto/pyami/installers/ubuntu/mysql.py4
-rw-r--r--boto/regioninfo.py1
-rw-r--r--boto/s3/key.py12
-rw-r--r--boto/sdb/db/manager/xmlmanager.py5
-rw-r--r--boto/utils.py24
-rw-r--r--boto/vpc/vpc_peering_connection.py2
23 files changed, 82 insertions, 82 deletions
diff --git a/boto/__init__.py b/boto/__init__.py
index 5b142e97..3d90e901 100644
--- a/boto/__init__.py
+++ b/boto/__init__.py
@@ -38,7 +38,7 @@ import logging.config
from boto.compat import urlparse
from boto.exception import InvalidUriError
-__version__ = '2.32.0'
+__version__ = '2.32.1'
Version = __version__ # for backware compatibility
# http://bugs.python.org/issue7980
diff --git a/boto/auth.py b/boto/auth.py
index 6d431461..6012962a 100644
--- a/boto/auth.py
+++ b/boto/auth.py
@@ -41,7 +41,7 @@ import sys
import time
import posixpath
-from boto.compat import urllib
+from boto.compat import urllib, encodebytes
from boto.auth_handler import AuthHandler
from boto.exception import BotoClientError
@@ -89,7 +89,7 @@ class HmacKeys(object):
def sign_string(self, string_to_sign):
new_hmac = self._get_hmac()
new_hmac.update(string_to_sign.encode('utf-8'))
- return base64.encodestring(new_hmac.digest()).decode('utf-8').strip()
+ return encodebytes(new_hmac.digest()).decode('utf-8').strip()
def __getstate__(self):
pickled_dict = copy.copy(self.__dict__)
@@ -99,7 +99,7 @@ class HmacKeys(object):
def __setstate__(self, dct):
self.__dict__ = dct
- self.update_provider(self._provider.encode('utf-8'))
+ self.update_provider(self._provider)
class AnonAuthHandler(AuthHandler, HmacKeys):
diff --git a/boto/cloudsearch/document.py b/boto/cloudsearch/document.py
index b5a6b455..0a1d9db2 100644
--- a/boto/cloudsearch/document.py
+++ b/boto/cloudsearch/document.py
@@ -240,6 +240,9 @@ class CommitResponse(object):
raise EncodingError("Illegal Unicode character in document")
elif e == "The Content-Length is too long":
raise ContentTooLongError("Content was too long")
+ if 'adds' not in self.content or 'deletes' not in self.content:
+ raise SearchServiceException("Error indexing documents"
+ " => %s" % self.content.get('message', ''))
else:
self.errors = []
diff --git a/boto/compat.py b/boto/compat.py
index 21a9193d..a7503f01 100644
--- a/boto/compat.py
+++ b/boto/compat.py
@@ -29,6 +29,13 @@ except ImportError:
import json
+# Switch to use encodebytes, which deprecates encodestring in Python 3
+try:
+ from base64 import encodebytes
+except ImportError:
+ from base64 import encodestring as encodebytes
+
+
# If running in Google App Engine there is no "user" and
# os.path.expanduser() will fail. Attempt to detect this case and use a
# no-op expanduser function in this case.
@@ -45,7 +52,6 @@ from boto.vendored.six import BytesIO, StringIO
from boto.vendored.six.moves import filter, http_client, map, _thread, \
urllib, zip
from boto.vendored.six.moves.queue import Queue
-from boto.vendored.six.moves.configparser import SafeConfigParser
from boto.vendored.six.moves.urllib.parse import parse_qs, quote, unquote, \
urlparse, urlsplit
from boto.vendored.six.moves.urllib.request import urlopen
@@ -54,6 +60,8 @@ if six.PY3:
# StandardError was removed, so use the base exception type instead
StandardError = Exception
long_type = int
+ from configparser import ConfigParser
else:
StandardError = StandardError
long_type = long
+ from ConfigParser import SafeConfigParser as ConfigParser
diff --git a/boto/connection.py b/boto/connection.py
index 9846a879..5fe9c198 100644
--- a/boto/connection.py
+++ b/boto/connection.py
@@ -42,9 +42,6 @@
"""
Handles basic connections to AWS
"""
-from __future__ import with_statement
-
-import base64
from datetime import datetime
import errno
import os
@@ -64,7 +61,7 @@ import boto.handler
import boto.cacerts
from boto import config, UserAgent
-from boto.compat import six, http_client, urlparse, quote
+from boto.compat import six, http_client, urlparse, quote, encodebytes
from boto.exception import AWSConnectionError
from boto.exception import BotoClientError
from boto.exception import BotoServerError
@@ -857,7 +854,7 @@ class AWSAuthConnection(object):
return path
def get_proxy_auth_header(self):
- auth = base64.encodestring(self.proxy_user + ':' + self.proxy_pass)
+ auth = encodebytes(self.proxy_user + ':' + self.proxy_pass)
return {'Proxy-Authorization': 'Basic %s' % auth}
def set_host_header(self, request):
diff --git a/boto/dynamodb/types.py b/boto/dynamodb/types.py
index 5e3bae69..2049c219 100644
--- a/boto/dynamodb/types.py
+++ b/boto/dynamodb/types.py
@@ -148,10 +148,10 @@ def dynamize_value(val):
if six.PY2:
class Binary(object):
def __init__(self, value):
- if isinstance(value, six.text_type): # Support only PY2 for backward compatibility.
- value = value.encode('utf-8')
- elif not isinstance(value, bytes):
+ if not isinstance(value, (bytes, six.text_type)):
raise TypeError('Value must be a string of binary data!')
+ if not isinstance(value, bytes):
+ value = value.encode("utf-8")
self.value = value
@@ -171,7 +171,7 @@ if six.PY2:
return 'Binary(%r)' % self.value
def __str__(self):
- return self.value.decode('utf-8')
+ return self.value
def __hash__(self):
return hash(self.value)
diff --git a/boto/emr/emrobject.py b/boto/emr/emrobject.py
index 0906bfab..f605834c 100644
--- a/boto/emr/emrobject.py
+++ b/boto/emr/emrobject.py
@@ -301,7 +301,7 @@ class ClusterSummaryList(EmrObject):
class StepConfig(EmrObject):
Fields = set([
- 'Jar'
+ 'Jar',
'MainClass'
])
@@ -434,11 +434,15 @@ class StepSummary(EmrObject):
def __init__(self, connection=None):
self.connection = connection
self.status = None
+ self.config = None
def startElement(self, name, attrs, connection):
if name == 'Status':
self.status = ClusterStatus()
return self.status
+ elif name == 'Config':
+ self.config = StepConfig()
+ return self.config
else:
return None
diff --git a/boto/fps/connection.py b/boto/fps/connection.py
index e8124ab2..6dc90a24 100644
--- a/boto/fps/connection.py
+++ b/boto/fps/connection.py
@@ -23,7 +23,6 @@
import urllib
import uuid
-from boto.compat import filter, map
from boto.connection import AWSQueryConnection
from boto.fps.exception import ResponseErrorFactory
from boto.fps.response import ResponseFactory
diff --git a/boto/glacier/concurrent.py b/boto/glacier/concurrent.py
index 93a12d4f..a4f3a224 100644
--- a/boto/glacier/concurrent.py
+++ b/boto/glacier/concurrent.py
@@ -19,8 +19,6 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
#
-from __future__ import with_statement
-
import os
import math
import threading
diff --git a/boto/glacier/job.py b/boto/glacier/job.py
index 097312a1..33e66a19 100644
--- a/boto/glacier/job.py
+++ b/boto/glacier/job.py
@@ -20,7 +20,6 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
#
-from __future__ import with_statement
import math
import socket
@@ -124,7 +123,7 @@ class Job(object):
verify_hashes, retry_exceptions)
def download_to_fileobj(self, output_file, chunk_size=DefaultPartSize,
- verify_hashes=True,
+ verify_hashes=True,
retry_exceptions=(socket.error,)):
"""Download an archive to a file object.
diff --git a/boto/glacier/layer1.py b/boto/glacier/layer1.py
index 45a142d8..39136cf0 100644
--- a/boto/glacier/layer1.py
+++ b/boto/glacier/layer1.py
@@ -89,12 +89,13 @@ class Layer1(AWSAuthConnection):
self.region = region
self.account_id = account_id
super(Layer1, self).__init__(region.endpoint,
- aws_access_key_id, aws_secret_access_key,
- is_secure, port, proxy, proxy_port,
- proxy_user, proxy_pass, debug,
- https_connection_factory,
- path, provider, security_token,
- suppress_consec_slashes, profile_name=profile_name)
+ aws_access_key_id, aws_secret_access_key,
+ is_secure, port, proxy, proxy_port,
+ proxy_user, proxy_pass, debug,
+ https_connection_factory,
+ path, provider, security_token,
+ suppress_consec_slashes,
+ profile_name=profile_name)
def _required_auth_capability(self):
return ['hmac-v4']
@@ -107,10 +108,10 @@ class Layer1(AWSAuthConnection):
headers['x-amz-glacier-version'] = self.Version
uri = '/%s/%s' % (self.account_id, resource)
response = super(Layer1, self).make_request(verb, uri,
- params=params,
- headers=headers,
- sender=sender,
- data=data)
+ params=params,
+ headers=headers,
+ sender=sender,
+ data=data)
if response.status in ok_responses:
return GlacierResponse(response, response_headers)
else:
@@ -826,9 +827,9 @@ class Layer1(AWSAuthConnection):
else:
sender = None
return self.make_request('POST', uri, headers=headers,
- sender=sender,
- data=archive, ok_responses=(201,),
- response_headers=response_headers)
+ sender=sender,
+ data=archive, ok_responses=(201,),
+ response_headers=response_headers)
def _is_file_like(self, archive):
return hasattr(archive, 'seek') and hasattr(archive, 'tell')
diff --git a/boto/glacier/utils.py b/boto/glacier/utils.py
index 21da67ba..98847e3f 100644
--- a/boto/glacier/utils.py
+++ b/boto/glacier/utils.py
@@ -23,6 +23,8 @@ import hashlib
import math
import binascii
+from boto.compat import six
+
_MEGABYTE = 1024 * 1024
DEFAULT_PART_SIZE = 4 * _MEGABYTE
@@ -122,10 +124,19 @@ def compute_hashes_from_fileobj(fileobj, chunk_size=1024 * 1024):
are returned in hex.
"""
+ # Python 3+, not binary
+ if six.PY3 and hasattr(fileobj, 'mode') and 'b' not in fileobj.mode:
+ raise ValueError('File-like object must be opened in binary mode!')
+
linear_hash = hashlib.sha256()
chunks = []
- chunk = fileobj.read(chunk_size).encode('utf-8')
+ chunk = fileobj.read(chunk_size)
while chunk:
+ # It's possible to get a file-like object that has no mode (checked
+ # above) and returns something other than bytes (e.g. str). So here
+ # we try to catch that and encode to bytes.
+ if not isinstance(chunk, bytes):
+ chunk = chunk.encode(getattr(fileobj, 'encoding', '') or 'utf-8')
linear_hash.update(chunk)
chunks.append(hashlib.sha256(chunk).digest())
chunk = fileobj.read(chunk_size)
diff --git a/boto/glacier/vault.py b/boto/glacier/vault.py
index e447c188..45d276ca 100644
--- a/boto/glacier/vault.py
+++ b/boto/glacier/vault.py
@@ -21,9 +21,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
#
-from __future__ import with_statement
import codecs
-from boto.compat import six
from boto.glacier.exceptions import UploadArchiveError
from boto.glacier.job import Job
from boto.glacier.writer import compute_hashes_from_fileobj, \
diff --git a/boto/gs/resumable_upload_handler.py b/boto/gs/resumable_upload_handler.py
index 5b88b621..d7443469 100644
--- a/boto/gs/resumable_upload_handler.py
+++ b/boto/gs/resumable_upload_handler.py
@@ -26,16 +26,13 @@ import re
import socket
import time
import urlparse
+from hashlib import md5
from boto import config, UserAgent
from boto.connection import AWSAuthConnection
from boto.exception import InvalidUriError
from boto.exception import ResumableTransferDisposition
from boto.exception import ResumableUploadException
from boto.s3.keyfile import KeyFile
-try:
- from hashlib import md5
-except ImportError:
- from md5 import md5
"""
Handler for Google Cloud Storage resumable uploads. See
diff --git a/boto/manage/volume.py b/boto/manage/volume.py
index a4fcb5f3..410414c7 100644
--- a/boto/manage/volume.py
+++ b/boto/manage/volume.py
@@ -18,7 +18,7 @@
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
-from __future__ import with_statement, print_function
+from __future__ import print_function
from boto.sdb.db.model import Model
from boto.sdb.db.property import StringProperty, IntegerProperty, ListProperty, ReferenceProperty, CalculatedProperty
diff --git a/boto/mws/connection.py b/boto/mws/connection.py
index 6759d028..01b0b30b 100644
--- a/boto/mws/connection.py
+++ b/boto/mws/connection.py
@@ -20,7 +20,6 @@
# IN THE SOFTWARE.
import xml.sax
import hashlib
-import base64
import string
import collections
from boto.connection import AWSQueryConnection
@@ -28,7 +27,7 @@ from boto.exception import BotoServerError
import boto.mws.exception
import boto.mws.response
from boto.handler import XmlHandler
-from boto.compat import filter, map, six
+from boto.compat import filter, map, six, encodebytes
__all__ = ['MWSConnection']
@@ -55,7 +54,7 @@ api_version_path = {
'OffAmazonPayments': ('2013-01-01', 'SellerId',
'/OffAmazonPayments/2013-01-01'),
}
-content_md5 = lambda c: base64.encodestring(hashlib.md5(c).digest()).strip()
+content_md5 = lambda c: encodebytes(hashlib.md5(c).digest()).strip()
decorated_attrs = ('action', 'response', 'section',
'quota', 'restore', 'version')
api_call_map = {}
diff --git a/boto/pyami/config.py b/boto/pyami/config.py
index 3789113b..37445f85 100644
--- a/boto/pyami/config.py
+++ b/boto/pyami/config.py
@@ -26,7 +26,7 @@ import warnings
import boto
-from boto.compat import expanduser, SafeConfigParser, StringIO
+from boto.compat import expanduser, ConfigParser, StringIO
# By default we use two locations for the boto configurations,
@@ -49,12 +49,12 @@ elif 'BOTO_PATH' in os.environ:
BotoConfigLocations.append(expanduser(path))
-class Config(SafeConfigParser):
+class Config(ConfigParser):
def __init__(self, path=None, fp=None, do_load=True):
# We don't use ``super`` here, because ``ConfigParser`` still uses
# old-style classes.
- SafeConfigParser.__init__(self, {'working_dir': '/mnt/pyami',
+ ConfigParser.__init__(self, {'working_dir': '/mnt/pyami',
'debug': '0'})
if do_load:
if path:
@@ -95,7 +95,7 @@ class Config(SafeConfigParser):
Replace any previous value. If the path doesn't exist, create it.
Also add the option the the in-memory config.
"""
- config = SafeConfigParser()
+ config = ConfigParser()
config.read(path)
if not config.has_section(section):
config.add_section(section)
@@ -139,21 +139,21 @@ class Config(SafeConfigParser):
def get(self, section, name, default=None):
try:
- val = SafeConfigParser.get(self, section, name)
+ val = ConfigParser.get(self, section, name)
except:
val = default
return val
def getint(self, section, name, default=0):
try:
- val = SafeConfigParser.getint(self, section, name)
+ val = ConfigParser.getint(self, section, name)
except:
val = int(default)
return val
def getfloat(self, section, name, default=0.0):
try:
- val = SafeConfigParser.getfloat(self, section, name)
+ val = ConfigParser.getfloat(self, section, name)
except:
val = float(default)
return val
diff --git a/boto/pyami/installers/ubuntu/mysql.py b/boto/pyami/installers/ubuntu/mysql.py
index 8dd643bf..5b0792ba 100644
--- a/boto/pyami/installers/ubuntu/mysql.py
+++ b/boto/pyami/installers/ubuntu/mysql.py
@@ -31,7 +31,7 @@ from boto.pyami.installers.ubuntu.installer import Installer
import os
import boto
from boto.utils import ShellCommand
-from ConfigParser import SafeConfigParser
+from boto.compat import ConfigParser
import time
ConfigSection = """
@@ -89,7 +89,7 @@ class MySQL(Installer):
self.start('mysql')
else:
#get the password ubuntu expects to use:
- config_parser = SafeConfigParser()
+ config_parser = ConfigParser()
config_parser.read('/etc/mysql/debian.cnf')
password = config_parser.get('client', 'password')
# start the mysql deamon, then mysql with the required grant statement piped into it:
diff --git a/boto/regioninfo.py b/boto/regioninfo.py
index eee20bbf..5862f16d 100644
--- a/boto/regioninfo.py
+++ b/boto/regioninfo.py
@@ -20,7 +20,6 @@
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
-from __future__ import with_statement
import os
import boto
diff --git a/boto/s3/key.py b/boto/s3/key.py
index ec9889b1..9674d356 100644
--- a/boto/s3/key.py
+++ b/boto/s3/key.py
@@ -20,8 +20,6 @@
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
-from __future__ import with_statement
-
import email.utils
import errno
import hashlib
@@ -31,8 +29,9 @@ import re
import base64
import binascii
import math
+from hashlib import md5
import boto.utils
-from boto.compat import BytesIO, six, urllib
+from boto.compat import BytesIO, six, urllib, encodebytes
from boto.exception import BotoClientError
from boto.exception import StorageDataError
@@ -45,11 +44,6 @@ from boto.utils import compute_md5, compute_hash
from boto.utils import find_matching_headers
from boto.utils import merge_headers_by_name
-try:
- from hashlib import md5
-except ImportError:
- from md5 import md5
-
class Key(object):
"""
@@ -211,7 +205,7 @@ class Key(object):
from just having a precalculated md5_hexdigest.
"""
digest = binascii.unhexlify(md5_hexdigest)
- base64md5 = base64.encodestring(digest)
+ base64md5 = encodebytes(digest)
if base64md5[-1] == '\n':
base64md5 = base64md5[0:-1]
return (md5_hexdigest, base64md5)
diff --git a/boto/sdb/db/manager/xmlmanager.py b/boto/sdb/db/manager/xmlmanager.py
index d19ad088..f457347a 100644
--- a/boto/sdb/db/manager/xmlmanager.py
+++ b/boto/sdb/db/manager/xmlmanager.py
@@ -22,7 +22,7 @@ import boto
from boto.utils import find_class, Password
from boto.sdb.db.key import Key
from boto.sdb.db.model import Model
-from boto.compat import six
+from boto.compat import six, encodebytes
from datetime import datetime
from xml.dom.minidom import getDOMImplementation, parse, parseString, Node
@@ -203,8 +203,7 @@ class XMLManager(object):
self.enable_ssl = enable_ssl
self.auth_header = None
if self.db_user:
- import base64
- base64string = base64.encodestring('%s:%s' % (self.db_user, self.db_passwd))[:-1]
+ base64string = encodebytes('%s:%s' % (self.db_user, self.db_passwd))[:-1]
authheader = "Basic %s" % base64string
self.auth_header = authheader
diff --git a/boto/utils.py b/boto/utils.py
index 1569209b..dd5f0956 100644
--- a/boto/utils.py
+++ b/boto/utils.py
@@ -57,25 +57,14 @@ import email.mime.text
import email.utils
import email.encoders
import gzip
-import base64
import threading
import locale
-from boto.compat import six, StringIO, urllib
+from boto.compat import six, StringIO, urllib, encodebytes
from contextlib import contextmanager
-try:
- from hashlib import md5
-except ImportError:
- from md5 import md5
-
-
-try:
- import hashlib
- _hashfn = hashlib.sha512
-except ImportError:
- import md5
- _hashfn = md5.md5
+from hashlib import md5, sha512
+_hashfn = sha512
from boto.compat import json
@@ -224,6 +213,11 @@ def retry_url(url, retry_on_404=True, num_retries=10):
req = urllib.request.Request(url)
r = opener.open(req)
result = r.read()
+
+ if(not isinstance(result, six.string_types) and
+ hasattr(result, 'decode')):
+ result = result.decode('utf-8')
+
return result
except urllib.error.HTTPError as e:
code = e.getcode()
@@ -1029,7 +1023,7 @@ def compute_hash(fp, buf_size=8192, size=None, hash_algorithm=md5):
else:
s = fp.read(buf_size)
hex_digest = hash_obj.hexdigest()
- base64_digest = base64.encodestring(hash_obj.digest()).decode('utf-8')
+ base64_digest = encodebytes(hash_obj.digest()).decode('utf-8')
if base64_digest[-1] == '\n':
base64_digest = base64_digest[0:-1]
# data_size based on bytes read.
diff --git a/boto/vpc/vpc_peering_connection.py b/boto/vpc/vpc_peering_connection.py
index d7c11e8e..cdb9af8d 100644
--- a/boto/vpc/vpc_peering_connection.py
+++ b/boto/vpc/vpc_peering_connection.py
@@ -145,7 +145,7 @@ class VpcPeeringConnection(TaggedEC2Object):
setattr(self, name, value)
def delete(self):
- return self.connection.delete_vpc(self.id)
+ return self.connection.delete_vpc_peering_connection(self.id)
def _update(self, updated):
self.__dict__.update(updated.__dict__)