about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/mako/testing
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/mako/testing')
-rw-r--r--.venv/lib/python3.12/site-packages/mako/testing/__init__.py0
-rw-r--r--.venv/lib/python3.12/site-packages/mako/testing/_config.py128
-rw-r--r--.venv/lib/python3.12/site-packages/mako/testing/assertions.py166
-rw-r--r--.venv/lib/python3.12/site-packages/mako/testing/config.py17
-rw-r--r--.venv/lib/python3.12/site-packages/mako/testing/exclusions.py80
-rw-r--r--.venv/lib/python3.12/site-packages/mako/testing/fixtures.py119
-rw-r--r--.venv/lib/python3.12/site-packages/mako/testing/helpers.py71
7 files changed, 581 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/mako/testing/__init__.py b/.venv/lib/python3.12/site-packages/mako/testing/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/mako/testing/__init__.py
diff --git a/.venv/lib/python3.12/site-packages/mako/testing/_config.py b/.venv/lib/python3.12/site-packages/mako/testing/_config.py
new file mode 100644
index 00000000..4ee3d0a6
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/mako/testing/_config.py
@@ -0,0 +1,128 @@
+import configparser
+import dataclasses
+from dataclasses import dataclass
+from pathlib import Path
+from typing import Callable
+from typing import ClassVar
+from typing import Optional
+from typing import Union
+
+from .helpers import make_path
+
+
+class ConfigError(BaseException):
+    pass
+
+
+class MissingConfig(ConfigError):
+    pass
+
+
+class MissingConfigSection(ConfigError):
+    pass
+
+
+class MissingConfigItem(ConfigError):
+    pass
+
+
+class ConfigValueTypeError(ConfigError):
+    pass
+
+
+class _GetterDispatch:
+    def __init__(self, initialdata, default_getter: Callable):
+        self.default_getter = default_getter
+        self.data = initialdata
+
+    def get_fn_for_type(self, type_):
+        return self.data.get(type_, self.default_getter)
+
+    def get_typed_value(self, type_, name):
+        get_fn = self.get_fn_for_type(type_)
+        return get_fn(name)
+
+
+def _parse_cfg_file(filespec: Union[Path, str]):
+    cfg = configparser.ConfigParser()
+    try:
+        filepath = make_path(filespec, check_exists=True)
+    except FileNotFoundError as e:
+        raise MissingConfig(f"No config file found at {filespec}") from e
+    else:
+        with open(filepath, encoding="utf-8") as f:
+            cfg.read_file(f)
+        return cfg
+
+
+def _build_getter(cfg_obj, cfg_section, method, converter=None):
+    def caller(option, **kwargs):
+        try:
+            rv = getattr(cfg_obj, method)(cfg_section, option, **kwargs)
+        except configparser.NoSectionError as nse:
+            raise MissingConfigSection(
+                f"No config section named {cfg_section}"
+            ) from nse
+        except configparser.NoOptionError as noe:
+            raise MissingConfigItem(f"No config item for {option}") from noe
+        except ValueError as ve:
+            # ConfigParser.getboolean, .getint, .getfloat raise ValueError
+            # on bad types
+            raise ConfigValueTypeError(
+                f"Wrong value type for {option}"
+            ) from ve
+        else:
+            if converter:
+                try:
+                    rv = converter(rv)
+                except Exception as e:
+                    raise ConfigValueTypeError(
+                        f"Wrong value type for {option}"
+                    ) from e
+            return rv
+
+    return caller
+
+
+def _build_getter_dispatch(cfg_obj, cfg_section, converters=None):
+    converters = converters or {}
+
+    default_getter = _build_getter(cfg_obj, cfg_section, "get")
+
+    # support ConfigParser builtins
+    getters = {
+        int: _build_getter(cfg_obj, cfg_section, "getint"),
+        bool: _build_getter(cfg_obj, cfg_section, "getboolean"),
+        float: _build_getter(cfg_obj, cfg_section, "getfloat"),
+        str: default_getter,
+    }
+
+    # use ConfigParser.get and convert value
+    getters.update(
+        {
+            type_: _build_getter(
+                cfg_obj, cfg_section, "get", converter=converter_fn
+            )
+            for type_, converter_fn in converters.items()
+        }
+    )
+
+    return _GetterDispatch(getters, default_getter)
+
+
+@dataclass
+class ReadsCfg:
+    section_header: ClassVar[str]
+    converters: ClassVar[Optional[dict]] = None
+
+    @classmethod
+    def from_cfg_file(cls, filespec: Union[Path, str]):
+        cfg = _parse_cfg_file(filespec)
+        dispatch = _build_getter_dispatch(
+            cfg, cls.section_header, converters=cls.converters
+        )
+        kwargs = {
+            field.name: dispatch.get_typed_value(field.type, field.name)
+            for field in dataclasses.fields(cls)
+        }
+        return cls(**kwargs)
diff --git a/.venv/lib/python3.12/site-packages/mako/testing/assertions.py b/.venv/lib/python3.12/site-packages/mako/testing/assertions.py
new file mode 100644
index 00000000..22221cd2
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/mako/testing/assertions.py
@@ -0,0 +1,166 @@
+import contextlib
+import re
+import sys
+
+
+def eq_(a, b, msg=None):
+    """Assert a == b, with repr messaging on failure."""
+    assert a == b, msg or "%r != %r" % (a, b)
+
+
+def ne_(a, b, msg=None):
+    """Assert a != b, with repr messaging on failure."""
+    assert a != b, msg or "%r == %r" % (a, b)
+
+
+def in_(a, b, msg=None):
+    """Assert a in b, with repr messaging on failure."""
+    assert a in b, msg or "%r not in %r" % (a, b)
+
+
+def not_in(a, b, msg=None):
+    """Assert a in not b, with repr messaging on failure."""
+    assert a not in b, msg or "%r is in %r" % (a, b)
+
+
+def _assert_proper_exception_context(exception):
+    """assert that any exception we're catching does not have a __context__
+    without a __cause__, and that __suppress_context__ is never set.
+
+    Python 3 will report nested as exceptions as "during the handling of
+    error X, error Y occurred". That's not what we want to do. We want
+    these exceptions in a cause chain.
+
+    """
+
+    if (
+        exception.__context__ is not exception.__cause__
+        and not exception.__suppress_context__
+    ):
+        assert False, (
+            "Exception %r was correctly raised but did not set a cause, "
+            "within context %r as its cause."
+            % (exception, exception.__context__)
+        )
+
+
+def _assert_proper_cause_cls(exception, cause_cls):
+    """assert that any exception we're catching does not have a __context__
+    without a __cause__, and that __suppress_context__ is never set.
+
+    Python 3 will report nested as exceptions as "during the handling of
+    error X, error Y occurred". That's not what we want to do. We want
+    these exceptions in a cause chain.
+
+    """
+    assert isinstance(exception.__cause__, cause_cls), (
+        "Exception %r was correctly raised but has cause %r, which does not "
+        "have the expected cause type %r."
+        % (exception, exception.__cause__, cause_cls)
+    )
+
+
+def assert_raises(except_cls, callable_, *args, **kw):
+    return _assert_raises(except_cls, callable_, args, kw)
+
+
+def assert_raises_with_proper_context(except_cls, callable_, *args, **kw):
+    return _assert_raises(except_cls, callable_, args, kw, check_context=True)
+
+
+def assert_raises_with_given_cause(
+    except_cls, cause_cls, callable_, *args, **kw
+):
+    return _assert_raises(except_cls, callable_, args, kw, cause_cls=cause_cls)
+
+
+def assert_raises_message(except_cls, msg, callable_, *args, **kwargs):
+    return _assert_raises(except_cls, callable_, args, kwargs, msg=msg)
+
+
+def assert_raises_message_with_proper_context(
+    except_cls, msg, callable_, *args, **kwargs
+):
+    return _assert_raises(
+        except_cls, callable_, args, kwargs, msg=msg, check_context=True
+    )
+
+
+def assert_raises_message_with_given_cause(
+    except_cls, msg, cause_cls, callable_, *args, **kwargs
+):
+    return _assert_raises(
+        except_cls, callable_, args, kwargs, msg=msg, cause_cls=cause_cls
+    )
+
+
+def _assert_raises(
+    except_cls,
+    callable_,
+    args,
+    kwargs,
+    msg=None,
+    check_context=False,
+    cause_cls=None,
+):
+    with _expect_raises(except_cls, msg, check_context, cause_cls) as ec:
+        callable_(*args, **kwargs)
+    return ec.error
+
+
+class _ErrorContainer:
+    error = None
+
+
+@contextlib.contextmanager
+def _expect_raises(except_cls, msg=None, check_context=False, cause_cls=None):
+    ec = _ErrorContainer()
+    if check_context:
+        are_we_already_in_a_traceback = sys.exc_info()[0]
+    try:
+        yield ec
+        success = False
+    except except_cls as err:
+        ec.error = err
+        success = True
+        if msg is not None:
+            # I'm often pdbing here, and "err" above isn't
+            # in scope, so assign the string explicitly
+            error_as_string = str(err)
+            assert re.search(msg, error_as_string, re.UNICODE), "%r !~ %s" % (
+                msg,
+                error_as_string,
+            )
+        if cause_cls is not None:
+            _assert_proper_cause_cls(err, cause_cls)
+        if check_context and not are_we_already_in_a_traceback:
+            _assert_proper_exception_context(err)
+        print(str(err).encode("utf-8"))
+
+    # it's generally a good idea to not carry traceback objects outside
+    # of the except: block, but in this case especially we seem to have
+    # hit some bug in either python 3.10.0b2 or greenlet or both which
+    # this seems to fix:
+    # https://github.com/python-greenlet/greenlet/issues/242
+    del ec
+
+    # assert outside the block so it works for AssertionError too !
+    assert success, "Callable did not raise an exception"
+
+
+def expect_raises(except_cls, check_context=False):
+    return _expect_raises(except_cls, check_context=check_context)
+
+
+def expect_raises_message(except_cls, msg, check_context=False):
+    return _expect_raises(except_cls, msg=msg, check_context=check_context)
+
+
+def expect_raises_with_proper_context(except_cls, check_context=True):
+    return _expect_raises(except_cls, check_context=check_context)
+
+
+def expect_raises_message_with_proper_context(
+    except_cls, msg, check_context=True
+):
+    return _expect_raises(except_cls, msg=msg, check_context=check_context)
diff --git a/.venv/lib/python3.12/site-packages/mako/testing/config.py b/.venv/lib/python3.12/site-packages/mako/testing/config.py
new file mode 100644
index 00000000..b77d0c08
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/mako/testing/config.py
@@ -0,0 +1,17 @@
+from dataclasses import dataclass
+from pathlib import Path
+
+from ._config import ReadsCfg
+from .helpers import make_path
+
+
+@dataclass
+class Config(ReadsCfg):
+    module_base: Path
+    template_base: Path
+
+    section_header = "mako_testing"
+    converters = {Path: make_path}
+
+
+config = Config.from_cfg_file("./setup.cfg")
diff --git a/.venv/lib/python3.12/site-packages/mako/testing/exclusions.py b/.venv/lib/python3.12/site-packages/mako/testing/exclusions.py
new file mode 100644
index 00000000..37b2d14a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/mako/testing/exclusions.py
@@ -0,0 +1,80 @@
+import pytest
+
+from mako.ext.beaker_cache import has_beaker
+from mako.util import update_wrapper
+
+
+try:
+    import babel.messages.extract as babel
+except ImportError:
+    babel = None
+
+
+try:
+    import lingua
+except ImportError:
+    lingua = None
+
+
+try:
+    import dogpile.cache  # noqa
+except ImportError:
+    has_dogpile_cache = False
+else:
+    has_dogpile_cache = True
+
+
+requires_beaker = pytest.mark.skipif(
+    not has_beaker, reason="Beaker is required for these tests."
+)
+
+
+requires_babel = pytest.mark.skipif(
+    babel is None, reason="babel not installed: skipping babelplugin test"
+)
+
+
+requires_lingua = pytest.mark.skipif(
+    lingua is None, reason="lingua not installed: skipping linguaplugin test"
+)
+
+
+requires_dogpile_cache = pytest.mark.skipif(
+    not has_dogpile_cache,
+    reason="dogpile.cache is required to run these tests",
+)
+
+
+def _pygments_version():
+    try:
+        import pygments
+
+        version = pygments.__version__
+    except:
+        version = "0"
+    return version
+
+
+requires_pygments_14 = pytest.mark.skipif(
+    _pygments_version() < "1.4", reason="Requires pygments 1.4 or greater"
+)
+
+
+# def requires_pygments_14(fn):
+
+#     return skip_if(
+#         lambda: version < "1.4", "Requires pygments 1.4 or greater"
+#     )(fn)
+
+
+def requires_no_pygments_exceptions(fn):
+    def go(*arg, **kw):
+        from mako import exceptions
+
+        exceptions._install_fallback()
+        try:
+            return fn(*arg, **kw)
+        finally:
+            exceptions._install_highlighting()
+
+    return update_wrapper(go, fn)
diff --git a/.venv/lib/python3.12/site-packages/mako/testing/fixtures.py b/.venv/lib/python3.12/site-packages/mako/testing/fixtures.py
new file mode 100644
index 00000000..01e99617
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/mako/testing/fixtures.py
@@ -0,0 +1,119 @@
+import os
+
+from mako.cache import CacheImpl
+from mako.cache import register_plugin
+from mako.template import Template
+from .assertions import eq_
+from .config import config
+
+
+class TemplateTest:
+    def _file_template(self, filename, **kw):
+        filepath = self._file_path(filename)
+        return Template(
+            uri=filename,
+            filename=filepath,
+            module_directory=config.module_base,
+            **kw,
+        )
+
+    def _file_path(self, filename):
+        name, ext = os.path.splitext(filename)
+        py3k_path = os.path.join(config.template_base, name + "_py3k" + ext)
+        if os.path.exists(py3k_path):
+            return py3k_path
+
+        return os.path.join(config.template_base, filename)
+
+    def _do_file_test(
+        self,
+        filename,
+        expected,
+        filters=None,
+        unicode_=True,
+        template_args=None,
+        **kw,
+    ):
+        t1 = self._file_template(filename, **kw)
+        self._do_test(
+            t1,
+            expected,
+            filters=filters,
+            unicode_=unicode_,
+            template_args=template_args,
+        )
+
+    def _do_memory_test(
+        self,
+        source,
+        expected,
+        filters=None,
+        unicode_=True,
+        template_args=None,
+        **kw,
+    ):
+        t1 = Template(text=source, **kw)
+        self._do_test(
+            t1,
+            expected,
+            filters=filters,
+            unicode_=unicode_,
+            template_args=template_args,
+        )
+
+    def _do_test(
+        self,
+        template,
+        expected,
+        filters=None,
+        template_args=None,
+        unicode_=True,
+    ):
+        if template_args is None:
+            template_args = {}
+        if unicode_:
+            output = template.render_unicode(**template_args)
+        else:
+            output = template.render(**template_args)
+
+        if filters:
+            output = filters(output)
+        eq_(output, expected)
+
+    def indicates_unbound_local_error(self, rendered_output, unbound_var):
+        var = f"&#39;{unbound_var}&#39;"
+        error_msgs = (
+            # < 3.11
+            f"local variable {var} referenced before assignment",
+            # >= 3.11
+            f"cannot access local variable {var} where it is not associated",
+        )
+        return any((msg in rendered_output) for msg in error_msgs)
+
+
+class PlainCacheImpl(CacheImpl):
+    """Simple memory cache impl so that tests which
+    use caching can run without beaker."""
+
+    def __init__(self, cache):
+        self.cache = cache
+        self.data = {}
+
+    def get_or_create(self, key, creation_function, **kw):
+        if key in self.data:
+            return self.data[key]
+        else:
+            self.data[key] = data = creation_function(**kw)
+            return data
+
+    def put(self, key, value, **kw):
+        self.data[key] = value
+
+    def get(self, key, **kw):
+        return self.data[key]
+
+    def invalidate(self, key, **kw):
+        del self.data[key]
+
+
+register_plugin("plain", __name__, "PlainCacheImpl")
diff --git a/.venv/lib/python3.12/site-packages/mako/testing/helpers.py b/.venv/lib/python3.12/site-packages/mako/testing/helpers.py
new file mode 100644
index 00000000..5ae9d38d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/mako/testing/helpers.py
@@ -0,0 +1,71 @@
+import contextlib
+import pathlib
+from pathlib import Path
+import re
+import time
+from typing import Union
+from unittest import mock
+
+
+def flatten_result(result):
+    return re.sub(r"[\s\r\n]+", " ", result).strip()
+
+
+def result_lines(result):
+    return [
+        x.strip()
+        for x in re.split(r"\r?\n", re.sub(r" +", " ", result))
+        if x.strip() != ""
+    ]
+
+
+def result_raw_lines(result):
+    return [x for x in re.split(r"\r?\n", result) if x.strip() != ""]
+
+
+def make_path(
+    filespec: Union[Path, str],
+    make_absolute: bool = True,
+    check_exists: bool = False,
+) -> Path:
+    path = Path(filespec)
+    if make_absolute:
+        path = path.resolve(strict=check_exists)
+    if check_exists and (not path.exists()):
+        raise FileNotFoundError(f"No file or directory at {filespec}")
+    return path
+
+
+def _unlink_path(path, missing_ok=False):
+    # Replicate 3.8+ functionality in 3.7
+    cm = contextlib.nullcontext()
+    if missing_ok:
+        cm = contextlib.suppress(FileNotFoundError)
+
+    with cm:
+        path.unlink()
+
+
+def replace_file_with_dir(pathspec):
+    path = pathlib.Path(pathspec)
+    _unlink_path(path, missing_ok=True)
+    path.mkdir(exist_ok=True)
+    return path
+
+
+def file_with_template_code(filespec):
+    with open(filespec, "w") as f:
+        f.write(
+            """
+i am an artificial template just for you
+"""
+        )
+    return filespec
+
+
+@contextlib.contextmanager
+def rewind_compile_time(hours=1):
+    rewound = time.time() - (hours * 3_600)
+    with mock.patch("mako.codegen.time") as codegen_time:
+        codegen_time.time.return_value = rewound
+        yield