Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bump to 7.14.0 #450

Merged
merged 34 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
6fcc9fc
feat: add retrier
lihsai0 Jul 12, 2024
73579c4
chore(utils): deprecate etag
lihsai0 Jul 16, 2024
fcc2fb9
refactor: update circle import solution between region and conf
lihsai0 Jul 28, 2024
2a15d32
feat: add new region and endpoint for source/accelerate uploading wit…
lihsai0 Aug 4, 2024
cfc89d8
fix: default_client will not work with config.set_default by call once
lihsai0 Aug 7, 2024
dfba4c5
chore: remove iter self for endpoint
lihsai0 Aug 7, 2024
d63a903
chore: improve error text
lihsai0 Aug 7, 2024
d925540
fix: some features are not compatible with old version and improve er…
lihsai0 Aug 7, 2024
4ce39f4
fix: TokenExpiredRetryPolicy not work
lihsai0 Aug 7, 2024
adaba98
fix: AccUnavailableRetryPolicy modify origin region service
lihsai0 Aug 7, 2024
d9d925e
fix: argument name typo on put_data
lihsai0 Aug 7, 2024
d819e9b
feat: bucket support regions and endpoints retry
lihsai0 Aug 7, 2024
566629c
test: add and improve test cases
lihsai0 Aug 7, 2024
c024485
feat: add field persistentType to strict policy fields
lihsai0 Aug 7, 2024
9ae678b
style: fix flake8 code styles
lihsai0 Aug 7, 2024
cbb55b3
fix: enum on python2
lihsai0 Aug 7, 2024
6f78b5b
test: fix compatibility of test cases on python 2.7
lihsai0 Aug 7, 2024
3843299
test: change test region to na0 from z0
lihsai0 Aug 7, 2024
e65e840
chore: ci add no accelerate bucket
lihsai0 Aug 8, 2024
b58675e
test: fix test error with python2
lihsai0 Aug 8, 2024
77282c2
fix: LegacyRegion.get_bucket_host not working in python2
lihsai0 Aug 8, 2024
9ffb8f6
doc: add more type info to functions
lihsai0 Aug 8, 2024
04c50c4
chore: change default hosts for querying regions
lihsai0 Aug 12, 2024
58365a3
fix: CachedRegionsProvider shrink not working
lihsai0 Aug 20, 2024
1857de1
feat: add uc backup hosts
lihsai0 Aug 20, 2024
02d2e2e
feat: update version and changelog
lihsai0 Aug 20, 2024
0dbde38
add Qiniu auth verify callback
lihsai0 May 14, 2024
2891faf
chore: remove `Region.from_region_id` backup domain qbox and s3
lihsai0 Aug 30, 2024
9bf3d35
feat: add idle-time fop support and get fop status
lihsai0 Aug 23, 2024
dbc5668
docs: fix authorization token link
lihsai0 Sep 12, 2024
84c6694
fix: form retry not working by no resume recorder
lihsai0 Sep 12, 2024
c1f2f4d
chore: fix flake8 lint on python >= 3.8
lihsai0 Sep 13, 2024
ba62a7d
Update CHANGELOG.md
lihsai0 Sep 19, 2024
3e5f2d8
fix: legacy region get_xxx_host and add more cases
lihsai0 Sep 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ jobs:
QINIU_ACCESS_KEY: ${{ secrets.QINIU_ACCESS_KEY }}
QINIU_SECRET_KEY: ${{ secrets.QINIU_SECRET_KEY }}
QINIU_TEST_BUCKET: ${{ secrets.QINIU_TEST_BUCKET }}
QINIU_TEST_NO_ACC_BUCKET: ${{ secrets.QINIU_TEST_NO_ACC_BUCKET }}
QINIU_TEST_DOMAIN: ${{ secrets.QINIU_TEST_DOMAIN }}
QINIU_UPLOAD_CALLBACK_URL: ${{secrets.QINIU_UPLOAD_CALLBACK_URL}}
QINIU_TEST_ENV: "travis"
Expand Down
24 changes: 20 additions & 4 deletions examples/upload.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# -*- coding: utf-8 -*-
# flake8: noqa
# import hashlib

from qiniu import Auth, put_file, etag, urlsafe_base64_encode
from qiniu import Auth, put_file, urlsafe_base64_encode
import qiniu.config
from qiniu.compat import is_py2, is_py3

Expand All @@ -24,13 +25,28 @@
# 要上传文件的本地路径
localfile = '/Users/jemy/Documents/qiniu.png'

ret, info = put_file(token, key, localfile)
# 上传时,sdk 会自动计算文件 hash 作为参数传递给服务端确保上传完整性
# (若不一致,服务端会拒绝完成上传)
# 但在访问文件时,服务端可能不会提供 MD5 或者编码格式不是期望的
# 因此若有需有,请通过元数据功能自定义 MD5 或其他 hash 字段
# hasher = hashlib.md5()
# with open(localfile, 'rb') as f:
# for d in f:
# hasher.update(d)
# object_metadata = {
# 'x-qn-meta-md5': hasher.hexdigest()
# }

ret, info = put_file(
token,
key,
localfile
# metadata=object_metadata
)
print(ret)
print(info)

if is_py2:
assert ret['key'].encode('utf-8') == key
elif is_py3:
assert ret['key'] == key

assert ret['hash'] == etag(localfile)
3 changes: 1 addition & 2 deletions examples/upload_callback.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# flake8: noqa

from qiniu import Auth, put_file, etag
from qiniu import Auth, put_file

access_key = '...'
secret_key = '...'
Expand All @@ -25,4 +25,3 @@
ret, info = put_file(token, key, localfile)
print(info)
assert ret['key'] == key
assert ret['hash'] == etag(localfile)
3 changes: 1 addition & 2 deletions examples/upload_pfops.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# flake8: noqa
from qiniu import Auth, put_file, etag, urlsafe_base64_encode
from qiniu import Auth, put_file, urlsafe_base64_encode

access_key = '...'
secret_key = '...'
Expand Down Expand Up @@ -36,4 +36,3 @@
ret, info = put_file(token, key, localfile)
print(info)
assert ret['key'] == key
assert ret['hash'] == etag(localfile)
3 changes: 1 addition & 2 deletions examples/upload_with_qvmzone.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# flake8: noqa

from qiniu import Auth, put_file, etag, urlsafe_base64_encode
from qiniu import Auth, put_file, urlsafe_base64_encode
import qiniu.config
from qiniu import Zone, set_default

Expand Down Expand Up @@ -37,4 +37,3 @@
ret, info = put_file(token, key, localfile)
print(info)
assert ret['key'] == key
assert ret['hash'] == etag(localfile)
4 changes: 2 additions & 2 deletions qiniu/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@

from .config import set_default
from .zone import Zone
from .region import Region
from .region import LegacyRegion as Region

from .services.storage.bucket import BucketManager, build_batch_copy, build_batch_rename, build_batch_move, \
build_batch_stat, build_batch_delete, build_batch_restoreAr
build_batch_stat, build_batch_delete, build_batch_restoreAr, build_batch_restore_ar
from .services.storage.uploader import put_data, put_file, put_stream
from .services.storage.upload_progress_recorder import UploadProgressRecorder
from .services.cdn.manager import CdnManager, create_timestamp_anti_leech_url, DomainManager
Expand Down
1 change: 1 addition & 0 deletions qiniu/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
str('persistentOps'), # 持久化处理操作
str('persistentNotifyUrl'), # 持久化处理结果通知URL
str('persistentPipeline'), # 持久化处理独享队列
str('persistentType'), # 指定是否开始闲时任务
str('deleteAfterDays'), # 文件多少天后自动删除
str('fileType'), # 文件的存储类型,0为标准存储,1为低频存储,2为归档存储,3为深度归档存储,4为归档直读存储
str('isPrefixalScope'), # 指定上传文件必须使用的前缀
Expand Down
23 changes: 13 additions & 10 deletions qiniu/config.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
# -*- coding: utf-8 -*-
from qiniu import region

RS_HOST = 'http://rs.qiniu.com' # 管理操作Host
RSF_HOST = 'http://rsf.qbox.me' # 列举操作Host
API_HOST = 'http://api.qiniuapi.com' # 数据处理操作Host
UC_HOST = region.UC_HOST # 获取空间信息Host
QUERY_REGION_HOST = 'https://kodo-config.qiniuapi.com'
UC_HOST = 'https://uc.qbox.me' # 获取空间信息Host
QUERY_REGION_HOST = 'https://uc.qiniuapi.com'
QUERY_REGION_BACKUP_HOSTS = [
'kodo-config.qiniuapi.com',
'uc.qbox.me'
]

_BLOCK_SIZE = 1024 * 1024 * 4 # 断点续传分块大小,该参数为接口规格,暂不支持修改

_config = {
'default_zone': region.Region(),
'default_zone': None,
'default_rs_host': RS_HOST,
'default_rsf_host': RSF_HOST,
'default_api_host': API_HOST,
'default_uc_host': UC_HOST,
'default_query_region_host': QUERY_REGION_HOST,
'default_query_region_backup_hosts': [
'uc.qbox.me',
'api.qiniu.com'
],
'default_backup_hosts_retry_times': 2,
'default_query_region_backup_hosts': QUERY_REGION_BACKUP_HOSTS,
'default_backup_hosts_retry_times': 3, # 仅控制旧区域 LegacyRegion 查询 Hosts 的重试次数
'connection_timeout': 30, # 链接超时为时间为30s
'connection_retries': 3, # 链接重试次数为3次
'connection_pool': 10, # 链接池个数为10
Expand Down Expand Up @@ -48,6 +47,10 @@ def is_customized_default(key):


def get_default(key):
if key == 'default_zone' and not _is_customized_default[key]:
# prevent circle import
from .region import LegacyRegion
return LegacyRegion()
return _config[key]


Expand Down
33 changes: 2 additions & 31 deletions qiniu/http/__init__.py
Original file line number Diff line number Diff line change
@@ -1,39 +1,15 @@
# -*- coding: utf-8 -*-
import logging
import platform
import functools

import requests
from requests.adapters import HTTPAdapter
from requests.auth import AuthBase

from qiniu import config, __version__
import qiniu.auth

from .client import HTTPClient
from .response import ResponseInfo
from .middleware import UserAgentMiddleware


qn_http_client = HTTPClient(
middlewares=[
UserAgentMiddleware(__version__)
]
)


# compatibility with some config from qiniu.config
def _before_send(func):
@functools.wraps(func)
def wrapper(self, *args, **kwargs):
if _session is None:
_init()
return func(self, *args, **kwargs)

return wrapper


qn_http_client.send_request = _before_send(qn_http_client.send_request)
from .default_client import qn_http_client, _init_http_adapter

_sys_info = '{0}; {1}'.format(platform.system(), platform.machine())
_python_ver = platform.python_version()
Expand Down Expand Up @@ -61,12 +37,7 @@ def _init():
global _session
if _session is None:
_session = qn_http_client.session

adapter = HTTPAdapter(
pool_connections=config.get_default('connection_pool'),
pool_maxsize=config.get_default('connection_pool'),
max_retries=config.get_default('connection_retries'))
_session.mount('http://', adapter)
_init_http_adapter()


def _post(url, data, files, auth, headers=None):
Expand Down
37 changes: 37 additions & 0 deletions qiniu/http/default_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import functools

from requests.adapters import HTTPAdapter

from qiniu import config, __version__

from .client import HTTPClient
from .middleware import UserAgentMiddleware

qn_http_client = HTTPClient(
middlewares=[
UserAgentMiddleware(__version__)
]
)


# compatibility with some config from qiniu.config
def _before_send(func):
@functools.wraps(func)
def wrapper(self, *args, **kwargs):
_init_http_adapter()
return func(self, *args, **kwargs)

return wrapper


qn_http_client.send_request = _before_send(qn_http_client.send_request)


def _init_http_adapter():
# may be optimized:
# only called when config changed, not every time before send request
adapter = HTTPAdapter(
pool_connections=config.get_default('connection_pool'),
pool_maxsize=config.get_default('connection_pool'),
max_retries=config.get_default('connection_retries'))
qn_http_client.session.mount('http://', adapter)
68 changes: 68 additions & 0 deletions qiniu/http/endpoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
class Endpoint:
@staticmethod
def from_host(host):
"""
Autodetect scheme from host string

Parameters
----------
host: str

Returns
-------
Endpoint
"""
if '://' in host:
scheme, host = host.split('://')
return Endpoint(host=host, default_scheme=scheme)
else:
return Endpoint(host=host)

def __init__(self, host, default_scheme='https'):
"""
Parameters
----------
host: str
default_scheme: str
"""
self.host = host
self.default_scheme = default_scheme

def __str__(self):
return 'Endpoint(host:\'{0}\',default_scheme:\'{1}\')'.format(
self.host,
self.default_scheme
)

def __repr__(self):
return self.__str__()

def __eq__(self, other):
if not isinstance(other, Endpoint):
raise TypeError('Cannot compare Endpoint with {0}'.format(type(other)))

return self.host == other.host and self.default_scheme == other.default_scheme

def get_value(self, scheme=None):
"""
Parameters
----------
scheme: str

Returns
-------
str
"""
scheme = scheme if scheme is not None else self.default_scheme
return ''.join([scheme, '://', self.host])

def clone(self):
"""
Returns
-------
Endpoint
"""
return Endpoint(
host=self.host,
default_scheme=self.default_scheme
)
13 changes: 13 additions & 0 deletions qiniu/http/endpoints_provider.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import abc


class EndpointsProvider:
__metaclass__ = abc.ABCMeta

@abc.abstractmethod
def __iter__(self):
"""
Returns
-------
list[Endpoint]
"""
56 changes: 56 additions & 0 deletions qiniu/http/endpoints_retry_policy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from qiniu.retry.abc import RetryPolicy


class EndpointsRetryPolicy(RetryPolicy):
def __init__(self, endpoints_provider=None, skip_init_context=False):
"""
Parameters
----------
endpoints_provider: Iterable[Endpoint]
skip_init_context: bool
"""
self.endpoints_provider = endpoints_provider if endpoints_provider else []
self.skip_init_context = skip_init_context

def init_context(self, context):
"""
Parameters
----------
context: dict

Returns
-------
None
"""
if self.skip_init_context:
return
context['alternative_endpoints'] = list(self.endpoints_provider)
if not context['alternative_endpoints']:
raise ValueError('There isn\'t available endpoint')
context['endpoint'] = context['alternative_endpoints'].pop(0)

def should_retry(self, attempt):
"""
Parameters
----------
attempt: qiniu.retry.Attempt

Returns
-------
bool
"""
return len(attempt.context['alternative_endpoints']) > 0

def prepare_retry(self, attempt):
"""
Parameters
----------
attempt: qiniu.retry.Attempt

Returns
-------
None
"""
if not attempt.context['alternative_endpoints']:
raise Exception('There isn\'t available endpoint for next try')
attempt.context['endpoint'] = attempt.context['alternative_endpoints'].pop(0)
Loading
Loading