class TemplateCollection:
class TemplateLookup(TemplateCollection):
    def has_template(self, uri):
    def get_template(self, uri, relativeto=None):
    def filename_to_uri(self, uri, filename):
    def adjust_uri(self, uri, filename):
    def __init__(
        self,
        directories=None,
        module_directory=None,
        filesystem_checks=True,
        collection_size=-1,
        format_exceptions=False,
        error_handler=None,
        output_encoding=None,
        encoding_errors="strict",
        cache_args=None,
        cache_impl="beaker",
        cache_enabled=True,
        cache_type=None,
        cache_dir=None,
        cache_url=None,
        modulename_callable=None,
        module_writer=None,
        default_filters=None,
        buffer_filters=(),
        strict_undefined=False,
        imports=None,
        future_imports=None,
        enable_loop=True,
        input_encoding=None,
        preprocessor=None,
        lexer_cls=None,
        include_error_handler=None,
    ):
    def get_template(self, uri):
    def adjust_uri(self, uri, relativeto):
    def filename_to_uri(self, filename):
    def _relativeize(self, filename):
    def _load(self, filename, uri):
    def _check(self, uri, template):
    def put_string(self, uri, text):
    def put_template(self, uri, template): class CacheImpl:

    """Provide a cache implementation for use by :class:`.Cache`."""

    def __init__(self, cache):
        self.cache = cache

    pass_context = False
    """If ``True``, the :class:`.Context` will be passed to
    :meth:`get_or_create <.CacheImpl.get_or_create>` as the name ``'context'``.
    """

    def get_or_create(self, key, creation_function, **kw):
        r"""Retrieve a value from the cache, using the given creation function
        to generate a new value.

        This function *must* return a value, either from
        the cache, or via the given creation function.
        If the creation function is called, the newly
        created value should be populated into the cache
        under the given key before being returned.

        :param key: the value's key.
        :param creation_function: function that when called generates
         a new value.
        :param \**kw: cache configuration arguments.

        """
        raise NotImplementedError()

    def set(self, key, value, **kw):
        r"""Place a value in the cache.

        :param key: the value's key.
        :param value: the value.
        :param \**kw: cache configuration arguments.

        """
        raise NotImplementedError()

    def get(self, key, **kw):
        r"""Retrieve a value from the cache.

        :param key: the value's key.
        :param \**kw: cache configuration arguments.

        """
        raise NotImplementedError()

    def invalidate(self, key, **kw):
        r"""Invalidate a value in the cache.

        :param key: the value's key.
        :param \**kw: cache configuration arguments.

        """
        raise NotImplementedError() class Cache:
class CacheImpl:
    def __init__(self, template, *args):
    def _load_impl(self, name):
    def get_or_create(self, key, creation_function, **kw):
    def _ctx_get_or_create(self, key, creation_function, context, **kw):
    def set(self, key, value, **kw):
    def get(self, key, **kw):
    def invalidate(self, key, **kw):
    def invalidate_body(self):
    def invalidate_def(self, name):
    def invalidate_closure(self, name):
    def _get_cache_kw(self, kw, context):
    def __init__(self, cache):
    def get_or_create(self, key, creation_function, **kw):
    def set(self, key, value, **kw):
    def get(self, key, **kw):
    def invalidate(self, key, **kw): class TemplateLookup(TemplateCollection):

    """Represent a collection of templates that locates template source files
    from the local filesystem.

    The primary argument is the ``directories`` argument, the list of
    directories to search:

    .. sourcecode:: python

        lookup = TemplateLookup(["/path/to/templates"])
        some_template = lookup.get_template("/index.html")

    The :class:`.TemplateLookup` can also be given :class:`.Template` objects
    programatically using :meth:`.put_string` or :meth:`.put_template`:

    .. sourcecode:: python

        lookup = TemplateLookup()
        lookup.put_string("base.html", '''
            <html><body>${self.next()}</body></html>
        ''')
        lookup.put_string("hello.html", '''
            <%include file='base.html'/>

            Hello, world !
        ''')


    :param directories: A list of directory names which will be
     searched for a particular template URI. The URI is appended
     to each directory and the filesystem checked.

    :param collection_size: Approximate size of the collection used
     to store templates. If left at its default of ``-1``, the size
     is unbounded, and a plain Python dictionary is used to
     relate URI strings to :class:`.Template` instances.
     Otherwise, a least-recently-used cache object is used which
     will maintain the size of the collection approximately to
     the number given.

    :param filesystem_checks: When at its default value of ``True``,
     each call to :meth:`.TemplateLookup.get_template()` will
     compare the filesystem last modified time to the time in
     which an existing :class:`.Template` object was created.
     This allows the :class:`.TemplateLookup` to regenerate a
     new :class:`.Template` whenever the original source has
     been updated. Set this to ``False`` for a very minor
     performance increase.

    :param modulename_callable: A callable which, when present,
     is passed the path of the source file as well as the
     requested URI, and then returns the full path of the
     generated Python module file. This is used to inject
     alternate schemes for Python module location. If left at
     its default of ``None``, the built in system of generation
     based on ``module_directory`` plus ``uri`` is used.

    All other keyword parameters available for
    :class:`.Template` are mirrored here. When new
    :class:`.Template` objects are created, the keywords
    established with this :class:`.TemplateLookup` are passed on
    to each new :class:`.Template`.

    """

    def __init__(
        self,
        directories=None,
        module_directory=None,
        filesystem_checks=True,
        collection_size=-1,
        format_exceptions=False,
        error_handler=None,
        output_encoding=None,
        encoding_errors="strict",
        cache_args=None,
        cache_impl="beaker",
        cache_enabled=True,
        cache_type=None,
        cache_dir=None,
        cache_url=None,
        modulename_callable=None,
        module_writer=None,
        default_filters=None,
        buffer_filters=(),
        strict_undefined=False,
        imports=None,
        future_imports=None,
        enable_loop=True,
        input_encoding=None,
        preprocessor=None,
        lexer_cls=None,
        include_error_handler=None,
    ):

        self.directories = [
            posixpath.normpath(d) for d in util.to_list(directories, ())
        ]
        self.module_directory = module_directory
        self.modulename_callable = modulename_callable
        self.filesystem_checks = filesystem_checks
        self.collection_size = collection_size

        if cache_args is None:
            cache_args = {}
        # transfer deprecated cache_* args
        if cache_dir:
            cache_args.setdefault("dir", cache_dir)
        if cache_url:
            cache_args.setdefault("url", cache_url)
        if cache_type:
            cache_args.setdefault("type", cache_type)

        self.template_args = {
            "format_exceptions": format_exceptions,
            "error_handler": error_handler,
            "include_error_handler": include_error_handler,
            "output_encoding": output_encoding,
            "cache_impl": cache_impl,
            "encoding_errors": encoding_errors,
            "input_encoding": input_encoding,
            "module_directory": module_directory,
            "module_writer": module_writer,
            "cache_args": cache_args,
            "cache_enabled": cache_enabled,
            "default_filters": default_filters,
            "buffer_filters": buffer_filters,
            "strict_undefined": strict_undefined,
            "imports": imports,
            "future_imports": future_imports,
            "enable_loop": enable_loop,
            "preprocessor": preprocessor,
            "lexer_cls": lexer_cls,
        }

        if collection_size == -1:
            self._collection = {}
            self._uri_cache = {}
        else:
            self._collection = util.LRUCache(collection_size)
            self._uri_cache = util.LRUCache(collection_size)
        self._mutex = threading.Lock()

    def get_template(self, uri):
        """Return a :class:`.Template` object corresponding to the given
        ``uri``.

        .. note:: The ``relativeto`` argument is not supported here at
           the moment.

        """

        try:
            if self.filesystem_checks:
                return self._check(uri, self._collection[uri])
            else:
                return self._collection[uri]
        except KeyError as e:
            u = re.sub(r"^\/+", "", uri)
            for dir_ in self.directories:
                # make sure the path seperators are posix - os.altsep is empty
                # on POSIX and cannot be used.
                dir_ = dir_.replace(os.path.sep, posixpath.sep)
                srcfile = posixpath.normpath(posixpath.join(dir_, u))
                if os.path.isfile(srcfile):
                    return self._load(srcfile, uri)
            else:
                raise exceptions.TopLevelLookupException(
                    "Can't locate template for uri %r" % uri
                ) from e

    def adjust_uri(self, uri, relativeto):
        """Adjust the given ``uri`` based on the given relative URI."""

        key = (uri, relativeto)
        if key in self._uri_cache:
            return self._uri_cache[key]

        if uri[0] == "/":
            v = self._uri_cache[key] = uri
        elif relativeto is not None:
            v = self._uri_cache[key] = posixpath.join(
                posixpath.dirname(relativeto), uri
            )
        else:
            v = self._uri_cache[key] = "/" + uri
        return v

    def filename_to_uri(self, filename):
        """Convert the given ``filename`` to a URI relative to
        this :class:`.TemplateCollection`."""

        try:
            return self._uri_cache[filename]
        except KeyError:
            value = self._relativeize(filename)
            self._uri_cache[filename] = value
            return value

    def _relativeize(self, filename):
        """Return the portion of a filename that is 'relative'
        to the directories in this lookup.

        """

        filename = posixpath.normpath(filename)
        for dir_ in self.directories:
            if filename[0 : len(dir_)] == dir_:
                return filename[len(dir_) :]
        else:
            return None

    def _load(self, filename, uri):
        self._mutex.acquire()
        try:
            try:
                # try returning from collection one
                # more time in case concurrent thread already loaded
                return self._collection[uri]
            except KeyError:
                pass
            try:
                if self.modulename_callable is not None:
                    module_filename = self.modulename_callable(filename, uri)
                else:
                    module_filename = None
                self._collection[uri] = template = Template(
                    uri=uri,
                    filename=posixpath.normpath(filename),
                    lookup=self,
                    module_filename=module_filename,
                    **self.template_args,
                )
                return template
            except:
                # if compilation fails etc, ensure
                # template is removed from collection,
                # re-raise
                self._collection.pop(uri, None)
                raise
        finally:
            self._mutex.release()

    def _check(self, uri, template):
        if template.filename is None:
            return template

        try:
            template_stat = os.stat(template.filename)
            if template.module._modified_time >= template_stat[stat.ST_MTIME]:
                return template
            self._collection.pop(uri, None)
            return self._load(template.filename, uri)
        except OSError as e:
            self._collection.pop(uri, None)
            raise exceptions.TemplateLookupException(
                "Can't locate template for uri %r" % uri
            ) from e

    def put_string(self, uri, text):
        """Place a new :class:`.Template` object into this
        :class:`.TemplateLookup`, based on the given string of
        ``text``.

        """
        self._collection[uri] = Template(
            text, lookup=self, uri=uri, **self.template_args
        )

    def put_template(self, uri, template):
        """Place a new :class:`.Template` object into this
        :class:`.TemplateLookup`, based on the given
        :class:`.Template` object.

        """
        self._collection[uri] = template class Template:

    r"""Represents a compiled template.

    :class:`.Template` includes a reference to the original
    template source (via the :attr:`.source` attribute)
    as well as the source code of the
    generated Python module (i.e. the :attr:`.code` attribute),
    as well as a reference to an actual Python module.

    :class:`.Template` is constructed using either a literal string
    representing the template text, or a filename representing a filesystem
    path to a source file.

    :param text: textual template source.  This argument is mutually
     exclusive versus the ``filename`` parameter.

    :param filename: filename of the source template.  This argument is
     mutually exclusive versus the ``text`` parameter.

    :param buffer_filters: string list of filters to be applied
     to the output of ``%def``\ s which are buffered, cached, or otherwise
     filtered, after all filters
     defined with the ``%def`` itself have been applied. Allows the
     creation of default expression filters that let the output
     of return-valued ``%def``\ s "opt out" of that filtering via
     passing special attributes or objects.

    :param cache_args: Dictionary of cache configuration arguments that
     will be passed to the :class:`.CacheImpl`.   See :ref:`caching_toplevel`.

    :param cache_dir:

     .. deprecated:: 0.6
        Use the ``'dir'`` argument in the ``cache_args`` dictionary.
        See :ref:`caching_toplevel`.

    :param cache_enabled: Boolean flag which enables caching of this
     template.  See :ref:`caching_toplevel`.

    :param cache_impl: String name of a :class:`.CacheImpl` caching
     implementation to use.   Defaults to ``'beaker'``.

    :param cache_type:

     .. deprecated:: 0.6
        Use the ``'type'`` argument in the ``cache_args`` dictionary.
        See :ref:`caching_toplevel`.

    :param cache_url:

     .. deprecated:: 0.6
        Use the ``'url'`` argument in the ``cache_args`` dictionary.
        See :ref:`caching_toplevel`.

    :param default_filters: List of string filter names that will
     be applied to all expressions.  See :ref:`filtering_default_filters`.

    :param enable_loop: When ``True``, enable the ``loop`` context variable.
     This can be set to ``False`` to support templates that may
     be making usage of the name "``loop``".   Individual templates can
     re-enable the "loop" context by placing the directive
     ``enable_loop="True"`` inside the ``<%page>`` tag -- see
     :ref:`migrating_loop`.

    :param encoding_errors: Error parameter passed to ``encode()`` when
     string encoding is performed. See :ref:`usage_unicode`.

    :param error_handler: Python callable which is called whenever
     compile or runtime exceptions occur. The callable is passed
     the current context as well as the exception. If the
     callable returns ``True``, the exception is considered to
     be handled, else it is re-raised after the function
     completes. Is used to provide custom error-rendering
     functions.

     .. seealso::

        :paramref:`.Template.include_error_handler` - include-specific
        error handler function

    :param format_exceptions: if ``True``, exceptions which occur during
     the render phase of this template will be caught and
     formatted into an HTML error page, which then becomes the
     rendered result of the :meth:`.render` call. Otherwise,
     runtime exceptions are propagated outwards.

    :param imports: String list of Python statements, typically individual
     "import" lines, which will be placed into the module level
     preamble of all generated Python modules. See the example
     in :ref:`filtering_default_filters`.

    :param future_imports: String list of names to import from `__future__`.
     These will be concatenated into a comma-separated string and inserted
     into the beginning of the template, e.g. ``futures_imports=['FOO',
     'BAR']`` results in ``from __future__ import FOO, BAR``.  If you're
     interested in using features like the new division operator, you must
     use future_imports to convey that to the renderer, as otherwise the
     import will not appear as the first executed statement in the generated
     code and will therefore not have the desired effect.

    :param include_error_handler: An error handler that runs when this template
     is included within another one via the ``<%include>`` tag, and raises an
     error.  Compare to the :paramref:`.Template.error_handler` option.

     .. versionadded:: 1.0.6

     .. seealso::

        :paramref:`.Template.error_handler` - top-level error handler function

    :param input_encoding: Encoding of the template's source code.  Can
     be used in lieu of the coding comment. See
     :ref:`usage_unicode` as well as :ref:`unicode_toplevel` for
     details on source encoding.

    :param lookup: a :class:`.TemplateLookup` instance that will be used
     for all file lookups via the ``<%namespace>``,
     ``<%include>``, and ``<%inherit>`` tags. See
     :ref:`usage_templatelookup`.

    :param module_directory: Filesystem location where generated
     Python module files will be placed.

    :param module_filename: Overrides the filename of the generated
     Python module file. For advanced usage only.

    :param module_writer: A callable which overrides how the Python
     module is written entirely.  The callable is passed the
     encoded source content of the module and the destination
     path to be written to.   The default behavior of module writing
     uses a tempfile in conjunction with a file move in order
     to make the operation atomic.   So a user-defined module
     writing function that mimics the default behavior would be:

     .. sourcecode:: python

         import tempfile
         import os
         import shutil

         def module_writer(source, outputpath):
             (dest, name) = \\
                 tempfile.mkstemp(
                     dir=os.path.dirname(outputpath)
                 )

             os.write(dest, source)
             os.close(dest)
             shutil.move(name, outputpath)

         from mako.template import Template
         mytemplate = Template(
                         filename="index.html",
                         module_directory="/path/to/modules",
                         module_writer=module_writer
                     )

     The function is provided for unusual configurations where
     certain platform-specific permissions or other special
     steps are needed.

    :param output_encoding: The encoding to use when :meth:`.render`
     is called.
     See :ref:`usage_unicode` as well as :ref:`unicode_toplevel`.

    :param preprocessor: Python callable which will be passed
     the full template source before it is parsed. The return
     result of the callable will be used as the template source
     code.

    :param lexer_cls: A :class:`.Lexer` class used to parse
     the template.   The :class:`.Lexer` class is used by
     default.

     .. versionadded:: 0.7.4

    :param strict_undefined: Replaces the automatic usage of
     ``UNDEFINED`` for any undeclared variables not located in
     the :class:`.Context` with an immediate raise of
     ``NameError``. The advantage is immediate reporting of
     missing variables which include the name.

     .. versionadded:: 0.3.6

    :param uri: string URI or other identifier for this template.
     If not provided, the ``uri`` is generated from the filesystem
     path, or from the in-memory identity of a non-file-based
     template. The primary usage of the ``uri`` is to provide a key
     within :class:`.TemplateLookup`, as well as to generate the
     file path of the generated Python module file, if
     ``module_directory`` is specified.

    """

    lexer_cls = Lexer

    def __init__(
        self,
        text=None,
        filename=None,
        uri=None,
        format_exceptions=False,
        error_handler=None,
        lookup=None,
        output_encoding=None,
        encoding_errors="strict",
        module_directory=None,
        cache_args=None,
        cache_impl="beaker",
        cache_enabled=True,
        cache_type=None,
        cache_dir=None,
        cache_url=None,
        module_filename=None,
        input_encoding=None,
        module_writer=None,
        default_filters=None,
        buffer_filters=(),
        strict_undefined=False,
        imports=None,
        future_imports=None,
        enable_loop=True,
        preprocessor=None,
        lexer_cls=None,
        include_error_handler=None,
    ):
        if uri:
            self.module_id = re.sub(r"\W", "_", uri)
            self.uri = uri
        elif filename:
            self.module_id = re.sub(r"\W", "_", filename)
            drive, path = os.path.splitdrive(filename)
            path = os.path.normpath(path).replace(os.path.sep, "/")
            self.uri = path
        else:
            self.module_id = "memory:" + hex(id(self))
            self.uri = self.module_id

        u_norm = self.uri
        if u_norm.startswith("/"):
            u_norm = u_norm[1:]
        u_norm = os.path.normpath(u_norm)
        if u_norm.startswith(".."):
            raise exceptions.TemplateLookupException(
                'Template uri "%s" is invalid - '
                "it cannot be relative outside "
                "of the root path." % self.uri
            )

        self.input_encoding = input_encoding
        self.output_encoding = output_encoding
        self.encoding_errors = encoding_errors
        self.enable_loop = enable_loop
        self.strict_undefined = strict_undefined
        self.module_writer = module_writer

        if default_filters is None:
            self.default_filters = ["str"]
        else:
            self.default_filters = default_filters
        self.buffer_filters = buffer_filters

        self.imports = imports
        self.future_imports = future_imports
        self.preprocessor = preprocessor

        if lexer_cls is not None:
            self.lexer_cls = lexer_cls

        # if plain text, compile code in memory only
        if text is not None:
            (code, module) = _compile_text(self, text, filename)
            self._code = code
            self._source = text
            ModuleInfo(module, None, self, filename, code, text, uri)
        elif filename is not None:
            # if template filename and a module directory, load
            # a filesystem-based module file, generating if needed
            if module_filename is not None:
                path = module_filename
            elif module_directory is not None:
                path = os.path.abspath(
                    os.path.join(
                        os.path.normpath(module_directory), u_norm + ".py"
                    )
                )
            else:
                path = None
            module = self._compile_from_file(path, filename)
        else:
            raise exceptions.RuntimeException(
                "Template requires text or filename"
            )

        self.module = module
        self.filename = filename
        self.callable_ = self.module.render_body
        self.format_exceptions = format_exceptions
        self.error_handler = error_handler
        self.include_error_handler = include_error_handler
        self.lookup = lookup

        self.module_directory = module_directory

        self._setup_cache_args(
            cache_impl,
            cache_enabled,
            cache_args,
            cache_type,
            cache_dir,
            cache_url,
        )

    @util.memoized_property
    def reserved_names(self):
        if self.enable_loop:
            return codegen.RESERVED_NAMES
        else:
            return codegen.RESERVED_NAMES.difference(["loop"])

    def _setup_cache_args(
        self,
        cache_impl,
        cache_enabled,
        cache_args,
        cache_type,
        cache_dir,
        cache_url,
    ):
        self.cache_impl = cache_impl
        self.cache_enabled = cache_enabled
        self.cache_args = cache_args or {}
        # transfer deprecated cache_* args
        if cache_type:
            self.cache_args["type"] = cache_type
        if cache_dir:
            self.cache_args["dir"] = cache_dir
        if cache_url:
            self.cache_args["url"] = cache_url

    def _compile_from_file(self, path, filename):
        if path is not None:
            util.verify_directory(os.path.dirname(path))
            filemtime = os.stat(filename)[stat.ST_MTIME]
            if (
                not os.path.exists(path)
                or os.stat(path)[stat.ST_MTIME] < filemtime
            ):
                data = util.read_file(filename)
                _compile_module_file(
                    self, data, filename, path, self.module_writer
                )
            module = compat.load_module(self.module_id, path)
            if module._magic_number != codegen.MAGIC_NUMBER:
                data = util.read_file(filename)
                _compile_module_file(
                    self, data, filename, path, self.module_writer
                )
                module = compat.load_module(self.module_id, path)
            ModuleInfo(module, path, self, filename, None, None, None)
        else:
            # template filename and no module directory, compile code
            # in memory
            data = util.read_file(filename)
            code, module = _compile_text(self, data, filename)
            self._source = None
            self._code = code
            ModuleInfo(module, None, self, filename, code, None, None)
        return module

    @property
    def source(self):
        """Return the template source code for this :class:`.Template`."""

        return _get_module_info_from_callable(self.callable_).source

    @property
    def code(self):
        """Return the module source code for this :class:`.Template`."""

        return _get_module_info_from_callable(self.callable_).code

    @util.memoized_property
    def cache(self):
        return cache.Cache(self)

    @property
    def cache_dir(self):
        return self.cache_args["dir"]

    @property
    def cache_url(self):
        return self.cache_args["url"]

    @property
    def cache_type(self):
        return self.cache_args["type"]

    def render(self, *args, **data):
        """Render the output of this template as a string.

        If the template specifies an output encoding, the string
        will be encoded accordingly, else the output is raw (raw
        output uses `StringIO` and can't handle multibyte
        characters). A :class:`.Context` object is created corresponding
        to the given data. Arguments that are explicitly declared
        by this template's internal rendering method are also
        pulled from the given ``*args``, ``**data`` members.

        """
        return runtime._render(self, self.callable_, args, data)

    def render_unicode(self, *args, **data):
        """Render the output of this template as a unicode object."""

        return runtime._render(
            self, self.callable_, args, data, as_unicode=True
        )

    def render_context(self, context, *args, **kwargs):
        """Render this :class:`.Template` with the given context.

        The data is written to the context's buffer.

        """
        if getattr(context, "_with_template", None) is None:
            context._set_with_template(self)
        runtime._render_context(self, self.callable_, context, *args, **kwargs)

    def has_def(self, name):
        return hasattr(self.module, "render_%s" % name)

    def get_def(self, name):
        """Return a def of this template as a :class:`.DefTemplate`."""

        return DefTemplate(self, getattr(self.module, "render_%s" % name))

    def list_defs(self):
        """return a list of defs in the template.

        .. versionadded:: 1.0.4

        """
        return [i[7:] for i in dir(self.module) if i[:7] == "render_"]

    def _get_def_callable(self, name):
        return getattr(self.module, "render_%s" % name)

    @property
    def last_modified(self):
        return self.module._modified_time def eq_(a, b, msg=None):
    """Assert a == b, with repr messaging on failure."""
    assert a == b, msg or "%r != %r" % (a, b) class Config(ReadsCfg): def _pygments_version():
def requires_no_pygments_exceptions(fn):
    def go(*arg, **kw): def _pygments_version():
def requires_no_pygments_exceptions(fn):
    def go(*arg, **kw): def result_lines(result):
    return [
        x.strip()
        for x in re.split(r"\r?\n", re.sub(r" +", " ", result))
        if x.strip() != ""
    ]
import time
        import beaker
from mako import lookup
from mako.cache import CacheImpl
from mako.cache import register_plugin
from mako.lookup import TemplateLookup
from mako.template import Template
from mako.testing.assertions import eq_
from mako.testing.config import config
from mako.testing.exclusions import requires_beaker
from mako.testing.exclusions import requires_dogpile_cache
from mako.testing.helpers import result_lines
        from dogpile.cache import make_region



module_base = str(config.module_base)


class SimpleBackend:
    def __init__(self):
        self.cache = {}

    def get(self, key, **kw):
        return self.cache[key]

    def invalidate(self, key, **kw):
        self.cache.pop(key, None)

    def put(self, key, value, **kw):
        self.cache[key] = value

    def get_or_create(self, key, creation_function, **kw):
        if key in self.cache:
            return self.cache[key]

        self.cache[key] = value = creation_function()
        return value



class MockCacheImpl(CacheImpl):