Skip to content

Commit

Permalink
refactor VersioningConfig with embedded XML handling
Browse files Browse the repository at this point in the history
  • Loading branch information
balamurugana committed Oct 14, 2020
1 parent 643dc04 commit e0a3156
Show file tree
Hide file tree
Showing 11 changed files with 203 additions and 60 deletions.
2 changes: 1 addition & 1 deletion docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,7 @@ __Parameters__
__Example__

```py
minio.set_bucket_versioning("my-bucketname", VersioningConfig("Enabled"))
minio.set_bucket_versioning("my-bucketname", VersioningConfig(ENABLED))
```

<a name="delete_bucket_replication"></a>
Expand Down
29 changes: 29 additions & 0 deletions examples/get_bucket_versioning.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# MinIO Python Library for Amazon S3 Compatible Cloud Storage.
# Copyright (C) 2020 MinIO, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Note: YOUR-ACCESSKEYID, YOUR-SECRETACCESSKEY and my-bucketname are
# dummy values, please replace them with original values.

from minio import Minio

client = Minio(
"play.min.io",
access_key="Q3AM3UQ867SPQQA43P2F",
secret_key="zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG",
)

config = client.get_bucket_versioning("my-bucketname")
print(config.status)
30 changes: 30 additions & 0 deletions examples/set_bucket_versioning.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# MinIO Python Library for Amazon S3 Compatible Cloud Storage.
# Copyright (C) 2020 MinIO, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Note: YOUR-ACCESSKEYID, YOUR-SECRETACCESSKEY and my-bucketname are
# dummy values, please replace them with original values.

from minio import Minio
from minio.commonconfig import ENABLED
from minio.versioningconfig import VersioningConfig

client = Minio(
"play.min.io",
access_key="Q3AM3UQ867SPQQA43P2F",
secret_key="zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG",
)

client.set_bucket_versioning("my-bucketname", VersioningConfig(ENABLED))
2 changes: 1 addition & 1 deletion minio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@
# pylint: disable=unused-import
from .api import Minio
from .copy_conditions import CopyConditions
from .definitions import Bucket, Object, VersioningConfig
from .definitions import Bucket, Object
from .error import InvalidResponseError, S3Error, ServerError
from .post_policy import PostPolicy
13 changes: 7 additions & 6 deletions minio/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,17 @@
parse_list_parts, parse_location_constraint,
parse_multi_delete_response,
parse_multipart_upload_result,
parse_new_multipart_upload, parse_versioning_config)
parse_new_multipart_upload)
from .replicationconfig import ReplicationConfig
from .select import SelectObjectReader
from .signer import (AMZ_DATE_FORMAT, SIGN_V4_ALGORITHM, get_credential_string,
post_presign_v4, presign_v4, sign_v4_s3)
from .sse import SseCustomerKey
from .thread_pool import ThreadPool
from .versioningconfig import VersioningConfig
from .xml import marshal, unmarshal
from .xml_marshal import (marshal_bucket_notifications,
marshal_complete_multipart,
marshal_versioning_config,
xml_marshal_bucket_constraint,
xml_marshal_bucket_encryption,
xml_marshal_delete_objects, xml_marshal_select,
Expand Down Expand Up @@ -876,11 +876,13 @@ def set_bucket_versioning(self, bucket_name, config):
Example::
minio.set_bucket_versioning(
"my-bucketname", VersioningConfig("Enabled"),
"my-bucketname", VersioningConfig(ENABLED),
)
"""
check_bucket_name(bucket_name)
body = marshal_versioning_config(config)
if not isinstance(config, VersioningConfig):
raise ValueError("config must be VersioningConfig type")
body = marshal(config)
self._execute(
"PUT",
bucket_name,
Expand All @@ -906,8 +908,7 @@ def get_bucket_versioning(self, bucket_name):
bucket_name,
query_params={"versioning": ""},
)

return parse_versioning_config(response.data)
return unmarshal(VersioningConfig, response.data.decode())

def fput_object(self, bucket_name, object_name, file_path,
content_type='application/octet-stream',
Expand Down
22 changes: 0 additions & 22 deletions minio/definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -472,25 +472,3 @@ def __init__(self, root):
self.parts = [
Part(part_element) for part_element in root.findall("Part")
]


class VersioningConfig:
"""Bucket versioning configuration."""

def __init__(self, status, mfa_delete=None):
if status:
status = status.title()
if status not in ["", "Enabled", "Suspended"]:
raise ValueError("status must be empty, Enabled or Suspended.")
self._status = status
self._mfa_delete = mfa_delete

@property
def status(self):
"""Get status."""
return self._status or "Off"

@property
def mfa_delete(self):
"""Get MFA delete."""
return self._mfa_delete
12 changes: 1 addition & 11 deletions minio/parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@
from xml.etree.ElementTree import ParseError

from .definitions import (Bucket, CopyObjectResult, ListMultipartUploadsResult,
ListPartsResult, MultipartUploadResult, Object,
VersioningConfig)
ListPartsResult, MultipartUploadResult, Object)
# minio specific.
from .error import MultiDeleteError, S3Error
from .helpers import RFC3339, RFC3339NANO
Expand Down Expand Up @@ -488,12 +487,3 @@ def parse_list_multipart_uploads(data):
def parse_list_parts(data):
"""Parse ListParts API resppnse XML."""
return ListPartsResult(S3Element.fromstring("ListPartsResult", data))


def parse_versioning_config(data):
"""Decode XML data into :class:`VersioningConfig <VersioningConfig>`"""
root = S3Element.fromstring("VersioningConfiguration", data)
return VersioningConfig(
root.get_child_text("Status"),
root.get_child_text("MFADelete"),
)
67 changes: 67 additions & 0 deletions minio/versioningconfig.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# -*- coding: utf-8 -*-
# MinIO Python Library for Amazon S3 Compatible Cloud Storage, (C)
# 2020 MinIO, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Request/response of PutBucketVersioning and GetBucketVersioning APIs."""

from __future__ import absolute_import

from .commonconfig import DISABLED, ENABLED
from .xml import Element, SubElement, findtext

OFF = "Off"
SUSPENDED = "Suspended"


class VersioningConfig:
"""Versioning configuration."""

def __init__(self, status=None, mfa_delete=None):
if status is not None and status not in [ENABLED, SUSPENDED]:
raise ValueError(
"status must be {0} or {1}".format(ENABLED, SUSPENDED),
)
if mfa_delete is not None and mfa_delete not in [ENABLED, DISABLED]:
raise ValueError(
"MFA delete must be {0} or {1}".format(ENABLED, DISABLED),
)
self._status = status
self._mfa_delete = mfa_delete

@property
def status(self):
"""Get status."""
return self._status or OFF

@property
def mfa_delete(self):
"""Get MFA delete."""
return self._mfa_delete

@classmethod
def fromxml(cls, element):
"""Create new object with values from XML element."""
status = findtext(element, "Status")
mfa_delete = findtext(element, "MFADelete")
return cls(status, mfa_delete)

def toxml(self, element):
"""Convert to XML."""
element = Element("VersioningConfiguration")
if self._status:
SubElement(element, "Status", self._status)
if self._mfa_delete:
SubElement(element, "MFADelete", self._mfa_delete)
return element
11 changes: 0 additions & 11 deletions minio/xml_marshal.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,14 +409,3 @@ def xml_marshal_delete_objects(keys):
SubElement(element, "VersionId", version_id)

return _get_xml_data(root)


def marshal_versioning_config(config):
"""Encode versioning configuration to XML bytes."""
root = Element("VersioningConfiguration", with_namespace=True)
SubElement(root, "Status", config.status)
if config.mfa_delete is not None:
SubElement(
root, "MFADelete", "Enabled" if config.mfa_delete else "Disabled",
)
return _get_xml_data(root)
18 changes: 10 additions & 8 deletions tests/functional/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,15 @@
import certifi
import urllib3

from minio import CopyConditions, Minio, PostPolicy, VersioningConfig
from minio import CopyConditions, Minio, PostPolicy
from minio.commonconfig import ENABLED
from minio.error import S3Error
from minio.select.helpers import calculate_crc
from minio.select.options import (CSVInput, CSVOutput, InputSerialization,
OutputSerialization, RequestProgress,
SelectObjectOptions)
from minio.sse import SseCustomerKey
from minio.versioningconfig import VersioningConfig

if sys.version_info[0] == 2:
from datetime import tzinfo # pylint: disable=ungrouped-imports
Expand Down Expand Up @@ -808,7 +810,7 @@ def _test_stat_object(log_entry, sse=None, version_check=False):
try:
if version_check:
_CLIENT.set_bucket_versioning(
bucket_name, VersioningConfig("Enabled"),
bucket_name, VersioningConfig(ENABLED),
)
# Put/Upload a streaming object of 1 MiB
reader = LimitedRandomReader(length)
Expand Down Expand Up @@ -878,7 +880,7 @@ def _test_remove_object(log_entry, version_check=False):
try:
if version_check:
_CLIENT.set_bucket_versioning(
bucket_name, VersioningConfig("Enabled"),
bucket_name, VersioningConfig(ENABLED),
)
_, version_id = _CLIENT.put_object(
bucket_name, object_name, LimitedRandomReader(length), length,
Expand Down Expand Up @@ -919,7 +921,7 @@ def _test_get_object(log_entry, sse=None, version_check=False):
try:
if version_check:
_CLIENT.set_bucket_versioning(
bucket_name, VersioningConfig("Enabled"),
bucket_name, VersioningConfig(ENABLED),
)
_, version_id = _CLIENT.put_object(
bucket_name, object_name, LimitedRandomReader(length),
Expand Down Expand Up @@ -972,7 +974,7 @@ def _test_fget_object(log_entry, sse=None, version_check=False):
try:
if version_check:
_CLIENT.set_bucket_versioning(
bucket_name, VersioningConfig("Enabled"),
bucket_name, VersioningConfig(ENABLED),
)
_, version_id = _CLIENT.put_object(
bucket_name, object_name, LimitedRandomReader(length),
Expand Down Expand Up @@ -1099,7 +1101,7 @@ def _test_list_objects(log_entry, use_api_v1=False, version_check=False):
try:
if version_check:
_CLIENT.set_bucket_versioning(
bucket_name, VersioningConfig("Enabled"),
bucket_name, VersioningConfig(ENABLED),
)
size = 1 * KB
_, version_id1 = _CLIENT.put_object(
Expand Down Expand Up @@ -1479,7 +1481,7 @@ def test_presigned_get_object_version( # pylint: disable=invalid-name
_CLIENT.make_bucket(bucket_name)
version_id = None
try:
_CLIENT.set_bucket_versioning(bucket_name, VersioningConfig("Enabled"))
_CLIENT.set_bucket_versioning(bucket_name, VersioningConfig(ENABLED))
size = 1 * KB
_, version_id = _CLIENT.put_object(
bucket_name, object_name, LimitedRandomReader(size), size,
Expand Down Expand Up @@ -1846,7 +1848,7 @@ def _test_remove_objects(log_entry, version_check=False):
try:
if version_check:
_CLIENT.set_bucket_versioning(
bucket_name, VersioningConfig("Enabled"),
bucket_name, VersioningConfig(ENABLED),
)
size = 1 * KB
# Upload some new objects to prepare for multi-object delete test.
Expand Down
57 changes: 57 additions & 0 deletions tests/unit/versioningconfig.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
# MinIO Python Library for Amazon S3 Compatible Cloud Storage,
# (C) 2020 MinIO, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from unittest import TestCase

from nose.tools import eq_

from minio import xml
from minio.commonconfig import DISABLED, ENABLED
from minio.versioningconfig import OFF, SUSPENDED, VersioningConfig


class VersioningConfigTest(TestCase):
def test_config(self):
config = VersioningConfig(ENABLED)
xml.marshal(config)

config = xml.unmarshal(
VersioningConfig,
"""<VersioningConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
</VersioningConfiguration>""",
)
xml.marshal(config)
eq_(config.status, OFF)

config = xml.unmarshal(
VersioningConfig,
"""<VersioningConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Status>Enabled</Status>
</VersioningConfiguration>""",
)
xml.marshal(config)
eq_(config.status, ENABLED)

config = xml.unmarshal(
VersioningConfig,
"""<VersioningConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Status>Suspended</Status>
<MFADelete>Disabled</MFADelete>
</VersioningConfiguration>""",
)
xml.marshal(config)
eq_(config.status, SUSPENDED)
eq_(config.mfa_delete, DISABLED)

0 comments on commit e0a3156

Please sign in to comment.