-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Update chrono and PyO3 to the latest versions - Rewrite the library in stable Rust - Update manylinux to 2010
- Loading branch information
Showing
10 changed files
with
67 additions
and
97 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,4 +11,5 @@ Cargo.lock | |
projectFilesBackup/ | ||
tests.svg | ||
benchmark*.svg | ||
build/ | ||
build/ | ||
venv/ |
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 |
---|---|---|
|
@@ -12,3 +12,4 @@ projectFilesBackup/ | |
benchmark*.svg | ||
build/ | ||
*py[cdo] | ||
venv/ |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,11 @@ | ||
FROM quay.io/pypa/manylinux1_x86_64 | ||
FROM quay.io/pypa/manylinux2010_x86_64 | ||
|
||
RUN mkdir ~/rust-installer | ||
RUN curl -sL https://static.rust-lang.org/rustup.sh -o ~/rust-installer/rustup.sh | ||
RUN sh ~/rust-installer/rustup.sh --prefix=~/rust --channel=nightly -y --disable-sudo | ||
|
||
RUN curl https://sh.rustup.rs -sSf | bash -s -- -y | ||
RUN echo "source $HOME/.cargo/env" >> "$HOME/.bashrc" | ||
RUN echo "source $HOME/.cargo/env" >> "$HOME/.bash_profile" | ||
|
||
COPY . /app | ||
|
||
ENTRYPOINT /app/dist/manylinux/build_wheels.sh |
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 |
---|---|---|
@@ -1,26 +1,29 @@ | ||
#!/bin/sh | ||
set -e -x | ||
|
||
export PATH="$HOME/rust/bin:$PATH" | ||
export PATH="$HOME/.cargo/bin:$PATH" | ||
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$HOME/rust/lib" | ||
|
||
mkdir /tmp/wheels | ||
WHEELS_TMP_DIR=/tmp/wheels | ||
|
||
|
||
# Compile wheels | ||
for PYBIN in /opt/python/cp{27,35,36}*/bin; do | ||
for PYBIN in /opt/python/cp{35,36,37,38,39}*/bin; do | ||
export PYTHON_SYS_EXECUTABLE="$PYBIN/python" | ||
export PYTHON_LIB=$("${PYBIN}/python" -c "import sysconfig; print(sysconfig.get_config_var('LIBDIR'))") | ||
export LIBRARY_PATH="$LIBRARY_PATH:$PYTHON_LIB" | ||
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PYTHON_LIB" | ||
|
||
"${PYBIN}/pip" install -U setuptools setuptools-rust wheel | ||
"${PYBIN}/pip" wheel /app/ -w /tmp/wheels | ||
done | ||
|
||
# `auditwheel repair` copies the external shared libraries into the wheel itself | ||
# and automatically modifies the appropriate RPATH entries such that these libraries | ||
# will be picked up at runtime. This accomplishes a similar result as if the libraries | ||
# had been statically linked without requiring changes to the build system. | ||
for whl in /tmp/wheels/*; do | ||
auditwheel repair "$whl" -w /app/dist/wheels | ||
# `auditwheel repair` copies the external shared libraries into the wheel itself | ||
# and automatically modifies the appropriate RPATH entries such that these libraries | ||
# will be picked up at runtime. This accomplishes a similar result as if the libraries | ||
# had been statically linked without requiring changes to the build system. | ||
mkdir $WHEELS_TMP_DIR | ||
"${PYBIN}/pip" wheel /app/ -w $WHEELS_TMP_DIR | ||
for whl in $WHEELS_TMP_DIR/*; do | ||
auditwheel repair "$whl" -w /app/dist/wheels | ||
done | ||
rm -rf $WHEELS_TMP_DIR | ||
done |
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 |
---|---|---|
@@ -1,10 +1,5 @@ | ||
from __future__ import absolute_import | ||
|
||
from datetime import datetime | ||
from ._dtparse import Parser # Import Parser from the rust binary | ||
from ._dtparse import parse # Import Parser from the rust binary | ||
|
||
__all__ = ['parse'] | ||
|
||
# It doesn't make sense to create a Parser instance every time. | ||
# We'll create just one and put it's parse method into the global scope. | ||
parse = Parser(datetime).parse |
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 |
---|---|---|
@@ -1,84 +1,50 @@ | ||
#![feature(proc_macro, specialization, const_fn)] | ||
#![feature(const_fn, const_align_of, const_size_of, const_ptr_null, const_ptr_null_mut)] | ||
extern crate pyo3; | ||
|
||
extern crate chrono; | ||
|
||
use chrono::prelude::*; | ||
use pyo3::exceptions; | ||
use pyo3::prelude::*; | ||
use std::error::Error; | ||
use pyo3::types::*; | ||
|
||
// https://pyo3.rs/v0.11.1/module.html | ||
// This macro makes Rust compile a _dtparse.so binary in Python-compatible format. | ||
// Such a binary can be imported from Python just like a regular Python module. | ||
#[pymodule(_dtparse)] | ||
fn init_mod(_py: Python, m: &PyModule) -> PyResult<()> { | ||
// We fill this module with everything we want to make visible from Python. | ||
|
||
// https://pyo3.github.io/pyo3/guide/class.html#define-new-class | ||
// py::class macro transforms a Rust's Parser struct into a Python class | ||
#[py::class] | ||
struct Parser { | ||
// we keep the datetime class in the structure, because we can't import it into the global | ||
// scope in Rust. We should either accept it in constructor, or accept it as a parameter | ||
// for parse, or import it at runtime. This looks like the most sensible way of three. | ||
datetime_class: PyObject, | ||
// token is needed to create a "rich" Python class, which has access to Python interpreter. | ||
token: PyToken, | ||
} | ||
|
||
|
||
// https://pyo3.github.io/pyo3/guide/class.html#instance-methods | ||
// py::methods macro generates Python-compatible wrappers for functions in the impl block. | ||
#[py::methods] | ||
impl Parser { | ||
// https://pyo3.github.io/pyo3/guide/class.html#constructor | ||
// Constructor is not created by default. | ||
#[new] | ||
fn __new__(obj: &PyRawObject, datetime_class: PyObject) -> PyResult<()> { | ||
obj.init(| token| | ||
Parser { datetime_class, token } | ||
) | ||
} | ||
|
||
// This function will be transformed into a Python method. | ||
// It has a special argument py: Python. If specified, it gets passed by PyO3 implicitly. | ||
// It contains the Python interpreter - we're going to use it to create Python objects. | ||
fn parse(&self, py: Python, str_datetime: String, fmt: String) -> PyResult<PyObject> { | ||
#[pyfn(m, "parse")] | ||
fn parse(_py: Python, str_datetime: String, fmt: String) -> PyResult<&PyDateTime> { | ||
// Call chrono and ask it to parse the datetime for us | ||
let result = Utc.datetime_from_str( | ||
str_datetime.as_str(), fmt.as_str() | ||
); | ||
let chrono_dt = Utc.datetime_from_str(str_datetime.as_str(), fmt.as_str()); | ||
|
||
// In case chrono couldn't parse datetime, raise a ValueError with chrono's error message. | ||
// Because there are no exceptions in Rust, we return an exc::ValueError instance here. | ||
// In case chrono couldn't parse a datetime, raise a ValueError with chrono's error message. | ||
// Because there are no exceptions in Rust, we return a ValueError instance here. | ||
// By convention, it will make PyO3 wrapper raise an exception in Python interpreter. | ||
// https://pyo3.github.io/pyo3/guide/exception.html#raise-an-exception | ||
if result.is_err() { | ||
return Err(exc::ValueError::new( | ||
result.err().unwrap().description().to_owned() | ||
// https://pyo3.rs/v0.11.1/exception.html | ||
if chrono_dt.is_err() { | ||
return Err(exceptions::ValueError::py_err( | ||
chrono_dt.err().unwrap().to_string().to_owned(), | ||
)); | ||
} | ||
|
||
// In case everything's fine, get Rust datetime out of the result and transform | ||
// it into a Python datetime. We use Python here to create a tuple of arguments | ||
// and the datetime itself. | ||
let dt = result.unwrap(); | ||
let args = PyTuple::new( | ||
py, &[ | ||
dt.year(), | ||
dt.month() as i32, | ||
dt.day() as i32, | ||
dt.hour() as i32, | ||
dt.minute() as i32, | ||
dt.second() as i32, | ||
] | ||
// it into a Python datetime. | ||
let dt = chrono_dt.unwrap(); | ||
let result = PyDateTime::new( | ||
_py, | ||
dt.year(), | ||
dt.month() as u8, | ||
dt.day() as u8, | ||
dt.hour() as u8, | ||
dt.minute() as u8, | ||
dt.second() as u8, | ||
0, | ||
None, | ||
); | ||
Ok(self.datetime_class.call1(py, args)?) | ||
Ok(result?) | ||
} | ||
} | ||
|
||
|
||
// https://pyo3.github.io/pyo3/guide/module.html | ||
// This macro will make Rust compile a _dtparse.so binary in Python-compatible format. | ||
// Such binary could be imported in Python just like a normal Python module. | ||
#[py::modinit(_dtparse)] | ||
fn init_mod(_py: Python, m: &PyModule) -> PyResult<()> { | ||
// Here we fill an empty module with everything we want to make visible from Python. | ||
m.add_class::<Parser>()?; | ||
Ok(()) | ||
} |
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