Skip to content

Commit a9addfe

Browse files
committed
rewrite of the book
1 parent 88ba737 commit a9addfe

File tree

9 files changed

+253
-47
lines changed

9 files changed

+253
-47
lines changed

Diff for: src/SUMMARY.md

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
# Summary
22

3-
- [Introduction](./intro.md)
4-
- [Writing Functions](./writing_functions.md)
3+
- [Introduction](introduction/index.md)
4+
- [Getting Started](getting_started/index.md)
5+
- [Installation](getting_started/installation.md)
6+
- [Initial Setup](getting_started/initial_setup.md)
7+
- [Interop](interop/index.md)
8+
- [Calling Rust from Python](interop/rust_from_python.md)
9+
- [Calling Python from Rust](interop/python_from_rust.md)

Diff for: src/getting_started/index.md

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Getting Started
2+
3+
- [Installation](./installation.md)
4+
- [Initial Setup](./initial_setup.md)

Diff for: src/getting_started/initial_setup.md

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Initial Setup
2+
3+
First `rustpython_vm` needs to be imported.
4+
If `rustpython` is installed, it can be imported as a re-export:
5+
```rust
6+
use rustpython::vm;
7+
```
8+
9+
if `rustpython_vm` is installed, it can be imported just like any other module.
10+
11+
```rust
12+
use rustpython::vm;
13+
14+
fn main() -> vm::PyResult<()> {
15+
vm::Interpreter::without_stdlib(Default::default()).enter(|vm| {
16+
let scope = vm.new_scope_with_builtins();
17+
let source = r#"print("Hello World!")"#;
18+
let code_obj = vm
19+
.compile(source, vm::compiler::Mode::Exec, "<embedded>".to_owned())
20+
.map_err(|err| vm.new_syntax_error(&err, Some(source)))?;
21+
22+
vm.run_code_obj(code_obj, scope)?;
23+
24+
Ok(())
25+
})
26+
}
27+
```
28+
29+
This will print `Hello World!` to the console.
30+
31+
## Adding the standard library
32+
If the `stdlib` feature is enabled,
33+
the standard library can be added to the interpreter by calling `add_native_modules`
34+
with the result of `rustpython_stdlib::get_module_inits()`.
35+
```rust
36+
use rustpython::vm as vm;
37+
use std::process::ExitCode;
38+
use vm::{Interpreter, builtins::PyStrRef};
39+
40+
fn py_main(interp: &Interpreter) -> vm::PyResult<PyStrRef> {
41+
interp.enter(|vm| {
42+
let scope = vm.new_scope_with_builtins();
43+
let source = r#"print("Hello World!")"#;
44+
let code_obj = vm
45+
.compile(source, vm::compiler::Mode::Exec, "<embedded>".to_owned())
46+
.map_err(|err| vm.new_syntax_error(&err, Some(source)))?;
47+
48+
vm.run_code_obj(code_obj, scope)?;
49+
})
50+
}
51+
52+
fn main() -> ExitCode {
53+
// Add standard library path
54+
let mut settings = vm::Settings::default();
55+
settings.path_list.push("Lib".to_owned());
56+
let interp = vm::Interpreter::with_init(settings, |vm| {
57+
vm.add_native_modules(rustpython_stdlib::get_module_inits());
58+
});
59+
let result = py_main(&interp);
60+
let result = result.map(|result| {
61+
println!("name: {result}");
62+
});
63+
ExitCode::from(interp.run(|_vm| result))
64+
}
65+
```
66+
67+
to import a module, the following code can be used:
68+
```rust, no_run
69+
// Add local library path
70+
vm.insert_sys_path(vm.new_pyobj("<module_path>"))
71+
.expect("add examples to sys.path failed");
72+
let module = vm.import("<module_name>", 0)?;
73+
```

Diff for: src/getting_started/installation.md

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Installation
2+
## Requirements
3+
RustPython requires Rust latest stable version to be installed
4+
5+
## Stable
6+
The latest stable version of the library can be installed using the following command:
7+
```bash
8+
cargo add rustpython
9+
```
10+
11+
or by adding the following to your `Cargo.toml`:
12+
```toml
13+
[dependencies]
14+
rustpython = "0.4"
15+
```
16+
17+
## Nightly
18+
Nightly releases are built weekly and are released on git.
19+
```toml
20+
[dependencies]
21+
rustpython = { git = "https://github.com/RustPython/RustPython", tag = "2025-02-24-main-13" }
22+
```
23+
24+
The tag should be pointed to the latest tag found at https://github.com/RustPython/RustPython/tags.
25+
26+
## Features
27+
By default `threading`, `stdlib`, and `importlib` are enabled.
28+
### `bz2`
29+
If you'd like to use the `bz2` module, you can enable the `bz2` feature.
30+
### `stdlib`
31+
`stdlib` is the default feature that enables the standard library.
32+
### `sqlite`
33+
If you'd like to use the `sqlite3` module, you can enable the `sqlite` feature.
34+
### `ssl`
35+
If you'd like to make https requests, you can enable the ssl feature,
36+
which also lets you install the pip package manager.
37+
Note that on Windows, you may need to install OpenSSL, or you can enable the ssl-vendor feature instead,
38+
which compiles OpenSSL for you but requires a C compiler, perl, and make.
39+
OpenSSL version 3 is expected and tested in CI. Older versions may not work.
40+

Diff for: src/interop/index.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Interpretation between Rust and Python
2+
- [Calling Rust from Python](./rust_from_python.md)
3+
- [Calling Python from Rust](./python_from_rust.md)

Diff for: src/interop/python_from_rust.md

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Calling Python from Rust
2+
TODO.

Diff for: src/interop/rust_from_python.md

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# Calling Rust from Python
2+
## Structure
3+
```rust, ignore
4+
use rustpython::vm::pymodule;
5+
#[pymodule]
6+
mod test_module {
7+
#[pyattr]
8+
pub const THE_ANSWER: i32 = 42;
9+
10+
#[pyfunction]
11+
pub fn add(a: i32, b: i32) -> i32 {
12+
a + b
13+
}
14+
15+
#[pyattr]
16+
#[pyclass]
17+
pub struct TestClass {
18+
pub value: i32,
19+
}
20+
21+
#[pyclass]
22+
impl TestClass {
23+
#[pygetset]
24+
pub fn value(&self) -> i32 {
25+
self.value
26+
}
27+
28+
#[pymethod]
29+
pub fn get_info(&self) -> i32 {
30+
self.value * 2
31+
}
32+
}
33+
}
34+
```
35+
This code defines a Python module named `test_module` with two items:
36+
a constant named `THE_ANSWER` and a function named `add`.
37+
The `#[pymodule]` attribute is used to mark the module,
38+
and the `#[pyattr]` and `#[pyfunction]` attributes are used to mark the constant and function, respectively.
39+
40+
RustPython allows for 3 types of items in a module:
41+
- Variables: Defined using the `#[pyattr]` attribute.
42+
- Functions: Defined using the `#[pyfunction]` attribute.
43+
- Classes: Defined using the `#[pyclass]` attribute.
44+
45+
## General Configuration
46+
Most attributes have a `name` parameter that can be used to specify the name of the item in Python.
47+
If the `name` parameter is not provided, the Rust identifier is used as the name in Python.
48+
49+
## Variables
50+
Variables are defined using the `#[pyattr]` attribute.
51+
A variable can either be a constant or a function.
52+
Note that classes are treated as attributes in RustPython
53+
and are annotated with `#[pyattr]` as well, but that can be done away with if needed.
54+
```rust, no_run
55+
#[pyattr]
56+
const THE_ANSWER: i32 = 42;
57+
// ... or
58+
#[pyattr]
59+
fn the_answer() -> i32 {
60+
42
61+
}
62+
// ... or
63+
// this will cache the result of the function
64+
// and return the same value every time it is called
65+
#[pyattr(once)]
66+
fn cached_answer() -> i32 {
67+
42
68+
}
69+
```
70+
71+
## Valid Arguments
72+
73+
Every return value must be convertible to PyResult. This is defined as IntoPyResult trait. So any return value of them must implement IntoPyResult. It will be PyResult<PyObjectRef>, PyObjectRef and any PyResult<T> when T implements IntoPyObject. Practically we can list them like:
74+
75+
76+
The `vm` paramter is just suffix. We add it as the last parameter unless we don't use `vm` at all - very rare case. It takes an object `obj` as `PyObjectRef`, which is a general python object. It returns `PyResult<String>`, which will turn into `PyResult<PyObjectRef>` the same representation of `PyResult`.
77+
78+
Every return value must be convertible to `PyResult`. This is defined as `IntoPyResult` trait. So any return value of them must implement `IntoPyResult`. It will be `PyResult<PyObjectRef>`, `PyObjectRef` and any `PyResult<T>` when T implements `IntoPyObject`. Practically we can list them like:
79+
- Any `T` when `PyResult<T>` is possible
80+
- `PyObjectRef`
81+
- `PyResult<()>` and `()` as `None`
82+
- `PyRef<T: PyValue>` like `PyIntRef`, `PyStrRef`
83+
- `T: PyValue` like `PyInt`, `PyStr`
84+
- Numbers like `usize` or `f64` for `PyInt` and `PyFloat`
85+
- `String` for `PyStr`
86+
- And more types implementing `IntoPyObject`.
87+
88+
The same could mostly be said about input arguments.
89+
90+
## Functions
91+
Functions are defined using the `#[pyfunction]` attribute.
92+
```rust, no_run
93+
#[pyfunction]
94+
fn add(a: i32, b: i32) -> i32 {
95+
a + b
96+
}
97+
```
98+
99+
## Classes
100+
Classes are defined using the `#[pyclass]` attribute.
101+
```rust, no_run
102+
#[pyclass]
103+
pub struct TestClass {
104+
pub value: i32,
105+
}
106+
#[pyclass]
107+
impl TestClass {
108+
}
109+
```
110+
### Associated Data
111+
TODO.
112+
### Methods
113+
TODO.
114+
### Getters and Setters
115+
TODO.
116+
### Class Methods
117+
TODO.
118+
### Static Methods
119+
TODO.
120+
### Inheritance
121+
TODO.

Diff for: src/introduction/index.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Introduction
2+
3+
RustPython is a Python interpreter written in Rust.

Diff for: src/writing_functions.md

-45
This file was deleted.

0 commit comments

Comments
 (0)