Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 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
1 change: 1 addition & 0 deletions .cspell.dict/cpython.txt
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ pybuilddir
pycore
pyinner
pydecimal
pyerrors
Pyfunc
pylifecycle
pymain
Expand Down
7 changes: 6 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,15 @@ jobs:
uses: ./.github/actions/install-macos-deps

- name: run rust tests
run: cargo test --workspace ${{ env.WORKSPACE_EXCLUDES }} --features threading ${{ env.CARGO_ARGS }}
run: cargo test --workspace --exclude rustpython-capi ${{ env.WORKSPACE_EXCLUDES }} --features threading ${{ env.CARGO_ARGS }}
Comment thread
bschoenmaeckers marked this conversation as resolved.
env:
INSTA_WORKSPACE_ROOT: ${{ github.workspace }}

- name: run c-api tests
working-directory: crates/capi
run: cargo test
if: runner.os != 'Windows' # Requires pyo3 0.29+ on Windows

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

anything wrong about this? we can pick proper pyo3 version for windows

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It used to work because we were accidentally linking with the system python. This is now solved. But to make the linker happy we need PyO3/pyo3#5866, this will land in PyO3 0.29 which is unreleased as the time of writing. Furthermore the windows linker expect all symbols to be defined we can only enable this at a later stage when we have defined all ABI3 symbols, see https://github.com/RustPython/RustPython/actions/runs/25607984643/job/75173077533


Comment thread
coderabbitai[bot] marked this conversation as resolved.
- run: cargo doc --locked
if: runner.os == 'Linux'

Expand Down
16 changes: 15 additions & 1 deletion crates/capi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
#![allow(clippy::missing_safety_doc)]

use crate::pyerrors::init_exception_statics;
use crate::pylifecycle::MAIN_INTERP;
use rustpython_vm::Interpreter;
pub use rustpython_vm::PyObject;
use rustpython_vm::{Context, Interpreter};
use std::sync::MutexGuard;

extern crate alloc;

pub mod object;
pub mod pyerrors;
pub mod pylifecycle;
pub mod pystate;
pub mod refcount;
mod util;

/// Get main interpreter of this process. Will be None if it has not been initialized yet.
pub fn get_main_interpreter() -> MutexGuard<'static, Option<Interpreter>> {
MAIN_INTERP
.lock()
.expect("Failed to lock interpreter mutex")
}

/// Set the main interpreter of this process. This method will panic when there is already an
/// interpreter set.
pub fn set_main_interpreter(interpreter: Interpreter) {
Comment thread
bschoenmaeckers marked this conversation as resolved.
Outdated
let mut interp = get_main_interpreter();
assert!(interp.is_none(), "Main interpreter is already set");
// Safety: Interpreter was not initialized before, so we can safely assume the statics are not used
unsafe { init_exception_statics(&Context::genesis().exceptions) };
*interp = Some(interpreter);
}
88 changes: 88 additions & 0 deletions crates/capi/src/object.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use crate::PyObject;
use crate::pystate::with_vm;
use core::ffi::{c_int, c_uint, c_ulong};
use rustpython_vm::builtins::PyType;
use rustpython_vm::{AsObject, Context, Py};

const PY_TPFLAGS_LONG_SUBCLASS: u64 = 1 << 24;
const PY_TPFLAGS_LIST_SUBCLASS: u64 = 1 << 25;
const PY_TPFLAGS_TUPLE_SUBCLASS: u64 = 1 << 26;
const PY_TPFLAGS_BYTES_SUBCLASS: u64 = 1 << 27;
const PY_TPFLAGS_UNICODE_SUBCLASS: u64 = 1 << 28;
const PY_TPFLAGS_DICT_SUBCLASS: u64 = 1 << 29;
const PY_TPFLAGS_BASE_EXC_SUBCLASS: u64 = 1 << 30;
const PY_TPFLAGS_TYPE_SUBCLASS: u64 = 1 << 31;

pub type PyTypeObject = Py<PyType>;

#[unsafe(no_mangle)]
pub unsafe extern "C" fn Py_TYPE(op: *mut PyObject) -> *const PyTypeObject {
unsafe { (*op).class() }
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn Py_IS_TYPE(op: *mut PyObject, ty: *mut PyTypeObject) -> c_int {
with_vm(|_vm| {
let obj = unsafe { &*op };
let ty = unsafe { &*ty };
obj.class().is(ty)
})
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn PyType_GetFlags(ptr: *const PyTypeObject) -> c_ulong {
let ctx = Context::genesis();
let zoo = &ctx.types;
let exp_zoo = &ctx.exceptions;

let ty = unsafe { &*ptr };
let mut flags = ty.slots.flags.bits();

if ty.is_subtype(zoo.int_type) {
flags |= PY_TPFLAGS_LONG_SUBCLASS;
}
if ty.is_subtype(zoo.list_type) {
flags |= PY_TPFLAGS_LIST_SUBCLASS
}
if ty.is_subtype(zoo.tuple_type) {
flags |= PY_TPFLAGS_TUPLE_SUBCLASS;
}
if ty.is_subtype(zoo.bytes_type) {
flags |= PY_TPFLAGS_BYTES_SUBCLASS;
}
if ty.is_subtype(zoo.str_type) {
flags |= PY_TPFLAGS_UNICODE_SUBCLASS;
}
if ty.is_subtype(zoo.dict_type) {
flags |= PY_TPFLAGS_DICT_SUBCLASS;
}
if ty.is_subtype(exp_zoo.base_exception_type) {
flags |= PY_TPFLAGS_BASE_EXC_SUBCLASS;
}
if ty.is_subtype(zoo.type_type) {
flags |= PY_TPFLAGS_TYPE_SUBCLASS;
}

flags as c_ulong
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
}

#[unsafe(no_mangle)]
pub extern "C" fn Py_GetConstantBorrowed(constant_id: c_uint) -> *mut PyObject {
with_vm(|vm| {
let ctx = &vm.ctx;
let constant = match constant_id {
0 => ctx.none.as_object(),
1 => ctx.false_value.as_object(),
2 => ctx.true_value.as_object(),
3 => ctx.ellipsis.as_object(),
4 => ctx.not_implemented.as_object(),
_ => {
return Err(
vm.new_system_error("Invalid constant ID passed to Py_GetConstantBorrowed")
);
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
.as_raw();
Ok(constant)
})
}
Loading
Loading