codekingpro/portable-devtools
114k
1# Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.2#3# Licensed under the Apache License, Version 2.0 (the "License"). You4# may not use this file except in compliance with the License. A copy of5# the License is located at6#7# https://aws.amazon.com/apache2.0/8#9# or in the "license" file accompanying this file. This file is10# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF11# ANY KIND, either express or implied. See the License for the specific12# language governing permissions and limitations under the License.13 14import logging15 16import boto317 18logger = logging.getLogger(__name__)19 20 21class ResourceMeta:22 """23 An object containing metadata about a resource.24 """25 26 def __init__(27 self,28 service_name,29 identifiers=None,30 client=None,31 data=None,32 resource_model=None,33 ):34 #: (``string``) The service name, e.g. 's3'35 self.service_name = service_name36 37 if identifiers is None:38 identifiers = []39 #: (``list``) List of identifier names40 self.identifiers = identifiers41 42 #: (:py:class:`~botocore.client.BaseClient`) Low-level Botocore client43 self.client = client44 #: (``dict``) Loaded resource data attributes45 self.data = data46 47 # The resource model for that resource48 self.resource_model = resource_model49 50 def __repr__(self):51 return 'ResourceMeta(\'{}\', identifiers={})'.format(52 self.service_name, self.identifiers53 )54 55 def __eq__(self, other):56 # Two metas are equal if their components are all equal57 if other.__class__.__name__ != self.__class__.__name__:58 return False59 60 return self.__dict__ == other.__dict__61 62 def copy(self):63 """64 Create a copy of this metadata object.65 """66 params = self.__dict__.copy()67 service_name = params.pop('service_name')68 return ResourceMeta(service_name, **params)69 70 71class ServiceResource:72 """73 A base class for resources.74 75 :type client: botocore.client76 :param client: A low-level Botocore client instance77 """78 79 meta = None80 """81 Stores metadata about this resource instance, such as the82 ``service_name``, the low-level ``client`` and any cached ``data``83 from when the instance was hydrated. For example::84 85 # Get a low-level client from a resource instance86 client = resource.meta.client87 response = client.operation(Param='foo')88 89 # Print the resource instance's service short name90 print(resource.meta.service_name)91 92 See :py:class:`ResourceMeta` for more information.93 """94 95 def __init__(self, *args, **kwargs):96 # Always work on a copy of meta, otherwise we would affect other97 # instances of the same subclass.98 self.meta = self.meta.copy()99 100 # Create a default client if none was passed101 if kwargs.get('client') is not None:102 self.meta.client = kwargs.get('client')103 else:104 self.meta.client = boto3.client(self.meta.service_name)105 106 # Allow setting identifiers as positional arguments in the order107 # in which they were defined in the ResourceJSON.108 for i, value in enumerate(args):109 setattr(self, '_' + self.meta.identifiers[i], value)110 111 # Allow setting identifiers via keyword arguments. Here we need112 # extra logic to ignore other keyword arguments like ``client``.113 for name, value in kwargs.items():114 if name == 'client':115 continue116 117 if name not in self.meta.identifiers:118 raise ValueError(f'Unknown keyword argument: {name}')119 120 setattr(self, '_' + name, value)121 122 # Validate that all identifiers have been set.123 for identifier in self.meta.identifiers:124 if getattr(self, identifier) is None:125 raise ValueError(f'Required parameter {identifier} not set')126 127 def __repr__(self):128 identifiers = []129 for identifier in self.meta.identifiers:130 identifiers.append(131 f'{identifier}={repr(getattr(self, identifier))}'132 )133 return "{}({})".format(134 self.__class__.__name__,135 ', '.join(identifiers),136 )137 138 def __eq__(self, other):139 # Should be instances of the same resource class140 if other.__class__.__name__ != self.__class__.__name__:141 return False142 143 # Each of the identifiers should have the same value in both144 # instances, e.g. two buckets need the same name to be equal.145 for identifier in self.meta.identifiers:146 if getattr(self, identifier) != getattr(other, identifier):147 return False148 149 return True150 151 def __hash__(self):152 identifiers = []153 for identifier in self.meta.identifiers:154 identifiers.append(getattr(self, identifier))155 return hash((self.__class__.__name__, tuple(identifiers)))156 