Skip to content

Commit b0242f3

Browse files
committed
Create azure-multiapi-storage package.
- Include set up docs. - Support wheel building - Add storage 0.30.0 and storage 0.34.0
1 parent 6916da0 commit b0242f3

File tree

110 files changed

+36831
-3
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

110 files changed

+36831
-3
lines changed

.gitignore

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Python cache
2+
__pycache__/
3+
*.pyc
4+
5+
# Virtual environment
6+
env/
7+
env27/
8+
.python-version
9+
10+
# PTVS analysis
11+
.ptvs/
12+
13+
# Build results
14+
obj/
15+
dist/
16+
MANIFEST
17+
packaged_releases/windows/out
18+
19+
# Result of running python setup.py install/pip install -e
20+
RECORD.txt
21+
build/
22+
*.egg-info/
23+
24+
# Test results
25+
TestResults/
26+
27+
# Credentials
28+
credentials_real.json
29+
testsettings_local.json
30+
servicebus_settings_real.py
31+
storage_settings_real.py
32+
legacy_mgmt_settings_real.py
33+
mgmt_settings_real.py
34+
app_creds_real.py
35+
36+
# User-specific files
37+
*.suo
38+
*.user
39+
*.sln.docstates
40+
.vs/
41+
42+
# Windows image file caches
43+
Thumbs.db
44+
ehthumbs.db
45+
46+
# Folder config file
47+
Desktop.ini
48+
49+
# Recycle Bin used on file shares
50+
$RECYCLE.BIN/
51+
52+
# Mac desktop service store files
53+
.DS_Store
54+
55+
.idea
56+
src/build
57+
*.iml
58+
/doc/_build
59+
/doc/sphinx/_build
60+
/.vs/config/applicationhost.config
61+
.vscode/settings.json
62+
.vscode/.ropeproject/
63+
.project
64+
.pydevproject
65+
66+
# Azure deployment credentials
67+
*.pubxml
68+
69+
# Auxiliary files
70+
command_coverage.txt
71+
72+
# Test artifacts
73+
private_config.json
74+
scripts/smart_create_gen/config.ini
75+
debug.log
76+
test_results/
77+
78+
# Code coverage
79+
.coverage

LICENSE

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2017 Derek Bekoe
3+
Copyright (c) 2017 Microsoft Corporation
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

MANIFEST.in

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
include *.rst
2+
exclude azure/__init__.py

README.md

-2
This file was deleted.

README.rst

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
Microsoft Azure Storage Client Library for Python - with Multi API version Support
2+
==================================================================================
3+
4+
Handles multi-API versions of Azure Storage Data Plane originally from https://github.com/Azure/azure-storage-python.
5+
6+
Change Log
7+
----------
8+
9+
0.1.0
10+
+++++
11+
* Initial release.
12+
* Supported API versions:
13+
- 2016-05-31 (from 0.34.0 of azure-storage)
14+
- 2015-04-05 (from 0.30.0 of azure-storage)
15+

azure/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__import__('pkg_resources').declare_namespace(__name__)

azure/multiapi/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__import__('pkg_resources').declare_namespace(__name__)

azure/multiapi/storage/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__import__('pkg_resources').declare_namespace(__name__)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#-------------------------------------------------------------------------
2+
# Copyright (c) Microsoft. All rights reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#--------------------------------------------------------------------------
15+
from ._constants import (
16+
__author__,
17+
__version__,
18+
X_MS_VERSION,
19+
)
20+
21+
from .models import (
22+
RetentionPolicy,
23+
Logging,
24+
Metrics,
25+
CorsRule,
26+
ServiceProperties,
27+
AccessPolicy,
28+
ResourceTypes,
29+
Services,
30+
AccountPermissions,
31+
Protocol,
32+
)
33+
34+
from .cloudstorageaccount import CloudStorageAccount
35+
from .sharedaccesssignature import (
36+
SharedAccessSignature,
37+
)
+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
#-------------------------------------------------------------------------
2+
# Copyright (c) Microsoft. All rights reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#--------------------------------------------------------------------------
15+
from ._common_conversion import (
16+
_sign_string,
17+
)
18+
19+
20+
class _StorageSharedKeyAuthentication(object):
21+
def __init__(self, account_name, account_key):
22+
self.account_name = account_name
23+
self.account_key = account_key
24+
25+
def _get_headers(self, request, headers_to_sign):
26+
headers = dict((name.lower(), value) for name, value in request.headers if value)
27+
if 'content-length' in headers and headers['content-length'] == '0':
28+
del headers['content-length']
29+
return '\n'.join(headers.get(x, '') for x in headers_to_sign) + '\n'
30+
31+
def _get_verb(self, request):
32+
return request.method + '\n'
33+
34+
def _get_canonicalized_resource(self, request):
35+
uri_path = request.path.split('?')[0]
36+
return '/' + self.account_name + uri_path
37+
38+
def _get_canonicalized_headers(self, request):
39+
string_to_sign = ''
40+
x_ms_headers = []
41+
for name, value in request.headers:
42+
if name.startswith('x-ms-'):
43+
x_ms_headers.append((name.lower(), value))
44+
x_ms_headers.sort()
45+
for name, value in x_ms_headers:
46+
if value is not None:
47+
string_to_sign += ''.join([name, ':', value, '\n'])
48+
return string_to_sign
49+
50+
def _add_authorization_header(self, request, string_to_sign):
51+
signature = _sign_string(self.account_key, string_to_sign)
52+
auth_string = 'SharedKey ' + self.account_name + ':' + signature
53+
request.headers.append(('Authorization', auth_string))
54+
55+
56+
class _StorageSharedKeyAuthentication(_StorageSharedKeyAuthentication):
57+
def sign_request(self, request):
58+
string_to_sign = \
59+
self._get_verb(request) + \
60+
self._get_headers(
61+
request,
62+
[
63+
'content-encoding', 'content-language', 'content-length',
64+
'content-md5', 'content-type', 'date', 'if-modified-since',
65+
'if-match', 'if-none-match', 'if-unmodified-since', 'byte_range'
66+
]
67+
) + \
68+
self._get_canonicalized_headers(request) + \
69+
self._get_canonicalized_resource(request) + \
70+
self._get_canonicalized_resource_query(request)
71+
72+
self._add_authorization_header(request, string_to_sign)
73+
74+
def _get_canonicalized_resource_query(self, request):
75+
request.query.sort()
76+
77+
string_to_sign = ''
78+
for name, value in request.query:
79+
if value:
80+
string_to_sign += '\n' + name.lower() + ':' + value
81+
82+
return string_to_sign
83+
84+
85+
class _StorageTableSharedKeyAuthentication(_StorageSharedKeyAuthentication):
86+
def sign_request(self, request):
87+
string_to_sign = \
88+
self._get_verb(request) + \
89+
self._get_headers(
90+
request,
91+
['content-md5', 'content-type', 'x-ms-date'],
92+
) + \
93+
self._get_canonicalized_resource(request) + \
94+
self._get_canonicalized_resource_query(request)
95+
96+
self._add_authorization_header(request, string_to_sign)
97+
98+
def _get_canonicalized_resource_query(self, request):
99+
for name, value in request.query:
100+
if name == 'comp':
101+
return '?comp=' + value
102+
return ''
103+
104+
105+
class _StorageNoAuthentication(object):
106+
def sign_request(self, request):
107+
pass
108+
109+
110+
class _StorageSASAuthentication(object):
111+
def __init__(self, sas_token):
112+
self.sas_token = sas_token
113+
114+
def sign_request(self, request):
115+
if '?' in request.path:
116+
request.path += '&'
117+
else:
118+
request.path += '?'
119+
120+
request.path += self.sas_token
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#-------------------------------------------------------------------------
2+
# Copyright (c) Microsoft. All rights reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#--------------------------------------------------------------------------
15+
16+
import base64
17+
import hashlib
18+
import hmac
19+
import sys
20+
from dateutil.tz import tzutc
21+
22+
from .models import (
23+
_unicode_type,
24+
)
25+
26+
27+
if sys.version_info < (3,):
28+
def _str(value):
29+
if isinstance(value, unicode):
30+
return value.encode('utf-8')
31+
32+
return str(value)
33+
else:
34+
_str = str
35+
36+
37+
def _to_str(value):
38+
return _str(value) if value is not None else None
39+
40+
def _int_to_str(value):
41+
return str(int(value)) if value is not None else None
42+
43+
def _bool_to_str(value):
44+
if value is None:
45+
return None
46+
47+
if isinstance(value, bool):
48+
if value:
49+
return 'true'
50+
else:
51+
return 'false'
52+
53+
return str(value)
54+
55+
def _to_utc_datetime(value):
56+
return value.strftime('%Y-%m-%dT%H:%M:%SZ')
57+
58+
def _datetime_to_utc_string(value):
59+
# Azure expects the date value passed in to be UTC.
60+
# Azure will always return values as UTC.
61+
# If a date is passed in without timezone info, it is assumed to be UTC.
62+
if value is None:
63+
return None
64+
65+
if value.tzinfo:
66+
value = value.astimezone(tzutc())
67+
68+
return value.strftime('%a, %d %b %Y %H:%M:%S GMT')
69+
70+
def _encode_base64(data):
71+
if isinstance(data, _unicode_type):
72+
data = data.encode('utf-8')
73+
encoded = base64.b64encode(data)
74+
return encoded.decode('utf-8')
75+
76+
77+
def _decode_base64_to_bytes(data):
78+
if isinstance(data, _unicode_type):
79+
data = data.encode('utf-8')
80+
return base64.b64decode(data)
81+
82+
83+
def _decode_base64_to_text(data):
84+
decoded_bytes = _decode_base64_to_bytes(data)
85+
return decoded_bytes.decode('utf-8')
86+
87+
88+
def _sign_string(key, string_to_sign, key_is_base64=True):
89+
if key_is_base64:
90+
key = _decode_base64_to_bytes(key)
91+
else:
92+
if isinstance(key, _unicode_type):
93+
key = key.encode('utf-8')
94+
if isinstance(string_to_sign, _unicode_type):
95+
string_to_sign = string_to_sign.encode('utf-8')
96+
signed_hmac_sha256 = hmac.HMAC(key, string_to_sign, hashlib.sha256)
97+
digest = signed_hmac_sha256.digest()
98+
encoded_digest = _encode_base64(digest)
99+
return encoded_digest
100+
101+
102+
def _lower(text):
103+
return text.lower()

0 commit comments

Comments
 (0)