From c733f671fc44960e435d9e4db983777777feaa32 Mon Sep 17 00:00:00 2001 From: BJ Dierkes Date: Wed, 17 Jul 2024 15:34:31 -0500 Subject: [PATCH] Type Annotations: ext.jinja2 - Resolves Issue #716 - Related to PR #628 --- CHANGELOG.md | 1 + cement/ext/ext_jinja2.py | 39 +++++++++++++++++++++++---------------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7a3f14a..2a71bffd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,7 @@ Refactoring: - `[ext.daemon]` [Issue #713](https://github.com/datafolklabs/cement/issues/713) - `[ext.dummy]` [Issue #714](https://github.com/datafolklabs/cement/issues/714) - `[ext.generate]` [Issue #715](https://github.com/datafolklabs/cement/issues/715) + - `[ext.jinja2]` [Issue #716](https://github.com/datafolklabs/cement/issues/716) - `[ext.logging]` [Issue #718](https://github.com/datafolklabs/cement/issues/718) - `[utils.fs]` [Issue #688](https://github.com/datafolklabs/cement/issues/688) - `[utils.misc]` [Issue #689](https://github.com/datafolklabs/cement/issues/689) diff --git a/cement/ext/ext_jinja2.py b/cement/ext/ext_jinja2.py index 11c267d2..168d4d8e 100644 --- a/cement/ext/ext_jinja2.py +++ b/cement/ext/ext_jinja2.py @@ -11,11 +11,16 @@ extensions. dependencies. """ +from __future__ import annotations +from typing import Any, Optional, Dict, Tuple, Union, TYPE_CHECKING from ..core.output import OutputHandler from ..core.template import TemplateHandler from ..utils.misc import minimal_logger from jinja2 import Environment, FileSystemLoader, PackageLoader +if TYPE_CHECKING: + from ..core.foundation import App # pragma: nocover + LOG = minimal_logger(__name__) @@ -31,22 +36,21 @@ class Jinja2OutputHandler(OutputHandler): """ - class Meta: + class Meta(OutputHandler.Meta): """Handler meta-data.""" label = 'jinja2' - def __init__(self, *args, **kw): + def __init__(self, *args: Any, **kw: Any) -> None: super(Jinja2OutputHandler, self).__init__(*args, **kw) - self.templater = None + self.templater: TemplateHandler = None # type: ignore - def _setup(self, app): + def _setup(self, app: App) -> None: super(Jinja2OutputHandler, self)._setup(app) - self.templater = self.app.handler.resolve('template', 'jinja2', - setup=True) + self.templater = self.app.handler.resolve('template', 'jinja2', setup=True) # type: ignore - def render(self, data, template=None, **kw): + def render(self, data: Dict[str, Any], template: str = None, **kw: Any) -> str: # type: ignore """ Take a data dictionary and render it using the given template file. Additional keyword arguments are ignored. @@ -66,7 +70,7 @@ class Jinja2OutputHandler(OutputHandler): LOG.debug(f"rendering content using '{template}' as a template.") content, _type, _path = self.templater.load(template) - return self.templater.render(content, data) + return self.templater.render(content, data) # type: ignore class Jinja2TemplateHandler(TemplateHandler): @@ -80,20 +84,20 @@ class Jinja2TemplateHandler(TemplateHandler): :cement:`Template Handling `. """ - class Meta: + class Meta(TemplateHandler.Meta): """Handler meta-data.""" label = 'jinja2' - def __init__(self, *args, **kw): + def __init__(self, *args: Any, **kw: Any) -> None: super(Jinja2TemplateHandler, self).__init__(*args, **kw) # expose Jinja2 Environment instance so that we can manipulate it # higher in application code if necessary self.env = Environment(keep_trailing_newline=True) - def load(self, *args, **kw): + def load(self, *args: Any, **kw: Any) -> Tuple[Union[str, bytes], str, Optional[str]]: """ Loads a template file first from ``self.app._meta.template_dirs`` and secondly from ``self.app._meta.template_module``. The @@ -113,18 +117,21 @@ class Jinja2TemplateHandler(TemplateHandler): cement.core.exc.FrameworkError: If the template does not exist in either the ``template_module`` or ``template_dirs``. """ - content, _type, _path = super(Jinja2TemplateHandler, self).load(*args, - **kw) + content, _type, _path = super(Jinja2TemplateHandler, self).load(*args, **kw) if _type == 'directory': self.env.loader = FileSystemLoader(self.app._meta.template_dirs) elif _type == 'module': - parts = self.app._meta.template_module.rsplit('.', 1) + parts = self.app._meta.template_module.rsplit('.', 1) # type: ignore self.env.loader = PackageLoader(parts[0], package_path=parts[1]) return content, _type, _path - def render(self, content, data, *args, **kw): + def render(self, + content: Union[str, bytes], + data: Dict[str, Any], + *args: Any, + **kw: Any) -> str: """ Render the given ``content`` as template with the ``data`` dictionary. @@ -146,6 +153,6 @@ class Jinja2TemplateHandler(TemplateHandler): return res -def load(app): +def load(app: App) -> None: app.handler.register(Jinja2OutputHandler) app.handler.register(Jinja2TemplateHandler)