Merge pull request #1245 from alex/abi3-merge-master
Merge master into abi3 branch, resolving conflicts
This commit is contained in:
commit
f74b64993e
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
@ -45,7 +45,7 @@ jobs:
|
|||
fail-fast: false # If one platform fails, allow the rest to keep testing.
|
||||
matrix:
|
||||
rust: [stable]
|
||||
python-version: [3.5, 3.6, 3.7, 3.8, 3.9, pypy3]
|
||||
python-version: [3.6, 3.7, 3.8, 3.9, pypy3]
|
||||
platform: [
|
||||
{ os: "macOS-latest", python-architecture: "x64", rust-target: "x86_64-apple-darwin" },
|
||||
{ os: "ubuntu-latest", python-architecture: "x64", rust-target: "x86_64-unknown-linux-gnu" },
|
||||
|
|
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -6,14 +6,24 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
### Packaging
|
||||
- Drop support for Python 3.5 (as it is now end-of-life). [#1250](https://github.com/PyO3/pyo3/pull/1250)
|
||||
|
||||
### Added
|
||||
- Add support for building for CPython limited API. This required a few minor changes to runtime behaviour of of pyo3 `#[pyclass]` types. See the migration guide for full details. [#1152](https://github.com/PyO3/pyo3/pull/1152)
|
||||
- Add argument names to `TypeError` messages generated by pymethod wrappers. [#1212](https://github.com/PyO3/pyo3/pull/1212)
|
||||
|
||||
### Changed
|
||||
- Change return type `PyType::name()` from `Cow<str>` to `PyResult<&str>`. [#1152](https://github.com/PyO3/pyo3/pull/1152)
|
||||
- `#[pyclass(subclass)]` is now required for subclassing from Rust (was previously just required for subclassing from Python). [#1152](https://github.com/PyO3/pyo3/pull/1152)
|
||||
- Change `PyIterator` to be consistent with other native types: it is now used as `&PyIterator` instead of `PyIterator<'a>`. [#1176](https://github.com/PyO3/pyo3/pull/1176)
|
||||
- Change formatting of `PyDowncastError` messages to be closer to Python's builtin error messages. [#1212](https://github.com/PyO3/pyo3/pull/1212)
|
||||
|
||||
## [Unreleased]
|
||||
### Removed
|
||||
- Remove deprecated ffi definitions `PyUnicode_AsUnicodeCopy`, `PyUnicode_GetMax`, `_Py_CheckRecursionLimit`, `PyObject_AsCharBuffer`, `PyObject_AsReadBuffer`, `PyObject_CheckReadBuffer` and `PyObject_AsWriteBuffer`, which will be removed in Python 3.10. [#1217](https://github.com/PyO3/pyo3/pull/1217)
|
||||
- Remove unused `python3` feature. [#1235](https://github.com/PyO3/pyo3/pull/1235)
|
||||
|
||||
## [0.12.3] - 2020-10-12
|
||||
### Fixed
|
||||
- Fix support for Rust versions 1.39 to 1.44, broken by an incorrect internal update to paste 1.0 which was done in PyO3 0.12.2. [#1234](https://github.com/PyO3/pyo3/pull/1234)
|
||||
|
||||
|
@ -523,7 +533,8 @@ Yanked
|
|||
### Added
|
||||
- Initial release
|
||||
|
||||
[Unreleased]: https://github.com/pyo3/pyo3/compare/v0.12.2...HEAD
|
||||
[Unreleased]: https://github.com/pyo3/pyo3/compare/v0.12.3...HEAD
|
||||
[0.12.3]: https://github.com/pyo3/pyo3/compare/v0.12.2...v0.12.3
|
||||
[0.12.2]: https://github.com/pyo3/pyo3/compare/v0.12.1...v0.12.2
|
||||
[0.12.1]: https://github.com/pyo3/pyo3/compare/v0.12.0...v0.12.1
|
||||
[0.12.0]: https://github.com/pyo3/pyo3/compare/v0.11.1...v0.12.0
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "pyo3"
|
||||
version = "0.12.2"
|
||||
version = "0.12.3"
|
||||
description = "Bindings to Python interpreter"
|
||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
||||
readme = "README.md"
|
||||
|
@ -23,7 +23,7 @@ parking_lot = "0.11.0"
|
|||
num-bigint = { version = "0.3", optional = true }
|
||||
num-complex = { version = "0.3", optional = true }
|
||||
paste = { version = "0.1.6", optional = true }
|
||||
pyo3cls = { path = "pyo3cls", version = "=0.12.2", optional = true }
|
||||
pyo3cls = { path = "pyo3cls", version = "=0.12.3", optional = true }
|
||||
unindent = { version = "0.1.4", optional = true }
|
||||
hashbrown = { version = "0.9", optional = true }
|
||||
|
||||
|
@ -42,9 +42,6 @@ abi3 = []
|
|||
# Optimizes PyObject to Vec conversion and so on.
|
||||
nightly = []
|
||||
|
||||
# this is no longer needed internally, but setuptools-rust assumes this feature
|
||||
python3 = []
|
||||
|
||||
# Use this feature when building an extension module.
|
||||
# It tells the linker to keep the python symbols unresolved,
|
||||
# so that the module can also be used with statically linked python interpreters.
|
||||
|
|
2
Makefile
2
Makefile
|
@ -20,5 +20,7 @@ lint: fmt clippy
|
|||
|
||||
publish: test
|
||||
cargo publish --manifest-path pyo3-derive-backend/Cargo.toml
|
||||
sleep 10 # wait for crates.io to update
|
||||
cargo publish --manifest-path pyo3cls/Cargo.toml
|
||||
sleep 10 # wait for crates.io to update
|
||||
cargo publish
|
||||
|
|
|
@ -18,7 +18,7 @@ A comparison with rust-cpython can be found [in the guide](https://pyo3.rs/maste
|
|||
|
||||
## Usage
|
||||
|
||||
PyO3 supports Python 3.5 and up. The minimum required Rust version is 1.39.0.
|
||||
PyO3 supports Python 3.6 and up. The minimum required Rust version is 1.39.0.
|
||||
|
||||
Building with PyPy is also possible (via cpyext) for Python 3.6, targeted PyPy version is 7.3+.
|
||||
Please refer to the [pypy section in the guide](https://pyo3.rs/master/pypy.html).
|
||||
|
@ -48,7 +48,7 @@ name = "string_sum"
|
|||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies.pyo3]
|
||||
version = "0.12.2"
|
||||
version = "0.12.3"
|
||||
features = ["extension-module"]
|
||||
```
|
||||
|
||||
|
@ -99,7 +99,7 @@ use it to run Python code, add `pyo3` to your `Cargo.toml` like this:
|
|||
|
||||
```toml
|
||||
[dependencies]
|
||||
pyo3 = "0.12.2"
|
||||
pyo3 = "0.12.3"
|
||||
```
|
||||
|
||||
Example program displaying the value of `sys.version` and the current user name:
|
||||
|
@ -155,6 +155,7 @@ about this topic.
|
|||
* [wasmer-python](https://github.com/wasmerio/wasmer-python) _Python library to run WebAssembly binaries_
|
||||
* [mocpy](https://github.com/cds-astro/mocpy) _Astronomical Python library offering data structures for describing any arbitrary coverage regions on the unit sphere_
|
||||
* [tokenizers](https://github.com/huggingface/tokenizers/tree/master/bindings/python) _Python bindings to the Hugging Face tokenizers (NLP) written in Rust_
|
||||
* [pyre](https://github.com/Project-Dream-Weaver/Pyre) _Fast Python HTTP server written in Rust_
|
||||
|
||||
## License
|
||||
|
||||
|
|
2
build.rs
2
build.rs
|
@ -775,7 +775,7 @@ fn configure(interpreter_config: &InterpreterConfig) -> Result<String> {
|
|||
}
|
||||
|
||||
if let Some(minor) = interpreter_config.version.minor {
|
||||
for i in 5..(minor + 1) {
|
||||
for i in 6..(minor + 1) {
|
||||
println!("cargo:rustc-cfg=Py_3_{}", i);
|
||||
flags += format!("CFG_Py_3_{},", i).as_ref();
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ class CargoModifiedSdist(SdistCommand):
|
|||
def get_py_version_cfgs():
|
||||
# For now each Cfg Py_3_X flag is interpreted as "at least 3.X"
|
||||
version = sys.version_info[0:2]
|
||||
py3_min = 5
|
||||
py3_min = 6
|
||||
out_cfg = []
|
||||
for minor in range(py3_min, version[1] + 1):
|
||||
out_cfg.append("--cfg=Py_3_%d" % minor)
|
||||
|
|
|
@ -42,7 +42,7 @@ fn make_time<'p>(
|
|||
)
|
||||
}
|
||||
|
||||
#[cfg(Py_3_6)]
|
||||
#[cfg(not(PyPy))]
|
||||
#[pyfunction]
|
||||
fn time_with_fold<'p>(
|
||||
py: Python<'p>,
|
||||
|
@ -77,7 +77,7 @@ fn get_time_tuple<'p>(py: Python<'p>, dt: &PyTime) -> &'p PyTuple {
|
|||
)
|
||||
}
|
||||
|
||||
#[cfg(all(Py_3_6, not(PyPy)))]
|
||||
#[cfg(not(PyPy))]
|
||||
#[pyfunction]
|
||||
fn get_time_tuple_fold<'p>(py: Python<'p>, dt: &PyTime) -> &'p PyTuple {
|
||||
PyTuple::new(
|
||||
|
@ -156,7 +156,7 @@ fn get_datetime_tuple<'p>(py: Python<'p>, dt: &PyDateTime) -> &'p PyTuple {
|
|||
)
|
||||
}
|
||||
|
||||
#[cfg(all(Py_3_6, not(PyPy)))]
|
||||
#[cfg(not(PyPy))]
|
||||
#[pyfunction]
|
||||
fn get_datetime_tuple_fold<'p>(py: Python<'p>, dt: &PyDateTime) -> &'p PyTuple {
|
||||
PyTuple::new(
|
||||
|
@ -226,15 +226,12 @@ fn datetime(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
|||
m.add_function(wrap_pyfunction!(get_datetime_tuple, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(datetime_from_timestamp, m)?)?;
|
||||
|
||||
// Python 3.6+ functions
|
||||
#[cfg(Py_3_6)]
|
||||
// Functions not supported by PyPy
|
||||
#[cfg(not(PyPy))]
|
||||
{
|
||||
m.add_function(wrap_pyfunction!(time_with_fold, m)?)?;
|
||||
#[cfg(not(PyPy))]
|
||||
{
|
||||
m.add_function(wrap_pyfunction!(get_time_tuple_fold, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(get_datetime_tuple_fold, m)?)?;
|
||||
}
|
||||
m.add_function(wrap_pyfunction!(get_time_tuple_fold, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(get_datetime_tuple_fold, m)?)?;
|
||||
}
|
||||
|
||||
m.add_function(wrap_pyfunction!(issue_219, m)?)?;
|
||||
|
|
|
@ -70,18 +70,6 @@ else:
|
|||
MAX_DATETIME = pdt.datetime(9999, 12, 31, 18, 59, 59)
|
||||
|
||||
PYPY = platform.python_implementation() == "PyPy"
|
||||
HAS_FOLD = getattr(pdt.datetime, "fold", False) and not PYPY
|
||||
|
||||
|
||||
xfail_date_bounds = pytest.mark.xfail(
|
||||
sys.version_info < (3, 6),
|
||||
reason="Date bounds were not checked in the C constructor prior to version 3.6",
|
||||
)
|
||||
|
||||
xfail_macos_datetime_bounds = pytest.mark.xfail(
|
||||
sys.version_info < (3, 6) and platform.system() == "Darwin",
|
||||
reason="Unclearly failing. See https://github.com/PyO3/pyo3/pull/830 for more.",
|
||||
)
|
||||
|
||||
|
||||
# Tests
|
||||
|
@ -97,13 +85,11 @@ def test_date_accessors(d):
|
|||
assert act == exp
|
||||
|
||||
|
||||
@xfail_date_bounds
|
||||
def test_invalid_date_fails():
|
||||
with pytest.raises(ValueError):
|
||||
rdt.make_date(2017, 2, 30)
|
||||
|
||||
|
||||
@xfail_macos_datetime_bounds
|
||||
@given(d=st.dates(MIN_DATETIME.date(), MAX_DATETIME.date()))
|
||||
def test_date_from_timestamp(d):
|
||||
if PYPY and d < pdt.date(1900, 1, 1):
|
||||
|
@ -137,7 +123,7 @@ def test_time(t):
|
|||
assert act == exp
|
||||
|
||||
|
||||
@pytest.mark.skipif(not HAS_FOLD, reason="Feature not available before 3.6")
|
||||
@pytest.mark.xfail(PYPY, reason="Feature not available on PyPy")
|
||||
@given(t=st.times())
|
||||
def test_time_fold(t):
|
||||
t_nofold = t.replace(fold=0)
|
||||
|
@ -150,7 +136,7 @@ def test_time_fold(t):
|
|||
assert act == exp
|
||||
|
||||
|
||||
@pytest.mark.skipif(not HAS_FOLD, reason="Feature not available before 3.6")
|
||||
@pytest.mark.xfail(PYPY, reason="Feature not available on PyPy")
|
||||
@pytest.mark.parametrize("fold", [False, True])
|
||||
def test_time_fold(fold):
|
||||
t = rdt.time_with_fold(0, 0, 0, 0, None, fold)
|
||||
|
@ -166,7 +152,6 @@ def test_invalid_time_fails_xfail(args):
|
|||
rdt.make_time(*args)
|
||||
|
||||
|
||||
@xfail_date_bounds
|
||||
@pytest.mark.parametrize(
|
||||
"args",
|
||||
[
|
||||
|
@ -219,7 +204,7 @@ def test_datetime_tuple(dt):
|
|||
assert act == exp
|
||||
|
||||
|
||||
@pytest.mark.skipif(not HAS_FOLD, reason="Feature not available before 3.6")
|
||||
@pytest.mark.xfail(PYPY, reason="Feature not available on PyPy")
|
||||
@given(dt=st.datetimes())
|
||||
def test_datetime_tuple_fold(dt):
|
||||
dt_fold = dt.replace(fold=1)
|
||||
|
@ -232,7 +217,6 @@ def test_datetime_tuple_fold(dt):
|
|||
assert act == exp
|
||||
|
||||
|
||||
@xfail_date_bounds
|
||||
def test_invalid_datetime_fails():
|
||||
with pytest.raises(ValueError):
|
||||
rdt.make_datetime(2011, 1, 42, 0, 0, 0, 0)
|
||||
|
@ -243,7 +227,6 @@ def test_datetime_typeerror():
|
|||
rdt.make_datetime("2011", 1, 1, 0, 0, 0, 0)
|
||||
|
||||
|
||||
@xfail_macos_datetime_bounds
|
||||
@given(dt=st.datetimes(MIN_DATETIME, MAX_DATETIME))
|
||||
@example(dt=pdt.datetime(1970, 1, 2, 0, 0))
|
||||
def test_datetime_from_timestamp(dt):
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
[tox]
|
||||
envlist = py35,
|
||||
py36,
|
||||
envlist = py36,
|
||||
py37,
|
||||
py38,
|
||||
py39,
|
||||
pypy3
|
||||
minversion = 3.4.0
|
||||
minversion = 3.6.0
|
||||
skip_missing_interpreters = true
|
||||
isolated_build = true
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ There are also a few special types related to the GIL and Rust-defined `#[pyclas
|
|||
| `PyRef<T>` | A `#[pyclass]` borrowed immutably. |
|
||||
| `PyRefMut<T>` | A `#[pyclass]` borrowed mutably. |
|
||||
|
||||
For more detail on accepting `#[pyclass]` values as function arguments, see [the section of this guide on Python Classes](class.md).
|
||||
For more detail on accepting `#[pyclass]` values as function arguments, see [the section of this guide on Python Classes](../class.md).
|
||||
|
||||
#### Using Rust library types vs Python-native types
|
||||
|
||||
|
|
|
@ -171,8 +171,7 @@ enum RustyEnum {
|
|||
```
|
||||
|
||||
If the input is neither a string nor an integer, the error message will be:
|
||||
`"Can't convert <INPUT> to Union[str, int]"`, where `<INPUT>` is replaced by the type name and
|
||||
`repr()` of the input object.
|
||||
`"'<INPUT_TYPE>' cannot be converted to 'Union[str, int]'"`.
|
||||
|
||||
#### `#[derive(FromPyObject)]` Container Attributes
|
||||
- `pyo3(transparent)`
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "pyo3-derive-backend"
|
||||
version = "0.12.2"
|
||||
version = "0.12.3"
|
||||
description = "Code generation for PyO3 package"
|
||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
||||
keywords = ["pyo3", "python", "cpython", "ffi"]
|
||||
|
|
|
@ -73,11 +73,7 @@ impl<'a> Enum<'a> {
|
|||
quote!(
|
||||
#(#var_extracts)*
|
||||
let type_name = obj.get_type().name()?;
|
||||
let from = obj
|
||||
.repr()
|
||||
.map(|s| format!("{} ({})", s.to_string_lossy(), type_name))
|
||||
.unwrap_or_else(|_| type_name.to_string());
|
||||
let err_msg = format!("Can't convert {} to {}", from, #error_names);
|
||||
let err_msg = format!("'{}' object cannot be converted to '{}'", type_name, #error_names);
|
||||
Err(::pyo3::exceptions::PyTypeError::new_err(err_msg))
|
||||
)
|
||||
}
|
||||
|
|
|
@ -267,7 +267,7 @@ fn impl_class(
|
|||
quote! {
|
||||
impl pyo3::freelist::PyClassWithFreeList for #cls {
|
||||
#[inline]
|
||||
fn get_free_list() -> &'static mut pyo3::freelist::FreeList<*mut pyo3::ffi::PyObject> {
|
||||
fn get_free_list(_py: pyo3::Python) -> &mut pyo3::freelist::FreeList<*mut pyo3::ffi::PyObject> {
|
||||
static mut FREELIST: *mut pyo3::freelist::FreeList<*mut pyo3::ffi::PyObject> = 0 as *mut _;
|
||||
unsafe {
|
||||
if FREELIST.is_null() {
|
||||
|
|
|
@ -475,10 +475,14 @@ fn impl_arg_param(
|
|||
|
||||
let ty = arg.ty;
|
||||
let name = arg.name;
|
||||
let transform_error = quote! {
|
||||
|e| pyo3::derive_utils::argument_extraction_error(_py, stringify!(#name), e)
|
||||
};
|
||||
|
||||
if spec.is_args(&name) {
|
||||
return quote! {
|
||||
let #arg_name = <#ty as pyo3::FromPyObject>::extract(_args.as_ref())?;
|
||||
let #arg_name = <#ty as pyo3::FromPyObject>::extract(_args.as_ref())
|
||||
.map_err(#transform_error)?;
|
||||
};
|
||||
} else if spec.is_kwargs(&name) {
|
||||
return quote! {
|
||||
|
@ -518,7 +522,7 @@ fn impl_arg_param(
|
|||
|
||||
quote! {
|
||||
let #mut_ _tmp: #target_ty = match #arg_value {
|
||||
Some(_obj) => _obj.extract()?,
|
||||
Some(_obj) => _obj.extract().map_err(#transform_error)?,
|
||||
None => #default,
|
||||
};
|
||||
let #arg_name = #borrow_tmp;
|
||||
|
@ -526,7 +530,7 @@ fn impl_arg_param(
|
|||
} else {
|
||||
quote! {
|
||||
let #arg_name = match #arg_value {
|
||||
Some(_obj) => _obj.extract()?,
|
||||
Some(_obj) => _obj.extract().map_err(#transform_error)?,
|
||||
None => #default,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "pyo3cls"
|
||||
version = "0.12.2"
|
||||
version = "0.12.3"
|
||||
description = "Proc macros for PyO3 package"
|
||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
||||
keywords = ["pyo3", "python", "cpython", "ffi"]
|
||||
|
@ -16,4 +16,4 @@ proc-macro = true
|
|||
[dependencies]
|
||||
quote = "1"
|
||||
syn = { version = "1", features = ["full", "extra-traits"] }
|
||||
pyo3-derive-backend = { path = "../pyo3-derive-backend", version = "=0.12.2" }
|
||||
pyo3-derive-backend = { path = "../pyo3-derive-backend", version = "=0.12.3" }
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::err::{PyErr, PyResult};
|
|||
use crate::exceptions::PyTypeError;
|
||||
use crate::instance::PyNativeType;
|
||||
use crate::pyclass::{PyClass, PyClassThreadChecker};
|
||||
use crate::types::{PyAny, PyDict, PyModule, PyTuple};
|
||||
use crate::types::{PyAny, PyDict, PyModule, PyString, PyTuple};
|
||||
use crate::{ffi, GILPool, IntoPy, PyCell, Python};
|
||||
use std::cell::UnsafeCell;
|
||||
|
||||
|
@ -111,6 +111,19 @@ pub fn parse_fn_args<'p>(
|
|||
Ok((args, kwargs))
|
||||
}
|
||||
|
||||
/// Add the argument name to the error message of an error which occurred during argument extraction
|
||||
pub fn argument_extraction_error(py: Python, arg_name: &str, error: PyErr) -> PyErr {
|
||||
if error.ptype(py) == py.get_type::<PyTypeError>() {
|
||||
let reason = error
|
||||
.instance(py)
|
||||
.str()
|
||||
.unwrap_or_else(|_| PyString::new(py, ""));
|
||||
PyTypeError::new_err(format!("argument '{}': {}", arg_name, reason))
|
||||
} else {
|
||||
error
|
||||
}
|
||||
}
|
||||
|
||||
/// `Sync` wrapper of `ffi::PyModuleDef`.
|
||||
#[doc(hidden)]
|
||||
pub struct ModuleDef(UnsafeCell<ffi::PyModuleDef>);
|
||||
|
|
|
@ -490,12 +490,8 @@ impl<'a> std::fmt::Display for PyDowncastError<'a> {
|
|||
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
write!(
|
||||
f,
|
||||
"Can't convert {} to {}",
|
||||
self.from
|
||||
.repr()
|
||||
.map(|s| s.to_string_lossy())
|
||||
.or_else(|_| self.from.get_type().name().map(|s| s.into()))
|
||||
.map_err(|_| std::fmt::Error)?,
|
||||
"'{}' object cannot be converted to '{}'",
|
||||
self.from.get_type().name().map_err(|_| std::fmt::Error)?,
|
||||
self.to
|
||||
)
|
||||
}
|
||||
|
|
|
@ -308,7 +308,6 @@ impl_native_exception!(
|
|||
impl_native_exception!(PyOSError, OSError, PyExc_OSError, ffi::PyOSErrorObject);
|
||||
impl_native_exception!(PyImportError, ImportError, PyExc_ImportError);
|
||||
|
||||
#[cfg(Py_3_6)]
|
||||
impl_native_exception!(
|
||||
PyModuleNotFoundError,
|
||||
ModuleNotFoundError,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#[cfg(all(Py_3_6, not(Py_LIMITED_API)))]
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
use crate::ffi::code::FreeFunc;
|
||||
use crate::ffi::object::PyObject;
|
||||
use crate::ffi::pystate::PyThreadState;
|
||||
|
@ -49,13 +49,7 @@ extern "C" {
|
|||
fn _Py_CheckRecursiveCall(_where: *mut c_char) -> c_int;
|
||||
}
|
||||
|
||||
#[cfg_attr(windows, link(name = "pythonXY"))]
|
||||
extern "C" {
|
||||
static mut _Py_CheckRecursionLimit: c_int;
|
||||
}
|
||||
|
||||
// TODO: Py_EnterRecursiveCall etc.
|
||||
#[cfg(Py_3_6)]
|
||||
// TODO: Py_EnterRecursiveCall etc
|
||||
pub type _PyFrameEvalFunction =
|
||||
extern "C" fn(*mut crate::ffi::PyFrameObject, c_int) -> *mut PyObject;
|
||||
|
||||
|
@ -64,12 +58,11 @@ extern "C" {
|
|||
pub fn PyEval_GetFuncDesc(arg1: *mut PyObject) -> *const c_char;
|
||||
pub fn PyEval_GetCallStats(arg1: *mut PyObject) -> *mut PyObject;
|
||||
pub fn PyEval_EvalFrame(arg1: *mut crate::ffi::PyFrameObject) -> *mut PyObject;
|
||||
#[cfg(Py_3_6)]
|
||||
pub fn _PyEval_EvalFrameDefault(
|
||||
arg1: *mut crate::ffi::PyFrameObject,
|
||||
exc: c_int,
|
||||
) -> *mut PyObject;
|
||||
#[cfg(all(Py_3_6, not(Py_LIMITED_API)))]
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
pub fn _PyEval_RequestCodeExtraIndex(func: FreeFunc) -> c_int;
|
||||
pub fn PyEval_EvalFrameEx(f: *mut crate::ffi::PyFrameObject, exc: c_int) -> *mut PyObject;
|
||||
#[cfg_attr(PyPy, link_name = "PyPyEval_SaveThread")]
|
||||
|
|
|
@ -14,7 +14,6 @@ pub struct PyCodeObject {
|
|||
pub co_nlocals: c_int,
|
||||
pub co_stacksize: c_int,
|
||||
pub co_flags: c_int,
|
||||
#[cfg(Py_3_6)]
|
||||
pub co_firstlineno: c_int,
|
||||
pub co_code: *mut PyObject,
|
||||
pub co_consts: *mut PyObject,
|
||||
|
@ -25,12 +24,9 @@ pub struct PyCodeObject {
|
|||
pub co_cell2arg: *mut c_uchar,
|
||||
pub co_filename: *mut PyObject,
|
||||
pub co_name: *mut PyObject,
|
||||
#[cfg(not(Py_3_6))]
|
||||
pub co_firstlineno: c_int,
|
||||
pub co_lnotab: *mut PyObject,
|
||||
pub co_zombieframe: *mut c_void,
|
||||
pub co_weakreflist: *mut PyObject,
|
||||
#[cfg(Py_3_6)]
|
||||
pub co_extra: *mut c_void,
|
||||
#[cfg(Py_3_8)]
|
||||
pub co_opcache_map: *mut c_uchar,
|
||||
|
@ -70,8 +66,6 @@ pub const CO_FUTURE_BARRY_AS_BDFL: c_int = 0x4_0000;
|
|||
pub const CO_FUTURE_GENERATOR_STOP: c_int = 0x8_0000;
|
||||
|
||||
pub const CO_MAXBLOCKS: usize = 20;
|
||||
|
||||
#[cfg(Py_3_6)]
|
||||
pub type FreeFunc = extern "C" fn(*mut c_void) -> c_void;
|
||||
|
||||
#[cfg_attr(windows, link(name = "pythonXY"))]
|
||||
|
@ -80,13 +74,11 @@ extern "C" {
|
|||
}
|
||||
|
||||
extern "C" {
|
||||
#[cfg(Py_3_6)]
|
||||
pub fn _PyCode_GetExtra(
|
||||
code: *mut PyObject,
|
||||
index: Py_ssize_t,
|
||||
extra: *const *mut c_void,
|
||||
) -> c_int;
|
||||
#[cfg(Py_3_6)]
|
||||
pub fn _PyCode_SetExtra(code: *mut PyObject, index: Py_ssize_t, extra: *mut c_void) -> c_int;
|
||||
|
||||
#[cfg_attr(PyPy, link_name = "PyPyCode_New")]
|
||||
|
|
|
@ -29,7 +29,7 @@ pub struct PyDateTime_CAPI {
|
|||
pub TimeType: *mut PyTypeObject,
|
||||
pub DeltaType: *mut PyTypeObject,
|
||||
pub TZInfoType: *mut PyTypeObject,
|
||||
#[cfg(Py_3_7)]
|
||||
#[cfg(all(Py_3_7, not(PyPy)))]
|
||||
pub TimeZone_UTC: *mut PyObject,
|
||||
#[cfg_attr(PyPy, link_name = "_PyPyDate_FromDate")]
|
||||
pub Date_FromDate: unsafe extern "C" fn(
|
||||
|
@ -67,7 +67,7 @@ pub struct PyDateTime_CAPI {
|
|||
normalize: c_int,
|
||||
cls: *mut PyTypeObject,
|
||||
) -> *mut PyObject,
|
||||
#[cfg(Py_3_7)]
|
||||
#[cfg(all(Py_3_7, not(PyPy)))]
|
||||
pub TimeZone_FromTimeZone:
|
||||
unsafe extern "C" fn(offset: *mut PyObject, name: *mut PyObject) -> *mut PyObject,
|
||||
|
||||
|
@ -80,7 +80,7 @@ pub struct PyDateTime_CAPI {
|
|||
// Defined for PyPy as `PyDate_FromTimestamp`
|
||||
pub Date_FromTimestamp:
|
||||
unsafe extern "C" fn(cls: *mut PyTypeObject, args: *mut PyObject) -> *mut PyObject,
|
||||
#[cfg(Py_3_6)]
|
||||
#[cfg(not(PyPy))]
|
||||
pub DateTime_FromDateAndTimeAndFold: unsafe extern "C" fn(
|
||||
year: c_int,
|
||||
month: c_int,
|
||||
|
@ -93,7 +93,7 @@ pub struct PyDateTime_CAPI {
|
|||
fold: c_int,
|
||||
cls: *mut PyTypeObject,
|
||||
) -> *mut PyObject,
|
||||
#[cfg(Py_3_6)]
|
||||
#[cfg(not(PyPy))]
|
||||
pub Time_FromTimeAndFold: unsafe extern "C" fn(
|
||||
hour: c_int,
|
||||
minute: c_int,
|
||||
|
@ -154,6 +154,7 @@ const _PyDateTime_DATETIME_DATASIZE: usize = 10;
|
|||
/// Structure representing a `datetime.date`
|
||||
pub struct PyDateTime_Date {
|
||||
pub ob_base: PyObject,
|
||||
#[cfg(not(PyPy))]
|
||||
pub hashcode: Py_hash_t,
|
||||
pub hastzinfo: c_char,
|
||||
pub data: [c_uchar; _PyDateTime_DATE_DATASIZE],
|
||||
|
@ -164,10 +165,12 @@ pub struct PyDateTime_Date {
|
|||
/// Structure representing a `datetime.time`
|
||||
pub struct PyDateTime_Time {
|
||||
pub ob_base: PyObject,
|
||||
#[cfg(not(PyPy))]
|
||||
pub hashcode: Py_hash_t,
|
||||
pub hastzinfo: c_char,
|
||||
#[cfg(not(PyPy))]
|
||||
pub data: [c_uchar; _PyDateTime_TIME_DATASIZE],
|
||||
#[cfg(Py_3_6)]
|
||||
#[cfg(not(PyPy))]
|
||||
pub fold: c_uchar,
|
||||
pub tzinfo: *mut PyObject,
|
||||
}
|
||||
|
@ -177,10 +180,12 @@ pub struct PyDateTime_Time {
|
|||
/// Structure representing a `datetime.datetime`
|
||||
pub struct PyDateTime_DateTime {
|
||||
pub ob_base: PyObject,
|
||||
#[cfg(not(PyPy))]
|
||||
pub hashcode: Py_hash_t,
|
||||
pub hastzinfo: c_char,
|
||||
#[cfg(not(PyPy))]
|
||||
pub data: [c_uchar; _PyDateTime_DATETIME_DATASIZE],
|
||||
#[cfg(Py_3_6)]
|
||||
#[cfg(not(PyPy))]
|
||||
pub fold: c_uchar,
|
||||
pub tzinfo: *mut PyObject,
|
||||
}
|
||||
|
@ -190,6 +195,7 @@ pub struct PyDateTime_DateTime {
|
|||
/// Structure representing a `datetime.timedelta`
|
||||
pub struct PyDateTime_Delta {
|
||||
pub ob_base: PyObject,
|
||||
#[cfg(not(PyPy))]
|
||||
pub hashcode: Py_hash_t,
|
||||
pub days: c_int,
|
||||
pub seconds: c_int,
|
||||
|
@ -381,7 +387,6 @@ macro_rules! _PyDateTime_GET_MICROSECOND {
|
|||
};
|
||||
}
|
||||
|
||||
#[cfg(Py_3_6)]
|
||||
#[cfg(not(PyPy))]
|
||||
macro_rules! _PyDateTime_GET_FOLD {
|
||||
($o: expr) => {
|
||||
|
@ -429,13 +434,10 @@ pub unsafe fn PyDateTime_DATE_GET_MICROSECOND(o: *mut PyObject) -> c_int {
|
|||
_PyDateTime_GET_MICROSECOND!((o as *mut PyDateTime_DateTime), _PyDateTime_DATE_DATASIZE)
|
||||
}
|
||||
|
||||
#[cfg(Py_3_6)]
|
||||
#[inline]
|
||||
#[cfg(not(PyPy))]
|
||||
/// Retrieve the fold component of a `PyDateTime_DateTime`.
|
||||
/// Returns a signed integer in the interval `[0, 1]`
|
||||
///
|
||||
/// Added in version Python 3.6
|
||||
pub unsafe fn PyDateTime_DATE_GET_FOLD(o: *mut PyObject) -> c_uchar {
|
||||
_PyDateTime_GET_FOLD!(o as *mut PyDateTime_DateTime)
|
||||
}
|
||||
|
@ -482,12 +484,10 @@ pub unsafe fn PyDateTime_TIME_GET_MICROSECOND(o: *mut PyObject) -> c_int {
|
|||
_PyDateTime_GET_MICROSECOND!((o as *mut PyDateTime_Time), 0)
|
||||
}
|
||||
|
||||
#[cfg(all(Py_3_6, not(PyPy)))]
|
||||
#[cfg(not(PyPy))]
|
||||
#[inline]
|
||||
/// Retrieve the fold component of a `PyDateTime_Time`.
|
||||
/// Returns a signed integer in the interval `[0, 1]`
|
||||
///
|
||||
/// Added in version Python 3.6
|
||||
pub unsafe fn PyDateTime_TIME_GET_FOLD(o: *mut PyObject) -> c_uchar {
|
||||
_PyDateTime_GET_FOLD!(o as *mut PyDateTime_Time)
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ pub struct PyDictKeysObject {
|
|||
pub struct PyDictObject {
|
||||
pub ob_base: PyObject,
|
||||
pub ma_used: Py_ssize_t,
|
||||
#[cfg(Py_3_6)]
|
||||
pub ma_version_tag: u64,
|
||||
pub ma_keys: *mut PyDictKeysObject,
|
||||
pub ma_values: *mut *mut PyObject,
|
||||
|
|
|
@ -27,7 +27,6 @@ extern "C" {
|
|||
#[cfg_attr(windows, link(name = "pythonXY"))]
|
||||
extern "C" {
|
||||
pub static mut Py_FileSystemDefaultEncoding: *const c_char;
|
||||
#[cfg(Py_3_6)]
|
||||
pub static mut Py_FileSystemDefaultEncodeErrors: *const c_char;
|
||||
pub static mut Py_HasFileSystemDefaultEncoding: c_int;
|
||||
}
|
||||
|
|
|
@ -58,20 +58,12 @@ pub unsafe fn PyCoroWrapper_Check(op: *mut PyObject) -> c_int {
|
|||
PyObject_TypeCheck(op, &mut _PyCoroWrapper_Type)
|
||||
}
|
||||
|
||||
#[cfg(Py_3_6)]
|
||||
#[cfg_attr(windows, link(name = "pythonXY"))]
|
||||
extern "C" {
|
||||
pub static mut PyAsyncGen_Type: PyTypeObject;
|
||||
}
|
||||
|
||||
#[cfg(Py_3_6)]
|
||||
#[inline]
|
||||
pub unsafe fn PyAsyncGen_Check(op: *mut PyObject) -> c_int {
|
||||
PyObject_TypeCheck(op, &mut PyAsyncGen_Type)
|
||||
}
|
||||
|
||||
#[cfg(not(Py_3_6))]
|
||||
#[inline]
|
||||
pub unsafe fn PyAsyncGen_Check(_op: *mut PyObject) -> c_int {
|
||||
0
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@ pub use self::moduleobject::*;
|
|||
pub use self::object::*;
|
||||
pub use self::objectabstract::*;
|
||||
pub use self::objimpl::*;
|
||||
#[cfg(Py_3_6)]
|
||||
pub use self::osmodule::*;
|
||||
pub use self::pyarena::*;
|
||||
pub use self::pycapsule::*;
|
||||
|
@ -124,7 +123,6 @@ mod pythonrun; // TODO some functions need to be moved to pylifecycle
|
|||
mod ceval; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
mod import;
|
||||
mod intrcheck; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
#[cfg(Py_3_6)]
|
||||
mod osmodule;
|
||||
mod sysmodule; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
|
||||
|
|
|
@ -71,26 +71,6 @@ extern "C" {
|
|||
pub fn PyObject_SetItem(o: *mut PyObject, key: *mut PyObject, v: *mut PyObject) -> c_int;
|
||||
pub fn PyObject_DelItemString(o: *mut PyObject, key: *const c_char) -> c_int;
|
||||
pub fn PyObject_DelItem(o: *mut PyObject, key: *mut PyObject) -> c_int;
|
||||
#[cfg_attr(PyPy, link_name = "PyPyObject_AsCharBuffer")]
|
||||
pub fn PyObject_AsCharBuffer(
|
||||
obj: *mut PyObject,
|
||||
buffer: *mut *const c_char,
|
||||
buffer_len: *mut Py_ssize_t,
|
||||
) -> c_int;
|
||||
#[cfg_attr(PyPy, link_name = "PyPyObject_CheckReadBuffer")]
|
||||
pub fn PyObject_CheckReadBuffer(obj: *mut PyObject) -> c_int;
|
||||
#[cfg_attr(PyPy, link_name = "PyPyObject_AsReadBuffer")]
|
||||
pub fn PyObject_AsReadBuffer(
|
||||
obj: *mut PyObject,
|
||||
buffer: *mut *const c_void,
|
||||
buffer_len: *mut Py_ssize_t,
|
||||
) -> c_int;
|
||||
#[cfg_attr(PyPy, link_name = "PyPyObject_AsWriteBuffer")]
|
||||
pub fn PyObject_AsWriteBuffer(
|
||||
obj: *mut PyObject,
|
||||
buffer: *mut *mut c_void,
|
||||
buffer_len: *mut Py_ssize_t,
|
||||
) -> c_int;
|
||||
}
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
|
@ -163,6 +143,11 @@ pub unsafe fn PyIter_Check(o: *mut PyObject) -> c_int {
|
|||
}) as c_int
|
||||
}
|
||||
|
||||
#[cfg(all(Py_LIMITED_API, Py_3_8))]
|
||||
extern "C" {
|
||||
pub fn PyIter_Check(obj: *mut PyObject) -> c_int;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
#[cfg_attr(PyPy, link_name = "PyPyIter_Next")]
|
||||
pub fn PyIter_Next(arg1: *mut PyObject) -> *mut PyObject;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// This header is new in Python 3.6
|
||||
use crate::ffi::object::PyObject;
|
||||
|
||||
extern "C" {
|
||||
|
|
|
@ -32,6 +32,6 @@ extern "C" {
|
|||
#[cfg_attr(PyPy, link_name = "PyPy_HashRandomizationFlag")]
|
||||
pub static mut Py_HashRandomizationFlag: c_int;
|
||||
pub static mut Py_IsolatedFlag: c_int;
|
||||
#[cfg(all(Py_3_6, windows))]
|
||||
#[cfg(windows)]
|
||||
pub static mut Py_LegacyWindowsStdioFlag: c_int;
|
||||
}
|
||||
|
|
|
@ -201,7 +201,6 @@ extern "C" {
|
|||
pub static mut PyExc_OSError: *mut PyObject;
|
||||
#[cfg_attr(PyPy, link_name = "PyPyExc_ImportError")]
|
||||
pub static mut PyExc_ImportError: *mut PyObject;
|
||||
#[cfg(Py_3_6)]
|
||||
#[cfg_attr(PyPy, link_name = "PyPyExc_ModuleNotFoundError")]
|
||||
pub static mut PyExc_ModuleNotFoundError: *mut PyObject;
|
||||
#[cfg_attr(PyPy, link_name = "PyPyExc_IndexError")]
|
||||
|
@ -339,7 +338,6 @@ extern "C" {
|
|||
) -> *mut PyObject;
|
||||
#[cfg_attr(PyPy, link_name = "PyPyErr_Format")]
|
||||
pub fn PyErr_Format(exception: *mut PyObject, format: *const c_char, ...) -> *mut PyObject;
|
||||
#[cfg(Py_3_6)]
|
||||
pub fn PyErr_SetImportErrorSubclass(
|
||||
arg1: *mut PyObject,
|
||||
arg2: *mut PyObject,
|
||||
|
|
|
@ -6,7 +6,6 @@ extern "C" {
|
|||
pub fn Py_Initialize();
|
||||
pub fn Py_InitializeEx(arg1: c_int);
|
||||
pub fn Py_Finalize();
|
||||
#[cfg(Py_3_6)]
|
||||
pub fn Py_FinalizeEx() -> c_int;
|
||||
|
||||
#[cfg_attr(PyPy, link_name = "PyPy_IsInitialized")]
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
#[cfg(Py_3_6)]
|
||||
use crate::ffi::ceval::_PyFrameEvalFunction;
|
||||
use crate::ffi::moduleobject::PyModuleDef;
|
||||
use crate::ffi::object::PyObject;
|
||||
use std::os::raw::{c_int, c_long};
|
||||
|
||||
#[cfg(Py_3_6)]
|
||||
pub const MAX_CO_EXTRA_USERS: c_int = 255;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct PyInterpreterState {
|
||||
pub ob_base: PyObject,
|
||||
#[cfg(Py_3_6)]
|
||||
pub eval_frame: _PyFrameEvalFunction,
|
||||
}
|
||||
|
||||
|
|
|
@ -96,9 +96,6 @@ extern "C" {
|
|||
index: Py_ssize_t,
|
||||
character: Py_UCS4,
|
||||
) -> c_int;
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
#[cfg_attr(PyPy, link_name = "PyPyUnicode_GetMax")]
|
||||
pub fn PyUnicode_GetMax() -> Py_UNICODE;
|
||||
#[cfg_attr(PyPy, link_name = "PyPyUnicode_Resize")]
|
||||
pub fn PyUnicode_Resize(unicode: *mut *mut PyObject, length: Py_ssize_t) -> c_int;
|
||||
#[cfg_attr(PyPy, link_name = "PyPyUnicode_FromEncodedObject")]
|
||||
|
@ -462,6 +459,4 @@ extern "C" {
|
|||
pub fn PyUnicode_Format(format: *mut PyObject, args: *mut PyObject) -> *mut PyObject;
|
||||
pub fn PyUnicode_Contains(container: *mut PyObject, element: *mut PyObject) -> c_int;
|
||||
pub fn PyUnicode_IsIdentifier(s: *mut PyObject) -> c_int;
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
pub fn PyUnicode_AsUnicodeCopy(unicode: *mut PyObject) -> *mut Py_UNICODE;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ extern "C" {
|
|||
format: *const c_char,
|
||||
...
|
||||
) -> c_int;
|
||||
#[cfg(Py_3_6)]
|
||||
pub fn PyErr_ResourceWarning(
|
||||
source: *mut PyObject,
|
||||
stack_level: Py_ssize_t,
|
||||
|
|
|
@ -12,7 +12,7 @@ use std::os::raw::c_void;
|
|||
/// The performance improvement applies to types that are often created and deleted in a row,
|
||||
/// so that they can benefit from a freelist.
|
||||
pub trait PyClassWithFreeList {
|
||||
fn get_free_list() -> &'static mut FreeList<*mut ffi::PyObject>;
|
||||
fn get_free_list(py: Python) -> &mut FreeList<*mut ffi::PyObject>;
|
||||
}
|
||||
|
||||
pub enum Slot<T> {
|
||||
|
@ -74,7 +74,7 @@ where
|
|||
unsafe fn new(py: Python, subtype: *mut ffi::PyTypeObject) -> *mut Self::Layout {
|
||||
// if subtype is not equal to this type, we cannot use the freelist
|
||||
if subtype == Self::type_object_raw(py) {
|
||||
if let Some(obj) = <Self as PyClassWithFreeList>::get_free_list().pop() {
|
||||
if let Some(obj) = <Self as PyClassWithFreeList>::get_free_list(py).pop() {
|
||||
ffi::PyObject_Init(obj, subtype);
|
||||
return obj as _;
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ where
|
|||
(*self_).py_drop(py);
|
||||
let obj = PyAny::from_borrowed_ptr_or_panic(py, self_ as _);
|
||||
|
||||
if let Some(obj) = <Self as PyClassWithFreeList>::get_free_list().insert(obj.as_ptr()) {
|
||||
if let Some(obj) = <Self as PyClassWithFreeList>::get_free_list(py).insert(obj.as_ptr()) {
|
||||
match get_type_free(ffi::Py_TYPE(obj)) {
|
||||
Some(free) => {
|
||||
let ty = ffi::Py_TYPE(obj);
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
//! crate-type = ["cdylib"]
|
||||
//!
|
||||
//! [dependencies.pyo3]
|
||||
//! version = "0.12.2"
|
||||
//! version = "0.12.3"
|
||||
//! features = ["extension-module"]
|
||||
//! ```
|
||||
//!
|
||||
|
@ -109,7 +109,7 @@
|
|||
//!
|
||||
//! ```toml
|
||||
//! [dependencies]
|
||||
//! pyo3 = "0.12.2"
|
||||
//! pyo3 = "0.12.3"
|
||||
//! ```
|
||||
//!
|
||||
//! Example program displaying the value of `sys.version`:
|
||||
|
|
|
@ -362,7 +362,7 @@ impl PyAny {
|
|||
///
|
||||
/// This is typically a new iterator but if the argument is an iterator,
|
||||
/// this returns itself.
|
||||
pub fn iter(&self) -> PyResult<PyIterator> {
|
||||
pub fn iter(&self) -> PyResult<&PyIterator> {
|
||||
PyIterator::from_object(self.py(), self)
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ use crate::ffi;
|
|||
use crate::ffi::datetime::{PyDateTime_FromTimestamp, PyDate_FromTimestamp};
|
||||
use crate::ffi::PyDateTimeAPI;
|
||||
use crate::ffi::{PyDateTime_Check, PyDate_Check, PyDelta_Check, PyTZInfo_Check, PyTime_Check};
|
||||
#[cfg(all(Py_3_6, not(PyPy)))]
|
||||
#[cfg(not(PyPy))]
|
||||
use crate::ffi::{PyDateTime_DATE_GET_FOLD, PyDateTime_TIME_GET_FOLD};
|
||||
use crate::ffi::{
|
||||
PyDateTime_DATE_GET_HOUR, PyDateTime_DATE_GET_MICROSECOND, PyDateTime_DATE_GET_MINUTE,
|
||||
|
@ -57,7 +57,7 @@ pub trait PyTimeAccess {
|
|||
fn get_minute(&self) -> u8;
|
||||
fn get_second(&self) -> u8;
|
||||
fn get_microsecond(&self) -> u32;
|
||||
#[cfg(all(Py_3_6, not(PyPy)))]
|
||||
#[cfg(not(PyPy))]
|
||||
fn get_fold(&self) -> u8;
|
||||
}
|
||||
|
||||
|
@ -223,7 +223,7 @@ impl PyTimeAccess for PyDateTime {
|
|||
unsafe { PyDateTime_DATE_GET_MICROSECOND(self.as_ptr()) as u32 }
|
||||
}
|
||||
|
||||
#[cfg(all(Py_3_6, not(PyPy)))]
|
||||
#[cfg(not(PyPy))]
|
||||
fn get_fold(&self) -> u8 {
|
||||
unsafe { PyDateTime_DATE_GET_FOLD(self.as_ptr()) as u8 }
|
||||
}
|
||||
|
@ -262,10 +262,8 @@ impl PyTime {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(Py_3_6)]
|
||||
#[cfg(not(PyPy))]
|
||||
/// Alternate constructor that takes a `fold` argument
|
||||
///
|
||||
/// First available in Python 3.6.
|
||||
pub fn new_with_fold<'p>(
|
||||
py: Python<'p>,
|
||||
hour: u8,
|
||||
|
@ -307,7 +305,7 @@ impl PyTimeAccess for PyTime {
|
|||
unsafe { PyDateTime_TIME_GET_MICROSECOND(self.as_ptr()) as u32 }
|
||||
}
|
||||
|
||||
#[cfg(all(Py_3_6, not(PyPy)))]
|
||||
#[cfg(not(PyPy))]
|
||||
fn get_fold(&self) -> u8 {
|
||||
unsafe { PyDateTime_TIME_GET_FOLD(self.as_ptr()) as u8 }
|
||||
}
|
||||
|
|
|
@ -3,12 +3,11 @@
|
|||
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
|
||||
|
||||
use crate::{ffi, AsPyPointer, PyAny, PyErr, PyNativeType, PyResult, Python};
|
||||
#[cfg(any(not(Py_LIMITED_API), Py_3_8))]
|
||||
use crate::{PyDowncastError, PyTryFrom};
|
||||
|
||||
/// A Python iterator object.
|
||||
///
|
||||
/// Unlike other Python objects, this class includes a `Python<'p>` token
|
||||
/// so that `PyIterator` can implement the Rust `Iterator` trait.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
|
@ -26,29 +25,25 @@ use crate::{ffi, AsPyPointer, PyAny, PyErr, PyNativeType, PyResult, Python};
|
|||
/// # }
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct PyIterator<'p>(&'p PyAny);
|
||||
#[repr(transparent)]
|
||||
pub struct PyIterator(PyAny);
|
||||
pyobject_native_type_named!(PyIterator);
|
||||
#[cfg(any(not(Py_LIMITED_API), Py_3_8))]
|
||||
pyobject_native_type_extract!(PyIterator);
|
||||
|
||||
impl<'p> PyIterator<'p> {
|
||||
/// Constructs a `PyIterator` from a Python iterator object.
|
||||
pub fn from_object<T>(py: Python<'p>, obj: &T) -> PyResult<PyIterator<'p>>
|
||||
impl PyIterator {
|
||||
/// Constructs a `PyIterator` from a Python iterable object.
|
||||
///
|
||||
/// Equivalent to Python's built-in `iter` function.
|
||||
pub fn from_object<'p, T>(py: Python<'p>, obj: &T) -> PyResult<&'p PyIterator>
|
||||
where
|
||||
T: AsPyPointer,
|
||||
{
|
||||
let iter = unsafe {
|
||||
// This looks suspicious, but is actually correct. Even though ptr is an owned
|
||||
// reference, PyIterator takes ownership of the reference and decreases the count
|
||||
// in its Drop implementation.
|
||||
//
|
||||
// Therefore we must use from_borrowed_ptr_or_err instead of from_owned_ptr_or_err so
|
||||
// that the GILPool does not take ownership of the reference.
|
||||
py.from_borrowed_ptr_or_err(ffi::PyObject_GetIter(obj.as_ptr()))?
|
||||
};
|
||||
|
||||
Ok(PyIterator(iter))
|
||||
unsafe { py.from_owned_ptr_or_err(ffi::PyObject_GetIter(obj.as_ptr())) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p> Iterator for PyIterator<'p> {
|
||||
impl<'p> Iterator for &'p PyIterator {
|
||||
type Item = PyResult<&'p PyAny>;
|
||||
|
||||
/// Retrieves the next item from an iterator.
|
||||
|
@ -73,10 +68,28 @@ impl<'p> Iterator for PyIterator<'p> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Dropping a `PyIterator` instance decrements the reference count on the object by 1.
|
||||
impl<'p> Drop for PyIterator<'p> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { ffi::Py_DECREF(self.0.as_ptr()) }
|
||||
// PyIter_Check does not exist in the limited API until 3.8
|
||||
#[cfg(any(not(Py_LIMITED_API), Py_3_8))]
|
||||
impl<'v> PyTryFrom<'v> for PyIterator {
|
||||
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v PyIterator, PyDowncastError<'v>> {
|
||||
let value = value.into();
|
||||
unsafe {
|
||||
if ffi::PyIter_Check(value.as_ptr()) != 0 {
|
||||
Ok(<PyIterator as PyTryFrom>::try_from_unchecked(value))
|
||||
} else {
|
||||
Err(PyDowncastError::new(value, "Iterator"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v PyIterator, PyDowncastError<'v>> {
|
||||
<PyIterator as PyTryFrom>::try_from(value)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v PyIterator {
|
||||
let ptr = value.into() as *const _ as *const PyIterator;
|
||||
&*ptr
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,8 +99,9 @@ mod tests {
|
|||
use crate::exceptions::PyTypeError;
|
||||
use crate::gil::GILPool;
|
||||
use crate::types::{PyDict, PyList};
|
||||
use crate::Python;
|
||||
use crate::ToPyObject;
|
||||
#[cfg(any(not(Py_LIMITED_API), Py_3_8))]
|
||||
use crate::{Py, PyAny, PyTryFrom};
|
||||
use crate::{Python, ToPyObject};
|
||||
use indoc::indoc;
|
||||
|
||||
#[test]
|
||||
|
@ -189,4 +203,14 @@ mod tests {
|
|||
|
||||
assert!(err.is_instance::<PyTypeError>(py))
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(not(Py_LIMITED_API), Py_3_8))]
|
||||
fn iterator_try_from() {
|
||||
let gil_guard = Python::acquire_gil();
|
||||
let py = gil_guard.python();
|
||||
let obj: Py<PyAny> = vec![10, 20].to_object(py).as_ref(py).iter().unwrap().into();
|
||||
let iter: &PyIterator = PyIterator::try_from(obj.as_ref(py)).unwrap();
|
||||
assert_eq!(obj, iter.into());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,8 +118,8 @@ impl PySet {
|
|||
}
|
||||
|
||||
#[cfg(Py_LIMITED_API)]
|
||||
pub struct PySetIterator<'py> {
|
||||
it: PyIterator<'py>,
|
||||
pub struct PySetIterator<'p> {
|
||||
it: &'p PyIterator,
|
||||
}
|
||||
|
||||
#[cfg(Py_LIMITED_API)]
|
||||
|
|
|
@ -16,9 +16,22 @@ macro_rules! py_expect_exception {
|
|||
let d = [(stringify!($val), &$val)].into_py_dict($py);
|
||||
|
||||
let res = $py.run($code, None, Some(d));
|
||||
let err = res.unwrap_err();
|
||||
let err = res.expect_err(&format!("Did not raise {}", stringify!($err)));
|
||||
if !err.matches($py, $py.get_type::<pyo3::exceptions::$err>()) {
|
||||
panic!("Expected {} but got {:?}", stringify!($err), err)
|
||||
}
|
||||
err
|
||||
}};
|
||||
($py:expr, $val:ident, $code:expr, $err:ident, $err_msg:expr) => {{
|
||||
let err = py_expect_exception!($py, $val, $code, $err);
|
||||
assert_eq!(
|
||||
err.instance($py)
|
||||
.str()
|
||||
.expect("error str() failed")
|
||||
.to_str()
|
||||
.expect("message was not valid utf8"),
|
||||
$err_msg
|
||||
);
|
||||
err
|
||||
}};
|
||||
}
|
||||
|
|
|
@ -604,7 +604,7 @@ mod return_not_implemented {
|
|||
c2,
|
||||
&format!("class Other: pass\nc2 {} Other()", operator),
|
||||
PyTypeError
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
fn _test_inplace_binary_operator(operator: &str, dunder: &str) {
|
||||
|
|
|
@ -121,7 +121,6 @@ fn test_datetime_utc() {
|
|||
assert_approx_eq!(offset, 0f32);
|
||||
}
|
||||
|
||||
#[cfg(Py_3_6)]
|
||||
static INVALID_DATES: &[(i32, u8, u8)] = &[
|
||||
(-1, 1, 1),
|
||||
(0, 1, 1),
|
||||
|
@ -134,16 +133,13 @@ static INVALID_DATES: &[(i32, u8, u8)] = &[
|
|||
(2018, 1, 32),
|
||||
];
|
||||
|
||||
#[cfg(Py_3_6)]
|
||||
static INVALID_TIMES: &[(u8, u8, u8, u32)] =
|
||||
&[(25, 0, 0, 0), (255, 0, 0, 0), (0, 60, 0, 0), (0, 0, 61, 0)];
|
||||
|
||||
#[cfg(Py_3_6)]
|
||||
#[test]
|
||||
fn test_pydate_out_of_bounds() {
|
||||
use pyo3::types::PyDate;
|
||||
|
||||
// This test is an XFAIL on Python < 3.6 until bounds checking is implemented
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
for val in INVALID_DATES {
|
||||
|
@ -153,12 +149,10 @@ fn test_pydate_out_of_bounds() {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(Py_3_6)]
|
||||
#[test]
|
||||
fn test_pytime_out_of_bounds() {
|
||||
use pyo3::types::PyTime;
|
||||
|
||||
// This test is an XFAIL on Python < 3.6 until bounds checking is implemented
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
for val in INVALID_TIMES {
|
||||
|
@ -168,13 +162,11 @@ fn test_pytime_out_of_bounds() {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(Py_3_6)]
|
||||
#[test]
|
||||
fn test_pydatetime_out_of_bounds() {
|
||||
use pyo3::types::PyDateTime;
|
||||
use std::iter;
|
||||
|
||||
// This test is an XFAIL on Python < 3.6 until bounds checking is implemented
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let valid_time = (0, 0, 0, 0);
|
||||
|
|
|
@ -296,6 +296,6 @@ fn test_err_rename() {
|
|||
assert!(f.is_err());
|
||||
assert_eq!(
|
||||
f.unwrap_err().to_string(),
|
||||
"TypeError: Can't convert {} (dict) to Union[str, uint, int]"
|
||||
"TypeError: 'dict' object cannot be converted to 'Union[str, uint, int]'"
|
||||
);
|
||||
}
|
||||
|
|
|
@ -135,3 +135,54 @@ fn test_raw_function() {
|
|||
.unwrap();
|
||||
assert_eq!(res, "Some(true)");
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn conversion_error(str_arg: &str, int_arg: i64, tuple_arg: (&str, f64), option_arg: Option<i64>) {
|
||||
println!(
|
||||
"{:?} {:?} {:?} {:?}",
|
||||
str_arg, int_arg, tuple_arg, option_arg
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_conversion_error() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
||||
let conversion_error = wrap_pyfunction!(conversion_error)(py).unwrap();
|
||||
py_expect_exception!(
|
||||
py,
|
||||
conversion_error,
|
||||
"conversion_error(None, None, None, None)",
|
||||
PyTypeError,
|
||||
"argument 'str_arg': 'NoneType' object cannot be converted to 'PyString'"
|
||||
);
|
||||
py_expect_exception!(
|
||||
py,
|
||||
conversion_error,
|
||||
"conversion_error(100, None, None, None)",
|
||||
PyTypeError,
|
||||
"argument 'str_arg': 'int' object cannot be converted to 'PyString'"
|
||||
);
|
||||
py_expect_exception!(
|
||||
py,
|
||||
conversion_error,
|
||||
"conversion_error('string1', 'string2', None, None)",
|
||||
PyTypeError,
|
||||
"argument 'int_arg': 'str' object cannot be interpreted as an integer"
|
||||
);
|
||||
py_expect_exception!(
|
||||
py,
|
||||
conversion_error,
|
||||
"conversion_error('string1', -100, 'string2', None)",
|
||||
PyTypeError,
|
||||
"argument 'tuple_arg': 'str' object cannot be converted to 'PyTuple'"
|
||||
);
|
||||
py_expect_exception!(
|
||||
py,
|
||||
conversion_error,
|
||||
"conversion_error('string1', -100, ('string2', 10.), 'string3')",
|
||||
PyTypeError,
|
||||
"argument 'option_arg': 'str' object cannot be interpreted as an integer"
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use pyo3::prelude::*;
|
||||
use pyo3::py_run;
|
||||
use pyo3::wrap_pyfunction;
|
||||
|
||||
mod common;
|
||||
|
@ -15,15 +14,11 @@ fn test_unicode_encode_error() {
|
|||
let py = gil.python();
|
||||
|
||||
let take_str = wrap_pyfunction!(take_str)(py).unwrap();
|
||||
py_run!(
|
||||
py_expect_exception!(
|
||||
py,
|
||||
take_str,
|
||||
r#"
|
||||
try:
|
||||
take_str('\ud800')
|
||||
except UnicodeEncodeError as e:
|
||||
error_msg = "'utf-8' codec can't encode character '\\ud800' in position 0: surrogates not allowed"
|
||||
assert str(e) == error_msg
|
||||
"#
|
||||
"take_str('\\ud800')",
|
||||
PyUnicodeEncodeError,
|
||||
"'utf-8' codec can't encode character '\\ud800' in position 0: surrogates not allowed"
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue