Skip to content

Commit 8af5c22

Browse files
committed
Merge pull request #95 from qiniu/develop
Release v6.1.4
2 parents 7a5a963 + b8969aa commit 8af5c22

File tree

10 files changed

+84
-14
lines changed

10 files changed

+84
-14
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
## CHANGE LOG
22

3+
### v6.1.4
4+
5+
2013-10-24 issue [#95](https://github.com/qiniu/python-sdk/pull/95)
6+
7+
- [#78] 增加 putpolicy 选项:saveKey,insertOnly,detectMime,fsizeLimit,persistentNotifyUrl,persistentOps
8+
- [#80] 增加 gettoken 过期时间参数,增加 rsf 返回为空的EOF判断
9+
- [#86] 修正 断点续传的bug
10+
- [#93] 修正 4M 分块计算bug
11+
- [#96] 修正 mime_type typo
12+
313
### v6.1.3
414

515
2013-10-24 issue [#77](https://github.com/qiniu/python-sdk/pull/77)

docs/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
title: Python SDK 使用指南
33
---
44

5+
# Python SDK 使用指南
6+
57
此 Python SDK 适用于2.x版本,基于 [七牛云存储官方API](http://docs.qiniu.com/) 构建。使用此 SDK 构建您的网络应用程序,能让您以非常便捷地方式将数据安全地存储到七牛云存储上。无论您的网络应用是一个网站程序,还是包括从云端(服务端程序)到终端(手持设备应用)的架构的服务或应用,通过七牛云存储及其 SDK,都能让您应用程序的终端用户高速上传和下载,同时也让您的服务端更加轻盈。
68

79
SDK 下载地址:<https://github.com/qiniu/python-sdk/tags>

qiniu/auth/up.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55

66
class Client(rpc.Client):
77
up_token = None
8-
8+
99
def __init__(self, up_token, host=None):
1010
if host is None:
1111
host = conf.UP_HOST
12+
if host.startswith("http://"):
13+
host = host[7:]
1214
self.up_token = up_token
1315
super(Client, self).__init__(host)
1416

qiniu/resumable_io.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
_chunk_size = 256 * 1024
1515
_try_times = 3
1616
_block_size = 4 * 1024 * 1024
17+
_block_mask = _block_size - 1
1718

1819
class Error(Exception):
1920
value = None
@@ -84,15 +85,14 @@ def put(uptoken, key, f, fsize, extra):
8485
if extra.chunk_size is None:
8586
extra.chunk_size = _chunk_size
8687

87-
client = auth.up.Client(uptoken)
8888
for i in xrange(0, block_cnt):
8989
try_time = extra.try_times
9090
read_length = _block_size
9191
if (i+1)*_block_size > fsize:
9292
read_length = fsize - i*_block_size
9393
data_slice = f.read(read_length)
9494
while True:
95-
err = resumable_block_put(client, data_slice, i, extra)
95+
err = resumable_block_put(data_slice, i, extra, uptoken)
9696
if err is None:
9797
break
9898

@@ -101,34 +101,38 @@ def put(uptoken, key, f, fsize, extra):
101101
return None, err_put_failed
102102
print err, ".. retry"
103103

104-
return mkfile(client, key, fsize, extra)
104+
mkfile_client = auth.up.Client(uptoken, extra.progresses[-1]["host"])
105+
return mkfile(mkfile_client, key, fsize, extra)
105106

106107
# ----------------------------------------------------------
107108

108-
def resumable_block_put(client, block, index, extra):
109+
def resumable_block_put(block, index, extra, uptoken):
109110
block_size = len(block)
110111

112+
mkblk_client = auth.up.Client(uptoken, conf.UP_HOST)
111113
if extra.progresses[index] is None or "ctx" not in extra.progresses[index]:
112114
end_pos = extra.chunk_size-1
113115
if block_size < extra.chunk_size:
114116
end_pos = block_size-1
115117
chunk = block[: end_pos]
116118
crc32 = gen_crc32(chunk)
117119
chunk = bytearray(chunk)
118-
extra.progresses[index], err = mkblock(client, block_size, chunk)
120+
extra.progresses[index], err = mkblock(mkblk_client, block_size, chunk)
119121
if not extra.progresses[index]["crc32"] == crc32:
120122
return err_unmatched_checksum
121123
if err is not None:
122124
extra.notify_err(index, end_pos + 1, err)
123125
return err
124126
extra.notify(index, end_pos + 1, extra.progresses[index])
125127

128+
bput_client = auth.up.Client(uptoken, extra.progresses[index]["host"])
126129
while extra.progresses[index]["offset"] < block_size:
127130
offset = extra.progresses[index]["offset"]
128131
chunk = block[offset: offset+extra.chunk_size-1]
129132
crc32 = gen_crc32(chunk)
130133
chunk = bytearray(chunk)
131-
extra.progresses[index], err = putblock(client, extra.progresses[index], chunk)
134+
135+
extra.progresses[index], err = putblock(bput_client, extra.progresses[index], chunk)
132136
if not extra.progresses[index]["crc32"] == crc32:
133137
return err_unmatched_checksum
134138
if err is not None:
@@ -138,7 +142,7 @@ def resumable_block_put(client, block, index, extra):
138142

139143
def block_count(size):
140144
global _block_size
141-
return size / _block_size + 1
145+
return (size + _block_mask) / _block_size
142146

143147
def mkblock(client, block_size, first_chunk):
144148
url = "http://%s/mkblk/%s" % (conf.UP_HOST, block_size)

qiniu/rpc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def encode_multipart_formdata(self, fields, files):
112112
disposition = "Content-Disposition: form-data;"
113113
filename = _qiniu_escape(file_info.get('filename'))
114114
L.append('%s name="file"; filename="%s"' % (disposition, filename))
115-
L.append('Content-Type: %s' % file_info.get('content_type', 'application/octet-stream'))
115+
L.append('Content-Type: %s' % file_info.get('mime_type', 'application/octet-stream'))
116116
L.append('')
117117
L.append('')
118118
b2 = CRLF.join(L)

qiniu/rs/rs_token.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ def token(self, mac=None):
7777

7878
class GetPolicy(object):
7979
expires = 3600
80-
def __init__(self):
81-
pass
80+
def __init__(self, expires=3600):
81+
self.expires = expires
8282

8383
def make_request(self, base_url, mac=None):
8484
'''

qiniu/rs/test/rs_token_test.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,38 @@ class TestToken(unittest.TestCase):
2222
def test_put_policy(self):
2323
policy = rs.PutPolicy(bucket_name)
2424
policy.endUser = "hello!"
25+
policy.returnUrl = "http://localhost:1234/path?query=hello"
26+
policy.returnBody = "$(sha1)"
27+
# Do not specify the returnUrl and callbackUrl at the same time
28+
policy.callbackUrl = "http://1.2.3.4/callback"
29+
policy.callbackBody = "$(bucket)"
30+
31+
policy.saveKey = "$(sha1)"
32+
policy.insertOnly = 1
33+
policy.detectMime = 1
34+
policy.fsizeLimit = 1024
35+
policy.persistentNotifyUrl = "http://4.3.2.1/persistentNotifyUrl"
36+
policy.persistentOps = "avthumb/flash"
37+
2538
tokens = policy.token().split(':')
39+
40+
# chcek first part of token
2641
self.assertEqual(conf.ACCESS_KEY, tokens[0])
2742
data = json.loads(decode(tokens[2]))
43+
44+
# check if same
2845
self.assertEqual(data["scope"], bucket_name)
2946
self.assertEqual(data["endUser"], policy.endUser)
47+
self.assertEqual(data["returnUrl"], policy.returnUrl)
48+
self.assertEqual(data["returnBody"], policy.returnBody)
49+
self.assertEqual(data["callbackUrl"], policy.callbackUrl)
50+
self.assertEqual(data["callbackBody"], policy.callbackBody)
51+
self.assertEqual(data["saveKey"], policy.saveKey)
52+
self.assertEqual(data["exclusive"], policy.insertOnly)
53+
self.assertEqual(data["detectMime"], policy.detectMime)
54+
self.assertEqual(data["fsizeLimit"], policy.fsizeLimit)
55+
self.assertEqual(data["persistentNotifyUrl"], policy.persistentNotifyUrl)
56+
self.assertEqual(data["persistentOps"], policy.persistentOps)
3057

3158
new_hmac = encode(hmac.new(conf.SECRET_KEY, tokens[2], sha1).digest())
3259
self.assertEqual(new_hmac, tokens[1])

qiniu/rsf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,6 @@ def list_prefix(self, bucket, prefix=None, marker=None, limit=None):
3636
ops['prefix'] = prefix
3737
url = '%s?%s' % ('/list', urllib.urlencode(ops))
3838
ret, err = self.conn.call_with(url, body=None, content_type='application/x-www-form-urlencoded')
39-
if not ret.get('marker'):
39+
if ret and not ret.get('marker'):
4040
err = EOF
4141
return ret, err

qiniu/test/resumable_io_test.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,31 @@ def test_put(self):
7777
self.assertEqual(ret["hash"], "FnyTMUqPNRTdk1Wou7oLqDHkBm_p", "hash not match")
7878
rs.Client().delete(bucket, key)
7979

80+
def test_put_4m(self):
81+
ostype = platform.system()
82+
if ostype.lower().find("windows") != -1:
83+
tmpf = "".join([os.getcwd(), os.tmpnam()])
84+
else:
85+
tmpf = os.tmpnam()
86+
dst = open(tmpf, 'wb')
87+
dst.write("abcd" * 1024 * 1024)
88+
dst.flush()
89+
90+
policy = rs.PutPolicy(bucket)
91+
extra = resumable_io.PutExtra(bucket)
92+
extra.bucket = bucket
93+
extra.params = {"x:foo": "test"}
94+
key = "sdk_py_resumable_block_6_%s" % r(9)
95+
localfile = dst.name
96+
ret, err = resumable_io.put_file(policy.token(), key, localfile, extra)
97+
assert ret.get("x:foo") == "test", "return data not contains 'x:foo'"
98+
dst.close()
99+
os.remove(tmpf)
100+
101+
assert err is None, err
102+
self.assertEqual(ret["hash"], "FnIVmMd_oaUV3MLDM6F9in4RMz2U", "hash not match")
103+
rs.Client().delete(bucket, key)
104+
80105

81106
if __name__ == "__main__":
82107
unittest.main()

qiniu/test/rsf_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
class TestRsf(unittest.TestCase):
1212
def test_list_prefix(self):
1313
c = rsf.Client()
14-
ret, err = c.list_prefix(bucket_name, limit = 1)
14+
ret, err = c.list_prefix(bucket_name, limit = 4)
1515
self.assertEqual(err is rsf.EOF or err is None, True)
16-
assert len(ret.get('items')) == 1
16+
assert len(ret.get('items')) == 4
1717

1818

1919
if __name__ == "__main__":

0 commit comments

Comments
 (0)