Various fixes to edge cases with GILGuard
This commit is contained in:
parent
11b6bacc4d
commit
1f37dbc1a7
|
@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
||||||
- Correct FFI definitions `Py_SetProgramName` and `Py_SetPythonHome` to take `*const` argument instead of `*mut`. [#1021](https://github.com/PyO3/pyo3/pull/1021)
|
- Correct FFI definitions `Py_SetProgramName` and `Py_SetPythonHome` to take `*const` argument instead of `*mut`. [#1021](https://github.com/PyO3/pyo3/pull/1021)
|
||||||
- Rename `PyString::to_string` to `to_str`, change return type `Cow<str>` to `&str`. [#1023](https://github.com/PyO3/pyo3/pull/1023)
|
- Rename `PyString::to_string` to `to_str`, change return type `Cow<str>` to `&str`. [#1023](https://github.com/PyO3/pyo3/pull/1023)
|
||||||
- Correct FFI definition `_PyLong_AsByteArray` `*mut c_uchar` argument instead of `*const c_uchar`. [#1029](https://github.com/PyO3/pyo3/pull/1029)
|
- Correct FFI definition `_PyLong_AsByteArray` `*mut c_uchar` argument instead of `*const c_uchar`. [#1029](https://github.com/PyO3/pyo3/pull/1029)
|
||||||
|
- Add `T: Send` bound to the return value of `Python::allow_threads`. [#1036](https://github.com/PyO3/pyo3/pull/1036)
|
||||||
- Rename `PYTHON_SYS_EXECUTABLE` to `PYO3_PYTHON`. The old name will continue to work but will be undocumented, and will be removed in a future release. [#1039](https://github.com/PyO3/pyo3/pull/1039)
|
- Rename `PYTHON_SYS_EXECUTABLE` to `PYO3_PYTHON`. The old name will continue to work but will be undocumented, and will be removed in a future release. [#1039](https://github.com/PyO3/pyo3/pull/1039)
|
||||||
- `PyType::as_type_ptr` is no longer `unsafe`. [#1047](https://github.com/PyO3/pyo3/pull/1047)
|
- `PyType::as_type_ptr` is no longer `unsafe`. [#1047](https://github.com/PyO3/pyo3/pull/1047)
|
||||||
- Change `PyIterator::from_object` to return `PyResult<PyIterator>` instead of `Result<PyIterator, PyDowncastError>`. [#1051](https://github.com/PyO3/pyo3/pull/1051)
|
- Change `PyIterator::from_object` to return `PyResult<PyIterator>` instead of `Result<PyIterator, PyDowncastError>`. [#1051](https://github.com/PyO3/pyo3/pull/1051)
|
||||||
|
@ -26,6 +27,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
||||||
### Removed
|
### Removed
|
||||||
- Remove `PyString::as_bytes`. [#1023](https://github.com/PyO3/pyo3/pull/1023)
|
- Remove `PyString::as_bytes`. [#1023](https://github.com/PyO3/pyo3/pull/1023)
|
||||||
- Remove `Python::register_any`. [#1023](https://github.com/PyO3/pyo3/pull/1023)
|
- Remove `Python::register_any`. [#1023](https://github.com/PyO3/pyo3/pull/1023)
|
||||||
|
- Remove `GILGuard::acquire` from the public API. Use `Python::acquire_gil` or `Python::with_gil`. [#1036](https://github.com/PyO3/pyo3/pull/1036)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Conversion from types with an `__index__` method to Rust BigInts. [#1027](https://github.com/PyO3/pyo3/pull/1027)
|
- Conversion from types with an `__index__` method to Rust BigInts. [#1027](https://github.com/PyO3/pyo3/pull/1027)
|
||||||
|
|
|
@ -879,12 +879,8 @@ impl PyGCProtocol for ClassWithGCSupport {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __clear__(&mut self) {
|
fn __clear__(&mut self) {
|
||||||
if let Some(obj) = self.obj.take() {
|
// Clear reference, this decrements ref counter.
|
||||||
// Release reference, this decrements ref counter.
|
self.obj = None;
|
||||||
let gil = GILGuard::acquire();
|
|
||||||
let py = gil.python();
|
|
||||||
py.release(obj);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -77,14 +77,12 @@ fn supermodule(_py: Python, module: &PyModule) -> PyResult<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nested_call() {
|
# Python::with_gil(|py| {
|
||||||
let gil = GILGuard::acquire();
|
# let supermodule = wrap_pymodule!(supermodule)(py);
|
||||||
let py = gil.python();
|
# let ctx = [("supermodule", supermodule)].into_py_dict(py);
|
||||||
let supermodule = wrap_pymodule!(supermodule)(py);
|
#
|
||||||
let ctx = [("supermodule", supermodule)].into_py_dict(py);
|
# py.run("assert supermodule.submodule.subfunction() == 'Subfunction'", None, Some(&ctx)).unwrap();
|
||||||
|
# })
|
||||||
py.run("assert supermodule.submodule.subfunction() == 'Subfunction'", None, Some(&ctx)).unwrap();
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
This way, you can create a module hierarchy within a single extension module.
|
This way, you can create a module hierarchy within a single extension module.
|
||||||
|
|
|
@ -52,7 +52,7 @@ extern "C" {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum PyGILState_STATE {
|
pub enum PyGILState_STATE {
|
||||||
PyGILState_LOCKED,
|
PyGILState_LOCKED,
|
||||||
PyGILState_UNLOCKED,
|
PyGILState_UNLOCKED,
|
||||||
|
|
63
src/gil.rs
63
src/gil.rs
|
@ -12,13 +12,13 @@ static START: sync::Once = sync::Once::new();
|
||||||
thread_local! {
|
thread_local! {
|
||||||
/// This is a internal counter in pyo3 monitoring whether this thread has the GIL.
|
/// This is a internal counter in pyo3 monitoring whether this thread has the GIL.
|
||||||
///
|
///
|
||||||
/// It will be incremented whenever a GILPool is created, and decremented whenever they are
|
/// It will be incremented whenever a GILGuard or GILPool is created, and decremented whenever
|
||||||
/// dropped.
|
/// they are dropped.
|
||||||
///
|
///
|
||||||
/// As a result, if this thread has the GIL, GIL_COUNT is greater than zero.
|
/// As a result, if this thread has the GIL, GIL_COUNT is greater than zero.
|
||||||
///
|
///
|
||||||
/// pub(crate) because it is manipulated temporarily by Python::allow_threads
|
/// pub(crate) because it is manipulated temporarily by Python::allow_threads
|
||||||
pub(crate) static GIL_COUNT: Cell<u32> = Cell::new(0);
|
pub(crate) static GIL_COUNT: Cell<usize> = Cell::new(0);
|
||||||
|
|
||||||
/// Temporally hold objects that will be released when the GILPool drops.
|
/// Temporally hold objects that will be released when the GILPool drops.
|
||||||
static OWNED_OBJECTS: RefCell<Vec<NonNull<ffi::PyObject>>> = RefCell::new(Vec::with_capacity(256));
|
static OWNED_OBJECTS: RefCell<Vec<NonNull<ffi::PyObject>>> = RefCell::new(Vec::with_capacity(256));
|
||||||
|
@ -110,7 +110,8 @@ pub fn prepare_freethreaded_python() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RAII type that represents the Global Interpreter Lock acquisition.
|
/// RAII type that represents the Global Interpreter Lock acquisition. To get hold of a value
|
||||||
|
/// of this type, see [`Python::acquire_gil`](struct.Python.html#method.acquire_gil).
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -128,15 +129,17 @@ pub struct GILGuard {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GILGuard {
|
impl GILGuard {
|
||||||
/// Acquires the global interpreter lock, which allows access to the Python runtime. This is
|
/// Retrieves the marker type that proves that the GIL was acquired.
|
||||||
/// safe to call multiple times without causing a deadlock.
|
#[inline]
|
||||||
///
|
pub fn python(&self) -> Python {
|
||||||
/// If the Python runtime is not already initialized, this function will initialize it.
|
unsafe { Python::assume_gil_acquired() }
|
||||||
/// See [prepare_freethreaded_python()](fn.prepare_freethreaded_python.html) for details.
|
}
|
||||||
|
|
||||||
|
/// PyO3 internal API for acquiring the GIL. The public API is Python::acquire_gil.
|
||||||
///
|
///
|
||||||
/// If PyO3 does not yet have a `GILPool` for tracking owned PyObject references, then this
|
/// If PyO3 does not yet have a `GILPool` for tracking owned PyObject references, then this
|
||||||
/// new `GILGuard` will also contain a `GILPool`.
|
/// new `GILGuard` will also contain a `GILPool`.
|
||||||
pub fn acquire() -> GILGuard {
|
pub(crate) fn acquire() -> GILGuard {
|
||||||
prepare_freethreaded_python();
|
prepare_freethreaded_python();
|
||||||
|
|
||||||
let gstate = unsafe { ffi::PyGILState_Ensure() }; // acquire GIL
|
let gstate = unsafe { ffi::PyGILState_Ensure() }; // acquire GIL
|
||||||
|
@ -146,6 +149,8 @@ impl GILGuard {
|
||||||
let pool = if !gil_is_acquired() {
|
let pool = if !gil_is_acquired() {
|
||||||
Some(unsafe { GILPool::new() })
|
Some(unsafe { GILPool::new() })
|
||||||
} else {
|
} else {
|
||||||
|
// As no GILPool was created, need to update the gil count manually.
|
||||||
|
increment_gil_count();
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -154,20 +159,35 @@ impl GILGuard {
|
||||||
pool: ManuallyDrop::new(pool),
|
pool: ManuallyDrop::new(pool),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves the marker type that proves that the GIL was acquired.
|
|
||||||
#[inline]
|
|
||||||
pub fn python(&self) -> Python {
|
|
||||||
unsafe { Python::assume_gil_acquired() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The Drop implementation for `GILGuard` will release the GIL.
|
/// The Drop implementation for `GILGuard` will release the GIL.
|
||||||
impl Drop for GILGuard {
|
impl Drop for GILGuard {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
// First up, try to detect if the order of destruction is correct.
|
||||||
|
let _ = GIL_COUNT.try_with(|c| {
|
||||||
|
if self.gstate == ffi::PyGILState_STATE::PyGILState_UNLOCKED && c.get() != 1 {
|
||||||
|
// XXX: this panic commits to leaking all objects in the pool as well as
|
||||||
|
// potentially meaning the GIL never releases. Perhaps should be an abort?
|
||||||
|
// Unfortunately abort UX is much worse than panic.
|
||||||
|
panic!("The first GILGuard acquired must be the last one dropped.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// If this GILGuard doesn't own a pool, then need to decrease the count after dropping
|
||||||
|
// all objects from the pool.
|
||||||
|
let should_decrement = self.pool.is_none();
|
||||||
|
|
||||||
|
// Drop the objects in the pool before attempting to release the thread state
|
||||||
unsafe {
|
unsafe {
|
||||||
// Must drop the objects in the pool before releasing the GILGuard
|
|
||||||
ManuallyDrop::drop(&mut self.pool);
|
ManuallyDrop::drop(&mut self.pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
if should_decrement {
|
||||||
|
decrement_gil_count();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
ffi::PyGILState_Release(self.gstate);
|
ffi::PyGILState_Release(self.gstate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -328,7 +348,7 @@ pub unsafe fn register_owned(_py: Python, obj: NonNull<ffi::PyObject>) {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn increment_gil_count() {
|
fn increment_gil_count() {
|
||||||
// Ignores the error in case this function called from `atexit`.
|
// Ignores the error in case this function called from `atexit`.
|
||||||
let _ = GIL_COUNT.with(|c| c.set(c.get() + 1));
|
let _ = GIL_COUNT.try_with(|c| c.set(c.get() + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decrement pyo3's internal GIL count - to be called whenever GILPool or GILGuard is dropped.
|
/// Decrement pyo3's internal GIL count - to be called whenever GILPool or GILGuard is dropped.
|
||||||
|
@ -522,16 +542,15 @@ mod test {
|
||||||
drop(pool);
|
drop(pool);
|
||||||
assert_eq!(get_gil_count(), 2);
|
assert_eq!(get_gil_count(), 2);
|
||||||
|
|
||||||
// Creating a new GILGuard should not increment the gil count if a GILPool already exists
|
|
||||||
let gil2 = Python::acquire_gil();
|
let gil2 = Python::acquire_gil();
|
||||||
|
assert_eq!(get_gil_count(), 3);
|
||||||
|
|
||||||
|
drop(gil2);
|
||||||
assert_eq!(get_gil_count(), 2);
|
assert_eq!(get_gil_count(), 2);
|
||||||
|
|
||||||
drop(pool2);
|
drop(pool2);
|
||||||
assert_eq!(get_gil_count(), 1);
|
assert_eq!(get_gil_count(), 1);
|
||||||
|
|
||||||
drop(gil2);
|
|
||||||
assert_eq!(get_gil_count(), 1);
|
|
||||||
|
|
||||||
drop(gil);
|
drop(gil);
|
||||||
assert_eq!(get_gil_count(), 0);
|
assert_eq!(get_gil_count(), 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,18 @@ impl<'p> Python<'p> {
|
||||||
///
|
///
|
||||||
/// If the Python runtime is not already initialized, this function will initialize it.
|
/// If the Python runtime is not already initialized, this function will initialize it.
|
||||||
/// See [prepare_freethreaded_python()](fn.prepare_freethreaded_python.html) for details.
|
/// See [prepare_freethreaded_python()](fn.prepare_freethreaded_python.html) for details.
|
||||||
|
///
|
||||||
|
/// Most users should not need to use this API directly, and should prefer one of two options:
|
||||||
|
/// 1. When implementing `#[pymethods]` or `#[pyfunction]` add a function argument
|
||||||
|
/// `py: Python` to receive access to the GIL context in which the function is running.
|
||||||
|
/// 2. Use [`Python::with_gil`](#method.with_gil) to run a closure with the GIL, acquiring
|
||||||
|
/// only if needed.
|
||||||
|
///
|
||||||
|
/// **Note:** This return type from this function, `GILGuard`, is implemented as a RAII guard
|
||||||
|
/// around the C-API Python_EnsureGIL. This means that multiple `acquire_gil()` calls are
|
||||||
|
/// allowed, and will not deadlock. However, `GILGuard`s must be dropped in the reverse order
|
||||||
|
/// to acquisition. If PyO3 detects this order is not maintained, it may be forced to begin
|
||||||
|
/// an irrecoverable panic.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn acquire_gil() -> GILGuard {
|
pub fn acquire_gil() -> GILGuard {
|
||||||
GILGuard::acquire()
|
GILGuard::acquire()
|
||||||
|
@ -135,6 +147,11 @@ impl<'p> Python<'p> {
|
||||||
/// cannot be used in the closure. This includes `&PyAny` and all the
|
/// cannot be used in the closure. This includes `&PyAny` and all the
|
||||||
/// concrete-typed siblings, like `&PyString`.
|
/// concrete-typed siblings, like `&PyString`.
|
||||||
///
|
///
|
||||||
|
/// This is achieved via the `Send` bound on the closure and the return type. This is slightly
|
||||||
|
/// more restrictive than necessary, but it's the most fitting solution available in stable
|
||||||
|
/// Rust. In the future this bound may be relaxed by a new "auto-trait", if auto-traits
|
||||||
|
/// become a stable feature of the Rust language.
|
||||||
|
///
|
||||||
/// You can convert such references to e.g. `PyObject` or `Py<PyString>`,
|
/// You can convert such references to e.g. `PyObject` or `Py<PyString>`,
|
||||||
/// which makes them independent of the GIL lifetime. However, you cannot
|
/// which makes them independent of the GIL lifetime. However, you cannot
|
||||||
/// do much with those without a `Python<'p>` token, for which you'd need to
|
/// do much with those without a `Python<'p>` token, for which you'd need to
|
||||||
|
@ -154,12 +171,12 @@ impl<'p> Python<'p> {
|
||||||
pub fn allow_threads<T, F>(self, f: F) -> T
|
pub fn allow_threads<T, F>(self, f: F) -> T
|
||||||
where
|
where
|
||||||
F: Send + FnOnce() -> T,
|
F: Send + FnOnce() -> T,
|
||||||
|
T: Send,
|
||||||
{
|
{
|
||||||
// The `Send` bound on the closure prevents the user from
|
// The `Send` bound on the closure prevents the user from
|
||||||
// transferring the `Python` token into the closure.
|
// transferring the `Python` token into the closure.
|
||||||
unsafe {
|
|
||||||
let count = gil::GIL_COUNT.with(|c| c.replace(0));
|
let count = gil::GIL_COUNT.with(|c| c.replace(0));
|
||||||
let save = ffi::PyEval_SaveThread();
|
let tstate = unsafe { ffi::PyEval_SaveThread() };
|
||||||
// Unwinding right here corrupts the Python interpreter state and leads to weird
|
// Unwinding right here corrupts the Python interpreter state and leads to weird
|
||||||
// crashes such as stack overflows. We will catch the unwind and resume as soon as
|
// crashes such as stack overflows. We will catch the unwind and resume as soon as
|
||||||
// we've restored the GIL state.
|
// we've restored the GIL state.
|
||||||
|
@ -167,12 +184,16 @@ impl<'p> Python<'p> {
|
||||||
// Because we will resume unwinding as soon as the GIL state is fixed, we can assert
|
// Because we will resume unwinding as soon as the GIL state is fixed, we can assert
|
||||||
// that the closure is unwind safe.
|
// that the closure is unwind safe.
|
||||||
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(f));
|
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(f));
|
||||||
ffi::PyEval_RestoreThread(save);
|
|
||||||
|
// Restore GIL state
|
||||||
gil::GIL_COUNT.with(|c| c.set(count));
|
gil::GIL_COUNT.with(|c| c.set(count));
|
||||||
|
unsafe {
|
||||||
|
ffi::PyEval_RestoreThread(tstate);
|
||||||
|
}
|
||||||
|
|
||||||
// Now that the GIL state has been safely reset, we can unwind if a panic was caught.
|
// Now that the GIL state has been safely reset, we can unwind if a panic was caught.
|
||||||
result.unwrap_or_else(|payload| std::panic::resume_unwind(payload))
|
result.unwrap_or_else(|payload| std::panic::resume_unwind(payload))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Evaluates a Python expression in the given context and returns the result.
|
/// Evaluates a Python expression in the given context and returns the result.
|
||||||
///
|
///
|
||||||
|
|
|
@ -130,7 +130,7 @@ impl PyByteArray {
|
||||||
/// # use pyo3::prelude::*;
|
/// # use pyo3::prelude::*;
|
||||||
/// # use pyo3::types::PyByteArray;
|
/// # use pyo3::types::PyByteArray;
|
||||||
/// # use pyo3::types::IntoPyDict;
|
/// # use pyo3::types::IntoPyDict;
|
||||||
/// # let gil = GILGuard::acquire();
|
/// # let gil = Python::acquire_gil();
|
||||||
/// # let py = gil.python();
|
/// # let py = gil.python();
|
||||||
/// #
|
/// #
|
||||||
/// let bytearray = PyByteArray::new(py, b"Hello World.");
|
/// let bytearray = PyByteArray::new(py, b"Hello World.");
|
||||||
|
|
|
@ -87,7 +87,6 @@ mod tests {
|
||||||
use crate::gil::GILPool;
|
use crate::gil::GILPool;
|
||||||
use crate::instance::AsPyRef;
|
use crate::instance::AsPyRef;
|
||||||
use crate::types::{PyDict, PyList};
|
use crate::types::{PyDict, PyList};
|
||||||
use crate::GILGuard;
|
|
||||||
use crate::Python;
|
use crate::Python;
|
||||||
use crate::ToPyObject;
|
use crate::ToPyObject;
|
||||||
use indoc::indoc;
|
use indoc::indoc;
|
||||||
|
@ -168,7 +167,7 @@ mod tests {
|
||||||
"#
|
"#
|
||||||
);
|
);
|
||||||
|
|
||||||
let gil = GILGuard::acquire();
|
let gil = Python::acquire_gil();
|
||||||
let py = gil.python();
|
let py = gil.python();
|
||||||
|
|
||||||
let context = PyDict::new(py);
|
let context = PyDict::new(py);
|
||||||
|
@ -183,7 +182,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn int_not_iterable() {
|
fn int_not_iterable() {
|
||||||
let gil = GILGuard::acquire();
|
let gil = Python::acquire_gil();
|
||||||
let py = gil.python();
|
let py = gil.python();
|
||||||
|
|
||||||
let x = 5.to_object(py);
|
let x = 5.to_object(py);
|
||||||
|
|
|
@ -2,6 +2,7 @@ use pyo3::class::basic::CompareOp;
|
||||||
use pyo3::class::*;
|
use pyo3::class::*;
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
use pyo3::py_run;
|
use pyo3::py_run;
|
||||||
|
use pyo3::PyNativeType;
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
|
|
||||||
|
@ -361,13 +362,11 @@ impl PyObjectProtocol for RichComparisons2 {
|
||||||
"RC2"
|
"RC2"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __richcmp__(&self, _other: &PyAny, op: CompareOp) -> PyObject {
|
fn __richcmp__(&self, other: &PyAny, op: CompareOp) -> PyObject {
|
||||||
let gil = GILGuard::acquire();
|
|
||||||
let py = gil.python();
|
|
||||||
match op {
|
match op {
|
||||||
CompareOp::Eq => true.into_py(py),
|
CompareOp::Eq => true.into_py(other.py()),
|
||||||
CompareOp::Ne => false.into_py(py),
|
CompareOp::Ne => false.into_py(other.py()),
|
||||||
_ => py.NotImplemented(),
|
_ => other.py().NotImplemented(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use pyo3::class::{
|
||||||
};
|
};
|
||||||
use pyo3::exceptions::{PyIndexError, PyValueError};
|
use pyo3::exceptions::{PyIndexError, PyValueError};
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
use pyo3::types::{IntoPyDict, PyBytes, PySlice, PyType};
|
use pyo3::types::{IntoPyDict, PySlice, PyType};
|
||||||
use pyo3::{ffi, py_run, AsPyPointer, PyCell};
|
use pyo3::{ffi, py_run, AsPyPointer, PyCell};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::{isize, iter};
|
use std::{isize, iter};
|
||||||
|
@ -94,9 +94,8 @@ impl<'p> PyObjectProtocol<'p> for StringMethods {
|
||||||
format!("format({})", format_spec)
|
format!("format({})", format_spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __bytes__(&self) -> PyObject {
|
fn __bytes__(&self) -> &'static [u8] {
|
||||||
let gil = GILGuard::acquire();
|
b"bytes"
|
||||||
PyBytes::new(gil.python(), b"bytes").into()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,7 +373,7 @@ impl<'p> PyContextProtocol<'p> for ContextManager {
|
||||||
_value: Option<&'p PyAny>,
|
_value: Option<&'p PyAny>,
|
||||||
_traceback: Option<&'p PyAny>,
|
_traceback: Option<&'p PyAny>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let gil = GILGuard::acquire();
|
let gil = Python::acquire_gil();
|
||||||
self.exit_called = true;
|
self.exit_called = true;
|
||||||
ty == Some(gil.python().get_type::<PyValueError>())
|
ty == Some(gil.python().get_type::<PyValueError>())
|
||||||
}
|
}
|
||||||
|
@ -426,16 +425,15 @@ struct Test {}
|
||||||
|
|
||||||
#[pyproto]
|
#[pyproto]
|
||||||
impl<'p> PyMappingProtocol<'p> for Test {
|
impl<'p> PyMappingProtocol<'p> for Test {
|
||||||
fn __getitem__(&self, idx: &PyAny) -> PyResult<PyObject> {
|
fn __getitem__(&self, idx: &PyAny) -> PyResult<&'static str> {
|
||||||
let gil = GILGuard::acquire();
|
|
||||||
if let Ok(slice) = idx.cast_as::<PySlice>() {
|
if let Ok(slice) = idx.cast_as::<PySlice>() {
|
||||||
let indices = slice.indices(1000)?;
|
let indices = slice.indices(1000)?;
|
||||||
if indices.start == 100 && indices.stop == 200 && indices.step == 1 {
|
if indices.start == 100 && indices.stop == 200 && indices.step == 1 {
|
||||||
return Ok("slice".into_py(gil.python()));
|
return Ok("slice");
|
||||||
}
|
}
|
||||||
} else if let Ok(idx) = idx.extract::<isize>() {
|
} else if let Ok(idx) = idx.extract::<isize>() {
|
||||||
if idx == 1 {
|
if idx == 1 {
|
||||||
return Ok("int".into_py(gil.python()));
|
return Ok("int");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(PyErr::new::<PyValueError, _>("error"))
|
Err(PyErr::new::<PyValueError, _>("error"))
|
||||||
|
|
|
@ -94,7 +94,7 @@ impl PyGCProtocol for GCIntegration {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __clear__(&mut self) {
|
fn __clear__(&mut self) {
|
||||||
let gil = GILGuard::acquire();
|
let gil = Python::acquire_gil();
|
||||||
self.self_ref = gil.python().None();
|
self.self_ref = gil.python().None();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -238,7 +238,7 @@ fn supermodule(_py: Python, module: &PyModule) -> PyResult<()> {
|
||||||
fn test_module_nesting() {
|
fn test_module_nesting() {
|
||||||
use pyo3::wrap_pymodule;
|
use pyo3::wrap_pymodule;
|
||||||
|
|
||||||
let gil = GILGuard::acquire();
|
let gil = Python::acquire_gil();
|
||||||
let py = gil.python();
|
let py = gil.python();
|
||||||
let supermodule = wrap_pymodule!(supermodule)(py);
|
let supermodule = wrap_pymodule!(supermodule)(py);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue