Skip to content

Updated for fluent.syntax 0.14+ / Fluent spec 1.0 #116

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

Merged
merged 1 commit into from
May 11, 2019
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
10 changes: 5 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,23 @@ python:
- "nightly"
env:
global:
- FLUENT_RUNTIME_DEFAULT_DEPS="fluent.syntax==0.13.0 attrs==19.1.0 babel==2.6.0 pytz==2018.9 six==1.12.0"
- FLUENT_RUNTIME_DEFAULT_DEPS="fluent.syntax==0.15 attrs==19.1.0 babel==2.6.0 pytz==2018.9 six==1.12.0"
- FLUENT_SYNTAX_DEFAULT_DEPS="six"
matrix:
- PACKAGE=fluent.syntax
- PACKAGE=fluent.runtime
matrix:
include:
- name: "fluent.runtime w/ fluent.syntax==0.10"
- name: "fluent.runtime w/ fluent.syntax==0.14"
python: "3.6"
env: PACKAGE=fluent.runtime TEST_DEPS="fluent.syntax==0.10.0 attrs==19.1.0 babel==2.6.0 pytz==2018.9 six==1.12.0"
env: PACKAGE=fluent.runtime TEST_DEPS="fluent.syntax==0.14 attrs==19.1.0 babel==2.6.0 pytz==2018.9 six==1.12.0"
- name: "fluent.runtime with latest everything"
python: "3.6"
# These are copy-pasted from setup.py
env: PACKAGE=fluent.runtime TEST_DEPS="fluent.syntax>=0.10,<=0.13 attrs babel pytz six"
env: PACKAGE=fluent.runtime TEST_DEPS="fluent.syntax>=0.14,<=0.16 attrs babel pytz six"
allow_failures:
- python: "3.6"
env: PACKAGE=fluent.runtime TEST_DEPS="fluent.syntax>=0.10,<=0.13 attrs babel pytz six"
env: PACKAGE=fluent.runtime TEST_DEPS="fluent.syntax>=0.14,<=0.16 attrs babel pytz six"

install:
- if [ "$PACKAGE" = "fluent.runtime" ]; then TEST_DEPS=${TEST_DEPS:-$FLUENT_RUNTIME_DEFAULT_DEPS}; else TEST_DEPS=${TEST_DEPS:-$FLUENT_SYNTAX_DEFAULT_DEPS}; fi
Expand Down
75 changes: 17 additions & 58 deletions fluent.runtime/fluent/runtime/resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ def __call__(self, env):

class StringLiteral(FTL.StringLiteral, Literal):
def __call__(self, env):
return self.value
return self.parse()['value']


class NumberLiteral(FTL.NumberLiteral, BaseResolver):
Expand All @@ -180,7 +180,14 @@ def __call__(self, env):

class TermReference(FTL.TermReference, BaseResolver):
def __call__(self, env):
with env.modified_for_term_reference():
if self.arguments:
if self.arguments.positional:
env.errors.append(FluentFormatError("Ignored positional arguments passed to term '{0}'"
.format(reference_to_id(self))))
kwargs = {kwarg.name.name: kwarg.value(env) for kwarg in self.arguments.named}
else:
kwargs = None
with env.modified_for_term_reference(args=kwargs):
return lookup_reference(self, env)(env)


Expand All @@ -200,9 +207,9 @@ def lookup_reference(ref, env):
except LookupError:
env.errors.append(unknown_reference_error_obj(ref_id))

if isinstance(ref, AttributeExpression):
if ref.attribute:
# Fallback
parent_id = reference_to_id(ref.ref)
parent_id = reference_to_id(ref, ignore_attributes=True)
try:
return env.context.lookup(parent_id)
except LookupError:
Expand Down Expand Up @@ -231,40 +238,10 @@ def __call__(self, env):
return FluentNone(name)


class AttributeExpression(FTL.AttributeExpression, BaseResolver):
def __call__(self, env):
return lookup_reference(self, env)(env)


class Attribute(FTL.Attribute, BaseResolver):
pass


class VariantList(FTL.VariantList, BaseResolver):
def __call__(self, env, key=None):
found = None
for variant in self.variants:
if variant.default:
default = variant
if key is None:
# We only want the default
break

compare_value = variant.key(env)
if match(key, compare_value, env):
found = variant
break

if found is None:
if (key is not None and not isinstance(key, FluentNone)):
env.errors.append(FluentReferenceError("Unknown variant: {0}"
.format(key)))
found = default
assert found, "Not having a default variant is a parse error"

return found.value(env)


class SelectExpression(FTL.SelectExpression, BaseResolver):
def __call__(self, env):
key = self.selector(env)
Expand Down Expand Up @@ -314,33 +291,15 @@ def __call__(self, env):
return self.name


class VariantExpression(FTL.VariantExpression, BaseResolver):
def __call__(self, env):
message = lookup_reference(self.ref, env)

# TODO What to do if message is not a VariantList?
# Need test at least.
assert isinstance(message, VariantList)

variant_name = self.key.name
return message(env, variant_name)
class CallArguments(FTL.CallArguments, BaseResolver):
pass


class CallExpression(FTL.CallExpression, BaseResolver):
class FunctionReference(FTL.FunctionReference, BaseResolver):
def __call__(self, env):
args = [arg(env) for arg in self.positional]
kwargs = {kwarg.name.name: kwarg.value(env) for kwarg in self.named}

if isinstance(self.callee, (TermReference, AttributeExpression)):
term = lookup_reference(self.callee, env)
if args:
env.errors.append(FluentFormatError("Ignored positional arguments passed to term '{0}'"
.format(reference_to_id(self.callee))))
with env.modified_for_term_reference(args=kwargs):
return term(env)

# builtin or custom function call
function_name = self.callee.id.name
args = [arg(env) for arg in self.arguments.positional]
kwargs = {kwarg.name.name: kwarg.value(env) for kwarg in self.arguments.named}
function_name = self.id.name
try:
function = env.context._functions[function_name]
except LookupError:
Expand Down
25 changes: 10 additions & 15 deletions fluent.runtime/fluent/runtime/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from datetime import date, datetime
from decimal import Decimal

from fluent.syntax.ast import AttributeExpression, Term, TermReference
from fluent.syntax.ast import Term, TermReference

from .types import FluentInt, FluentFloat, FluentDecimal, FluentDate, FluentDateTime
from .errors import FluentReferenceError
Expand Down Expand Up @@ -39,9 +39,9 @@ def native_to_fluent(val):
return val


def reference_to_id(ref):
def reference_to_id(ref, ignore_attributes=False):
"""
Returns a string reference for a MessageReference, TermReference or AttributeExpression
Returns a string reference for a MessageReference or TermReference
AST node.

e.g.
Expand All @@ -50,12 +50,14 @@ def reference_to_id(ref):
-term
-term.attr
"""
if isinstance(ref, AttributeExpression):
return _make_attr_id(reference_to_id(ref.ref),
ref.name.name)
if isinstance(ref, TermReference):
return TERM_SIGIL + ref.id.name
return ref.id.name
start = TERM_SIGIL + ref.id.name
else:
start = ref.id.name

if not ignore_attributes and ref.attribute:
return ''.join([start, ATTRIBUTE_SEPARATOR, ref.attribute.name])
return start


def unknown_reference_error_obj(ref_id):
Expand All @@ -64,10 +66,3 @@ def unknown_reference_error_obj(ref_id):
if ref_id.startswith(TERM_SIGIL):
return FluentReferenceError("Unknown term: {0}".format(ref_id))
return FluentReferenceError("Unknown message: {0}".format(ref_id))


def _make_attr_id(parent_ref_id, attr_name):
"""
Given a parent id and the attribute name, return the attribute id
"""
return ''.join([parent_ref_id, ATTRIBUTE_SEPARATOR, attr_name])
2 changes: 1 addition & 1 deletion fluent.runtime/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
packages=['fluent', 'fluent.runtime'],
# These should also be duplicated in tox.ini and ../.travis.yml
install_requires=[
'fluent.syntax>=0.10,<=0.13',
'fluent.syntax>=0.14,<=0.16',
'attrs',
'babel',
'pytz',
Expand Down
6 changes: 0 additions & 6 deletions fluent.runtime/tests/format/test_placeables.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ def setUp(self):
uses-message = { message }
uses-message-attr = { message.attr }
uses-term = { -term }
uses-term-variant = { -term2[variant2] }

bad-message-ref = Text { not-a-message }
bad-message-attr-ref = Text { message.not-an-attr }
Expand Down Expand Up @@ -57,11 +56,6 @@ def test_placeable_term(self):
self.assertEqual(val, 'Term')
self.assertEqual(len(errs), 0)

def test_placeable_term_variant(self):
val, errs = self.ctx.format('uses-term-variant', {})
self.assertEqual(val, 'Term Variant 2')
self.assertEqual(len(errs), 0)

def test_placeable_bad_message(self):
val, errs = self.ctx.format('bad-message-ref', {})
self.assertEqual(val, 'Text not-a-message')
Expand Down
9 changes: 8 additions & 1 deletion fluent.runtime/tests/format/test_primitives.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals

import unittest
Expand All @@ -10,7 +11,7 @@
class TestSimpleStringValue(unittest.TestCase):
def setUp(self):
self.ctx = FluentBundle(['en-US'], use_isolating=False)
self.ctx.add_messages(dedent_ftl("""
self.ctx.add_messages(dedent_ftl(r"""
foo = Foo
placeable-literal = { "Foo" } Bar
placeable-message = { foo } Bar
Expand All @@ -27,6 +28,7 @@ def setUp(self):
[BazAttribute] Member 3
*[other] Member 4
}
escapes = {" "}stuff{"\u0258}\"\\end"}
"""))

def test_can_be_used_as_a_value(self):
Expand Down Expand Up @@ -64,6 +66,11 @@ def test_can_be_a_value_of_an_attribute_used_as_a_selector(self):
self.assertEqual(val, 'Member 3')
self.assertEqual(len(errs), 0)

def test_escapes(self):
val, errs = self.ctx.format('escapes', {})
self.assertEqual(val, r' stuffɘ}"\end')
self.assertEqual(len(errs), 0)


class TestComplexStringValue(unittest.TestCase):
def setUp(self):
Expand Down
47 changes: 0 additions & 47 deletions fluent.runtime/tests/format/test_variants.py

This file was deleted.

8 changes: 4 additions & 4 deletions fluent.runtime/tox.ini
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# This config is for local testing. It should be duplicated into .travis.yml
[tox]
envlist = {py27,py35,py36,py37,pypy,pypy3}-syntax0.13, py36-syntax0.10, latest
envlist = {py27,py35,py36,py37,pypy,pypy3}-syntax0.15, py36-syntax0.14, latest
skipsdist=True

[testenv]
setenv =
PYTHONPATH = {toxinidir}
deps =
syntax0.10: fluent.syntax==0.10.0
syntax0.13: fluent.syntax==0.13.0
syntax0.15: fluent.syntax==0.15
syntax0.14: fluent.syntax==0.14
attrs==19.1.0
babel==2.6.0
pytz==2018.9
Expand All @@ -22,7 +22,7 @@ deps =
# It's tempting to use '.' here to get 'pip install .'
# Unfortunately it is super slow: https://github.com/pypa/pip/issues/2195
# Instead we copy-paste from setup.py
fluent.syntax>=0.10,<=0.13
fluent.syntax>=0.14,<=0.16
attrs
babel
pytz
Expand Down