Compare commits

...

6 Commits

Author SHA1 Message Date
Dorian b13cab107b Update and fix test setup. 2019-11-15 11:45:57 -05:00
Dorian 85bd911959 Update the tests. 2019-11-06 20:16:25 -05:00
Dorian 4d8777a9af Add a test for the temperature check. 2019-11-06 19:40:51 -05:00
Dorian 5c53942b62 Add a class and windchill example. 2019-11-06 17:42:41 -05:00
Dorian 57bfde36c0 Update API. 2019-11-06 17:38:19 -05:00
Dorian b6943545be Merged batch-theory-check into master 2019-11-06 17:29:12 -05:00
5 changed files with 61 additions and 20 deletions

View File

@ -7,7 +7,11 @@ license = "Apache-2.0"
[lib] [lib]
name = "unit_converter" name = "unit_converter"
crate-type = ["cdylib"] crate-type = ["cdylib", "rlib"]
[dependencies] [dependencies.pyo3]
pyo3 = { version = "0.8", features = ["extension-module"] } version = "0.8"
[features]
extension-module = ["pyo3/extension-module"]
default = ["extension-module"]

View File

@ -20,8 +20,13 @@ Insure the following dependencies are in place:
1. Build the rust crate first: `cargo build` 1. Build the rust crate first: `cargo build`
1. Install dependencies and run in a virtualenv: `pipenv install && pipenv shell` 1. Install dependencies and run in a virtualenv: `pipenv install && pipenv shell`
1. Create the Python package with: `maturin build` 1. Create the Python package with: `maturin build`
1. Run the tests: `pytest test.py` 1. Run the Python tests: `pytest test.py batch_test.py`
1. Run the Rust test: `cargo test --no-default-features`
## Documentation ## Documentation
* [PyO3 Python - Rust bindings](https://pyo3.rs/master/get_started.html) * [PyO3 Python - Rust bindings](https://pyo3.rs/master/get_started.html)
* Windchill calculations:
* [PDF from US Gov](https://www.weather.gov/media/epz/wxcalc/windChill.pdf)
* [Calculation in Celsius and kph](https://www.calcunation.com/calculator/wind-chill-celsius.php)
* [Windchill Calculator](https://www.weather.gov/epz/wxcalc_windchill)

View File

@ -21,4 +21,4 @@ def test_using_python_batch(benchmark, batch_numbers):
def test_using_rust_batch(benchmark, batch_numbers): def test_using_rust_batch(benchmark, batch_numbers):
benchmark(unit_converter.batch_convert_celsius_to_fahrenheit, batch_numbers) benchmark(unit_converter.batch_convert_to_fahrenheit, batch_numbers)

View File

@ -5,33 +5,64 @@ extern crate pyo3;
use pyo3::prelude::*; use pyo3::prelude::*;
#[pyclass(module = "unit_converter")]
struct Temperature {
celsius: f32,
}
#[pymethods]
impl Temperature {
#[new]
fn new(obj: &PyRawObject, temperature: f32) {
obj.init(Temperature {
celsius: temperature,
});
}
fn to_fahrenheit(&self) -> f32 {
self.celsius * 1.8 + 32.0
}
fn windchill(&self, wind_speed_kph: f32) -> f32 {
13.12 + (0.6215 * self.celsius) - (11.37 * wind_speed_kph.powf(0.16))
+ (0.3965 * self.celsius * wind_speed_kph.powf(0.16))
}
}
#[pyfunction] #[pyfunction]
fn convert_celsius_to_fahrenheit(celsius: f32) -> f32 { fn convert_to_fahrenheit(celsius: f32) -> f32 {
celsius * 1.8 + 32.0 celsius * 1.8 + 32.0
} }
#[pyfunction] #[pyfunction]
fn batch_convert_celsius_to_fahrenheit(celsius: Vec<f32>) -> Vec<f32> { fn batch_convert_to_fahrenheit(celsius: Vec<f32>) -> Vec<f32> {
celsius celsius
.iter() .iter()
.map(|temperature| convert_celsius_to_fahrenheit(temperature.clone())) .map(|temperature| convert_to_fahrenheit(temperature.clone()))
.collect() .collect()
} }
#[pymodule] #[pymodule]
fn unit_converter(_py: Python, m: &PyModule) -> PyResult<()> { fn unit_converter(_py: Python, module: &PyModule) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(convert_celsius_to_fahrenheit))?; module.add_wrapped(wrap_pyfunction!(convert_to_fahrenheit))?;
m.add_wrapped(wrap_pyfunction!(batch_convert_celsius_to_fahrenheit))?; module.add_wrapped(wrap_pyfunction!(batch_convert_to_fahrenheit))?;
module.add_class::<Temperature>()?;
Ok(()) Ok(())
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::convert_celsius_to_fahrenheit; use super::{convert_to_fahrenheit, Temperature};
#[test] #[test]
fn conversion_celsius_to_fahrenheit() { fn conversion_celsius_to_fahrenheit() {
assert_eq!(convert_celsius_to_fahrenheit(25.0), 77.0); assert_eq!(convert_to_fahrenheit(25.0), 77.0);
}
#[test]
fn windchill_test() {
let temperature = Temperature{ celsius: -20.0 };
assert_eq!(temperature.windchill(32.0).round(), -33.0);
} }
} }

15
test.py
View File

@ -7,22 +7,23 @@ def python_unit_converter(celsius):
return celsius * 1.8 + 32.0 return celsius * 1.8 + 32.0
def batch_python_unit_converter(temperatures):
return [celsius * 1.8 + 32.0 for celsius in temperatures]
def test_using_unit_converter(): def test_using_unit_converter():
assert unit_converter.convert_celsius_to_fahrenheit(25.0) == 77.0 assert unit_converter.convert_to_fahrenheit(25.0) == 77.0
assert python_unit_converter(25.0) == 77.0 assert python_unit_converter(25.0) == 77.0
def test_windchill():
temperature = unit_converter.Temperature(-20.0)
assert round(temperature.windchill(32.0), 1) == -32.9
def test_using_python_constant(benchmark): def test_using_python_constant(benchmark):
result = benchmark(python_unit_converter, 25.0) result = benchmark(python_unit_converter, 25.0)
assert round(result, 3) == round(77.0, 3) assert round(result, 3) == round(77.0, 3)
def test_using_rust_constant(benchmark): def test_using_rust_constant(benchmark):
result = benchmark(unit_converter.convert_celsius_to_fahrenheit, 25.0) result = benchmark(unit_converter.convert_to_fahrenheit, 25.0)
assert round(result, 3) == round(77.0, 3) assert round(result, 3) == round(77.0, 3)
@ -34,5 +35,5 @@ def test_using_python(benchmark):
def test_using_rust(benchmark): def test_using_rust(benchmark):
temperature = random.random() * 100 temperature = random.random() * 100
result = benchmark(unit_converter.convert_celsius_to_fahrenheit, temperature) result = benchmark(unit_converter.convert_to_fahrenheit, temperature)
assert round(result, 3) == round(python_unit_converter(temperature), 3) assert round(result, 3) == round(python_unit_converter(temperature), 3)