import re from sys import maxsize import six from mongoengine import ( EmbeddedDocumentListField, ListField, FloatField, StringField, EmbeddedDocumentField, SortedListField, MapField, DictField, ) class LengthRangeListField(ListField): def __init__(self, field=None, max_length=maxsize, min_length=0, **kwargs): self.__min_length = min_length self.__max_length = max_length super(LengthRangeListField, self).__init__(field, **kwargs) def validate(self, value): min, val, max = self.__min_length, len(value), self.__max_length if not min <= val <= max: self.error("Item count %d exceeds range [%d, %d]" % (val, min, max)) super(LengthRangeListField, self).validate(value) class LengthRangeEmbeddedDocumentListField(LengthRangeListField): def __init__(self, field=None, *args, **kwargs): super(LengthRangeEmbeddedDocumentListField, self).__init__( EmbeddedDocumentField(field), *args, **kwargs ) class UniqueEmbeddedDocumentListField(EmbeddedDocumentListField): def __init__(self, document_type, key, **kwargs): """ Create a unique embedded document list field for a document type with a unique comparison key func/property :param document_type: The type of :class:`~mongoengine.EmbeddedDocument` the list will hold. :param key: A callable to extract a key from each item """ if not callable(key): raise KeyError("key must be callable") self.__key = key super(UniqueEmbeddedDocumentListField, self).__init__(document_type) def validate(self, value): if len({self.__key(i) for i in value}) != len(value): self.error("Items with duplicate key exist in the list") super(UniqueEmbeddedDocumentListField, self).validate(value) def object_to_key_value_pairs(obj): if isinstance(obj, dict): return [(key, object_to_key_value_pairs(value)) for key, value in obj.items()] if isinstance(obj, list): return list(map(object_to_key_value_pairs, obj)) return obj class EmbeddedDocumentSortedListField(EmbeddedDocumentListField): """ A sorted list of embedded documents """ def to_mongo(self, value, use_db_field=True, fields=None): value = super(EmbeddedDocumentSortedListField, self).to_mongo( value, use_db_field, fields ) return sorted(value, key=object_to_key_value_pairs) class LengthRangeSortedListField(LengthRangeListField, SortedListField): pass class CustomFloatField(FloatField): def __init__(self, greater_than=None, **kwargs): self.greater_than = greater_than super(CustomFloatField, self).__init__(**kwargs) def validate(self, value): super(CustomFloatField, self).validate(value) if self.greater_than is not None and value <= self.greater_than: self.error("Float value must be greater than %s" % str(self.greater_than)) # TODO: bucket name should be at most 63 characters.... aws_s3_bucket_only_regex = ( r"^s3://" r"(?:(?:\w[A-Z0-9\-]+\w)\.)*(?:\w[A-Z0-9\-]+\w)" # bucket name ) aws_s3_url_with_bucket_regex = ( r"^s3://" r"(?:(?:\w[A-Z0-9\-]+\w)\.)*(?:\w[A-Z0-9\-]+\w)" # bucket name r"(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}(?