You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
4.9 KiB
156 lines
4.9 KiB
6 months ago
|
# Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||
|
#
|
||
|
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
||
|
# may not use this file except in compliance with the License. A copy of
|
||
|
# the License is located at
|
||
|
#
|
||
|
# https://aws.amazon.com/apache2.0/
|
||
|
#
|
||
|
# or in the "license" file accompanying this file. This file 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.
|
||
|
|
||
|
import logging
|
||
|
|
||
|
import boto3
|
||
|
|
||
|
logger = logging.getLogger(__name__)
|
||
|
|
||
|
|
||
|
class ResourceMeta:
|
||
|
"""
|
||
|
An object containing metadata about a resource.
|
||
|
"""
|
||
|
|
||
|
def __init__(
|
||
|
self,
|
||
|
service_name,
|
||
|
identifiers=None,
|
||
|
client=None,
|
||
|
data=None,
|
||
|
resource_model=None,
|
||
|
):
|
||
|
#: (``string``) The service name, e.g. 's3'
|
||
|
self.service_name = service_name
|
||
|
|
||
|
if identifiers is None:
|
||
|
identifiers = []
|
||
|
#: (``list``) List of identifier names
|
||
|
self.identifiers = identifiers
|
||
|
|
||
|
#: (:py:class:`~botocore.client.BaseClient`) Low-level Botocore client
|
||
|
self.client = client
|
||
|
#: (``dict``) Loaded resource data attributes
|
||
|
self.data = data
|
||
|
|
||
|
# The resource model for that resource
|
||
|
self.resource_model = resource_model
|
||
|
|
||
|
def __repr__(self):
|
||
|
return 'ResourceMeta(\'{}\', identifiers={})'.format(
|
||
|
self.service_name, self.identifiers
|
||
|
)
|
||
|
|
||
|
def __eq__(self, other):
|
||
|
# Two metas are equal if their components are all equal
|
||
|
if other.__class__.__name__ != self.__class__.__name__:
|
||
|
return False
|
||
|
|
||
|
return self.__dict__ == other.__dict__
|
||
|
|
||
|
def copy(self):
|
||
|
"""
|
||
|
Create a copy of this metadata object.
|
||
|
"""
|
||
|
params = self.__dict__.copy()
|
||
|
service_name = params.pop('service_name')
|
||
|
return ResourceMeta(service_name, **params)
|
||
|
|
||
|
|
||
|
class ServiceResource:
|
||
|
"""
|
||
|
A base class for resources.
|
||
|
|
||
|
:type client: botocore.client
|
||
|
:param client: A low-level Botocore client instance
|
||
|
"""
|
||
|
|
||
|
meta = None
|
||
|
"""
|
||
|
Stores metadata about this resource instance, such as the
|
||
|
``service_name``, the low-level ``client`` and any cached ``data``
|
||
|
from when the instance was hydrated. For example::
|
||
|
|
||
|
# Get a low-level client from a resource instance
|
||
|
client = resource.meta.client
|
||
|
response = client.operation(Param='foo')
|
||
|
|
||
|
# Print the resource instance's service short name
|
||
|
print(resource.meta.service_name)
|
||
|
|
||
|
See :py:class:`ResourceMeta` for more information.
|
||
|
"""
|
||
|
|
||
|
def __init__(self, *args, **kwargs):
|
||
|
# Always work on a copy of meta, otherwise we would affect other
|
||
|
# instances of the same subclass.
|
||
|
self.meta = self.meta.copy()
|
||
|
|
||
|
# Create a default client if none was passed
|
||
|
if kwargs.get('client') is not None:
|
||
|
self.meta.client = kwargs.get('client')
|
||
|
else:
|
||
|
self.meta.client = boto3.client(self.meta.service_name)
|
||
|
|
||
|
# Allow setting identifiers as positional arguments in the order
|
||
|
# in which they were defined in the ResourceJSON.
|
||
|
for i, value in enumerate(args):
|
||
|
setattr(self, '_' + self.meta.identifiers[i], value)
|
||
|
|
||
|
# Allow setting identifiers via keyword arguments. Here we need
|
||
|
# extra logic to ignore other keyword arguments like ``client``.
|
||
|
for name, value in kwargs.items():
|
||
|
if name == 'client':
|
||
|
continue
|
||
|
|
||
|
if name not in self.meta.identifiers:
|
||
|
raise ValueError(f'Unknown keyword argument: {name}')
|
||
|
|
||
|
setattr(self, '_' + name, value)
|
||
|
|
||
|
# Validate that all identifiers have been set.
|
||
|
for identifier in self.meta.identifiers:
|
||
|
if getattr(self, identifier) is None:
|
||
|
raise ValueError(f'Required parameter {identifier} not set')
|
||
|
|
||
|
def __repr__(self):
|
||
|
identifiers = []
|
||
|
for identifier in self.meta.identifiers:
|
||
|
identifiers.append(
|
||
|
f'{identifier}={repr(getattr(self, identifier))}'
|
||
|
)
|
||
|
return "{}({})".format(
|
||
|
self.__class__.__name__,
|
||
|
', '.join(identifiers),
|
||
|
)
|
||
|
|
||
|
def __eq__(self, other):
|
||
|
# Should be instances of the same resource class
|
||
|
if other.__class__.__name__ != self.__class__.__name__:
|
||
|
return False
|
||
|
|
||
|
# Each of the identifiers should have the same value in both
|
||
|
# instances, e.g. two buckets need the same name to be equal.
|
||
|
for identifier in self.meta.identifiers:
|
||
|
if getattr(self, identifier) != getattr(other, identifier):
|
||
|
return False
|
||
|
|
||
|
return True
|
||
|
|
||
|
def __hash__(self):
|
||
|
identifiers = []
|
||
|
for identifier in self.meta.identifiers:
|
||
|
identifiers.append(getattr(self, identifier))
|
||
|
return hash((self.__class__.__name__, tuple(identifiers)))
|