1use crate::err::PyResult;
2use crate::ffi_ptr_ext::FfiPtrExt;
3use crate::py_result_ext::PyResultExt;
4use crate::{ffi, Bound, PyAny, Python};
5
6/// Represents a Python [`types.GenericAlias`](https://docs.python.org/3/library/types.html#types.GenericAlias) object.
7///
8/// Values of this type are accessed via PyO3's smart pointers, e.g. as
9/// [`Py<PyGenericAlias>`][crate::Py] or [`Bound<'py, PyGenericAlias>`][Bound].
10///
11/// This type is particularly convenient for users implementing
12/// [`__class_getitem__`](https://docs.python.org/3/reference/datamodel.html#object.__class_getitem__)
13/// for PyO3 classes to allow runtime parameterization.
14#[repr(transparent)]
15pub struct PyGenericAlias(PyAny);
16
17pyobject_native_type!(
18 PyGenericAlias,
19 ffi::PyDictObject,
20 pyobject_native_static_type_object!(ffi::Py_GenericAliasType)
21);
22
23impl PyGenericAlias {
24 /// Creates a new Python GenericAlias object.
25 ///
26 /// origin should be a non-parameterized generic class.
27 /// args should be a tuple (possibly of length 1) of types which parameterize origin.
28 pub fn new<'py>(
29 py: Python<'py>,
30 origin: &Bound<'py, PyAny>,
31 args: &Bound<'py, PyAny>,
32 ) -> PyResult<Bound<'py, PyGenericAlias>> {
33 unsafe {
34 ffiResult, …>::Py_GenericAlias(origin.as_ptr(), args.as_ptr())
35 .assume_owned_or_err(py)
36 .downcast_into_unchecked()
37 }
38 }
39}
40
41#[cfg(test)]
42mod tests {
43 use crate::instance::BoundObject;
44 use crate::types::any::PyAnyMethods;
45 use crate::{ffi, Python};
46
47 use super::PyGenericAlias;
48
49 // Tests that PyGenericAlias::new is identical to types.GenericAlias
50 // created from Python.
51 #[test]
52 fn equivalency_test() {
53 Python::with_gil(|py| {
54 let list_int = py
55 .eval(ffi::c_str!("list[int]"), None, None)
56 .unwrap()
57 .into_bound();
58
59 let cls = py
60 .eval(ffi::c_str!("list"), None, None)
61 .unwrap()
62 .into_bound();
63 let key = py
64 .eval(ffi::c_str!("(int,)"), None, None)
65 .unwrap()
66 .into_bound();
67 let generic_alias = PyGenericAlias::new(py, &cls, &key).unwrap();
68
69 assert!(generic_alias.eq(list_int).unwrap());
70 })
71 }
72}
73