Skip to content

Commit

Permalink
Merge pull request #7 from kraken-tech/strict-mode
Browse files Browse the repository at this point in the history
Strict mode
  • Loading branch information
seddonym authored Sep 23, 2024
2 parents 3dc1946 + 80f482d commit 39014d0
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 19 deletions.
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,16 @@ bundle = rustfluent.Bundle(

#### Parameters

| Name | Type | Description |
|-------------|-------------|-------------------------------------------------------------------------------------------------------------------------|
| `language` | `str` | [Unicode Language Identifier](https://unicode.org/reports/tr35/tr35.html#Unicode_language_identifier) for the language. |
| `ftl_files` | `list[str]` | Full paths to the FTL files containing the translations. Entries in later files overwrite earlier ones. |
| Name | Type | Description |
|-------------|------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `language` | `str` | [Unicode Language Identifier](https://unicode.org/reports/tr35/tr35.html#Unicode_language_identifier) for the language. |
| `ftl_files` | `list[str]` | Full paths to the FTL files containing the translations. Entries in later files overwrite earlier ones. |
| `strict` | `bool`, optional | In strict mode, a `ParserError` will be raised if there are any errors in the file. In non-strict mode, invalid Fluent messages will be excluded from the Bundle. |

#### Raises

- `FileNotFoundError` if any of the FTL files could not be found.
- `ValueError` if any of the FTL files contain errors.
- `rustfluent.ParserError` if any of the FTL files contain errors (strict mode only).

### `Bundle.get_translation`

Expand Down
28 changes: 20 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@ use pyo3::types::{PyDict, PyList};
use std::fs;
use unic_langid::LanguageIdentifier;

use pyo3::create_exception;

create_exception!(rustfluent, PyParserError, pyo3::exceptions::PyException);

#[pymodule]
fn rustfluent(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<Bundle>()?;
m.add("ParserError", m.py().get_type_bound::<PyParserError>())?;
Ok(())
}

Expand All @@ -21,7 +26,8 @@ struct Bundle {
#[pymethods]
impl Bundle {
#[new]
fn new(language: &str, ftl_filenames: &'_ Bound<'_, PyList>) -> PyResult<Self> {
#[pyo3(signature = (language, ftl_filenames, strict=false))]
fn new(language: &str, ftl_filenames: &'_ Bound<'_, PyList>, strict: bool) -> PyResult<Self> {
let langid: LanguageIdentifier = language.parse().expect("Parsing failed");
let mut bundle = FluentBundle::new_concurrent(vec![langid]);

Expand All @@ -32,16 +38,22 @@ impl Bundle {
Err(_) => return Err(PyFileNotFoundError::new_err(file_path.to_string())),
};

let res = match FluentResource::try_new(contents) {
Ok(res) => res,
let resource = match FluentResource::try_new(contents) {
Ok(resource) => resource,
Err(error) => {
return Err(PyValueError::new_err(format!(
"{error:?} - Fluent file contains errors"
)))
if strict {
return Err(PyParserError::new_err(format!(
"Error when parsing {}.",
file_path
)));
} else {
// The first element of the error is the parsed resource, minus any
// invalid messages.
error.0
}
}
};

bundle.add_resource_overriding(res);
bundle.add_resource_overriding(resource);
}

Ok(Self { bundle })
Expand Down
2 changes: 1 addition & 1 deletion src/rustfluent.pyi
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
class Bundle:
def __init__(self, language: str, ftl_filenames: list[str]) -> None: ...
def __init__(self, language: str, ftl_filenames: list[str], strict: bool = False) -> None: ...
def get_translation(self, identifier: str, variables: dict[str, str] | None = None) -> str: ...
4 changes: 3 additions & 1 deletion tests/data/errors.ftl
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
bobbins
invalid-message

valid-message = I'm valid.
21 changes: 17 additions & 4 deletions tests/test_python_interface.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python

import pathlib
import re

import pytest

Expand Down Expand Up @@ -66,6 +66,19 @@ def test_file_not_found():
fluent.Bundle("fr", [str(data_dir / "none.ftl")])


def test_file_has_errors():
with pytest.raises(ValueError):
fluent.Bundle("fr", [str(data_dir / "errors.ftl")])
@pytest.mark.parametrize("pass_strict_argument_explicitly", (True, False))
def test_parses_other_parts_of_file_that_contains_errors_in_non_strict_mode(
pass_strict_argument_explicitly,
):
kwargs = dict(strict=False) if pass_strict_argument_explicitly else {}

bundle = fluent.Bundle("fr", [str(data_dir / "errors.ftl")], **kwargs)
translation = bundle.get_translation("valid-message")

assert translation == "I'm valid."


def test_raises_parser_error_on_file_that_contains_errors_in_strict_mode():
filename = str(data_dir / "errors.ftl")
with pytest.raises(fluent.ParserError, match=re.escape(f"Error when parsing {filename}.")):
fluent.Bundle("fr", [filename], strict=True)

0 comments on commit 39014d0

Please sign in to comment.