miniopy-async 1.16__tar.gz → 1.18__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {miniopy-async-1.16 → miniopy-async-1.18}/PKG-INFO +2 -2
- {miniopy-async-1.16 → miniopy-async-1.18}/README.md +1 -1
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/__init__.py +1 -1
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/api.py +136 -5
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/commonconfig.py +48 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/helpers.py +35 -44
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/time.py +5 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async.egg-info/PKG-INFO +2 -2
- {miniopy-async-1.16 → miniopy-async-1.18}/LICENSE +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/credentials/__init__.py +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/credentials/credentials.py +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/credentials/providers.py +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/datatypes.py +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/deleteobjects.py +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/error.py +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/legalhold.py +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/lifecycleconfig.py +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/minioadmin.py +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/notificationconfig.py +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/objectlockconfig.py +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/progress.py +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/replicationconfig.py +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/retention.py +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/select.py +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/signer.py +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/sse.py +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/sseconfig.py +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/tagging.py +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/versioningconfig.py +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async/xml.py +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async.egg-info/SOURCES.txt +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async.egg-info/dependency_links.txt +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async.egg-info/requires.txt +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/miniopy_async.egg-info/top_level.txt +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/setup.cfg +0 -0
- {miniopy-async-1.16 → miniopy-async-1.18}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: miniopy-async
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.18
|
|
4
4
|
Summary: Asynchronous MinIO Client SDK for Python
|
|
5
5
|
Home-page: https://github.com/hlf20010508/miniopy-async
|
|
6
6
|
Author: L-ING
|
|
@@ -87,7 +87,7 @@ pipenv install miniopy-async
|
|
|
87
87
|
|
|
88
88
|
Github Repository
|
|
89
89
|
```sh
|
|
90
|
-
pipenv install git+https://github.com/hlf20010508/miniopy-async.git
|
|
90
|
+
pipenv install "miniopy-async@ git+https://github.com/hlf20010508/miniopy-async.git"
|
|
91
91
|
```
|
|
92
92
|
|
|
93
93
|
<span id="example"></span>
|
|
@@ -60,7 +60,7 @@ pipenv install miniopy-async
|
|
|
60
60
|
|
|
61
61
|
Github Repository
|
|
62
62
|
```sh
|
|
63
|
-
pipenv install git+https://github.com/hlf20010508/miniopy-async.git
|
|
63
|
+
pipenv install "miniopy-async@ git+https://github.com/hlf20010508/miniopy-async.git"
|
|
64
64
|
```
|
|
65
65
|
|
|
66
66
|
<span id="example"></span>
|
|
@@ -33,6 +33,9 @@ import asyncio
|
|
|
33
33
|
import itertools
|
|
34
34
|
import os
|
|
35
35
|
import platform
|
|
36
|
+
from random import random
|
|
37
|
+
from io import BytesIO
|
|
38
|
+
import tarfile
|
|
36
39
|
|
|
37
40
|
# import weakref
|
|
38
41
|
from concurrent.futures import ThreadPoolExecutor
|
|
@@ -44,7 +47,7 @@ import aiofile
|
|
|
44
47
|
import aiohttp
|
|
45
48
|
|
|
46
49
|
from . import __title__, __version__, time
|
|
47
|
-
from .commonconfig import COPY, ComposeSource, CopySource, REPLACE, Tags
|
|
50
|
+
from .commonconfig import COPY, ComposeSource, CopySource, REPLACE, Tags, SnowballObject
|
|
48
51
|
from .credentials import StaticProvider
|
|
49
52
|
from .datatypes import (
|
|
50
53
|
AsyncEventIterable,
|
|
@@ -376,7 +379,7 @@ class Minio: # pylint: disable=too-many-public-methods
|
|
|
376
379
|
query_params=query_params,
|
|
377
380
|
session=session,
|
|
378
381
|
)
|
|
379
|
-
|
|
382
|
+
return response
|
|
380
383
|
else:
|
|
381
384
|
response = await self._url_open(
|
|
382
385
|
method,
|
|
@@ -407,7 +410,7 @@ class Minio: # pylint: disable=too-many-public-methods
|
|
|
407
410
|
query_params=query_params,
|
|
408
411
|
session=session,
|
|
409
412
|
)
|
|
410
|
-
|
|
413
|
+
return response
|
|
411
414
|
else:
|
|
412
415
|
response = await self._url_open(
|
|
413
416
|
method,
|
|
@@ -2502,6 +2505,7 @@ class Minio: # pylint: disable=too-many-public-methods
|
|
|
2502
2505
|
object_name,
|
|
2503
2506
|
ssec=None,
|
|
2504
2507
|
version_id=None,
|
|
2508
|
+
request_headers=None,
|
|
2505
2509
|
extra_query_params=None,
|
|
2506
2510
|
):
|
|
2507
2511
|
"""
|
|
@@ -2511,6 +2515,7 @@ class Minio: # pylint: disable=too-many-public-methods
|
|
|
2511
2515
|
:param object_name: Object name in the bucket.
|
|
2512
2516
|
:param ssec: Server-side encryption customer key.
|
|
2513
2517
|
:param version_id: Version ID of the object.
|
|
2518
|
+
:param request_headers: Any additional headers to be added with GET request.
|
|
2514
2519
|
:param extra_query_params: Extra query parameters for advanced usage.
|
|
2515
2520
|
:return: :class:`Object <Object>`.
|
|
2516
2521
|
|
|
@@ -2570,6 +2575,8 @@ class Minio: # pylint: disable=too-many-public-methods
|
|
|
2570
2575
|
check_ssec(ssec)
|
|
2571
2576
|
|
|
2572
2577
|
headers = ssec.headers() if ssec else {}
|
|
2578
|
+
if request_headers:
|
|
2579
|
+
headers.update(request_headers)
|
|
2573
2580
|
query_params = extra_query_params or {}
|
|
2574
2581
|
query_params.update({"versionId": version_id} if version_id else {})
|
|
2575
2582
|
async with aiohttp.ClientSession() as session:
|
|
@@ -3973,8 +3980,11 @@ class Minio: # pylint: disable=too-many-public-methods
|
|
|
3973
3980
|
days=10))
|
|
3974
3981
|
|
|
3975
3982
|
async def main():
|
|
3976
|
-
await client.set_object_retention(
|
|
3977
|
-
|
|
3983
|
+
await client.set_object_retention(
|
|
3984
|
+
"my-bucket",
|
|
3985
|
+
"my-object",
|
|
3986
|
+
config
|
|
3987
|
+
)
|
|
3978
3988
|
|
|
3979
3989
|
loop = asyncio.get_event_loop()
|
|
3980
3990
|
loop.run_until_complete(main())
|
|
@@ -3996,6 +4006,127 @@ class Minio: # pylint: disable=too-many-public-methods
|
|
|
3996
4006
|
query_params=query_params,
|
|
3997
4007
|
)
|
|
3998
4008
|
|
|
4009
|
+
async def upload_snowball_objects(
|
|
4010
|
+
self,
|
|
4011
|
+
bucket_name,
|
|
4012
|
+
object_list,
|
|
4013
|
+
metadata=None,
|
|
4014
|
+
sse=None,
|
|
4015
|
+
tags=None,
|
|
4016
|
+
retention=None,
|
|
4017
|
+
legal_hold=False,
|
|
4018
|
+
staging_filename=None,
|
|
4019
|
+
compression=False,
|
|
4020
|
+
):
|
|
4021
|
+
"""
|
|
4022
|
+
Uploads multiple objects in a single put call. It is done by creating
|
|
4023
|
+
intermediate TAR file optionally compressed which is uploaded to S3
|
|
4024
|
+
service.
|
|
4025
|
+
|
|
4026
|
+
:param bucket_name: Name of the bucket.
|
|
4027
|
+
:param object_list: An iterable containing
|
|
4028
|
+
:class:`SnowballObject <SnowballObject>` object.
|
|
4029
|
+
:param metadata: Any additional metadata to be uploaded along
|
|
4030
|
+
with your PUT request.
|
|
4031
|
+
:param sse: Server-side encryption.
|
|
4032
|
+
:param tags: :class:`Tags` for the object.
|
|
4033
|
+
:param retention: :class:`Retention` configuration object.
|
|
4034
|
+
:param legal_hold: Flag to set legal hold for the object.
|
|
4035
|
+
:param staging_filename: A staging filename to create intermediate tarball.
|
|
4036
|
+
:param compression: Flag to compress TAR ball.
|
|
4037
|
+
:return: :class:`ObjectWriteResult` object.
|
|
4038
|
+
|
|
4039
|
+
Example::
|
|
4040
|
+
from miniopy_async import Minio
|
|
4041
|
+
from miniopy_async.commonconfig import SnowballObject
|
|
4042
|
+
import io
|
|
4043
|
+
from datetime import datetime
|
|
4044
|
+
import asyncio
|
|
4045
|
+
|
|
4046
|
+
client = Minio(
|
|
4047
|
+
"play.min.io",
|
|
4048
|
+
access_key="Q3AM3UQ867SPQQA43P2F",
|
|
4049
|
+
secret_key="zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG",
|
|
4050
|
+
secure=True, # http for False, https for True
|
|
4051
|
+
)
|
|
4052
|
+
|
|
4053
|
+
async def main():
|
|
4054
|
+
result = await client.upload_snowball_objects(
|
|
4055
|
+
"my-bucket",
|
|
4056
|
+
[
|
|
4057
|
+
SnowballObject("my-object1", filename="filename"),
|
|
4058
|
+
SnowballObject(
|
|
4059
|
+
"my-object2", data=io.BytesIO(b"hello"), length=5,
|
|
4060
|
+
),
|
|
4061
|
+
SnowballObject(
|
|
4062
|
+
"my-object3", data=io.BytesIO(b"world"), length=5,
|
|
4063
|
+
mod_time=datetime.now(),
|
|
4064
|
+
),
|
|
4065
|
+
],
|
|
4066
|
+
)
|
|
4067
|
+
|
|
4068
|
+
loop = asyncio.get_event_loop()
|
|
4069
|
+
loop.run_until_complete(main())
|
|
4070
|
+
loop.close()
|
|
4071
|
+
"""
|
|
4072
|
+
check_bucket_name(bucket_name, s3_check=self._base_url.is_aws_host)
|
|
4073
|
+
|
|
4074
|
+
object_name = f"snowball.{random()}.tar"
|
|
4075
|
+
|
|
4076
|
+
# turn list like objects into an iterator.
|
|
4077
|
+
object_list = itertools.chain(object_list)
|
|
4078
|
+
|
|
4079
|
+
metadata = metadata or {}
|
|
4080
|
+
metadata["X-Amz-Meta-Snowball-Auto-Extract"] = "true"
|
|
4081
|
+
|
|
4082
|
+
name = staging_filename
|
|
4083
|
+
mode = "w:gz" if compression else "w"
|
|
4084
|
+
fileobj = None if name else BytesIO()
|
|
4085
|
+
with tarfile.open(name=name, mode=mode, fileobj=fileobj) as tar:
|
|
4086
|
+
for obj in object_list:
|
|
4087
|
+
if obj.filename:
|
|
4088
|
+
tar.add(obj.filename, obj.object_name)
|
|
4089
|
+
else:
|
|
4090
|
+
info = tarfile.TarInfo(obj.object_name)
|
|
4091
|
+
info.size = obj.length
|
|
4092
|
+
info.mtime = int(
|
|
4093
|
+
time.to_float(obj.mod_time or time.utcnow()),
|
|
4094
|
+
)
|
|
4095
|
+
tar.addfile(info, obj.data)
|
|
4096
|
+
|
|
4097
|
+
if not name:
|
|
4098
|
+
length = fileobj.tell()
|
|
4099
|
+
fileobj.seek(0)
|
|
4100
|
+
else:
|
|
4101
|
+
length = os.stat(name).st_size
|
|
4102
|
+
|
|
4103
|
+
part_size = 0 if length < MIN_PART_SIZE else length
|
|
4104
|
+
|
|
4105
|
+
if name:
|
|
4106
|
+
return await self.fput_object(
|
|
4107
|
+
bucket_name,
|
|
4108
|
+
object_name,
|
|
4109
|
+
staging_filename,
|
|
4110
|
+
metadata=metadata,
|
|
4111
|
+
sse=sse,
|
|
4112
|
+
tags=tags,
|
|
4113
|
+
retention=retention,
|
|
4114
|
+
legal_hold=legal_hold,
|
|
4115
|
+
part_size=part_size,
|
|
4116
|
+
)
|
|
4117
|
+
return await self.put_object(
|
|
4118
|
+
bucket_name,
|
|
4119
|
+
object_name,
|
|
4120
|
+
fileobj,
|
|
4121
|
+
length,
|
|
4122
|
+
metadata=metadata,
|
|
4123
|
+
sse=sse,
|
|
4124
|
+
tags=tags,
|
|
4125
|
+
retention=retention,
|
|
4126
|
+
legal_hold=legal_hold,
|
|
4127
|
+
part_size=part_size,
|
|
4128
|
+
)
|
|
4129
|
+
|
|
3999
4130
|
async def _list_objects(
|
|
4000
4131
|
# pylint: disable=too-many-arguments,too-many-branches
|
|
4001
4132
|
self,
|
|
@@ -508,3 +508,51 @@ class ComposeSource(ObjectConditionalReadArgs):
|
|
|
508
508
|
src.modified_since,
|
|
509
509
|
src.unmodified_since,
|
|
510
510
|
)
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
class SnowballObject:
|
|
514
|
+
"""A source object definition for upload_snowball_objects method."""
|
|
515
|
+
|
|
516
|
+
def __init__(
|
|
517
|
+
self,
|
|
518
|
+
object_name,
|
|
519
|
+
filename=None,
|
|
520
|
+
data=None,
|
|
521
|
+
length=None,
|
|
522
|
+
mod_time=None,
|
|
523
|
+
):
|
|
524
|
+
self._object_name = object_name
|
|
525
|
+
if (filename is not None) ^ (data is not None):
|
|
526
|
+
self._filename = filename
|
|
527
|
+
self._data = data
|
|
528
|
+
self._length = length
|
|
529
|
+
else:
|
|
530
|
+
raise ValueError("only one of filename or data must be provided")
|
|
531
|
+
if mod_time is not None and not isinstance(mod_time, datetime.datetime):
|
|
532
|
+
raise ValueError("mod_time must be datetime.datetime type")
|
|
533
|
+
self._mod_time = mod_time
|
|
534
|
+
|
|
535
|
+
@property
|
|
536
|
+
def object_name(self):
|
|
537
|
+
"""Get object name."""
|
|
538
|
+
return self._object_name
|
|
539
|
+
|
|
540
|
+
@property
|
|
541
|
+
def filename(self):
|
|
542
|
+
"""Get filename."""
|
|
543
|
+
return self._filename
|
|
544
|
+
|
|
545
|
+
@property
|
|
546
|
+
def data(self):
|
|
547
|
+
"""Get data."""
|
|
548
|
+
return self._data
|
|
549
|
+
|
|
550
|
+
@property
|
|
551
|
+
def length(self):
|
|
552
|
+
"""Get length."""
|
|
553
|
+
return self._length
|
|
554
|
+
|
|
555
|
+
@property
|
|
556
|
+
def mod_time(self):
|
|
557
|
+
"""Get modification time."""
|
|
558
|
+
return self._mod_time
|
|
@@ -43,19 +43,16 @@ MAX_MULTIPART_OBJECT_SIZE = 5 * 1024 * 1024 * 1024 * 1024 # 5TiB
|
|
|
43
43
|
MAX_PART_SIZE = 5 * 1024 * 1024 * 1024 # 5GiB
|
|
44
44
|
MIN_PART_SIZE = 5 * 1024 * 1024 # 5MiB
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
_BUCKET_NAME_REGEX = re.compile(r'^[a-z0-9][a-z0-9\.\-]{1,61}[a-z0-9]$')
|
|
47
|
+
_OLD_BUCKET_NAME_REGEX = re.compile(
|
|
48
|
+
r'^[a-z0-9][a-z0-9_\.\-\:]{1,61}[a-z0-9]$',
|
|
49
|
+
re.IGNORECASE
|
|
48
50
|
)
|
|
49
|
-
_VALID_BUCKETNAME_STRICT_REGEX = re.compile("^[a-z0-9][a-z0-9\\.\\-]{1,61}[a-z0-9]$")
|
|
50
|
-
_VALID_IP_ADDRESS = re.compile(r"^(\d+\.){3}\d+$")
|
|
51
|
-
_ALLOWED_HOSTNAME_REGEX = re.compile(
|
|
52
|
-
"^((?!-)(?!_)[A-Z_\\d-]{1,63}(?<!-)(?<!_)\\.)*((?!_)(?!-)"
|
|
53
|
-
+ "[A-Z_\\d-]{1,63}(?<!-)(?<!_))$",
|
|
54
|
-
re.IGNORECASE,
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
_EXTRACT_REGION_REGEX = re.compile("s3[.-]?(.+?).amazonaws.com")
|
|
58
51
|
|
|
52
|
+
_IPV4_REGEX = re.compile(
|
|
53
|
+
r'^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}'
|
|
54
|
+
r'(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$'
|
|
55
|
+
)
|
|
59
56
|
|
|
60
57
|
def quote(resource, safe="/", encoding=None, errors=None):
|
|
61
58
|
"""
|
|
@@ -191,44 +188,38 @@ def makedirs(path):
|
|
|
191
188
|
) from exc
|
|
192
189
|
|
|
193
190
|
|
|
194
|
-
def check_bucket_name(
|
|
191
|
+
def check_bucket_name(
|
|
192
|
+
bucket_name: str,
|
|
193
|
+
strict: bool = False,
|
|
194
|
+
s3_check: bool = False,
|
|
195
|
+
):
|
|
195
196
|
"""Check whether bucket name is valid optional with strict check or not."""
|
|
196
197
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
if len(bucket_name) < 3:
|
|
204
|
-
raise ValueError("Bucket name cannot be less than" " 3 characters.")
|
|
205
|
-
if len(bucket_name) > 63:
|
|
206
|
-
raise ValueError("Bucket name cannot be greater than" " 63 characters.")
|
|
198
|
+
if strict:
|
|
199
|
+
if not _BUCKET_NAME_REGEX.match(bucket_name):
|
|
200
|
+
raise ValueError(f'invalid bucket name {bucket_name}')
|
|
201
|
+
else:
|
|
202
|
+
if not _OLD_BUCKET_NAME_REGEX.match(bucket_name):
|
|
203
|
+
raise ValueError(f'invalid bucket name {bucket_name}')
|
|
207
204
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
205
|
+
if _IPV4_REGEX.match(bucket_name):
|
|
206
|
+
raise ValueError(f'bucket name {bucket_name} must not be formatted '
|
|
207
|
+
'as an IP address')
|
|
211
208
|
|
|
212
|
-
unallowed_successive_chars = [
|
|
209
|
+
unallowed_successive_chars = ['..', '.-', '-.']
|
|
213
210
|
if any(x in bucket_name for x in unallowed_successive_chars):
|
|
214
|
-
raise ValueError(
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
match = _VALID_BUCKETNAME_REGEX.match(bucket_name)
|
|
227
|
-
if (not match) or match.end() != len(bucket_name):
|
|
228
|
-
raise ValueError(
|
|
229
|
-
"Bucket name does not follow S3 standards."
|
|
230
|
-
" Bucket: {0}".format(bucket_name)
|
|
231
|
-
)
|
|
211
|
+
raise ValueError(f'bucket name {bucket_name} contains invalid '
|
|
212
|
+
'successive characters')
|
|
213
|
+
|
|
214
|
+
if (
|
|
215
|
+
s3_check and
|
|
216
|
+
bucket_name.startswith("xn--") or
|
|
217
|
+
bucket_name.endswith("-s3alias") or
|
|
218
|
+
bucket_name.endswith("--ol-s3")
|
|
219
|
+
):
|
|
220
|
+
raise ValueError(f"bucket name {bucket_name} must not start with "
|
|
221
|
+
"'xn--' and must not end with '--s3alias' or "
|
|
222
|
+
"'--ol-s3'")
|
|
232
223
|
|
|
233
224
|
|
|
234
225
|
def check_non_empty_string(string):
|
|
@@ -22,6 +22,7 @@ from __future__ import absolute_import
|
|
|
22
22
|
|
|
23
23
|
import locale
|
|
24
24
|
from contextlib import contextmanager
|
|
25
|
+
import time as ctime
|
|
25
26
|
from datetime import datetime, timezone
|
|
26
27
|
|
|
27
28
|
from . import __LOCALE_LOCK__
|
|
@@ -96,3 +97,7 @@ def utcnow():
|
|
|
96
97
|
def to_signer_date(value):
|
|
97
98
|
"""Format datetime into SignatureV4 date formatted string."""
|
|
98
99
|
return _to_utc(value).strftime("%Y%m%d")
|
|
100
|
+
|
|
101
|
+
def to_float(value: datetime) -> float:
|
|
102
|
+
"""Convert datetime into float value."""
|
|
103
|
+
return ctime.mktime(value.timetuple()) + value.microsecond * 1e-6
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: miniopy-async
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.18
|
|
4
4
|
Summary: Asynchronous MinIO Client SDK for Python
|
|
5
5
|
Home-page: https://github.com/hlf20010508/miniopy-async
|
|
6
6
|
Author: L-ING
|
|
@@ -87,7 +87,7 @@ pipenv install miniopy-async
|
|
|
87
87
|
|
|
88
88
|
Github Repository
|
|
89
89
|
```sh
|
|
90
|
-
pipenv install git+https://github.com/hlf20010508/miniopy-async.git
|
|
90
|
+
pipenv install "miniopy-async@ git+https://github.com/hlf20010508/miniopy-async.git"
|
|
91
91
|
```
|
|
92
92
|
|
|
93
93
|
<span id="example"></span>
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|