mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-16 02:02:58 -07:00
Bump mako from 1.1.6 to 1.2.0 (#1684)
* Bump mako from 1.1.6 to 1.2.0 Bumps [mako](https://github.com/sqlalchemy/mako) from 1.1.6 to 1.2.0. - [Release notes](https://github.com/sqlalchemy/mako/releases) - [Changelog](https://github.com/sqlalchemy/mako/blob/main/CHANGES) - [Commits](https://github.com/sqlalchemy/mako/commits) --- updated-dependencies: - dependency-name: mako dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * Update mako==1.2.0 * Update MarkupSafe==2.1.1 * Add importlib-metadata==4.11.3 * Update requirements.txt Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> [skip ci]
This commit is contained in:
parent
aa0c58ef0e
commit
238afb4794
45 changed files with 2948 additions and 848 deletions
0
lib/mako/testing/__init__.py
Normal file
0
lib/mako/testing/__init__.py
Normal file
128
lib/mako/testing/_config.py
Normal file
128
lib/mako/testing/_config.py
Normal file
|
@ -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)
|
167
lib/mako/testing/assertions.py
Normal file
167
lib/mako/testing/assertions.py
Normal file
|
@ -0,0 +1,167 @@
|
|||
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)
|
17
lib/mako/testing/config.py
Normal file
17
lib/mako/testing/config.py
Normal file
|
@ -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")
|
80
lib/mako/testing/exclusions.py
Normal file
80
lib/mako/testing/exclusions.py
Normal file
|
@ -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)
|
109
lib/mako/testing/fixtures.py
Normal file
109
lib/mako/testing/fixtures.py
Normal file
|
@ -0,0 +1,109 @@
|
|||
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)
|
||||
|
||||
|
||||
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")
|
67
lib/mako/testing/helpers.py
Normal file
67
lib/mako/testing/helpers.py
Normal file
|
@ -0,0 +1,67 @@
|
|||
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 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
|
Loading…
Add table
Add a link
Reference in a new issue