# Path: muninn/_compat.py
# PY3 = sys.version_info[0] == 3
#     def is_python2_unicode(x):
#     def dictkeys(d):
#     def dictvalues(d):
#     def path_utf8(path):
#     def encode(s):
#     def decode(s):
#     def is_python2_unicode(x):
#     def path_utf8(path):
#     def decode(s):
#     def encode(s):
# 
# Path: muninn/core.py
# class Core(Mapping):
#     uuid = UUID()
#     active = Boolean(index=True)
#     hash = Text(optional=True, index=True)
#     size = Long(optional=True, index=True)
#     metadata_date = Timestamp(index=True)
#     archive_date = Timestamp(optional=True, index=True)
#     archive_path = ArchivePath(optional=True)
#     product_type = Text(index=True)
#     product_name = Text(index=True)
#     physical_name = Basename(index=True)
#     validity_start = Timestamp(optional=True, index=True)
#     validity_stop = Timestamp(optional=True, index=True)
#     creation_date = Timestamp(optional=True, index=True)
#     footprint = Geometry(optional=True, index=True)
#     remote_url = Remote(optional=True)
# 
# Path: muninn/extension.py
# class CascadeRule(Enum):
#     _items = ("IGNORE", "CASCADE_PURGE_AS_STRIP", "CASCADE_PURGE", "STRIP", "CASCADE", "PURGE")
# 
# Path: muninn/struct.py
# class Struct(object):
#     def __init__(self, data=None):
#         super(Struct, self).__init__()
#         if data is not None:
#             for key in data:
#                 if type(data[key]) == dict:
#                     self[key] = Struct(data[key])
#                 else:
#                     self[key] = data[key]
# 
#     def __getitem__(self, key):
#         try:
#             return getattr(self, key)
#         except AttributeError:
#             raise KeyError(key)
# 
#     def __setitem__(self, key, value):
#         setattr(self, key, value)
# 
#     def __delitem__(self, key):
#         try:
#             return delattr(self, key)
#         except AttributeError:
#             raise KeyError(key)
# 
#     def __contains__(self, key):
#         return hasattr(self, key)
# 
#     def __len__(self):
#         return len(vars(self))
# 
#     def __iter__(self):
#         return iter(vars(self))
# 
#     def __repr__(self):
#         return "Struct(%r)" % vars(self)
# 
#     def update(self, other):
#         '''update a struct, using the same semantics as dict.update()'''
#         for key in other:
#             other_item = other[key]
#             if isinstance(other_item, Struct):
#                 if key not in self:
#                     self[key] = Struct()
#                 else:
#                     if not isinstance(self[key], Struct):
#                         raise Error('Incompatible structs: %s vs %s' % (self, other))
#                 self[key].update(other_item)
#             else:
#                 self[key] = other_item
# 
# Path: muninn/remote.py
# class DownloadError(Error):
# class RemoteBackend(object):
# class FileBackend(RemoteBackend):
# class HTTPBackend(RemoteBackend):
# class FTPBackend(RemoteBackend):
# def get_credentials(archive, url):
# def download_http_oath2(url, target_dir, credentials, timeout=60):
# def download_http(url, target_dir, credentials=None, timeout=60):
# def download_ftp(url, target_dir, credentials=None, timeout=60):
#     def __init__(self, prefix):
#     def indentify(self, url):
#     def auto_extract(self, file_path, product):
#     def pull(self, archive, product, target_dir):
#     def pull(self, archive, product, target_dir):
#     def pull(self, archive, product, target_dir):
# def retrieve_function(archive, product, verify_hash_download):
#     def retrieve_files(target_dir):
# REMOTE_BACKENDS = {
#     'http': HTTPBackend(prefix='http://'),
#     'https': HTTPBackend(prefix='https://'),
#     'file': FileBackend(prefix='file://'),
#     'ftp': FTPBackend(prefix='ftp://'),
# }


from muninn._compat import string_types as basestring
from muninn.core import Core
from muninn.exceptions import *
from muninn.extension import CascadeRule
from muninn.schema import *
from muninn.struct import Struct
from muninn import remote
import collections
import copy
import datetime
import errno
import functools
import inspect
import hashlib
import os
import re
import sys
import uuid
import warnings
import muninn.config as config
import muninn.util as util
        group_by_tag  --  If set to True, results will also be grouped by available tag values.
                          Note that products will be counted multiple times if they have multiple tags.
        order_by      --  A list of result column names that determines the ordering of the results. If the list is
                          empty, the order of the results is ordered by the `group_by` specification. Each name in the
                          list can have a '+' (ascending) or '-' (descending) prefix, or no prefix (ascending).

        Note that the property names must always include the namespace. 'core' is not assumed.
        """
        return self._database.summary(where, parameters, aggregates, group_by, group_by_tag, order_by)

    def tag(self, uuid, tags):
        """Set one or more tags on a product."""
        if isinstance(tags, basestring):
            tags = [tags]

        self._database.tag(uuid, tags)

    def tags(self, uuid):
        """Return the tags of a product."""
        return self._database.tags(uuid)

    def unlink(self, uuid_, source_uuids=None):
        """Remove the link between a product and one or more of its source products."""
        if isinstance(source_uuids, uuid.UUID):
            source_uuids = [source_uuids]

        self._database.unlink(uuid_, source_uuids)

    def untag(self, uuid, tags=None):
        """Remove one or more tags from a product."""

# Path: muninn/_compat.py
# PY3 = sys.version_info[0] == 3
#     def is_python2_unicode(x):
#     def dictkeys(d):
#     def dictvalues(d):
#     def path_utf8(path):
#     def encode(s):
#     def decode(s):
#     def is_python2_unicode(x):
#     def path_utf8(path):
#     def decode(s):
#     def encode(s):
# 
# Path: muninn/core.py
# class Core(Mapping):
#     uuid = UUID()
#     active = Boolean(index=True)
#     hash = Text(optional=True, index=True)
#     size = Long(optional=True, index=True)
#     metadata_date = Timestamp(index=True)
#     archive_date = Timestamp(optional=True, index=True)
#     archive_path = ArchivePath(optional=True)
#     product_type = Text(index=True)
#     product_name = Text(index=True)
#     physical_name = Basename(index=True)
#     validity_start = Timestamp(optional=True, index=True)
#     validity_stop = Timestamp(optional=True, index=True)
#     creation_date = Timestamp(optional=True, index=True)
#     footprint = Geometry(optional=True, index=True)
#     remote_url = Remote(optional=True)
# 
# Path: muninn/extension.py
# class CascadeRule(Enum):
#     _items = ("IGNORE", "CASCADE_PURGE_AS_STRIP", "CASCADE_PURGE", "STRIP", "CASCADE", "PURGE")
# 
# Path: muninn/struct.py
# class Struct(object):
#     def __init__(self, data=None):
#         super(Struct, self).__init__()
#         if data is not None:
#             for key in data:
#                 if type(data[key]) == dict:
#                     self[key] = Struct(data[key])
#                 else:
#                     self[key] = data[key]
# 
#     def __getitem__(self, key):
#         try:
#             return getattr(self, key)
#         except AttributeError:
#             raise KeyError(key)
# 
#     def __setitem__(self, key, value):
#         setattr(self, key, value)
# 
#     def __delitem__(self, key):
#         try:
#             return delattr(self, key)
#         except AttributeError:
#             raise KeyError(key)
# 
#     def __contains__(self, key):
#         return hasattr(self, key)
# 
#     def __len__(self):
#         return len(vars(self))
# 
#     def __iter__(self):
#         return iter(vars(self))
# 
#     def __repr__(self):
#         return "Struct(%r)" % vars(self)
# 
#     def update(self, other):
#         '''update a struct, using the same semantics as dict.update()'''
#         for key in other:
#             other_item = other[key]
#             if isinstance(other_item, Struct):
#                 if key not in self:
#                     self[key] = Struct()
#                 else:
#                     if not isinstance(self[key], Struct):
#                         raise Error('Incompatible structs: %s vs %s' % (self, other))
#                 self[key].update(other_item)
#             else:
#                 self[key] = other_item
# 
# Path: muninn/remote.py
# class DownloadError(Error):
# class RemoteBackend(object):
# class FileBackend(RemoteBackend):
# class HTTPBackend(RemoteBackend):
# class FTPBackend(RemoteBackend):
# def get_credentials(archive, url):
# def download_http_oath2(url, target_dir, credentials, timeout=60):
# def download_http(url, target_dir, credentials=None, timeout=60):
# def download_ftp(url, target_dir, credentials=None, timeout=60):
#     def __init__(self, prefix):
#     def indentify(self, url):
#     def auto_extract(self, file_path, product):
#     def pull(self, archive, product, target_dir):
#     def pull(self, archive, product, target_dir):
#     def pull(self, archive, product, target_dir):
# def retrieve_function(archive, product, verify_hash_download):
#     def retrieve_files(target_dir):
# REMOTE_BACKENDS = {
#     'http': HTTPBackend(prefix='http://'),
#     'https': HTTPBackend(prefix='https://'),
#     'file': FileBackend(prefix='file://'),
#     'ftp': FTPBackend(prefix='ftp://'),
# }


# Path: muninn/archive.py
from muninn._compat import string_types as basestring
from muninn.core import Core
from muninn.exceptions import *
from muninn.extension import CascadeRule
from muninn.schema import *
from muninn.struct import Struct
from muninn import remote
import collections
import copy
import datetime
import errno
import functools
import inspect
import hashlib
import os
import re
import sys
import uuid
import warnings
import muninn.config as config
import muninn.util as util

        group_by_tag  --  If set to True, results will also be grouped by available tag values.
                          Note that products will be counted multiple times if they have multiple tags.
        order_by      --  A list of result column names that determines the ordering of the results. If the list is
                          empty, the order of the results is ordered by the `group_by` specification. Each name in the
                          list can have a '+' (ascending) or '-' (descending) prefix, or no prefix (ascending).

        Note that the property names must always include the namespace. 'core' is not assumed.
        """
        return self._database.summary(where, parameters, aggregates, group_by, group_by_tag, order_by)

    def tag(self, uuid, tags):
        """Set one or more tags on a product."""
        if isinstance(tags, basestring):
            tags = [tags]

        self._database.tag(uuid, tags)

    def tags(self, uuid):
        """Return the tags of a product."""
        return self._database.tags(uuid)

    def unlink(self, uuid_, source_uuids=None):
        """Remove the link between a product and one or more of its source products."""
        if isinstance(source_uuids, uuid.UUID):
            source_uuids = [source_uuids]

        self._database.unlink(uuid_, source_uuids)

    def untag(self, uuid, tags=None):
        """Remove one or more tags from a product."""

        if isinstance(tags, basestring):