# Path: elasticmagic/document.py
# class DynamicDocument(with_metaclass(DynamicDocumentMeta, Document)):
#     def _process_source_key_value(self, key, value):
#         key, value = (
#             super(DynamicDocument, self)._process_source_key_value(key, value)
#         )
#         if isinstance(value, dict):
#             return key, DynamicDocument(**value)
#         return key, value
# 
# Path: elasticmagic/document.py
# def get_doc_type_for_hit(hit):
#     fields = hit.get('fields', {})
#     custom_doc_type = fields.get(DOC_TYPE_NAME_FIELD)
#     if custom_doc_type:
#         return custom_doc_type[0]
#     return hit['_type']
# 
# Path: elasticmagic/expression.py
# class ParamsExpression(Expression):
#     def __init__(self, **kwargs):
#         super(ParamsExpression, self).__init__()
#         self.params = Params(kwargs)
# 
#     def _collect_doc_classes(self):
#         return collect_doc_classes(self.params)
# 
# class Params(Expression, Mapping):
#     __visit_name__ = 'params'
# 
#     def __init__(self, *args, **kwargs):
#         params = {}
#         for d in args:
#             params.update(d)
#         params.update(kwargs)
#         self._params = {}
#         for k, v in clean_params(params).items():
#             if k.endswith('_') and not k.startswith('_'):
#                 k = k.rstrip('_')
#             self._params[k] = v
# 
#     def _collect_doc_classes(self):
#         return collect_doc_classes(self._params)
# 
#     def __len__(self):
#         return len(self._params)
# 
#     def __iter__(self):
#         return iter(self._params)
# 
#     def __getitem__(self, key):
#         return self._params[key]
# 
#     def __contains__(self, key):
#         return key in self._params
# 
# Path: elasticmagic/compat.py
# def force_unicode(value):
#     """
#     Forces a bytestring to become a Unicode string.
#     """
#     if PY2:
#         # Python 2.X
#         if isinstance(value, str):
#             value = value.decode('utf-8', 'replace')
#         elif not isinstance(value, basestring):  # noqa:F821
#             value = unicode(value)  # noqa:F821
#     else:
#         # Python 3.X
#         if isinstance(value, bytes):
#             value = value.decode('utf-8', errors='replace')
#         elif not isinstance(value, str):
#             value = str(value)
# 
#     return value
# 
# Path: elasticmagic/types.py
# def instantiate(typeobj, *args, **kwargs):
#     if inspect.isclass(typeobj):
#         return typeobj(*args, **kwargs)
#     return typeobj
# 
# class Type(object):
#     python_type = None
# 
#     def __init__(self):
#         self.sub_type = None
#         self.doc_cls = None
# 
#     def to_python(self, value):
#         if value is None:
#             return None
#         if self.python_type is not None:
#             return self.python_type(value)
#         return value
# 
#     def to_python_single(self, value):
#         return self.to_python(value)
# 
#     def from_python(self, value, compiler, validate=False):
#         return value
# 
# Path: elasticmagic/util.py
# def _with_clone(fn):
#     @wraps(fn)
#     def wrapper(self, *args, **kwargs):
#         clone = self.clone()
#         res = fn(clone, *args, **kwargs)
#         if res is not None:
#             return res
#         return clone
#     return wrapper
# 
# class cached_property(object):
#     def __init__(self, func):
#         self.func = func
# 
#     def __get__(self, instance, type=None):
#         if instance is None:
#             return self
# 
#         res = instance.__dict__[self.func.__name__] = self.func(instance)
#         return res
# 
# def maybe_float(value):
#     if value is None:
#         return None
#     return float(value)
# 
# def merge_params(params, args, kwargs):
#     assert isinstance(args, Iterable), args
#     assert isinstance(kwargs, Mapping), kwargs
#     new = dict()
#     for a in args:
#         new.update(a)
#     new.update(kwargs)
#     return type(params)(params, **new)


from itertools import chain
from .document import DynamicDocument
from .document import get_doc_type_for_hit
from .expression import ParamsExpression, Params
from .compat import force_unicode
from .types import instantiate, Type
from .util import _with_clone, cached_property, maybe_float, merge_params
        raise NotImplementedError()


class AggResult(object):
    def __init__(self, agg_expr):
        self.expr = agg_expr


class MetricsAgg(AggExpression):
    def build_agg_result(
            self, raw_data, doc_cls_map=None, mapper_registry=None,
    ):
        return self.result_cls(self, raw_data)


class BucketAgg(AggExpression):
    __visit_name__ = 'bucket_agg'

    def __init__(self, aggs=None, **kwargs):
        super(BucketAgg, self).__init__(**kwargs)
        self._aggregations = Params(
            aggs or {}, **kwargs.pop('aggregations', {})
        )

    def clone(self):
        return self.__class__(aggs=self._aggregations, **self.params)

    @_with_clone
    def aggregations(self, *args, **kwargs):
        if len(args) == 1 and args[0] is None:

# Path: elasticmagic/document.py
# class DynamicDocument(with_metaclass(DynamicDocumentMeta, Document)):
#     def _process_source_key_value(self, key, value):
#         key, value = (
#             super(DynamicDocument, self)._process_source_key_value(key, value)
#         )
#         if isinstance(value, dict):
#             return key, DynamicDocument(**value)
#         return key, value
# 
# Path: elasticmagic/document.py
# def get_doc_type_for_hit(hit):
#     fields = hit.get('fields', {})
#     custom_doc_type = fields.get(DOC_TYPE_NAME_FIELD)
#     if custom_doc_type:
#         return custom_doc_type[0]
#     return hit['_type']
# 
# Path: elasticmagic/expression.py
# class ParamsExpression(Expression):
#     def __init__(self, **kwargs):
#         super(ParamsExpression, self).__init__()
#         self.params = Params(kwargs)
# 
#     def _collect_doc_classes(self):
#         return collect_doc_classes(self.params)
# 
# class Params(Expression, Mapping):
#     __visit_name__ = 'params'
# 
#     def __init__(self, *args, **kwargs):
#         params = {}
#         for d in args:
#             params.update(d)
#         params.update(kwargs)
#         self._params = {}
#         for k, v in clean_params(params).items():
#             if k.endswith('_') and not k.startswith('_'):
#                 k = k.rstrip('_')
#             self._params[k] = v
# 
#     def _collect_doc_classes(self):
#         return collect_doc_classes(self._params)
# 
#     def __len__(self):
#         return len(self._params)
# 
#     def __iter__(self):
#         return iter(self._params)
# 
#     def __getitem__(self, key):
#         return self._params[key]
# 
#     def __contains__(self, key):
#         return key in self._params
# 
# Path: elasticmagic/compat.py
# def force_unicode(value):
#     """
#     Forces a bytestring to become a Unicode string.
#     """
#     if PY2:
#         # Python 2.X
#         if isinstance(value, str):
#             value = value.decode('utf-8', 'replace')
#         elif not isinstance(value, basestring):  # noqa:F821
#             value = unicode(value)  # noqa:F821
#     else:
#         # Python 3.X
#         if isinstance(value, bytes):
#             value = value.decode('utf-8', errors='replace')
#         elif not isinstance(value, str):
#             value = str(value)
# 
#     return value
# 
# Path: elasticmagic/types.py
# def instantiate(typeobj, *args, **kwargs):
#     if inspect.isclass(typeobj):
#         return typeobj(*args, **kwargs)
#     return typeobj
# 
# class Type(object):
#     python_type = None
# 
#     def __init__(self):
#         self.sub_type = None
#         self.doc_cls = None
# 
#     def to_python(self, value):
#         if value is None:
#             return None
#         if self.python_type is not None:
#             return self.python_type(value)
#         return value
# 
#     def to_python_single(self, value):
#         return self.to_python(value)
# 
#     def from_python(self, value, compiler, validate=False):
#         return value
# 
# Path: elasticmagic/util.py
# def _with_clone(fn):
#     @wraps(fn)
#     def wrapper(self, *args, **kwargs):
#         clone = self.clone()
#         res = fn(clone, *args, **kwargs)
#         if res is not None:
#             return res
#         return clone
#     return wrapper
# 
# class cached_property(object):
#     def __init__(self, func):
#         self.func = func
# 
#     def __get__(self, instance, type=None):
#         if instance is None:
#             return self
# 
#         res = instance.__dict__[self.func.__name__] = self.func(instance)
#         return res
# 
# def maybe_float(value):
#     if value is None:
#         return None
#     return float(value)
# 
# def merge_params(params, args, kwargs):
#     assert isinstance(args, Iterable), args
#     assert isinstance(kwargs, Mapping), kwargs
#     new = dict()
#     for a in args:
#         new.update(a)
#     new.update(kwargs)
#     return type(params)(params, **new)


# Path: elasticmagic/agg.py
from itertools import chain
from .document import DynamicDocument
from .document import get_doc_type_for_hit
from .expression import ParamsExpression, Params
from .compat import force_unicode
from .types import instantiate, Type
from .util import _with_clone, cached_property, maybe_float, merge_params

        raise NotImplementedError()


class AggResult(object):
    def __init__(self, agg_expr):
        self.expr = agg_expr


class MetricsAgg(AggExpression):
    def build_agg_result(
            self, raw_data, doc_cls_map=None, mapper_registry=None,
    ):
        return self.result_cls(self, raw_data)


class BucketAgg(AggExpression):
    __visit_name__ = 'bucket_agg'

    def __init__(self, aggs=None, **kwargs):
        super(BucketAgg, self).__init__(**kwargs)
        self._aggregations = Params(
            aggs or {}, **kwargs.pop('aggregations', {})
        )

    def clone(self):
        return self.__class__(aggs=self._aggregations, **self.params)

    @_with_clone
    def aggregations(self, *args, **kwargs):
        if len(args) == 1 and args[0] is None:

            self._aggregations = Params()