Skip to content

Commit 6455f6c

Browse files
committed
Use PyO3 declarative module syntax
1 parent 7cd790d commit 6455f6c

File tree

1 file changed

+106
-101
lines changed

1 file changed

+106
-101
lines changed

src/lib.rs

Lines changed: 106 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -13,123 +13,128 @@ use pyo3::create_exception;
1313
create_exception!(rustfluent, ParserError, pyo3::exceptions::PyException);
1414

1515
#[pymodule]
16-
fn rustfluent(m: &Bound<'_, PyModule>) -> PyResult<()> {
17-
m.add_class::<Bundle>()?;
18-
m.add("ParserError", m.py().get_type::<ParserError>())?;
19-
Ok(())
20-
}
16+
mod rustfluent {
17+
use super::*;
2118

22-
#[pyclass]
23-
struct Bundle {
24-
bundle: FluentBundle<FluentResource>,
25-
}
19+
#[pymodule_export]
20+
use super::ParserError;
2621

27-
#[pymethods]
28-
impl Bundle {
29-
#[new]
30-
#[pyo3(signature = (language, ftl_filenames, strict=false))]
31-
fn new(language: &str, ftl_filenames: &'_ Bound<'_, PyList>, strict: bool) -> PyResult<Self> {
32-
let langid: LanguageIdentifier = language.parse().expect("Parsing failed");
33-
let mut bundle = FluentBundle::new_concurrent(vec![langid]);
22+
#[pyclass]
23+
struct Bundle {
24+
bundle: FluentBundle<FluentResource>,
25+
}
3426

35-
for file_path in ftl_filenames.iter() {
36-
let path_string = file_path.to_string();
37-
let contents = fs::read_to_string(path_string)
38-
.map_err(|_| PyFileNotFoundError::new_err(file_path.to_string()))?;
27+
#[pymethods]
28+
impl Bundle {
29+
#[new]
30+
#[pyo3(signature = (language, ftl_filenames, strict=false))]
31+
fn new(
32+
language: &str,
33+
ftl_filenames: &'_ Bound<'_, PyList>,
34+
strict: bool,
35+
) -> PyResult<Self> {
36+
let langid: LanguageIdentifier = language.parse().expect("Parsing failed");
37+
let mut bundle = FluentBundle::new_concurrent(vec![langid]);
3938

40-
let resource = match FluentResource::try_new(contents) {
41-
Ok(resource) => resource,
42-
Err(_) if strict => {
43-
return Err(ParserError::new_err(format!(
44-
"Error when parsing {file_path}."
45-
)));
46-
}
47-
Err(error) => {
48-
// The first element of the error is the parsed resource, minus any
49-
// invalid messages.
50-
error.0
51-
}
52-
};
53-
bundle.add_resource_overriding(resource);
54-
}
39+
for file_path in ftl_filenames.iter() {
40+
let path_string = file_path.to_string();
41+
let contents = fs::read_to_string(path_string)
42+
.map_err(|_| PyFileNotFoundError::new_err(file_path.to_string()))?;
5543

56-
Ok(Self { bundle })
57-
}
44+
let resource = match FluentResource::try_new(contents) {
45+
Ok(resource) => resource,
46+
Err(_) if strict => {
47+
return Err(ParserError::new_err(format!(
48+
"Error when parsing {file_path}."
49+
)));
50+
}
51+
Err(error) => {
52+
// The first element of the error is the parsed resource, minus any
53+
// invalid messages.
54+
error.0
55+
}
56+
};
57+
bundle.add_resource_overriding(resource);
58+
}
5859

59-
#[pyo3(signature = (identifier, variables=None, use_isolating=true))]
60-
pub fn get_translation(
61-
&mut self,
62-
identifier: &str,
63-
variables: Option<&Bound<'_, PyDict>>,
64-
use_isolating: bool,
65-
) -> PyResult<String> {
66-
self.bundle.set_use_isolating(use_isolating);
60+
Ok(Self { bundle })
61+
}
6762

68-
let msg = self
69-
.bundle
70-
.get_message(identifier)
71-
.ok_or_else(|| (PyValueError::new_err(format!("{identifier} not found"))))?;
63+
#[pyo3(signature = (identifier, variables=None, use_isolating=true))]
64+
pub fn get_translation(
65+
&mut self,
66+
identifier: &str,
67+
variables: Option<&Bound<'_, PyDict>>,
68+
use_isolating: bool,
69+
) -> PyResult<String> {
70+
self.bundle.set_use_isolating(use_isolating);
7271

73-
let mut errors = vec![];
74-
let pattern = msg.value().ok_or_else(|| {
75-
PyValueError::new_err(format!("{identifier} - Message has no value.",))
76-
})?;
72+
let msg = self
73+
.bundle
74+
.get_message(identifier)
75+
.ok_or_else(|| (PyValueError::new_err(format!("{identifier} not found"))))?;
7776

78-
let mut args = FluentArgs::new();
77+
let mut errors = vec![];
78+
let pattern = msg.value().ok_or_else(|| {
79+
PyValueError::new_err(format!("{identifier} - Message has no value.",))
80+
})?;
7981

80-
if let Some(variables) = variables {
81-
for variable in variables {
82-
// Make sure the variable key is a Python string,
83-
// raising a TypeError if not.
84-
let python_key = variable.0;
85-
if !python_key.is_instance_of::<PyString>() {
86-
return Err(PyTypeError::new_err(format!(
87-
"Variable key not a str, got {python_key}."
88-
)));
89-
}
90-
let key = python_key.to_string();
91-
// Set the variable value as a string or integer,
92-
// raising a TypeError if not.
93-
let python_value = variable.1;
94-
if python_value.is_instance_of::<PyString>() {
95-
args.set(key, python_value.to_string());
96-
} else if python_value.is_instance_of::<PyInt>() {
97-
match python_value.extract::<i32>() {
98-
Ok(int_value) => {
99-
args.set(key, int_value);
100-
}
101-
_ => {
102-
// The Python integer overflowed i32.
103-
// Fall back to displaying the variable key as its value.
104-
let fallback_value = key.clone();
105-
args.set(key, fallback_value);
106-
}
82+
let mut args = FluentArgs::new();
83+
84+
if let Some(variables) = variables {
85+
for variable in variables {
86+
// Make sure the variable key is a Python string,
87+
// raising a TypeError if not.
88+
let python_key = variable.0;
89+
if !python_key.is_instance_of::<PyString>() {
90+
return Err(PyTypeError::new_err(format!(
91+
"Variable key not a str, got {python_key}."
92+
)));
10793
}
108-
} else if python_value.is_instance_of::<PyDate>() {
109-
// Display the Python date as YYYY-MM-DD.
110-
match python_value.extract::<NaiveDate>() {
111-
Ok(chrono_date) => {
112-
args.set(key, chrono_date.format("%Y-%m-%d").to_string());
94+
let key = python_key.to_string();
95+
// Set the variable value as a string or integer,
96+
// raising a TypeError if not.
97+
let python_value = variable.1;
98+
if python_value.is_instance_of::<PyString>() {
99+
args.set(key, python_value.to_string());
100+
} else if python_value.is_instance_of::<PyInt>() {
101+
match python_value.extract::<i32>() {
102+
Ok(int_value) => {
103+
args.set(key, int_value);
104+
}
105+
_ => {
106+
// The Python integer overflowed i32.
107+
// Fall back to displaying the variable key as its value.
108+
let fallback_value = key.clone();
109+
args.set(key, fallback_value);
110+
}
113111
}
114-
_ => {
115-
// Could not convert.
116-
// Fall back to displaying the variable key as its value.
117-
let fallback_value = key.clone();
118-
args.set(key, fallback_value);
112+
} else if python_value.is_instance_of::<PyDate>() {
113+
// Display the Python date as YYYY-MM-DD.
114+
match python_value.extract::<NaiveDate>() {
115+
Ok(chrono_date) => {
116+
args.set(key, chrono_date.format("%Y-%m-%d").to_string());
117+
}
118+
_ => {
119+
// Could not convert.
120+
// Fall back to displaying the variable key as its value.
121+
let fallback_value = key.clone();
122+
args.set(key, fallback_value);
123+
}
119124
}
125+
} else {
126+
// The variable value was of an unsupported type.
127+
// Fall back to displaying the variable key as its value.
128+
let fallback_value = key.clone();
129+
args.set(key, fallback_value);
120130
}
121-
} else {
122-
// The variable value was of an unsupported type.
123-
// Fall back to displaying the variable key as its value.
124-
let fallback_value = key.clone();
125-
args.set(key, fallback_value);
126131
}
127132
}
128-
}
129133

130-
let value = self
131-
.bundle
132-
.format_pattern(pattern, Some(&args), &mut errors);
133-
Ok(value.to_string())
134+
let value = self
135+
.bundle
136+
.format_pattern(pattern, Some(&args), &mut errors);
137+
Ok(value.to_string())
138+
}
134139
}
135140
}

0 commit comments

Comments
 (0)