Skip to content

Update docs #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
# Summary

- [Introduction](./intro.md)
- [Writing Functions](./writing_functions.md)
- [Introduction](introduction/index.md)
- [Getting Started](getting_started/index.md)
- [Installation](getting_started/installation.md)
- [Initial Setup](getting_started/initial_setup.md)
- [Interop](interop/index.md)
- [Calling Rust from Python](interop/rust_from_python.md)
- [Calling Python from Rust](interop/python_from_rust.md)
4 changes: 4 additions & 0 deletions src/getting_started/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Getting Started

- [Installation](./installation.md)
- [Initial Setup](./initial_setup.md)
73 changes: 73 additions & 0 deletions src/getting_started/initial_setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Initial Setup

First `rustpython_vm` needs to be imported.
If `rustpython` is installed, it can be imported as a re-export:
```rust
use rustpython::vm;
```

if `rustpython_vm` is installed, it can be imported just like any other module.

```rust
use rustpython::vm;

fn main() -> vm::PyResult<()> {
vm::Interpreter::without_stdlib(Default::default()).enter(|vm| {
let scope = vm.new_scope_with_builtins();
let source = r#"print("Hello World!")"#;
let code_obj = vm
.compile(source, vm::compiler::Mode::Exec, "<embedded>".to_owned())
.map_err(|err| vm.new_syntax_error(&err, Some(source)))?;

vm.run_code_obj(code_obj, scope)?;

Ok(())
})
}
```

This will print `Hello World!` to the console.

## Adding the standard library
If the `stdlib` feature is enabled,
the standard library can be added to the interpreter by calling `add_native_modules`
with the result of `rustpython_stdlib::get_module_inits()`.
```rust
use rustpython::vm as vm;
use std::process::ExitCode;
use vm::{Interpreter, builtins::PyStrRef};

fn py_main(interp: &Interpreter) -> vm::PyResult<PyStrRef> {
interp.enter(|vm| {
let scope = vm.new_scope_with_builtins();
let source = r#"print("Hello World!")"#;
let code_obj = vm
.compile(source, vm::compiler::Mode::Exec, "<embedded>".to_owned())
.map_err(|err| vm.new_syntax_error(&err, Some(source)))?;

vm.run_code_obj(code_obj, scope)?;
})
}

fn main() -> ExitCode {
// Add standard library path
let mut settings = vm::Settings::default();
settings.path_list.push("Lib".to_owned());
let interp = vm::Interpreter::with_init(settings, |vm| {
vm.add_native_modules(rustpython_stdlib::get_module_inits());
});
let result = py_main(&interp);
let result = result.map(|result| {
println!("name: {result}");
});
ExitCode::from(interp.run(|_vm| result))
}
```

to import a module, the following code can be used:
```rust, no_run
// Add local library path
vm.insert_sys_path(vm.new_pyobj("<module_path>"))
.expect("add examples to sys.path failed");
let module = vm.import("<module_name>", 0)?;
```
40 changes: 40 additions & 0 deletions src/getting_started/installation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Installation
## Requirements
RustPython requires Rust latest stable version to be installed

## Stable
The latest stable version of the library can be installed using the following command:
```bash
cargo add rustpython
```

or by adding the following to your `Cargo.toml`:
```toml
[dependencies]
rustpython = "0.4"
```

## Nightly
Nightly releases are built weekly and are released on git.
```toml
[dependencies]
rustpython = { git = "https://github.com/RustPython/RustPython", tag = "2025-02-24-main-13" }
```

The tag should be pointed to the latest tag found at https://github.com/RustPython/RustPython/tags.

## Features
By default `threading`, `stdlib`, and `importlib` are enabled.
### `bz2`
If you'd like to use the `bz2` module, you can enable the `bz2` feature.
### `stdlib`
`stdlib` is the default feature that enables the standard library.
### `sqlite`
If you'd like to use the `sqlite3` module, you can enable the `sqlite` feature.
### `ssl`
If you'd like to make https requests, you can enable the ssl feature,
which also lets you install the pip package manager.
Note that on Windows, you may need to install OpenSSL, or you can enable the ssl-vendor feature instead,
which compiles OpenSSL for you but requires a C compiler, perl, and make.
OpenSSL version 3 is expected and tested in CI. Older versions may not work.

3 changes: 3 additions & 0 deletions src/interop/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Interpretation between Rust and Python
- [Calling Rust from Python](./rust_from_python.md)
- [Calling Python from Rust](./python_from_rust.md)
2 changes: 2 additions & 0 deletions src/interop/python_from_rust.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Calling Python from Rust
TODO.
171 changes: 171 additions & 0 deletions src/interop/rust_from_python.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
# Calling Rust from Python
## Structure
```rust, ignore
use rustpython::vm::pymodule;
#[pymodule]
mod test_module {
#[pyattr]
pub const THE_ANSWER: i32 = 42;

#[pyfunction]
pub fn add(a: i32, b: i32) -> i32 {
a + b
}

#[pyattr]
#[pyclass]
pub struct TestClass {
pub value: i32,
}

#[pyclass]
impl TestClass {
#[pygetset]
pub fn value(&self) -> i32 {
self.value
}

#[pymethod]
pub fn get_info(&self) -> i32 {
self.value * 2
}
}
}
```
This code defines a Python module named `test_module` with two items:
a constant named `THE_ANSWER` and a function named `add`.
The `#[pymodule]` attribute is used to mark the module,
and the `#[pyattr]` and `#[pyfunction]` attributes are used to mark the constant and function, respectively.

RustPython allows for 3 types of items in a module:
- Variables: Defined using the `#[pyattr]` attribute.
- Functions: Defined using the `#[pyfunction]` attribute.
- Classes: Defined using the `#[pyclass]` attribute.

## General Configuration
Most attributes have a `name` parameter that can be used to specify the name of the item in Python.
If the `name` parameter is not provided, the Rust identifier is used as the name in Python.

## Variables
Variables are defined using the `#[pyattr]` attribute.
A variable can either be a constant or a function.
Note that classes are treated as attributes in RustPython
and are annotated with `#[pyattr]` as well, but that can be done away with if needed.
```rust, no_run
#[pyattr]
const THE_ANSWER: i32 = 42;
// ... or
#[pyattr]
fn the_answer() -> i32 {
42
}
// ... or
// this will cache the result of the function
// and return the same value every time it is called
#[pyattr(once)]
fn cached_answer() -> i32 {
42
}
```

## Valid Arguments/Return Types
Every input and 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:
- Any `T` when `PyResult<T>` is possible
- `PyObjectRef`
- `PyResult<()>` and `()` as `None`
- `PyRef<T: PyValue>` like `PyIntRef`, `PyStrRef`
- `T: PyValue` like `PyInt`, `PyStr`
- Numbers like `usize` or `f64` for `PyInt` and `PyFloat`
- `String` for `PyStr`
- And more types implementing `IntoPyObject`.

The `vm` paramter is optional. 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`. The `vm` parameter does not need to be passed in by the python code.

If needed a seperate struct can be used for arguments using the `FromArgs` trait like so:

```rust
#[derive(FromArgs)]
struct BisectArgs {
a: PyObjectRef,
x: PyObjectRef
#[pyarg(any, optional)]
lo: OptionalArg<ArgIndex>,
#[pyarg(any, optional)]
hi: OptionalArg<ArgIndex>,
#[pyarg(named, default)]
key: Option<PyObjectRef>,
}

#[pyfunction]
fn bisect_left(
BisectArgs { a, x, lo, hi, key }: BisectArgs,
vm: &VirtualMachine,
) -> PyResult<usize> {
// ...
}

// or ...

#[pyfunction]
fn bisect_left(
args: BisectArgs,
vm: &VirtualMachine,
) -> PyResult<usize> {
// ...
}
```

## Errors

Returning a PyResult is the supported error handling strategy. Builtin python errors are created with `vm.new_xxx_error` methods.

### Custom Errors

```
#[pyattr(once)]
fn error(vm: &VirtualMachine) -> PyTypeRef {
vm.ctx.new_exception_type(
"<module_name>",
"<error_name>",
Some(vec![vm.ctx.exceptions.exception_type.to_owned()]),
)
}

// convenience function
fn new_error(message: &str, vm: &VirtualMachine) -> PyBaseExceptionRef {
vm.new_exception_msg(vm.class("<module_name>", "<error_name>"), message.to_owned())
}
```

## Functions
Functions are defined using the `#[pyfunction]` attribute.
```rust, no_run
#[pyfunction]
fn add(a: i32, b: i32) -> i32 {
a + b
}
```

## Classes
Classes are defined using the `#[pyclass]` attribute.
```rust, no_run
#[pyclass]
pub struct TestClass {
pub value: i32,
}
#[pyclass]
impl TestClass {
}
```
### Associated Data
TODO.
### Methods
TODO.
### Getters and Setters
TODO.
### Class Methods
TODO.
### Static Methods
TODO.
### Inheritance
TODO.
3 changes: 3 additions & 0 deletions src/introduction/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Introduction

RustPython is a Python interpreter written in Rust.
45 changes: 0 additions & 45 deletions src/writing_functions.md

This file was deleted.