1
0
mirror of https://github.com/bspeice/dtparse synced 2024-12-22 12:28:08 -05:00

Use much more concise macros

Compile time down from ~2 minutes to ~2 seconds.
This commit is contained in:
Bradlee Speice 2018-06-04 20:23:34 -04:00
parent b0e737f088
commit 78ad8f2b94

View File

@ -3,14 +3,18 @@ extern crate pyo3;
use chrono::Datelike; use chrono::Datelike;
use chrono::NaiveDate; use chrono::NaiveDate;
use chrono::NaiveDateTime;
use chrono::Timelike; use chrono::Timelike;
use pyo3::ObjectProtocol; use pyo3::ObjectProtocol;
use pyo3::PyBool; use pyo3::PyBool;
use pyo3::PyDict; use pyo3::PyDict;
use pyo3::PyList; use pyo3::PyList;
use pyo3::PyObject; use pyo3::PyObject;
use pyo3::PyModule;
use pyo3::Python; use pyo3::Python;
use std::collections::HashMap; use std::collections::HashMap;
use std::time::Duration;
use std::thread;
extern crate dtparse; extern crate dtparse;
@ -60,74 +64,75 @@ macro_rules! py_offset_secs {
}); });
} }
macro_rules! test_parse { fn parse_and_assert(
// Full parsing options py: Python,
( parser: &PyModule,
$py:ident, datetime: &PyModule,
$parser:ident, info: ParserInfo,
$datetime:ident, s: &str,
$info:expr, dayfirst: Option<bool>,
$s:expr, yearfirst: Option<bool>,
$dayfirst:expr, fuzzy: bool,
$yearfirst:expr, fuzzy_with_tokens: bool,
$fuzzy:expr, default: Option<&NaiveDateTime>,
$fuzzy_with_tokens:expr, ignoretz: bool,
$default:expr, tzinfos: Vec<String>,
$ignoretz:expr, ) {
$tzinfos:expr
) => { let default_pydate = datetime
let default_pydate = $datetime
.call_method1("datetime", (2003, 9, 25)) .call_method1("datetime", (2003, 9, 25))
.expect("Unable to create default datetime"); .expect("Unable to create default datetime");
let default_tzinfos = PyDict::new($py); let default_tzinfos = PyDict::new(py);
default_tzinfos.set_item("BRST", -10800).unwrap(); default_tzinfos.set_item("BRST", -10800).unwrap();
let mut kwargs = HashMap::new(); let mut kwargs = HashMap::new();
kwargs.insert("default", default_pydate); kwargs.insert("default", default_pydate);
kwargs.insert("tzinfos", default_tzinfos.into()); kwargs.insert("tzinfos", default_tzinfos.into());
kwargs.insert("ignoretz", PyBool::new($py, $ignoretz).into()); kwargs.insert("ignoretz", PyBool::new(py, ignoretz).into());
let py_true = PyBool::new($py, true); let py_true = PyBool::new(py, true);
if $dayfirst == Some(true) { if dayfirst == Some(true) {
kwargs.insert("dayfirst", py_true.into()); kwargs.insert("dayfirst", py_true.into());
} }
if $yearfirst == Some(true) { if yearfirst == Some(true) {
kwargs.insert("yearfirst", py_true.into()); kwargs.insert("yearfirst", py_true.into());
} }
let py_parsed: PyObject = $parser // pyo3 has issues if we don't sleep here
.call_method("parse", $s, kwargs) thread::sleep(Duration::from_millis(5));
let py_parsed: PyObject = parser
.call_method("parse", s, kwargs)
.expect("Unable to call method `parse`") .expect("Unable to call method `parse`")
.extract() .extract()
.expect("Unable to extract result of `parse` call"); .expect("Unable to extract result of `parse` call");
let mut parser = Parser::new($info); let mut parser = Parser::new(info);
let rs_parsed = parser.parse( let rs_parsed = parser.parse(
$s, s,
$dayfirst, dayfirst,
$yearfirst, yearfirst,
$fuzzy, fuzzy,
$fuzzy_with_tokens, fuzzy_with_tokens,
$default, default,
$ignoretz, ignoretz,
$tzinfos).expect(&format!("Unable to parse date in Rust '{}'", $s)); tzinfos).expect(&format!("Unable to parse date in Rust '{}'", s));
if let Some(tzoffset) = rs_parsed.1 { if let Some(tzoffset) = rs_parsed.1 {
// Make sure the offsets are correct, and then normalize the naive date // Make sure the offsets are correct, and then normalize the naive date
// to match the aware date // to match the aware date
let offset_secs = py_offset_secs!($py, py_parsed); let offset_secs = py_offset_secs!(py, py_parsed);
// TODO: Should I be using utc_minus_local instead? // TODO: Should I be using utc_minus_local instead?
assert_eq!(offset_secs, tzoffset.local_minus_utc(), "Mismatched tzoffset for '{}'", $s); assert_eq!(offset_secs, tzoffset.local_minus_utc(), "Mismatched tzoffset for '{}'", s);
} else { } else {
// First make sure that Python doesn't have any timestamps set // First make sure that Python doesn't have any timestamps set
let py_tzoffset = py_parsed let py_tzoffset = py_parsed
.getattr($py, "tzinfo") .getattr(py, "tzinfo")
.expect("Unable to get `tzinfo` value"); .expect("Unable to get `tzinfo` value");
if py_tzoffset != $py.None() { if py_tzoffset != py.None() {
let offset_secs = py_offset_secs!($py, py_parsed); let offset_secs = py_offset_secs!(py, py_parsed);
assert!(false, "Tzinfo had value {} when dtparse didn't detect timezone for '{}'", offset_secs, $s); assert!(false, "Tzinfo had value {} when dtparse didn't detect timezone for '{}'", offset_secs, s);
} }
} }
@ -136,70 +141,66 @@ macro_rules! test_parse {
// TODO: Should years by i32? // TODO: Should years by i32?
let py_year: i32 = py_parsed let py_year: i32 = py_parsed
.getattr($py, "year") .getattr(py, "year")
.expect("Unable to get `year` value") .expect("Unable to get `year` value")
.extract($py) .extract(py)
.expect("Unable to convert `year` to i32"); .expect("Unable to convert `year` to i32");
assert_eq!(py_year, rs_dt.year(), "Mismatched year for '{}'", $s); assert_eq!(py_year, rs_dt.year(), "Mismatched year for '{}'", s);
let py_month: u32 = py_parsed let py_month: u32 = py_parsed
.getattr($py, "month") .getattr(py, "month")
.expect("Unable to get `month` value") .expect("Unable to get `month` value")
.extract($py) .extract(py)
.expect("Unable to convert `month` to u32"); .expect("Unable to convert `month` to u32");
assert_eq!(py_month, rs_dt.month(), "Mismatched month for '{}'", $s); assert_eq!(py_month, rs_dt.month(), "Mismatched month for '{}'", s);
let py_day: u32 = py_parsed let py_day: u32 = py_parsed
.getattr($py, "day") .getattr(py, "day")
.expect("Unable to get `day` value") .expect("Unable to get `day` value")
.extract($py) .extract(py)
.expect("Unable to convert `day` to u32"); .expect("Unable to convert `day` to u32");
assert_eq!(py_day, rs_dt.day(), "Mismatched day for '{}'", $s); assert_eq!(py_day, rs_dt.day(), "Mismatched day for '{}'", s);
let py_hour: u32 = py_parsed let py_hour: u32 = py_parsed
.getattr($py, "hour") .getattr(py, "hour")
.expect("Unable to get `hour` value") .expect("Unable to get `hour` value")
.extract($py) .extract(py)
.expect("Unable to convert `hour` to u32"); .expect("Unable to convert `hour` to u32");
assert_eq!(py_hour, rs_dt.hour(), "Mismatched hour for '{}'", $s); assert_eq!(py_hour, rs_dt.hour(), "Mismatched hour for '{}'", s);
let py_minute: u32 = py_parsed let py_minute: u32 = py_parsed
.getattr($py, "minute") .getattr(py, "minute")
.expect("Unable to get `minute` value") .expect("Unable to get `minute` value")
.extract($py) .extract(py)
.expect("Unable to convert `minute` to u32"); .expect("Unable to convert `minute` to u32");
assert_eq!(py_minute, rs_dt.minute(), "Mismatched minute for '{}'", $s); assert_eq!(py_minute, rs_dt.minute(), "Mismatched minute for '{}'", s);
let py_second: u32 = py_parsed let py_second: u32 = py_parsed
.getattr($py, "second") .getattr(py, "second")
.expect("Unable to get `second` value") .expect("Unable to get `second` value")
.extract($py) .extract(py)
.expect("Unable to convert `second` to u32"); .expect("Unable to convert `second` to u32");
assert_eq!(py_second, rs_dt.second(), "Mismatched second for '{}'", $s); assert_eq!(py_second, rs_dt.second(), "Mismatched second for '{}'", s);
let py_microsecond: u32 = py_parsed let py_microsecond: u32 = py_parsed
.getattr($py, "microsecond") .getattr(py, "microsecond")
.expect("Unable to get `microsecond` value") .expect("Unable to get `microsecond` value")
.extract($py) .extract(py)
.expect("Unable to convert `microsecond` to u32"); .expect("Unable to convert `microsecond` to u32");
assert_eq!( assert_eq!(
py_microsecond, py_microsecond,
rs_dt.nanosecond() / 1000, rs_dt.nanosecond() / 1000,
"Mismatched microsecond for '{}'", "Mismatched microsecond for '{}'",
$s s
); );
}; }
( macro_rules! test_parse {
$py:ident, ($py:ident, $parser:ident, $datetime:ident, $s:expr) => {
$parser:ident,
$datetime:ident,
$s:expr
) => {
let info = ParserInfo::default(); let info = ParserInfo::default();
let default_rsdate = &NaiveDate::from_ymd(2003, 9, 25).and_hms(0, 0, 0); let default_rsdate = &NaiveDate::from_ymd(2003, 9, 25).and_hms(0, 0, 0);
test_parse!( parse_and_assert(
$py, $py,
$parser, $parser,
$datetime, $datetime,
@ -221,7 +222,7 @@ macro_rules! test_parse_yearfirst {
let info = ParserInfo::default(); let info = ParserInfo::default();
let default_rsdate = &NaiveDate::from_ymd(2003, 9, 25).and_hms(0, 0, 0); let default_rsdate = &NaiveDate::from_ymd(2003, 9, 25).and_hms(0, 0, 0);
test_parse!( parse_and_assert(
$py, $py,
$parser, $parser,
$datetime, $datetime,
@ -243,7 +244,7 @@ macro_rules! test_parse_dayfirst {
let info = ParserInfo::default(); let info = ParserInfo::default();
let default_rsdate = &NaiveDate::from_ymd(2003, 9, 25).and_hms(0, 0, 0); let default_rsdate = &NaiveDate::from_ymd(2003, 9, 25).and_hms(0, 0, 0);
test_parse!( parse_and_assert(
$py, $py,
$parser, $parser,
$datetime, $datetime,
@ -265,7 +266,7 @@ macro_rules! test_parse_ignoretz {
let info = ParserInfo::default(); let info = ParserInfo::default();
let default_rsdate = &NaiveDate::from_ymd(2003, 9, 25).and_hms(0, 0, 0); let default_rsdate = &NaiveDate::from_ymd(2003, 9, 25).and_hms(0, 0, 0);
test_parse!( parse_and_assert(
$py, $py,
$parser, $parser,
$datetime, $datetime,