Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Python module in Rust

dv
June 08, 2017
140

Python module in Rust

dv

June 08, 2017
Tweet

Transcript

  1. Who am I • Software Engineer @ Deep Sentinel (My

    First Job !) • Last Year: First try for CAS, SymPy with codegen • GitHub: @wdv4758h
  2. Documentation for Crates You can build your docs by cargo

    doc API doc with your docstring autogen for your crates: https://docs.rs/
  3. Lower Level ... Wait ! It doesn't look like that

    low level !? I pick what I want to show you :P
  4. Python Code • Pure Python Code • Python Code +

    Binary built from (C/C++/…) • Python Code + Other Language's Code
  5. ctypes • pip • IPython • PyInstaller • SymPy •

    prompt_toolkit • ... Cases CPython Extension • NumPy • Pillow • simplejson • TensorFlow • psutil • ... CFFI • Cryptography • psycopg2cffi • pyzmq • ...
  6. ctypes - quick view import ctypes from ctypes import c_char_p

    , c_void_p lib = ctypes.cdll.LoadLibrary("pycontw.so") lib.hello_world.argtypes = (c_void_p,) lib.hello.argtypes = (c_char_p,) lib.hello.restypes = c_char_p
  7. CFFI - quick view from cffi import FFI ffi =

    FFI() lib = ffi.dlopen("pycontw.so") ffi.cdef(""" void hello_world(); char* hello(const char* name); """)
  8. CPython Extension - simple call path import Find <modulename>.so POSIX

    dlsym PyModule_Create() PyInit_<modulename>()
  9. CPython Extension - quick view static PyMethodDef pycontw_methods[] = {

    {"hello_world", hello_world, METH_VARARGS, NULL}, {"hello", hello, METH_VARARGS, NULL}, {NULL, NULL, 0, NULL} };
  10. CPython Extension - quick view static PyModuleDef pycontw_module = {

    PyModuleDef_HEAD_INIT, "pycontw", "PyCon TW 2017", -1, pycontw_methods, NULL, NULL, NULL, NULL };
  11. CPython Extension - build from distutils.core import setup, Extension module1

    = Extension('pycontw', sources = ['cpython-extension-sample.c']) setup(name = 'pycontw', version = '1.0', description = 'This is a demo package', ext_modules = [module1])
  12. CPython + Rust: by ctypes or CFFI extern "C" fn

    myfunc() { println!("It's PyCon TW 2017 !!!"); }
  13. CPython + Rust: by ctypes or CFFI • ctypes: use

    it like C • CFFI: provide a C header for Rust code
  14. rust-cpython - quick view // things like Python "import" #[macro_use]

    extern crate cpython; use cpython::{PyObject, PyResult, Python};
  15. rust-cpython - quick view fn hello(_: Python, name: &str) ->

    PyResult<String> { Ok(format!("It's PyCon TW 2017, hello {} !!!", name)) }
  16. rust-cpython - quick view py_module_initializer!(pycontw, initpycontw, PyInit_pycontw, |py, m| {

    m.add(py, "__doc__", "PyCon TW 2017")?; m.add(py, "hello", py_fn!(py, hello(name: &str)))?; m.add(py, "hello_world", py_fn!(py, hello_world()))?; Ok(()) });
  17. rust-cpython - Cargo.toml [package] name = "pycontw" version = "0.1.0"

    [lib] name = "pycontw" crate-type = ["cdylib"] [dependencies] cpython = { version = "0.1.0", features = ["extension-module"] }
  18. setuptools-rust - setup.py from setuptools import setup from setuptools_rust import

    RustExtension setup( name='pycontw', version='2017', rust_extensions=[RustExtension('pycontw', './Cargo.toml')], packages=['pycontw'], # Rust extensions are not zip safe, just like C extensions zip_safe=False, )
  19. Dropbox Brotli in Rust - src/lib.rs extern crate brotli as

    _brotli; use _brotli::enc::reader::CompressorReader; py_module_initializer!(pycontw, initpycontw, PyInit_pycontw, |py, m| { m.add(py, "brotli", py_fn!(py, brotli(data: Vec<u8>)))?; Ok(()) });
  20. Dropbox Brotli in Rust - src/lib.rs fn brotli(_: Python, data:

    Vec<u8>) -> PyResult<Vec<u8>> { let quality = 5_u32; let lg_window_size = 20_u32; let mut enc_data = vec![]; let mut reader = CompressorReader::new(data.as_slice(), 4096, quality, lg_window_size); let _ = reader.read_to_end(&mut enc_data); Ok(enc_data) }
  21. Future Work • Build module by CI for multiple platforms

    • Cross Compile module • More complete Python & Rust integration • ...