rustpython_vm/builtins/
namespace.rs

1use 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/// A simple attribute-based namespace.
14///
15/// SimpleNamespace(**kwargs)
16#[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}
Morty Proxy This is a proxified and sanitized view of the page, visit original site.