Skip to content
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
typing.NoDefault
  • Loading branch information
youknowone committed Jun 24, 2025
commit 499c7247df108cc6ce140ece8c4e046767ec6827
6 changes: 2 additions & 4 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -9706,14 +9706,14 @@ class CustomerModel(ModelBase, init=False):


class NoDefaultTests(BaseTestCase):
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_pickling(self):
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
s = pickle.dumps(NoDefault, proto)
loaded = pickle.loads(s)
self.assertIs(NoDefault, loaded)

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_constructor(self):
self.assertIs(NoDefault, type(NoDefault)())
with self.assertRaises(TypeError):
Expand All @@ -9731,8 +9731,6 @@ def test_doc(self):
def test_class(self):
self.assertIs(NoDefault.__class__, type(NoDefault))

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_no_call(self):
with self.assertRaises(TypeError):
NoDefault()
Expand Down
46 changes: 26 additions & 20 deletions vm/src/stdlib/typing.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
pub(crate) use _typing::make_module;
use crate::{PyRef, VirtualMachine, stdlib::PyModule};

pub(crate) use _typing::NoDefault;

pub(crate) fn make_module(vm: &VirtualMachine) -> PyRef<PyModule> {
let module = _typing::make_module(vm);
extend_module!(vm, &module, {
"NoDefault" => vm.ctx.typing_no_default.clone(),
});
module
}

#[pymodule]
pub(crate) mod _typing {
Expand Down Expand Up @@ -109,15 +119,16 @@ pub(crate) mod _typing {
#[pygetset(magic)]
fn default(&self, vm: &VirtualMachine) -> PyResult {
let mut default_value = self.default_value.lock();
if !vm.is_none(&default_value) {
// Check if default_value is NoDefault (not just None)
if !default_value.is(&vm.ctx.typing_no_default) {
return Ok(default_value.clone());
}
if !vm.is_none(&self.evaluate_default) {
*default_value = self.evaluate_default.call((), vm)?;
Ok(default_value.clone())
} else {
// Return NoDefault singleton
vm.import("typing", 0)?.get_attr("NoDefault", vm)
Ok(vm.ctx.typing_no_default.clone().into())
}
}

Expand All @@ -142,16 +153,8 @@ pub(crate) mod _typing {
return true;
}
let default_value = self.default_value.lock();
if vm.is_none(&default_value) {
return false;
}
// Check if default_value is NoDefault
if let Ok(typing_module) = vm.import("typing", 0) {
if let Ok(no_default) = typing_module.get_attr("NoDefault", vm) {
return !default_value.is(&no_default);
}
}
true
// Check if default_value is not NoDefault
!default_value.is(&vm.ctx.typing_no_default)
}
}

Expand Down Expand Up @@ -264,8 +267,12 @@ pub(crate) mod _typing {
};

// Handle default value
let default_value = default.unwrap_or_else(|| vm.ctx.none());
let evaluate_default = vm.ctx.none();
let (default_value, evaluate_default) = if let Some(default) = default {
(default, vm.ctx.none())
} else {
// If no default provided, use NoDefault singleton
(vm.ctx.typing_no_default.clone().into(), vm.ctx.none())
};

let typevar = TypeVar {
name,
Expand Down Expand Up @@ -408,10 +415,9 @@ pub(crate) mod _typing {
}
}

#[pyattr]
#[pyclass(name = "NoDefault", module = "typing")]
#[pyclass(no_attr, name = "NoDefaultType", module = "typing")]
#[derive(Debug, PyPayload)]
pub(crate) struct NoDefault;
pub struct NoDefault;

#[pyclass(with(Constructor), flags(BASETYPE))]
impl NoDefault {
Expand All @@ -429,8 +435,8 @@ pub(crate) mod _typing {
return Err(vm.new_type_error("NoDefaultType takes no arguments".to_owned()));
}

// Return singleton instance
vm.import("typing", 0)?.get_attr("NoDefault", vm)
// Return singleton instance from context
Ok(vm.ctx.typing_no_default.clone().into())
}
}

Expand Down
2 changes: 2 additions & 0 deletions vm/src/types/zoo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ pub struct TypeZoo {
pub object_type: &'static Py<PyType>,
pub ellipsis_type: &'static Py<PyType>,
pub none_type: &'static Py<PyType>,
pub typing_no_default_type: &'static Py<PyType>,
pub not_implemented_type: &'static Py<PyType>,
pub generic_alias_type: &'static Py<PyType>,
pub union_type: &'static Py<PyType>,
Expand Down Expand Up @@ -179,6 +180,7 @@ impl TypeZoo {
weakproxy_type: weakproxy::PyWeakProxy::init_builtin_type(),
method_descriptor_type: descriptor::PyMethodDescriptor::init_builtin_type(),
none_type: singletons::PyNone::init_builtin_type(),
typing_no_default_type: crate::stdlib::typing::NoDefault::init_builtin_type(),
not_implemented_type: singletons::PyNotImplemented::init_builtin_type(),
generic_alias_type: genericalias::PyGenericAlias::init_builtin_type(),
union_type: union_::PyUnion::init_builtin_type(),
Expand Down
8 changes: 8 additions & 0 deletions vm/src/vm/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ pub struct Context {
pub ellipsis: PyRef<PyEllipsis>,
pub not_implemented: PyRef<PyNotImplemented>,

pub typing_no_default: PyRef<crate::stdlib::typing::NoDefault>,

pub types: TypeZoo,
pub exceptions: exceptions::ExceptionZoo,
pub int_cache_pool: Vec<PyIntRef>,
Expand Down Expand Up @@ -278,6 +280,11 @@ impl Context {
let ellipsis = create_object(PyEllipsis, PyEllipsis::static_type());
let not_implemented = create_object(PyNotImplemented, PyNotImplemented::static_type());

let typing_no_default = create_object(
crate::stdlib::typing::NoDefault,
crate::stdlib::typing::NoDefault::static_type(),
);

let int_cache_pool = Self::INT_CACHE_POOL_RANGE
.map(|v| {
PyRef::new_ref(
Expand Down Expand Up @@ -317,6 +324,7 @@ impl Context {
true_value,
false_value,
none,
typing_no_default,
empty_tuple,
empty_frozenset,
empty_str,
Expand Down