-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refined and documented error handling for functions
- Loading branch information
1 parent
9730d3f
commit 9a5aa1d
Showing
11 changed files
with
549 additions
and
78 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
Error handling | ||
============== | ||
|
||
The Fluent philosophy is to try to recover from errors, and not throw | ||
exceptions, on the basis that a partial translation is usually better than one | ||
that is entirely missing or a 500 page. | ||
|
||
python-fluent adopts that philosophy, but also tries to abide by the Zen of | ||
Python - “Errors should never pass silently. Unless explicitly silenced.” | ||
|
||
The combination of these two different philosophies works as follows: | ||
|
||
* Errors made by **translators** in the contents of FTL files do not raise | ||
exceptions. Instead the errors are collected in the ``errors`` argument returned | ||
by ``FluentBundle.format``, and some kind of substitute string is returned. | ||
For example, if a non-existent term ``-brand-name`` is referenced from a | ||
message, the string ``-brand-name`` is inserted into the returned string. | ||
|
||
Also, if the translator uses a function and passes the wrong number of | ||
positional arguments, or unavailable keyword arguments, this error will be | ||
caught and reported, without allowing the exception to propagate. | ||
|
||
* Exceptions triggered by **developer** errors (whether the authors of | ||
python-fluent or a user of python-fluent) are not caught, but are allowed to | ||
propagate. For example: | ||
|
||
* An incorrect message ID passed to ``FluentBundle.format`` is most likely a | ||
developer error (a typo in the message ID), and so causes an exception to be | ||
raised. | ||
|
||
A message ID that is correct but missing in some languages will cause the | ||
same error, but it is expected that to cover this eventuality | ||
``FluentBundle.format`` will be wrapped with functions that automatically | ||
perform fallback to languages that have all messages defined. This fallback | ||
mechanism is outside the scope of ``fluent.runtime`` itself. | ||
|
||
* Message arguments of unexpected types will raise exceptions, since it is the | ||
developer's job to ensure the right arguments are being passed to the | ||
``FluentBundle.format`` method. | ||
|
||
* Exceptions raised by custom functions are also assumed to be developer | ||
errors (as documented in :doc:`functions`, these functions should not raise | ||
exceptions), and are not caught. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
Custom functions | ||
---------------- | ||
|
||
You can add functions to the ones available to FTL authors by passing a | ||
``functions`` dictionary to the ``FluentBundle`` constructor: | ||
|
||
.. code-block:: python | ||
>>> import platform | ||
>>> def os_name(): | ||
... """Returns linux/mac/windows/other""" | ||
... return {'Linux': 'linux', | ||
... 'Darwin': 'mac', | ||
... 'Windows': 'windows'}.get(platform.system(), 'other') | ||
>>> bundle = FluentBundle(['en-US'], functions={'OS': os_name}) | ||
>>> bundle.add_messages(""" | ||
... welcome = { OS() -> | ||
... [linux] Welcome to Linux | ||
... [mac] Welcome to Mac | ||
... [windows] Welcome to Windows | ||
... *[other] Welcome | ||
... } | ||
... """) | ||
>>> print(bundle.format('welcome')[0] | ||
Welcome to Linux | ||
These functions can accept positional and keyword arguments, like the ``NUMBER`` | ||
and ``DATETIME`` builtins. They must accept the following types of objects | ||
passed as arguments: | ||
- unicode strings (i.e. ``unicode`` on Python 2, ``str`` on Python 3) | ||
- ``fluent.runtime.types.FluentType`` subclasses, namely: | ||
- ``FluentNumber`` - ``int``, ``float`` or ``Decimal`` objects passed in | ||
externally, or expressed as literals, are wrapped in these. Note that these | ||
objects also subclass builtin ``int``, ``float`` or ``Decimal``, so can be | ||
used as numbers in the normal way. | ||
- ``FluentDateType`` - ``date`` or ``datetime`` objects passed in are wrapped in | ||
these. Again, these classes also subclass ``date`` or ``datetime``, and can | ||
be used as such. | ||
- ``FluentNone`` - in error conditions, such as a message referring to an | ||
argument that hasn't been passed in, objects of this type are passed in. | ||
Custom functions should not throw errors, but return ``FluentNone`` instances to | ||
indicate an error or missing data. Otherwise they should return unicode strings, | ||
or instances of a ``FluentType`` subclass as above. Returned numbers and | ||
datetimes should be converted to ``FluentNumber`` or ``FluentDateType`` | ||
subclasses using ``fluent.types.fluent_number`` and ``fluent.types.fluent_date`` | ||
respectively. | ||
The type signatures of custom functions are checked before they are used, to | ||
ensure the right the number of positional arguments are used, and only available | ||
keyword arguments are used - otherwise a ``TypeError`` will be appended to the | ||
``errors`` list. Using ``*args`` or ``**kwargs`` to allow any number of | ||
positional or keyword arguments is supported, but you should ensure that your | ||
function actually does allow all positional or keyword arguments. | ||
If you want to override the detected type signature (for example, to limit the | ||
arguments that can be used in an FTL file, or to provide a proper signature for | ||
a function that has a signature using ``*args`` and ``**kwargs`` but is more | ||
restricted in reality), you can add an ``ftl_arg_spec`` attribute to the | ||
function. The value should be a two-tuple containing 1) an integer specifying | ||
the number of positional arguments, and 2) a list of allowed keyword arguments. | ||
For example, for a custom function ``my_func`` the following will stop the | ||
``restricted`` keyword argument from being used from FTL files, while allowing | ||
``allowed``, and will require that a single positional argument is passed: | ||
|
||
.. code-block:: python | ||
def my_func(arg1, allowed=None, restricted=None): | ||
pass | ||
my_func.ftl_arg_spec = (1, ['allowed']) | ||
The Fluent spec allows keyword arguments with hyphens (``-``) in them. | ||
Since these cannot be used in valid Python keyword arguments, they are | ||
disallowed by ``fluent.runtime`` and will be filtered out and generate | ||
errors if you specify such a keyword in ``ftl_arg_spec`` or use one in a | ||
message. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,4 +15,6 @@ significant changes. | |
|
||
installation | ||
usage | ||
functions | ||
errors | ||
history |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.