8000 more typing by youknowone · Pull Request #5840 · RustPython/RustPython · GitHub
[go: up one dir, main page]

Skip to content

more typing #5840

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 9 commits into from
Jun 26, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Comparable for typing
  • Loading branch information
youknowone committed Jun 26, 2025
commit d6e04aacad8bb0e18dc940275a35e8f03f681db8
8 changes: 0 additions & 8 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,8 +387,6 @@ def test_basic_plain(self):
self.assertIs(T.__infer_variance__, False)
self.assertEqual(T.__module__, __name__)

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_basic_with_exec(self):
ns = {}
exec('from typing import TypeVar; T = TypeVar("T", bound=float)', ns, ns)
Expand Down Expand Up @@ -1286,8 +1284,6 @@ def test_module(self):
Ts = TypeVarTuple('Ts')
self.assertEqual(Ts.__module__, __name__)

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_exec(self):
ns = {}
exec('from typing import TypeVarTuple; Ts = TypeVarTuple("Ts")', ns)
Expand Down Expand Up @@ -8788,8 +8784,6 @@ def test_basic_plain(self):
self.assertEqual(P.__name__, 'P')
self.assertEqual(P.__module__, __name__)

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_basic_with_exec(self):
ns = {}
exec('from typing import ParamSpec; P = ParamSpec("P")', ns, ns)
Expand Down Expand Up @@ -9177,8 +9171,6 @@ def test_paramspec_gets_copied(self):
self.assertEqual(C2[Concatenate[str, P2]].__parameters__, (P2,))
self.assertEqual(C2[Concatenate[T, P2]].__parameters__, (T, P2))

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_cannot_subclass(self):
with self.assertRaisesRegex(TypeError, NOT_A_BASE_TYPE % 'ParamSpec'):
class C(ParamSpec): pass
Expand Down
108 changes: 85 additions & 23 deletions vm/src/stdlib/typing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ pub(crate) fn make_module(vm: &VirtualMachine) -> PyRef<PyModule> {
#[pymodule(name = "_typing")]
pub(crate) mod decl {
use crate::{
AsObject, PyObjectRef, PyPayload, PyResult, VirtualMachine,
AsObject, PyObject, PyObjectRef, PyPayload, PyResult, VirtualMachine,
builtins::{PyGenericAlias, PyTupleRef, PyTypeRef, pystr::AsPyStr},
function::{FuncArgs, IntoFuncArgs},
function::{FuncArgs, IntoFuncArgs, PyComparisonValue},
protocol::PyNumberMethods,
types::{AsNumber, Constructor, Representable},
types::{AsNumber, Comparable, Constructor, PyComparisonOp, Representable},
};

pub(crate) fn _call_typing_func_object<'a>(
Expand Down Expand Up @@ -751,7 +751,7 @@ pub(crate) mod decl {
pub(crate) struct ParamSpecArgs {
__origin__: PyObjectRef,
}
#[pyclass(flags(BASETYPE), with(Constructor, Representable))]
#[pyclass(with(Constructor, Representable, Comparable))]
impl ParamSpecArgs {
#[pymethod(magic)]
fn mro_entries(&self, _bases: PyObjectRef, vm: &VirtualMachine) -> PyResult {
Expand All @@ -762,15 +762,6 @@ pub(crate) mod decl {
fn origin(&self) -> PyObjectRef {
self.__origin__.clone()
}

#[pymethod(magic)]
fn eq(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
// Check if other has __origin__ attribute
if let Ok(other_origin) = other.get_attr("__origin__", vm) {
return Ok(self.__origin__.is(&other_origin));
}
Ok(false)
}
}

impl Constructor for ParamSpecArgs {
Expand All @@ -794,14 +785,52 @@ pub(crate) mod decl {
}
}

impl Comparable for ParamSpecArgs {
fn cmp(
zelf: &crate::Py<Self>,
other: &PyObject,
op: PyComparisonOp,
vm: &VirtualMachine,
) -> PyResult<PyComparisonValue> {
fn eq(
zelf: &crate::Py<ParamSpecArgs>,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<bool> {
// Check if other has __origin__ attribute
if let Ok(other_origin) = other.get_attr("__origin__", vm) {
return Ok(zelf.__origin__.is(&other_origin));
}
Ok(false)
}
match op {
PyComparisonOp::Eq => {
if let Ok(result) = eq(zelf, other.to_owned(), vm) {
Ok(result.into())
} else {
Ok(PyComparisonValue::NotImplemented)
}
}
PyComparisonOp::Ne => {
if let Ok(result) = eq(zelf, other.to_owned(), vm) {
Ok((!result).into())
} else {
Ok(PyComparisonValue::NotImplemented)
8000 }
}
_ => Ok(PyComparisonValue::NotImplemented),
}
}
}

#[pyattr]
#[pyclass(name = "ParamSpecKwargs", module = "typing")]
#[derive(Debug, PyPayload)]
#[allow(dead_code)]
pub(crate) struct ParamSpecKwargs {
__origin__: PyObjectRef,
}
#[pyclass(flags(BASETYPE), with(Constructor, Representable))]
#[pyclass(with(Constructor, Representable, Comparable))]
impl ParamSpecKwargs {
#[pymethod(magic)]
fn mro_entries(&self, _bases: PyObjectRef, vm: &VirtualMachine) -> PyResult {
Expand All @@ -812,15 +841,6 @@ pub(crate) mod decl {
fn origin(&self) -> PyObjectRef {
self.__origin__.clone()
}

#[pymethod(magic)]
fn eq(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
// Check if other has __origin__ attribute
if let Ok(other_origin) = other.get_attr("__origin__", vm) {
return Ok(self.__origin__.is(&other_origin));
}
Ok(false)
}
}

impl Constructor for ParamSpecKwargs {
Expand All @@ -844,6 +864,44 @@ pub(crate) mod decl {
}
}

impl Comparable for ParamSpecKwargs {
fn cmp(
zelf: &crate::Py<Self>,
other: &PyObject,
op: PyComparisonOp,
vm: &VirtualMachine,
) -> PyResult<PyComparisonValue> {
fn eq(
zelf: &crate::Py<ParamSpecKwargs>,
other: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<bool> {
// Check if other has __origin__ attribute
if let Ok(other_origin) = other.get_attr("__origin__", vm) {
return Ok(zelf.__origin__.is(&other_origin));
}
Ok(false)
}
match op {
PyComparisonOp::Eq => {
if let Ok(result) = eq(zelf, other.to_owned(), vm) {
Ok(result.into())
} else {
Ok(PyComparisonValue::NotImplemented)
}
}
PyComparisonOp::Ne => {
if let Ok(result) = eq(zelf, other.to_owned(), vm) {
Ok((!result).into())
} else {
Ok(PyComparisonValue::NotImplemented)
}
}
_ => Ok(PyComparisonValue::NotImplemented),
}
}
}

#[pyattr]
#[pyclass(name)]
#[derive(Debug, PyPayload)]
Expand Down Expand Up @@ -922,13 +980,17 @@ pub(crate) mod decl {
if let Ok(name_str) = module_name.str(vm) {
let name = name_str.as_str();
// CPython sets __module__ to None for builtins and <...> modules
// Also set to None for exec contexts (no __name__ in globals means exec)
if name == "builtins" || name.starts_with('<') {
// Don't set __module__ attribute at all (CPython behavior)
// This allows the typing module to handle it
return Ok(());
}
}
obj.set_attr("__module__", module_name, vm)?;
} else {
// If no module name is found (e.g., in exec context), set __module__ to None
obj.set_attr("__module__", vm.ctx.none(), vm)?;
}
Ok(())
}
Expand Down
Loading
0