|
9 | 9 | from pathlib import Path |
10 | 10 | from typing import TYPE_CHECKING, Any, Callable, Optional |
11 | 11 |
|
12 | | -import jinja2 |
13 | 12 | import typer |
14 | 13 | import ujson |
15 | 14 | from rich.console import Console |
|
18 | 17 | from rich.panel import Panel |
19 | 18 | from rich.pretty import Pretty |
20 | 19 | from rich.table import Table |
21 | | -from rich.traceback import Traceback |
22 | 20 |
|
23 | 21 | from .. import __version__ as sdk_version |
24 | 22 | from ..async_typer import AsyncTyper |
|
44 | 42 | ) |
45 | 43 | from ..ctl.validate import app as validate_app |
46 | 44 | from ..exceptions import GraphQLError, ModuleImportError |
47 | | -from ..jinja2 import identify_faulty_jinja_code |
48 | 45 | from ..schema import MainSchemaTypesAll, SchemaRoot |
| 46 | +from ..template import Jinja2Template |
| 47 | +from ..template.exceptions import ( |
| 48 | + JinjaTemplateError, |
| 49 | + JinjaTemplateNotFoundError, |
| 50 | + JinjaTemplateSyntaxError, |
| 51 | + JinjaTemplateUndefinedError, |
| 52 | +) |
49 | 53 | from ..utils import get_branch, write_to_file |
50 | 54 | from ..yaml import SchemaFile |
51 | 55 | from .exporter import dump |
@@ -174,37 +178,50 @@ async def run( |
174 | 178 | await func(client=client, log=log, branch=branch, **variables_dict) |
175 | 179 |
|
176 | 180 |
|
177 | | -def render_jinja2_template(template_path: Path, variables: dict[str, str], data: dict[str, Any]) -> str: |
| 181 | +async def render_jinja2_template(template_path: Path, variables: dict[str, Any], data: dict[str, Any]) -> str: |
178 | 182 | if not template_path.is_file(): |
179 | 183 | console.print(f"[red]Unable to locate the template at {template_path}") |
180 | 184 | raise typer.Exit(1) |
181 | 185 |
|
182 | | - templateLoader = jinja2.FileSystemLoader(searchpath=".") |
183 | | - templateEnv = jinja2.Environment(loader=templateLoader, trim_blocks=True, lstrip_blocks=True) |
184 | | - template = templateEnv.get_template(str(template_path)) |
185 | | - |
| 186 | + variables["data"] = data |
| 187 | + jinja_template = Jinja2Template(template_directory=Path()) |
186 | 188 | try: |
187 | | - rendered_tpl = template.render(**variables, data=data) # type: ignore[arg-type] |
188 | | - except jinja2.TemplateSyntaxError as exc: |
189 | | - console.print("[red]Syntax Error detected on the template") |
190 | | - console.print(f"[yellow] {exc}") |
| 189 | + rendered_tpl = await jinja_template.render_from_file(template=template_path, variables=variables) |
| 190 | + except JinjaTemplateNotFoundError as exc: |
| 191 | + console.print("[red]An error occurred while rendering the jinja template") |
| 192 | + console.print("") |
| 193 | + if exc.base_template: |
| 194 | + console.print(f"Base template: [yellow]{exc.base_template}") |
| 195 | + console.print(f"Missing template: [yellow]{exc.filename}") |
191 | 196 | raise typer.Exit(1) from exc |
192 | 197 |
|
193 | | - except jinja2.UndefinedError as exc: |
| 198 | + except JinjaTemplateUndefinedError as exc: |
| 199 | + console.print("[red]An error occurred while rendering the jinja template") |
| 200 | + for error in exc.errors: |
| 201 | + console.print(f"[yellow]{error.frame.filename} on line {error.frame.lineno}\n") |
| 202 | + console.print(error.syntax) |
| 203 | + console.print("") |
| 204 | + console.print(exc.message) |
| 205 | + raise typer.Exit(1) from exc |
| 206 | + except JinjaTemplateSyntaxError as exc: |
| 207 | + console.print("[red]A syntax error was encountered within the template") |
| 208 | + console.print("") |
| 209 | + if exc.filename: |
| 210 | + console.print(f"Filename: [yellow]{exc.filename}") |
| 211 | + console.print(f"Line number: [yellow]{exc.lineno}") |
| 212 | + console.print() |
| 213 | + console.print(exc.message) |
| 214 | + raise typer.Exit(1) from exc |
| 215 | + except JinjaTemplateError as exc: |
194 | 216 | console.print("[red]An error occurred while rendering the jinja template") |
195 | | - traceback = Traceback(show_locals=False) |
196 | | - errors = identify_faulty_jinja_code(traceback=traceback) |
197 | | - for frame, syntax in errors: |
198 | | - console.print(f"[yellow]{frame.filename} on line {frame.lineno}\n") |
199 | | - console.print(syntax) |
200 | 217 | console.print("") |
201 | | - console.print(traceback.trace.stacks[0].exc_value) |
| 218 | + console.print(f"[yellow]{exc.message}") |
202 | 219 | raise typer.Exit(1) from exc |
203 | 220 |
|
204 | 221 | return rendered_tpl |
205 | 222 |
|
206 | 223 |
|
207 | | -def _run_transform( |
| 224 | +async def _run_transform( |
208 | 225 | query_name: str, |
209 | 226 | variables: dict[str, Any], |
210 | 227 | transform_func: Callable, |
@@ -249,15 +266,15 @@ def _run_transform( |
249 | 266 | raise typer.Abort() |
250 | 267 |
|
251 | 268 | if asyncio.iscoroutinefunction(transform_func): |
252 | | - output = asyncio.run(transform_func(response)) |
| 269 | + output = await transform_func(response) |
253 | 270 | else: |
254 | 271 | output = transform_func(response) |
255 | 272 | return output |
256 | 273 |
|
257 | 274 |
|
258 | 275 | @app.command(name="render") |
259 | 276 | @catch_exception(console=console) |
260 | | -def render( |
| 277 | +async def render( |
261 | 278 | transform_name: str = typer.Argument(default="", help="Name of the Python transformation", show_default=False), |
262 | 279 | variables: Optional[list[str]] = typer.Argument( |
263 | 280 | None, help="Variables to pass along with the query. Format key=value key=value." |
@@ -289,7 +306,7 @@ def render( |
289 | 306 | transform_func = functools.partial(render_jinja2_template, transform_config.template_path, variables_dict) |
290 | 307 |
|
291 | 308 | # Query GQL and run the transform |
292 | | - result = _run_transform( |
| 309 | + result = await _run_transform( |
293 | 310 | query_name=transform_config.query, |
294 | 311 | variables=variables_dict, |
295 | 312 | transform_func=transform_func, |
|
0 commit comments