대부분 Rust인 Python 클라이언트를 구축한 방법

이번 주에 Python client library for Fluvio 의 추가를 발표하게 되어 기쁩니다. Python 클라이언트를 사용하는 것은 다른 클라이언트를 사용하는 것만큼 쉽습니다. 사용법은 hello world in Python tutorial 또는 documentation을 확인하세요.

이 게시물에서 우리는 Python 자체를 많이 작성하지 않고도 Python 클라이언트를 구축하기 위해 훌륭한 Rust 도구 중 일부를 활용할 수 있었던 방법에 대해 이야기할 것입니다.

개요



간단히 말해서, 우리는:
  • flapigen을 사용하여 Rust 구조체가 FFI를 통과하는 방법을 정의합니다.
  • 은 Python 프로젝트에서 rust-cpython 확장을 사용하고 호출합니다.

  • 설정



    시작하기 위해 두 가지 모두에 대해 설정된 새 프로젝트 폴더를 만듭니다.
    Rust 및 Python, cargovenv 사용.

    cargo new --lib my-python-lib
    cd my-python-lib
    python -m venv venv
    source venv/bin/activate
    


    위는 my-python-lib 이라는 이름의 Rust 크레이트를 만든 다음 Python virtual environment 을 설정합니다.

    Note: You'll need to have the rust toolchain and python 3.6 or above installed.



    녹 접착제



    이것을 Cargo.toml에 추가해야 합니다.

    [lib]
    crate-type = ["cdylib"]
    
    [dependencies]
    cpython = { version = "0.5", features = ["extension-module"] }
    
    [build-dependencies]
    flapigen = "0.6.0-pre7"
    

    crate-type = ["cdylib"]은 Rust에게 일반적인 크레이트가 아닌 C 호환 dynamic library으로 크레이트를 빌드하도록 지시합니다. 이 크레이트 유형을 사용하면 Python 코드가 Rust가 아닌 컴파일된 C 코드인 것처럼 라이브러리와 상호 작용할 수 있습니다.

    이제 다음을 추가하여 build.rsbuild script을 만듭니다.

    use flapigen::{LanguageConfig, PythonConfig};
    use std::{env, path::Path};
    
    fn main() {
        let in_src = Path::new("src").join("glue.rs.in");
        let out_dir = env::var("OUT_DIR").unwrap();
        let out_src = Path::new(&out_dir).join("glue.rs");
    
        let python_cfg = PythonConfig::new("my_python_lib".to_owned());
        let flap_gen =
            flapigen::Generator::new(LanguageConfig::PythonConfig(python_cfg)).rustfmt_bindings(true);
        flap_gen.expand("python bindings", &in_src, &out_src);
        println!("cargo:rerun-if-changed={}", in_src.display());
    }
    


    코드는 우리 프로젝트에서 실행되도록 flapigen을 설정합니다. 빌드할 때 src/glue.rs.in 에 작성한 "접착제 코드"를 읽고 Python과 상호 작용하는 Rust 코드를 생성하여 ${OUT_DIR}/glue.rs에 배치합니다.

    이제 다음과 같은 src/glue.rs.in 파일을 추가합니다.

    pub struct Foo {
        val: i32
    }
    impl Foo {
        pub fn new(val: i32) -> Self {
            Self {
                val
            }
        }
        pub fn set_field(&mut self, new_val: i32) {
            self.val = new_val;
        }
        pub fn val(&self) -> i32 {
            self.val
        }
    }
    foreign_class!(class Foo {
        self_type Foo;
        constructor Foo::new(_: i32) -> Foo;
        fn Foo::set_field(&mut self, _: i32);
        fn Foo::val(&self) -> i32;
    });
    


    이 간단한 예는 flapigen book에 게시되었으며 여기에 복사하여 붙여넣을 수 있습니다.
    src/lib.rs에는 현재 몇 가지 기본 테스트가 있어야 합니다. 다음과 같이 변경하겠습니다.

    #![allow(non_snake_case, unused)]
    
    include!(concat!(env!("OUT_DIR"), "/glue.rs"));
    


    이것은 빌드 스크립트를 사용할 때의 전형적인 Rust 패턴입니다. 코드는 ${OUT_DIR}/glue.rs에 있는 파일을 가져와서 빌드 디렉토리의 src/lib.rs에 내용을 포함합니다. 결과는 생성된 코드를lib.rs 파일입니다.

    이 섹션에서는 Flapigen을 사용하여 foreign_class 매크로를 많은 cpython 기능으로 확장하고 extension module으로, 화물은 이를 cdylib 으로 컴파일합니다. 어떻게 생겼는지 보려면 cargo-expand 을 설치하고 cargo expand을 실행하십시오. 생성된 많은 녹 코드를 얻을 수 있습니다.

    파이썬 접착제



    setup 에서 가상 환경을 만들었으며 이제 다음을 통해 일부 Python 도구를 설치해야 합니다.

    $ source venv/bin/activate && pip install setuptools-rust
    


    이제 python 패키지를 생성하기 위해 다음을 사용하여 setup.py이라는 파일을 생성합니다.

    from setuptools import setup
    from setuptools_rust import Binding, RustExtension
    
    setup(
        name="my-python-lib",
        version="1.0",
        rust_extensions=[RustExtension("my_python_lib", binding=Binding.RustCPython)],
        # rust extensions are not zip safe, just like C-extensions.
        zip_safe=False,
    )
    


    이것은 setuptools-rust을 바인딩으로 사용하는 것을 제외하고는 가장 기본적인 RustCPython 설정입니다.

    Rust와 Python 패키지를 빌드하려면 python setup.py develop 을 실행하면 됩니다. Python은 cargo을 호출하고 cdylib을 로컬 디렉토리로 이동합니다.

    모든 것을 테스트



    다음이 포함된 simple.py 스크립트를 생성합니다.

    from my_python_lib import Foo
    foo = Foo(1)
    print(foo.val())
    foo.set_field(11)
    print(foo.val())
    

    python simple.py을 통해 스크립트를 실행하면 다음과 같은 결과가 나타납니다.

    $ python simple.py
    1
    11
    


    자, Python에서 Rust를 호출했습니다!

    결론



    이 게시물의 출처는 fluvio-demo-apps-rust 저장소에서 얻을 수 있습니다.

    이것들은 Python 래퍼를 설정하기 위한 기본 사항일 뿐입니다. Fluvio Python 클라이언트에서 Rust 상자는 _fluvio_python 입니다. Rust 구조체를 python 클래스로 감싸는 private python 모듈은 우리에게 멋진 documentation generation을 제공합니다.
    pypi에 대한 패키징, 테스트 및 게시는 이 블로그의 범위를 벗어납니다. 추가 정보는 Makefile github publishing workflow을 확인하십시오.

    이 블로그는 here에 처음 게시되었습니다.

    좋은 웹페이지 즐겨찾기