# Path: grafana_dashboards/context.py
# class DictDefaultingToPlaceholder(dict):
#     def __missing__(self, key):
#         return '{' + key + '}'
# 
# class Context(object):
# 
#     _pattern = re.compile('{.*}')
# 
#     def __init__(self, context=None):
#         super(Context, self).__init__()
#         if not context:
#             self._context = None
#         else:
#             self._context = DictDefaultingToPlaceholder(context)
# 
#     def expand_placeholders(self, to_expand):
#         """
# 
#         :rtype : dict
#         """
#         if not self._context:
#             return to_expand
# 
#         if isinstance(to_expand, basestring):
#             (result, to_expand) = self._expand(to_expand)
#             while result != to_expand:
#                 (result, to_expand) = self._expand(result)
#             if isinstance(result, basestring):
#                 return string.Formatter().vformat(result, (), self._context)
#             else:
#                 return result
#         elif isinstance(to_expand, list):
#             return [self.expand_placeholders(value) for value in to_expand]
#         elif isinstance(to_expand, dict):
#             return dict([(key, self.expand_placeholders(value)) for (key, value) in to_expand.items()])
#         else:
#             return to_expand
# 
#     def _expand(self, to_expand):
#         if not isinstance(to_expand, basestring):
#             return to_expand, to_expand
#         elif self._pattern.match(to_expand) and to_expand[1:-1] in self._context:
#             return self._context[to_expand[1:-1]], to_expand
#         escaped = to_expand.replace('{{', '{{{{').replace('}}', '}}}}')
#         return string.Formatter().vformat(escaped, (), self._context), to_expand
# 
#     def __str__(self):
#         return str(self._context)
# 
#     @staticmethod
#     def create_context(data, keys_to_expand=None):
#         return (Context(Context(context).expand_placeholders(context))
#                 for context in ContextExpander(keys_to_expand).create_context(None, data))


from grafana_dashboards.context import DictDefaultingToPlaceholder, Context
        'wrapped': '{single}',
        'double-wrapped': '{wrapped}'
    }
    contexts = [context for context in Context.create_context(data, keys_to_expand=('expanded-list', 'expanded-dict'))]
    assert len(contexts) == 1
    expected = {
        'double-wrapped': 'first',
        'single': 'first',
        'wrapped': 'first',
        'single-escaped': '{not-expanded}',
        'double-escaped': '{{not-expanded}}'
    }
    to_expand = {
        'single': '{single}',
        'wrapped': '{wrapped}',
        'double-wrapped': '{double-wrapped}',
        'single-escaped': '{{not-expanded}}',
        'double-escaped': '{{{{not-expanded}}}}'
    }
    assert contexts[0].expand_placeholders(to_expand) == expected


def test_context_expands_list_value():
    data = {
        'single': 'first',
        'expanded-list': [
            'list0',
            'list1'
        ]
    }

# Path: grafana_dashboards/context.py
# class DictDefaultingToPlaceholder(dict):
#     def __missing__(self, key):
#         return '{' + key + '}'
# 
# class Context(object):
# 
#     _pattern = re.compile('{.*}')
# 
#     def __init__(self, context=None):
#         super(Context, self).__init__()
#         if not context:
#             self._context = None
#         else:
#             self._context = DictDefaultingToPlaceholder(context)
# 
#     def expand_placeholders(self, to_expand):
#         """
# 
#         :rtype : dict
#         """
#         if not self._context:
#             return to_expand
# 
#         if isinstance(to_expand, basestring):
#             (result, to_expand) = self._expand(to_expand)
#             while result != to_expand:
#                 (result, to_expand) = self._expand(result)
#             if isinstance(result, basestring):
#                 return string.Formatter().vformat(result, (), self._context)
#             else:
#                 return result
#         elif isinstance(to_expand, list):
#             return [self.expand_placeholders(value) for value in to_expand]
#         elif isinstance(to_expand, dict):
#             return dict([(key, self.expand_placeholders(value)) for (key, value) in to_expand.items()])
#         else:
#             return to_expand
# 
#     def _expand(self, to_expand):
#         if not isinstance(to_expand, basestring):
#             return to_expand, to_expand
#         elif self._pattern.match(to_expand) and to_expand[1:-1] in self._context:
#             return self._context[to_expand[1:-1]], to_expand
#         escaped = to_expand.replace('{{', '{{{{').replace('}}', '}}}}')
#         return string.Formatter().vformat(escaped, (), self._context), to_expand
# 
#     def __str__(self):
#         return str(self._context)
# 
#     @staticmethod
#     def create_context(data, keys_to_expand=None):
#         return (Context(Context(context).expand_placeholders(context))
#                 for context in ContextExpander(keys_to_expand).create_context(None, data))


# Path: tests/grafana_dashboards/test_context.py
from grafana_dashboards.context import DictDefaultingToPlaceholder, Context

        'wrapped': '{single}',
        'double-wrapped': '{wrapped}'
    }
    contexts = [context for context in Context.create_context(data, keys_to_expand=('expanded-list', 'expanded-dict'))]
    assert len(contexts) == 1
    expected = {
        'double-wrapped': 'first',
        'single': 'first',
        'wrapped': 'first',
        'single-escaped': '{not-expanded}',
        'double-escaped': '{{not-expanded}}'
    }
    to_expand = {
        'single': '{single}',
        'wrapped': '{wrapped}',
        'double-wrapped': '{double-wrapped}',
        'single-escaped': '{{not-expanded}}',
        'double-escaped': '{{{{not-expanded}}}}'
    }
    assert contexts[0].expand_placeholders(to_expand) == expected


def test_context_expands_list_value():
    data = {
        'single': 'first',
        'expanded-list': [
            'list0',
            'list1'
        ]
    }

    contexts = [context for context in Context.create_context(data, keys_to_expand=('expanded-list', 'expanded-dict'))]