base.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. # Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License"). You
  4. # may not use this file except in compliance with the License. A copy of
  5. # the License is located at
  6. #
  7. # http://aws.amazon.com/apache2.0/
  8. #
  9. # or in the "license" file accompanying this file. This file is
  10. # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
  11. # ANY KIND, either express or implied. See the License for the specific
  12. # language governing permissions and limitations under the License.
  13. import logging
  14. import boto3
  15. logger = logging.getLogger(__name__)
  16. class ResourceMeta(object):
  17. """
  18. An object containing metadata about a resource.
  19. """
  20. def __init__(self, service_name, identifiers=None, client=None,
  21. data=None, resource_model=None):
  22. #: (``string``) The service name, e.g. 's3'
  23. self.service_name = service_name
  24. if identifiers is None:
  25. identifiers = []
  26. #: (``list``) List of identifier names
  27. self.identifiers = identifiers
  28. #: (:py:class:`~botocore.client.BaseClient`) Low-level Botocore client
  29. self.client = client
  30. #: (``dict``) Loaded resource data attributes
  31. self.data = data
  32. # The resource model for that resource
  33. self.resource_model = resource_model
  34. def __repr__(self):
  35. return 'ResourceMeta(\'{0}\', identifiers={1})'.format(
  36. self.service_name, self.identifiers)
  37. def __eq__(self, other):
  38. # Two metas are equal if their components are all equal
  39. if other.__class__.__name__ != self.__class__.__name__:
  40. return False
  41. return self.__dict__ == other.__dict__
  42. def copy(self):
  43. """
  44. Create a copy of this metadata object.
  45. """
  46. params = self.__dict__.copy()
  47. service_name = params.pop('service_name')
  48. return ResourceMeta(service_name, **params)
  49. class ServiceResource(object):
  50. """
  51. A base class for resources.
  52. :type client: botocore.client
  53. :param client: A low-level Botocore client instance
  54. """
  55. meta = None
  56. """
  57. Stores metadata about this resource instance, such as the
  58. ``service_name``, the low-level ``client`` and any cached ``data``
  59. from when the instance was hydrated. For example::
  60. # Get a low-level client from a resource instance
  61. client = resource.meta.client
  62. response = client.operation(Param='foo')
  63. # Print the resource instance's service short name
  64. print(resource.meta.service_name)
  65. See :py:class:`ResourceMeta` for more information.
  66. """
  67. def __init__(self, *args, **kwargs):
  68. # Always work on a copy of meta, otherwise we would affect other
  69. # instances of the same subclass.
  70. self.meta = self.meta.copy()
  71. # Create a default client if none was passed
  72. if kwargs.get('client') is not None:
  73. self.meta.client = kwargs.get('client')
  74. else:
  75. self.meta.client = boto3.client(self.meta.service_name)
  76. # Allow setting identifiers as positional arguments in the order
  77. # in which they were defined in the ResourceJSON.
  78. for i, value in enumerate(args):
  79. setattr(self, '_' + self.meta.identifiers[i], value)
  80. # Allow setting identifiers via keyword arguments. Here we need
  81. # extra logic to ignore other keyword arguments like ``client``.
  82. for name, value in kwargs.items():
  83. if name == 'client':
  84. continue
  85. if name not in self.meta.identifiers:
  86. raise ValueError('Unknown keyword argument: {0}'.format(name))
  87. setattr(self, '_' + name, value)
  88. # Validate that all identifiers have been set.
  89. for identifier in self.meta.identifiers:
  90. if getattr(self, identifier) is None:
  91. raise ValueError(
  92. 'Required parameter {0} not set'.format(identifier))
  93. def __repr__(self):
  94. identifiers = []
  95. for identifier in self.meta.identifiers:
  96. identifiers.append('{0}={1}'.format(
  97. identifier, repr(getattr(self, identifier))))
  98. return "{0}({1})".format(
  99. self.__class__.__name__,
  100. ', '.join(identifiers),
  101. )
  102. def __eq__(self, other):
  103. # Should be instances of the same resource class
  104. if other.__class__.__name__ != self.__class__.__name__:
  105. return False
  106. # Each of the identifiers should have the same value in both
  107. # instances, e.g. two buckets need the same name to be equal.
  108. for identifier in self.meta.identifiers:
  109. if getattr(self, identifier) != getattr(other, identifier):
  110. return False
  111. return True
  112. def __hash__(self):
  113. identifiers = []
  114. for identifier in self.meta.identifiers:
  115. identifiers.append(getattr(self, identifier))
  116. return hash((self.__class__.__name__, tuple(identifiers)))