UPYUN Python SDK
UPYUN Python SDK,集合 UPYUN HTTP REST 接口,UPYUN HTTP FORM 接口 和 视频处理接口。
更新说明
- 不再兼容 1.x 的版本,新版接口设计和实现更加 Pythonic,且代码风格完全符合 pep8 规范。
- 2.2.0 及以上版本同时兼容了最新版本的 Python 2.6 / 2.7 / 3.3 / 3.4。
- 2.3.0 及以上版本不再支持直接使用默认标准库 httplib,必须依赖 requests 这个第三方 HTTP Client 库。
- 2.5.0 及以上版本更新了 REST API,FORM API 以及预处理接口的签名算法,同时移除分块上传接口。
安装说明
安装第三方依赖库 requests: HTTP for Humans!
pip install requests
安装 UPYUN SDK
pip install upyun
运行测试用例
export UPYUN_SERVICE=<service>
export UPYUN_USERNAME=<username>
export UPYUN_PASSWORD=<password>
make init test
基本函数接口
初始化 UpYun
import upyun
up = upyun.UpYun('service', 'username', 'password', timeout=30, endpoint=upyun.ED_AUTO)
service
,username
,password
分别为服务名,授权操作员帐号,密码。timeout
为 HTTP 请求超时时间,默认 60 秒,可选。
由于直接在 SDK 中暴露密码可能存在安全隐患,因此对于安全性要求较高的用户,可使用如下远程签名方式:
import upyun
up = upyun.UpYun('service', username='username', auth_server='http://localhost:8080')
签名服务示例代码见 examples/auth_server.py
远程签名方式暂不支持缓存刷新功能
初始化示例
import upyun
up = upyun.UpYun('service', username='username', password='password')
以及,根据国内的网络情况,UPYUN API 目前提供了电信、联通网通、移动铁通三个接入点,在初始化时可由参数 endpoint
进行设置,其可选的值有:
upyun.ED_AUTO # 根据网络条件自动选择接入点,默认
upyun.ED_TELECOM # 电信接入点
upyun.ED_CNC # 联通网通接入点
upyun.ED_CTT # 移动铁通接入点
默认设置为 upyun.ED_AUTO
,但是我们推荐根据服务器网络状况,手动设置合理的接入点以获取最佳的访问速度。同时,也可通过:
up.<api>.endpoint = upyun.ED_TELECOM
在对象使用过程中更改,其中 <api>
为你所要调用接口,REST 为 up_rest
,表单为 up_form
,视频处理为 av
。
上传文件
直接传递文件内容的形式上传
up.put('/upyun-python-sdk/ascii.txt', 'abcdefghijklmnopqrstuvwxyz\n')
其中,方法 up.put
默认自动创建相应目录。
数据流方式上传,可降低内存占用
headers = { 'x-gmkerl-rotate': '180' }
with open('unix.png', 'rb') as f:
res = up.put('/upyun-python-sdk/xinu.png', f, checksum=True, headers=headers)
其中,参数 checksum
和 headers
可选,前者默认 False,表示不进行 MD5 校验; 后者可根据需求设置自定义 HTTP Header,例如作图参数 x-gmkerl-*
,具体请参考 REST API 上传文件。
上传成功,如果是图片类型文件,那么 res
返回的是一个包含图片长、宽、帧数和类型信息的 Python Dict 对象 ( 其他文件类型, 返回一个空的 Dict):
{'frames': '1', 'width': '1280', 'file-type': 'PNG', 'height': '800'}
上传失败,则抛出相应异常。
移动文件
up.move('/upyun-python-sdk/move-from.txt', '/upyun-python-sdk/move-to.txt')
第一个参数是源文件地址, 第二个参数是目的文件地址
拷贝文件
up.copy('/upyun-python-sdk/copy-from.txt', '/upyun-python-sdk/copy-to.txt')
第一个参数是源文件地址, 第二个参数是目的文件地址
断点续传
with open('unix.png', 'rb') as f:
res = up.put('/upyun-python-sdk/xinu.png', f, checksum=True, need_resume=True)
参数 need_resume
默认 False, 置为 True 后, 采用断点续传方式上传文件。
from upyun import FileStore
from upyun import print_reporter
with open('unix.png', 'rb') as f:
res = up.put('/upyun-python-sdk/xinu.png', f, checksum=True, need_resume=True, headers={'X-Upyun-Multi-Type': 'image/png'}, store=FileStore(), reporter=print_reporter)
参数 store
用来保存断点信息, 默认保存断点信息在内存中。 FileStore()
可以保存断点信息到文件, 注意文件夹的权限, 默认保存在 ~/.up-python-resume/
, 提供参数 directory
用于修改默认的文件夹路径。 也可以选择继承 BaseStore
实现自己的断点存储。
参数 reporter
用于报告上传进度, 默认忽略上传进度。 print_reporter
只是 print
上传进度, 有需要的请继承 BaseReporter
自行处理。
可以使用头部 X-Upyun-Multi-Type
来指定待上传文件的 MIME 类型,默认 application/octet-stream,建议自行设置。
并发上传
并发上传是把文件按照part_size切割后,并发上传,都上传完毕后调用complete
结束上传。
part_size取值1M(1024*1024)的整数倍,默认是1M。
下面的示例是并发上传一个2.5M的文件,数据内容是随机生成的。其中的upload
方法可以多线程并发调用
uploader = up.init_multi_uploader(key) #初始化上传
#并发上传需要数据块
uploader.upload(2, os.urandom(512 * 1024))
uploader.upload(0, os.urandom(1024 * 1024))
uploader.upload(1, os.urandom(1024 * 1024))
res = uploader.complete() #所有块都上传完毕后,调用结束
一次上传没有完成, 可以把uploader.upload_id的值保存下来, 下次继续上传
uploader = up.init_multi_uploader(remote_file, upload_id=uploader.upload_id)
如果有需要,可以列出来已经上传成功的parts
datas = uploader.list_uploaded_parts()
返回一个json结构的数组
[{
"id": 0,
"suze": 1048576,
"etag": "cf97350abc2b45804d09a829b55eeeaf",
}]
若在上传过程中不需要上传了,可以调用uploader.cancel()
取消上传任务。取消的任务无法再继续上传。
表单方式上传
用户可直接上传文件到 UPYUN,而不需要通过客户服务器进行中转。
kwargs = { 'allow-file-type': 'jpg,jpeg,png',
'notify-url': 'http://httpbin.org/post', }
with open('unix.png', 'rb') as f:
res = up.put('/upyun-python-sdk/xinu.png', f, checksum=True, form=True, **kwargs)
其中,参数 form
表示是否使用表单上传方式,必选。
同时表单上传可携带许多额外的可选参数,可以组合成字典作为函数可选参数传入,例如表单参数 allow-file-type
,具体请参考 表单 API 参数。
表单上传还支持同步通知及异步通知机制,可以通过设置 return-url
和 notify-url
来指定 URL。具体请参考通知规则。
上传成功,如果是图片类型文件,那么 res
返回的是一个包含图片长、宽、帧数、类型信息、图片上传地址、返回状态码、返回状态信息和 signature 的 Python Dict 对象 (其他文件类型,则返回信息不包括图片长、宽和帧数参数):
{u'code': 200, u'image-height': 410, u'url': u'/upyun-python-sdk/xinu.png', u'image-frames': 1, u'sign': u'60e63662202e50bddedd01f8ca601ba5', u'image-type': u'PNG', u'time': 1450783577, u'message': u'ok', u'image-width': 1000}
下载文件
直接读取文件内容
res = up.get('/upyun-python-sdk/ascii.txt')
下载成功,返回文件内容; 失败则抛出相应异常。
使用数据流模式下载,节省内存占用
with open('xinu.png', 'wb') as f:
up.get('/upyun-python-sdk/xinu.png', f)
下载成功,返回 Python None
对象; 失败则抛出相应异常。
创建目录
up.mkdir('/upyun-python-sdk/temp/')
创建成功,返回 Python None
对象; 失败则抛出相应异常。
删除目录或文件
up.delete('/upyun-python-sdk/xinu.png')
up.delete('/upyun-python-sdk/temp/')
删除成功,返回 Python None
对象; 失败则抛出相应异常。注意删除目录时,必须保证目录为空。
获取目录文件列表
res = up.getlist('/upyun-python-sdk/')
获取成功,返回一个包含该目录下所有目录或文件条目信息的 Python List 对象:
[{'time': '1363247311', 'type': 'F', 'name': 'temp', 'size': '0'}, {'time': '1363247311', 'type': 'N', 'name': 'xinu.png', 'size': '477908'}]
其中每个条目信息是又是一个 Python Dict 对象:
item = res[0]
print item['name'] # 文件名称
print item['type'] # 文件类型
print item['size'] # 文件大小
print item['time'] # 创建时间
获取失败,则抛出相应的异常。该方法默认获取根目录列表信息。
分页功能
res = up.getlist('/upyun-python-sdk/', limit=10, order='asc', begin='xxx')
三个分页参数,默认为空,具体含义请参见 分页参数
分页获取文件
res = get_list_with_iter('/upyun-python-sdk/', limit=10, order='asc', begin='xxx')
{
'files': [{
'name': 'xxx.m4a',
'type': 'N',
'size': '332918',
'time': '1449137388'
}],
'iter': 'xxxxx'
}
三个分页参数,默认为空,具体含义请参见 分页参数
流式返回
iter_items = up.iterlist('/upyun-python-sdk/', limit=10, order='asc', begin='xxx')
# the resulting iterator object
for item in iter_items:
print(item['type'], item['name'], item['size'])
三个分页参数,默认为空,具体含义请参见 分页参数
获取文件信息
res = up.getinfo('/upyun-python-sdk/xinu.png')
print res['file-type']
print res['file-size']
print res['file-date']
获取成功,返回一个 Python Dict 对象; 失败则抛出相应异常。
获取服务使用情况
res = up.usage()
获取成功,始终返回该服务当前使用的总容量,单位 Bytes,值类型为 Python String 对象; 失败则抛出相应异常。
视频处理
用于处理已经上传到对应存储服务中的视频文件,进行转码、截图等操作。
source = '/service/test.mp4'
tasks = [{'type': 'probe', }, {'type': 'hls', 'hls_time': '100'}]
notify_url = 'http://httpbin.org/post'
up.pretreat(tasks, source, notify_url)
tasks
为提交的任务数据,需将所有任务组成数组,若仅有一个任务,也应组成数组结构,必选。UPYUN 的视频处理服务目前支持四种类型的处理请求:
- 视频转码
- HLS 切割
- 视频截图
- 视频信息获取
具体请参考视频处理参数
notify_url
为异步回调地址,在处理完成之后将会以 HTTP POST
请求进行异步通知,参考回调参数, 必选。source
为待处理源文件路径,需提供已上传文件的相对路径。
视频处理任务提交成功,则会针对提交的处理任务返回一组唯一的 task_id
,可以根据这个 task_id
查询处理进度,如:
[
'35f0148d414a688a275bf915ba7cebb2',
'98adbaa52b2f63d6d7f327a0ff223348',
...
]
任务提交失败则会抛出相应异常。
视频处理进度查询
ids = ['35f0148d414a688a275bf915ba7cebb2','98adbaa52b2f63d6d7f327a0ff223348', ...]
up.status(ids)
以视频处理接口返回的数组作为传入参数,需为 Python List 结构。
返回的数据示例如下:
{
tasks: {
35f0148d414a688a275bf915ba7cebb2: 100,
98adbaa52b2f63d6d7f327a0ff223348: null,
...
}
}
特别的,当值为 null 时,表示没有查询到相关的任务信息。同时,由于视频处理所用时间较长,当提交任务后立刻去查询进度,也有可能会返回 null。
异步任务提交
notify_url = 'http://httpbin.org/post' // 回调地址
compress_tasks = [
{
"sources": ["a/b/c/source/1.jpg","a/b/c/source/2.jpg"],
"save_as": "/result/t.zip",
"home_dir": "a/b/c"
},
]
print up.put_tasks(compress_tasks, notify_url, 'compress')
depress_tasks = [
{
"sources": "/source/t.zip", //UPYUN 存储服务中内文件路径
"save_as": "/result/t/", //保存路径
},
]
print up.put_tasks(depress_tasks, notify_url, 'depress')
fetch_tasks = [
{
'url': 'http://www.upyun.com/index.html', // 需要拉取文件的 URL
'random': False, // 是否追加随机数, 默认 false
'overwrite': True, // 是否覆盖,默认 true
'save_as': '/site/index.html', // 保存路径
}
]
print up.put_tasks(fetch_tasks, notify_url, 'spiderman')
异常处理
try:
res = up.usage()
# do something else
except upyun.UpYunServiceException as se:
print 'Except an UpYunServiceException ...'
print 'Request Id: ' + se.request_id
print 'HTTP Status Code: ' + str(se.status)
print 'Error Message: ' + se.msg + '\n'
except upyun.UpYunClientException as ce:
print 'Except an UpYunClientException ...'
print 'Error Message: ' + ce.msg + '\n'
其中, UpYunServiceException
主要是 UPYUN 端返回的错误信息,具体错误代码请参考 标准 API 错误代码表; 而 UpYunClientException
则主要是一些客户端环境的异常,例如客户端网络超时,或客户端参数不完整等。
高级特性
自定义数据流大小
up = upyun.UpYun('service', 'username', 'password', chunksize=8192)
当通过数据流方式上传和下载文件时,chunksize
决定了每次读操作的缓存区大小,默认 8192 字节。
自定义文件上传和下载过程
例如,通过如下代码可以很容易实现上传下载的进度条显示:
from progressbar import *
class ProgressBarHandler(object):
def __init__(self, totalsize, params):
widgets = [params, Percentage(), ' ',
Bar(marker='=', left='[', right=']'), ' ',
ETA(), ' ', FileTransferSpeed()]
self.pbar = ProgressBar(widgets=widgets, maxval=totalsize).start()
def update(self, readsofar):
self.pbar.update(readsofar)
def finish(self):
self.pbar.finish()
with open('unix.png', 'rb') as f:
res = up.put('xinu.png', f, handler=ProgressBarHandler, params='Uploading ')
with open('xinu.png', 'wb') as f:
up.get('xinu.png', f, handler=ProgressBarHandler, params='Downloading ')
原图密钥保护
with open('unix.png', 'rb') as f:
res = up.put('xinu.png', f, secret="abc")
其中参数 secret
可指定具体密钥内容;默认 None
,表示不设置密钥。特别地,该功能仅对配置了缩略图版本号的图片服务有效。
详见 UPYUN HTTP REST API 接口 中关于原图密钥保护的说明。
缓存刷新
基于 UPYUN 缓存刷新 API 接口 开发,方便对 CDN 服务缓存资源进行主动刷新。
特别地,云存储服务正常情况下,资源更新则不需要额外提交刷新请求,缓存系统会自动进行处理。
>>> print up.purge('/upyun-python-sdk/xinu.png')
[]
>>> print up.purge(['/unix.png', '/xinu.png'], domain='invalid.upyun.com')
['/unix.png', '/unix.png']
支持提交单个或一组 URI 到缓存刷新队列,其中 domain
参数可特别指定为该服务对应的绑定域名作为本次刷新的域,默认其值为 None
,表示始终使用默认域名。
提交成功,返回一个 Python List 对象,包含本次提交中无效的 URI 列表;失败则抛出相应异常。
签名验证
如果在表单或异步任务提交接口使用了 return-url
或 notify-url
等通知方法后,回调结果信息头会包含 Authorization
字段,用于验证回调信息是否正确。
import upyun
up = upyun.UpYun('service', 'username', 'password')
headers = {
'Date': 'Fri, 20 Jan 2017 08:46:20 GMT',
'Content-MD5': 'd36489794822f8d33fd28217d8a5bed4',
'Authorization': 'UPYUN username:W738BergX15B+jso8fSPzKd0/zQ='
}
assert up.verify_signature(headers['Authorization'], '/api/v1/echo', headers)
远程签名服务
创建自己的远程签名服务以提供签名功能。实现 API 如下:
URL:任意合法 URL
HTTP 方法:POST
文档格式:JSON
请求参数:
参数名称 | 必选 | 类型 |
---|---|---|
username | true | string |
method | true | string |
uri | true | string |
date | true | stirng |
policy | false | string |
content_md5 | false | string |
返回结果: UPYUN: username:signature
参数说明及签名算法见签名算法