diff env/lib/python3.9/site-packages/boto/sdb/db/property.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/env/lib/python3.9/site-packages/boto/sdb/db/property.py	Mon Mar 22 18:12:50 2021 +0000
@@ -0,0 +1,704 @@
+# Copyright (c) 2006,2007,2008 Mitch Garnaat http://garnaat.org/
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish, dis-
+# tribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the fol-
+# lowing conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+import datetime
+from boto.sdb.db.key import Key
+from boto.utils import Password
+from boto.sdb.db.query import Query
+import re
+import boto
+import boto.s3.key
+from boto.sdb.db.blob import Blob
+from boto.compat import six, long_type
+
+
+class Property(object):
+
+    data_type = str
+    type_name = ''
+    name = ''
+    verbose_name = ''
+
+    def __init__(self, verbose_name=None, name=None, default=None,
+                 required=False, validator=None, choices=None, unique=False):
+        self.verbose_name = verbose_name
+        self.name = name
+        self.default = default
+        self.required = required
+        self.validator = validator
+        self.choices = choices
+        if self.name:
+            self.slot_name = '_' + self.name
+        else:
+            self.slot_name = '_'
+        self.unique = unique
+
+    def __get__(self, obj, objtype):
+        if obj:
+            obj.load()
+            return getattr(obj, self.slot_name)
+        else:
+            return None
+
+    def __set__(self, obj, value):
+        self.validate(value)
+
+        # Fire off any on_set functions
+        try:
+            if obj._loaded and hasattr(obj, "on_set_%s" % self.name):
+                fnc = getattr(obj, "on_set_%s" % self.name)
+                value = fnc(value)
+        except Exception:
+            boto.log.exception("Exception running on_set_%s" % self.name)
+
+        setattr(obj, self.slot_name, value)
+
+    def __property_config__(self, model_class, property_name):
+        self.model_class = model_class
+        self.name = property_name
+        self.slot_name = '_' + self.name
+
+    def default_validator(self, value):
+        if isinstance(value, six.string_types) or value == self.default_value():
+            return
+        if not isinstance(value, self.data_type):
+            raise TypeError('Validation Error, %s.%s expecting %s, got %s' % (self.model_class.__name__, self.name, self.data_type, type(value)))
+
+    def default_value(self):
+        return self.default
+
+    def validate(self, value):
+        if self.required and value is None:
+            raise ValueError('%s is a required property' % self.name)
+        if self.choices and value and value not in self.choices:
+            raise ValueError('%s not a valid choice for %s.%s' % (value, self.model_class.__name__, self.name))
+        if self.validator:
+            self.validator(value)
+        else:
+            self.default_validator(value)
+        return value
+
+    def empty(self, value):
+        return not value
+
+    def get_value_for_datastore(self, model_instance):
+        return getattr(model_instance, self.name)
+
+    def make_value_from_datastore(self, value):
+        return value
+
+    def get_choices(self):
+        if callable(self.choices):
+            return self.choices()
+        return self.choices
+
+
+def validate_string(value):
+    if value is None:
+        return
+    elif isinstance(value, six.string_types):
+        if len(value) > 1024:
+            raise ValueError('Length of value greater than maxlength')
+    else:
+        raise TypeError('Expecting String, got %s' % type(value))
+
+
+class StringProperty(Property):
+
+    type_name = 'String'
+
+    def __init__(self, verbose_name=None, name=None, default='',
+                 required=False, validator=validate_string,
+                 choices=None, unique=False):
+        super(StringProperty, self).__init__(verbose_name, name, default, required,
+                          validator, choices, unique)
+
+
+class TextProperty(Property):
+
+    type_name = 'Text'
+
+    def __init__(self, verbose_name=None, name=None, default='',
+                 required=False, validator=None, choices=None,
+                 unique=False, max_length=None):
+        super(TextProperty, self).__init__(verbose_name, name, default, required,
+                          validator, choices, unique)
+        self.max_length = max_length
+
+    def validate(self, value):
+        value = super(TextProperty, self).validate(value)
+        if not isinstance(value, six.string_types):
+            raise TypeError('Expecting Text, got %s' % type(value))
+        if self.max_length and len(value) > self.max_length:
+            raise ValueError('Length of value greater than maxlength %s' % self.max_length)
+
+
+class PasswordProperty(StringProperty):
+    """
+
+    Hashed property whose original value can not be
+    retrieved, but still can be compared.
+
+    Works by storing a hash of the original value instead
+    of the original value.  Once that's done all that
+    can be retrieved is the hash.
+
+    The comparison
+
+       obj.password == 'foo'
+
+    generates a hash of 'foo' and compares it to the
+    stored hash.
+
+    Underlying data type for hashing, storing, and comparing
+    is boto.utils.Password.  The default hash function is
+    defined there ( currently sha512 in most cases, md5
+    where sha512 is not available )
+
+    It's unlikely you'll ever need to use a different hash
+    function, but if you do, you can control the behavior
+    in one of two ways:
+
+      1) Specifying hashfunc in PasswordProperty constructor
+
+         import hashlib
+
+         class MyModel(model):
+             password = PasswordProperty(hashfunc=hashlib.sha224)
+
+      2) Subclassing Password and PasswordProperty
+
+         class SHA224Password(Password):
+             hashfunc=hashlib.sha224
+
+         class SHA224PasswordProperty(PasswordProperty):
+             data_type=MyPassword
+             type_name="MyPassword"
+
+         class MyModel(Model):
+             password = SHA224PasswordProperty()
+
+    """
+    data_type = Password
+    type_name = 'Password'
+
+    def __init__(self, verbose_name=None, name=None, default='', required=False,
+                 validator=None, choices=None, unique=False, hashfunc=None):
+
+        """
+           The hashfunc parameter overrides the default hashfunc in boto.utils.Password.
+
+           The remaining parameters are passed through to StringProperty.__init__"""
+
+        super(PasswordProperty, self).__init__(verbose_name, name, default, required,
+                                validator, choices, unique)
+        self.hashfunc = hashfunc
+
+    def make_value_from_datastore(self, value):
+        p = self.data_type(value, hashfunc=self.hashfunc)
+        return p
+
+    def get_value_for_datastore(self, model_instance):
+        value = super(PasswordProperty, self).get_value_for_datastore(model_instance)
+        if value and len(value):
+            return str(value)
+        else:
+            return None
+
+    def __set__(self, obj, value):
+        if not isinstance(value, self.data_type):
+            p = self.data_type(hashfunc=self.hashfunc)
+            p.set(value)
+            value = p
+        super(PasswordProperty, self).__set__(obj, value)
+
+    def __get__(self, obj, objtype):
+        return self.data_type(super(PasswordProperty, self).__get__(obj, objtype), hashfunc=self.hashfunc)
+
+    def validate(self, value):
+        value = super(PasswordProperty, self).validate(value)
+        if isinstance(value, self.data_type):
+            if len(value) > 1024:
+                raise ValueError('Length of value greater than maxlength')
+        else:
+            raise TypeError('Expecting %s, got %s' % (type(self.data_type), type(value)))
+
+
+class BlobProperty(Property):
+    data_type = Blob
+    type_name = "blob"
+
+    def __set__(self, obj, value):
+        if value != self.default_value():
+            if not isinstance(value, Blob):
+                oldb = self.__get__(obj, type(obj))
+                id = None
+                if oldb:
+                    id = oldb.id
+                b = Blob(value=value, id=id)
+                value = b
+        super(BlobProperty, self).__set__(obj, value)
+
+
+class S3KeyProperty(Property):
+
+    data_type = boto.s3.key.Key
+    type_name = 'S3Key'
+    validate_regex = "^s3:\/\/([^\/]*)\/(.*)$"
+
+    def __init__(self, verbose_name=None, name=None, default=None,
+                 required=False, validator=None, choices=None, unique=False):
+        super(S3KeyProperty, self).__init__(verbose_name, name, default, required,
+                          validator, choices, unique)
+
+    def validate(self, value):
+        value = super(S3KeyProperty, self).validate(value)
+        if value == self.default_value() or value == str(self.default_value()):
+            return self.default_value()
+        if isinstance(value, self.data_type):
+            return
+        match = re.match(self.validate_regex, value)
+        if match:
+            return
+        raise TypeError('Validation Error, expecting %s, got %s' % (self.data_type, type(value)))
+
+    def __get__(self, obj, objtype):
+        value = super(S3KeyProperty, self).__get__(obj, objtype)
+        if value:
+            if isinstance(value, self.data_type):
+                return value
+            match = re.match(self.validate_regex, value)
+            if match:
+                s3 = obj._manager.get_s3_connection()
+                bucket = s3.get_bucket(match.group(1), validate=False)
+                k = bucket.get_key(match.group(2))
+                if not k:
+                    k = bucket.new_key(match.group(2))
+                    k.set_contents_from_string("")
+                return k
+        else:
+            return value
+
+    def get_value_for_datastore(self, model_instance):
+        value = super(S3KeyProperty, self).get_value_for_datastore(model_instance)
+        if value:
+            return "s3://%s/%s" % (value.bucket.name, value.name)
+        else:
+            return None
+
+
+class IntegerProperty(Property):
+
+    data_type = int
+    type_name = 'Integer'
+
+    def __init__(self, verbose_name=None, name=None, default=0, required=False,
+                 validator=None, choices=None, unique=False, max=2147483647, min=-2147483648):
+        super(IntegerProperty, self).__init__(verbose_name, name, default, required, validator, choices, unique)
+        self.max = max
+        self.min = min
+
+    def validate(self, value):
+        value = int(value)
+        value = super(IntegerProperty, self).validate(value)
+        if value > self.max:
+            raise ValueError('Maximum value is %d' % self.max)
+        if value < self.min:
+            raise ValueError('Minimum value is %d' % self.min)
+        return value
+
+    def empty(self, value):
+        return value is None
+
+    def __set__(self, obj, value):
+        if value == "" or value is None:
+            value = 0
+        return super(IntegerProperty, self).__set__(obj, value)
+
+
+class LongProperty(Property):
+
+    data_type = long_type
+    type_name = 'Long'
+
+    def __init__(self, verbose_name=None, name=None, default=0, required=False,
+                 validator=None, choices=None, unique=False):
+        super(LongProperty, self).__init__(verbose_name, name, default, required, validator, choices, unique)
+
+    def validate(self, value):
+        value = long_type(value)
+        value = super(LongProperty, self).validate(value)
+        min = -9223372036854775808
+        max = 9223372036854775807
+        if value > max:
+            raise ValueError('Maximum value is %d' % max)
+        if value < min:
+            raise ValueError('Minimum value is %d' % min)
+        return value
+
+    def empty(self, value):
+        return value is None
+
+
+class BooleanProperty(Property):
+
+    data_type = bool
+    type_name = 'Boolean'
+
+    def __init__(self, verbose_name=None, name=None, default=False, required=False,
+                 validator=None, choices=None, unique=False):
+        super(BooleanProperty, self).__init__(verbose_name, name, default, required, validator, choices, unique)
+
+    def empty(self, value):
+        return value is None
+
+
+class FloatProperty(Property):
+
+    data_type = float
+    type_name = 'Float'
+
+    def __init__(self, verbose_name=None, name=None, default=0.0, required=False,
+                 validator=None, choices=None, unique=False):
+        super(FloatProperty, self).__init__(verbose_name, name, default, required, validator, choices, unique)
+
+    def validate(self, value):
+        value = float(value)
+        value = super(FloatProperty, self).validate(value)
+        return value
+
+    def empty(self, value):
+        return value is None
+
+
+class DateTimeProperty(Property):
+    """This class handles both the datetime.datetime object
+    And the datetime.date objects. It can return either one,
+    depending on the value stored in the database"""
+
+    data_type = datetime.datetime
+    type_name = 'DateTime'
+
+    def __init__(self, verbose_name=None, auto_now=False, auto_now_add=False, name=None,
+                 default=None, required=False, validator=None, choices=None, unique=False):
+        super(DateTimeProperty, self).__init__(verbose_name, name, default, required, validator, choices, unique)
+        self.auto_now = auto_now
+        self.auto_now_add = auto_now_add
+
+    def default_value(self):
+        if self.auto_now or self.auto_now_add:
+            return self.now()
+        return super(DateTimeProperty, self).default_value()
+
+    def validate(self, value):
+        if value is None:
+            return
+        if isinstance(value, datetime.date):
+            return value
+        return super(DateTimeProperty, self).validate(value)
+
+    def get_value_for_datastore(self, model_instance):
+        if self.auto_now:
+            setattr(model_instance, self.name, self.now())
+        return super(DateTimeProperty, self).get_value_for_datastore(model_instance)
+
+    def now(self):
+        return datetime.datetime.utcnow()
+
+
+class DateProperty(Property):
+
+    data_type = datetime.date
+    type_name = 'Date'
+
+    def __init__(self, verbose_name=None, auto_now=False, auto_now_add=False, name=None,
+                 default=None, required=False, validator=None, choices=None, unique=False):
+        super(DateProperty, self).__init__(verbose_name, name, default, required, validator, choices, unique)
+        self.auto_now = auto_now
+        self.auto_now_add = auto_now_add
+
+    def default_value(self):
+        if self.auto_now or self.auto_now_add:
+            return self.now()
+        return super(DateProperty, self).default_value()
+
+    def validate(self, value):
+        value = super(DateProperty, self).validate(value)
+        if value is None:
+            return
+        if not isinstance(value, self.data_type):
+            raise TypeError('Validation Error, expecting %s, got %s' % (self.data_type, type(value)))
+
+    def get_value_for_datastore(self, model_instance):
+        if self.auto_now:
+            setattr(model_instance, self.name, self.now())
+        val = super(DateProperty, self).get_value_for_datastore(model_instance)
+        if isinstance(val, datetime.datetime):
+            val = val.date()
+        return val
+
+    def now(self):
+        return datetime.date.today()
+
+
+class TimeProperty(Property):
+    data_type = datetime.time
+    type_name = 'Time'
+
+    def __init__(self, verbose_name=None, name=None,
+                 default=None, required=False, validator=None, choices=None, unique=False):
+        super(TimeProperty, self).__init__(verbose_name, name, default, required, validator, choices, unique)
+
+    def validate(self, value):
+        value = super(TimeProperty, self).validate(value)
+        if value is None:
+            return
+        if not isinstance(value, self.data_type):
+            raise TypeError('Validation Error, expecting %s, got %s' % (self.data_type, type(value)))
+
+
+class ReferenceProperty(Property):
+
+    data_type = Key
+    type_name = 'Reference'
+
+    def __init__(self, reference_class=None, collection_name=None,
+                 verbose_name=None, name=None, default=None, required=False, validator=None, choices=None, unique=False):
+        super(ReferenceProperty, self).__init__(verbose_name, name, default, required, validator, choices, unique)
+        self.reference_class = reference_class
+        self.collection_name = collection_name
+
+    def __get__(self, obj, objtype):
+        if obj:
+            value = getattr(obj, self.slot_name)
+            if value == self.default_value():
+                return value
+            # If the value is still the UUID for the referenced object, we need to create
+            # the object now that is the attribute has actually been accessed.  This lazy
+            # instantiation saves unnecessary roundtrips to SimpleDB
+            if isinstance(value, six.string_types):
+                value = self.reference_class(value)
+                setattr(obj, self.name, value)
+            return value
+
+    def __set__(self, obj, value):
+        """Don't allow this object to be associated to itself
+        This causes bad things to happen"""
+        if value is not None and (obj.id == value or (hasattr(value, "id") and obj.id == value.id)):
+            raise ValueError("Can not associate an object with itself!")
+        return super(ReferenceProperty, self).__set__(obj, value)
+
+    def __property_config__(self, model_class, property_name):
+        super(ReferenceProperty, self).__property_config__(model_class, property_name)
+        if self.collection_name is None:
+            self.collection_name = '%s_%s_set' % (model_class.__name__.lower(), self.name)
+        if hasattr(self.reference_class, self.collection_name):
+            raise ValueError('duplicate property: %s' % self.collection_name)
+        setattr(self.reference_class, self.collection_name,
+                _ReverseReferenceProperty(model_class, property_name, self.collection_name))
+
+    def check_uuid(self, value):
+        # This does a bit of hand waving to "type check" the string
+        t = value.split('-')
+        if len(t) != 5:
+            raise ValueError
+
+    def check_instance(self, value):
+        try:
+            obj_lineage = value.get_lineage()
+            cls_lineage = self.reference_class.get_lineage()
+            if obj_lineage.startswith(cls_lineage):
+                return
+            raise TypeError('%s not instance of %s' % (obj_lineage, cls_lineage))
+        except:
+            raise ValueError('%s is not a Model' % value)
+
+    def validate(self, value):
+        if self.validator:
+            self.validator(value)
+        if self.required and value is None:
+            raise ValueError('%s is a required property' % self.name)
+        if value == self.default_value():
+            return
+        if not isinstance(value, six.string_types):
+            self.check_instance(value)
+
+
+class _ReverseReferenceProperty(Property):
+    data_type = Query
+    type_name = 'query'
+
+    def __init__(self, model, prop, name):
+        self.__model = model
+        self.__property = prop
+        self.collection_name = prop
+        self.name = name
+        self.item_type = model
+
+    def __get__(self, model_instance, model_class):
+        """Fetches collection of model instances of this collection property."""
+        if model_instance is not None:
+            query = Query(self.__model)
+            if isinstance(self.__property, list):
+                props = []
+                for prop in self.__property:
+                    props.append("%s =" % prop)
+                return query.filter(props, model_instance)
+            else:
+                return query.filter(self.__property + ' =', model_instance)
+        else:
+            return self
+
+    def __set__(self, model_instance, value):
+        """Not possible to set a new collection."""
+        raise ValueError('Virtual property is read-only')
+
+
+class CalculatedProperty(Property):
+
+    def __init__(self, verbose_name=None, name=None, default=None,
+                 required=False, validator=None, choices=None,
+                 calculated_type=int, unique=False, use_method=False):
+        super(CalculatedProperty, self).__init__(verbose_name, name, default, required,
+                          validator, choices, unique)
+        self.calculated_type = calculated_type
+        self.use_method = use_method
+
+    def __get__(self, obj, objtype):
+        value = self.default_value()
+        if obj:
+            try:
+                value = getattr(obj, self.slot_name)
+                if self.use_method:
+                    value = value()
+            except AttributeError:
+                pass
+        return value
+
+    def __set__(self, obj, value):
+        """Not possible to set a new AutoID."""
+        pass
+
+    def _set_direct(self, obj, value):
+        if not self.use_method:
+            setattr(obj, self.slot_name, value)
+
+    def get_value_for_datastore(self, model_instance):
+        if self.calculated_type in [str, int, bool]:
+            value = self.__get__(model_instance, model_instance.__class__)
+            return value
+        else:
+            return None
+
+
+class ListProperty(Property):
+
+    data_type = list
+    type_name = 'List'
+
+    def __init__(self, item_type, verbose_name=None, name=None, default=None, **kwds):
+        if default is None:
+            default = []
+        self.item_type = item_type
+        super(ListProperty, self).__init__(verbose_name, name, default=default, required=True, **kwds)
+
+    def validate(self, value):
+        if self.validator:
+            self.validator(value)
+        if value is not None:
+            if not isinstance(value, list):
+                value = [value]
+
+        if self.item_type in six.integer_types:
+            item_type = six.integer_types
+        elif self.item_type in six.string_types:
+            item_type = six.string_types
+        else:
+            item_type = self.item_type
+
+        for item in value:
+            if not isinstance(item, item_type):
+                if item_type == six.integer_types:
+                    raise ValueError('Items in the %s list must all be integers.' % self.name)
+                else:
+                    raise ValueError('Items in the %s list must all be %s instances' %
+                                     (self.name, self.item_type.__name__))
+        return value
+
+    def empty(self, value):
+        return value is None
+
+    def default_value(self):
+        return list(super(ListProperty, self).default_value())
+
+    def __set__(self, obj, value):
+        """Override the set method to allow them to set the property to an instance of the item_type instead of requiring a list to be passed in"""
+        if self.item_type in six.integer_types:
+            item_type = six.integer_types
+        elif self.item_type in six.string_types:
+            item_type = six.string_types
+        else:
+            item_type = self.item_type
+        if isinstance(value, item_type):
+            value = [value]
+        elif value is None:  # Override to allow them to set this to "None" to remove everything
+            value = []
+        return super(ListProperty, self).__set__(obj, value)
+
+
+class MapProperty(Property):
+
+    data_type = dict
+    type_name = 'Map'
+
+    def __init__(self, item_type=str, verbose_name=None, name=None, default=None, **kwds):
+        if default is None:
+            default = {}
+        self.item_type = item_type
+        super(MapProperty, self).__init__(verbose_name, name, default=default, required=True, **kwds)
+
+    def validate(self, value):
+        value = super(MapProperty, self).validate(value)
+        if value is not None:
+            if not isinstance(value, dict):
+                raise ValueError('Value must of type dict')
+
+        if self.item_type in six.integer_types:
+            item_type = six.integer_types
+        elif self.item_type in six.string_types:
+            item_type = six.string_types
+        else:
+            item_type = self.item_type
+
+        for key in value:
+            if not isinstance(value[key], item_type):
+                if item_type == six.integer_types:
+                    raise ValueError('Values in the %s Map must all be integers.' % self.name)
+                else:
+                    raise ValueError('Values in the %s Map must all be %s instances' %
+                                     (self.name, self.item_type.__name__))
+        return value
+
+    def empty(self, value):
+        return value is None
+
+    def default_value(self):
+        return {}