Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/support for floating point #20

Merged
merged 5 commits into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ var/
.installed.cfg
*.egg

# Python environment
.venv

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ This is a fork of the original [`airspeed`](https://github.com/purcell/airspeed)
⚠️ Note: This fork of `airspeed` focuses on providing maximum parity with AWS' implementation of Velocity templates (used in, e.g., API Gateway or AppSync). In some cases, the behavior may diverge from the VTL spec, or from the Velocity [reference implementation](https://velocity.apache.org/download.cgi).

## Change Log:
* v0.6.7: fix support for floating point starting with a decimal; Implement `REPLACE_FORMAL_TEXT` to allow bypassing silent behavior of `FormalReference` element.
* v0.6.6: add support for `$string.matches( $pattern )`; fix bug where some escaped character would prevent string matching
* v0.6.5: handle `$map.put('key', null)` correctly
* v0.6.4: add support for string.indexOf, string.substring and array.isEmpty
Expand Down
10 changes: 8 additions & 2 deletions airspeed/operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
LOG = logging.getLogger(__name__)


# This can be used by a function to bypass the silent behavior of a FormalReference.
# If a function returns this value instead of None, the origial text of the reference will be returned instead.
REPLACE_FORMAL_TEXT = "__FORMAL_REFERENCE__REPLACE_TEXT__"
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure about that name, I am welcome to a suggestion to make it more obvious as to what it does. 🤔


# A dict that maps classes to dicts of additional methods.
# This allows support for methods that are available in Java-based Velocity
# implementations, e.g., .size() of a list or .length() of a string.
Expand Down Expand Up @@ -434,7 +438,7 @@ def calculate(self, namespace, loader):


class FloatingPointLiteral(_Element):
FLOAT = re.compile(r"(-?\d+\.\d+)(.*)", re.S)
FLOAT = re.compile(r"(-?\d*\.\d+)(.*)", re.S)

def parse(self):
(self.value,) = self.identity_match(self.FLOAT)
Expand Down Expand Up @@ -795,7 +799,9 @@ def evaluate_raw(self, stream, namespace, loader):
value = None
if self.expression is not None:
value = self.expression.calculate(namespace, loader)
if value is None:
if value == REPLACE_FORMAL_TEXT:
value = self.my_text()
elif value is None:
if self.alternate is not None:
value = self.alternate.calculate(namespace, loader) or ""
elif self.silent and self.expression is not None:
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setup(
name="airspeed-ext",
version="0.6.6",
version="0.6.7",
description=(
"Airspeed is a powerful and easy-to-use templating engine "
"for Python that aims for a high level of compatibility "
Expand Down
36 changes: 31 additions & 5 deletions tests/test_templating.py
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,10 @@ def test_string_with_escaped_char(self, test_render):
template = '"\{\n\t\r\%\5"' # noqa
test_render(template)

def test_floating_point_starting_with_decimal(self, test_render):
template = """#set($x = .5*.1)$x"""
test_render(template)


class TestInternals:
"""
Expand Down Expand Up @@ -1206,15 +1210,37 @@ def test_template_cannot_modify_its_args(self, test_render):

def test_doesnt_blow_stack(self, test_render):
template = airspeed.Template(
"""
#foreach($i in [1..$end])
$assembly##
#end
"""
textwrap.dedent(
"""
#foreach($i in [1..$end])
$assembly##
#end
"""
)
)
ns = {"end": 400}
template.merge(ns)

def test_formal_reference_test_bypass(self, test_render_locally):
test_render = test_render_locally(
f'#set($bypass = "{airspeed.operators.REPLACE_FORMAL_TEXT}")$bypass'
)
assert test_render == "$bypass"

test_render_map = test_render_locally(
textwrap.dedent(
f"""
#set( $map = {{}})
#set($ignore = $map.put('bypass', "{airspeed.operators.REPLACE_FORMAL_TEXT}"))
#set($ignore = $map.put('no-bypass', "value"))
$map.bypass
$map.no-bypass
"""
)
)

assert test_render_map == "\n$map.bypass\nvalue\n"


class TestMacros:
"""
Expand Down
7 changes: 7 additions & 0 deletions tests/test_templating.snapshot.json
Original file line number Diff line number Diff line change
Expand Up @@ -1104,5 +1104,12 @@
"render-result-2-cli": "true",
"render-result-2": "true"
}
},
"tests/test_templating.py::TestTemplating::test_floating_point_starting_with_decimal": {
"recorded-date": "10-11-2024, 04:53:47",
"recorded-content": {
"render-result-1-cli": "0.05",
"render-result-1": "0.05"
}
}
}
Loading