rustpython_vm/builtins/
namespace.rs1use super::{tuple::IntoPyTuple, PyTupleRef, PyType};
2use crate::{
3 builtins::PyDict,
4 class::PyClassImpl,
5 function::{FuncArgs, PyComparisonValue},
6 recursion::ReprGuard,
7 types::{
8 Comparable, Constructor, DefaultConstructor, Initializer, PyComparisonOp, Representable,
9 },
10 AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
11};
12
13#[pyclass(module = "types", name = "SimpleNamespace")]
17#[derive(Debug, Default)]
18pub struct PyNamespace {}
19
20impl PyPayload for PyNamespace {
21 fn class(ctx: &Context) -> &'static Py<PyType> {
22 ctx.types.namespace_type
23 }
24}
25
26impl DefaultConstructor for PyNamespace {}
27
28impl PyNamespace {
29 pub fn new_ref(ctx: &Context) -> PyRef<Self> {
30 PyRef::new_ref(
31 Self {},
32 ctx.types.namespace_type.to_owned(),
33 Some(ctx.new_dict()),
34 )
35 }
36}
37
38#[pyclass(
39 flags(BASETYPE, HAS_DICT),
40 with(Constructor, Initializer, Comparable, Representable)
41)]
42impl PyNamespace {
43 #[pymethod(magic)]
44 fn reduce(zelf: PyObjectRef, vm: &VirtualMachine) -> PyTupleRef {
45 let dict = zelf.as_object().dict().unwrap();
46 let obj = zelf.as_object().to_owned();
47 let result: (PyObjectRef, PyObjectRef, PyObjectRef) = (
48 obj.class().to_owned().into(),
49 vm.new_tuple(()).into(),
50 dict.into(),
51 );
52 result.into_pytuple(vm)
53 }
54}
55
56impl Initializer for PyNamespace {
57 type Args = FuncArgs;
58
59 fn init(zelf: PyRef<Self>, args: Self::Args, vm: &VirtualMachine) -> PyResult<()> {
60 if !args.args.is_empty() {
61 return Err(vm.new_type_error("no positional arguments expected".to_owned()));
62 }
63 for (name, value) in args.kwargs.into_iter() {
64 let name = vm.ctx.new_str(name);
65 zelf.as_object().set_attr(&name, value, vm)?;
66 }
67 Ok(())
68 }
69}
70
71impl Comparable for PyNamespace {
72 fn cmp(
73 zelf: &Py<Self>,
74 other: &PyObject,
75 op: PyComparisonOp,
76 vm: &VirtualMachine,
77 ) -> PyResult<PyComparisonValue> {
78 let other = class_or_notimplemented!(Self, other);
79 let (d1, d2) = (
80 zelf.as_object().dict().unwrap(),
81 other.as_object().dict().unwrap(),
82 );
83 PyDict::cmp(&d1, d2.as_object(), op, vm)
84 }
85}
86
87impl Representable for PyNamespace {
88 #[inline]
89 fn repr_str(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<String> {
90 let o = zelf.as_object();
91 let name = if o.class().is(vm.ctx.types.namespace_type) {
92 "namespace".to_owned()
93 } else {
94 o.class().slot_name().to_owned()
95 };
96
97 let repr = if let Some(_guard) = ReprGuard::enter(vm, zelf.as_object()) {
98 let dict = zelf.as_object().dict().unwrap();
99 let mut parts = Vec::with_capacity(dict.len());
100 for (key, value) in dict {
101 let k = &key.repr(vm)?;
102 let key_str = k.as_str();
103 let value_repr = value.repr(vm)?;
104 parts.push(format!("{}={}", &key_str[1..key_str.len() - 1], value_repr));
105 }
106 format!("{}({})", name, parts.join(", "))
107 } else {
108 format!("{name}(...)")
109 };
110 Ok(repr)
111 }
112}
113
114pub fn init(context: &Context) {
115 PyNamespace::extend_class(context, context.types.namespace_type);
116}