1
0
mirror of synced 2026-01-03 06:02:23 -05:00
Files
airbyte/airbyte-cdk/python/airbyte_cdk/sources/declarative/interpolation/jinja.py
Alexander Marquardt 26b6317198 Added new "filters" python file, along with a "hash" filter. This can… (#18000)
* Added new "filters" python file, along with a "hash" filter. This can be extended to include other custom filters in the future.

* Added additional comments

* Moved usage of the hash_obj inside the conditional that confirms it exists

* Moved the hash function call inside a condition to ensure that it exists

* Fixed the application of the salt , so that it does not modify the hash unless it is actually passed in.

* Added unit tests to validate new jinja hash functionality

* Updated unit test to pass numeric value as a float instead of string

* Removed unreferenced import to pytest

* Updated version

* format

* format

* format

* format

* format

Co-authored-by: Alexandre Girard <alexandre@airbyte.io>
2022-10-17 23:19:55 -07:00

67 lines
2.6 KiB
Python

#
# Copyright (c) 2022 Airbyte, Inc., all rights reserved.
#
import ast
from typing import Optional
from airbyte_cdk.sources.declarative.interpolation.filters import filters
from airbyte_cdk.sources.declarative.interpolation.interpolation import Interpolation
from airbyte_cdk.sources.declarative.interpolation.macros import macros
from airbyte_cdk.sources.declarative.types import Config
from jinja2 import Environment
from jinja2.exceptions import UndefinedError
class JinjaInterpolation(Interpolation):
"""
Interpolation strategy using the Jinja2 template engine.
If the input string is a raw string, the interpolated string will be the same.
`eval("hello world") -> "hello world"`
The engine will evaluate the content passed within {{}}, interpolating the keys from the config and context-specific arguments.
`eval("hello {{ name }}", name="airbyte") -> "hello airbyte")`
`eval("hello {{ config.name }}", config={"name": "airbyte"}) -> "hello airbyte")`
In additional to passing additional values through the kwargs argument, macros can be called from within the string interpolation.
For example,
"{{ max(2, 3) }}" will return 3
Additional information on jinja templating can be found at https://jinja.palletsprojects.com/en/3.1.x/templates/#
"""
def __init__(self):
self._environment = Environment()
self._environment.filters.update(**filters)
self._environment.globals.update(**macros)
def eval(self, input_str: str, config: Config, default: Optional[str] = None, **additional_options):
context = {"config": config, **additional_options}
try:
if isinstance(input_str, str):
result = self._eval(input_str, context)
if result:
return self._literal_eval(result)
else:
# If input is not a string, return it as is
raise Exception(f"Expected a string. got {input_str}")
except UndefinedError:
pass
# If result is empty or resulted in an undefined error, evaluate and return the default string
return self._literal_eval(self._eval(default, context))
def _literal_eval(self, result):
try:
return ast.literal_eval(result)
except (ValueError, SyntaxError):
return result
def _eval(self, s: str, context):
try:
return self._environment.from_string(s).render(context)
except TypeError:
# The string is a static value, not a jinja template
# It can be returned as is
return s