Skip to content

Commit d24ca41

Browse files
youknowdotcodex
andauthored
Accept JSON encoder keyword arguments and normalize initial indentation (#9459)
Match CPython encoder_new/encoder_call keyword names and negative initial indentation prefix behavior. Refresh the complete speedups test module through update_lib after scoped canonical and oracle validation. Assisted-by: OpenAI Codex: model version unavailable Co-authored-by: Codex <codex@openai.com>
1 parent f98543d commit d24ca41

2 files changed

Lines changed: 50 additions & 25 deletions

File tree

‎Lib/test/test_json/test_speedups.py‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
from test.test_json import CTest
22
from test.support import gc_collect
33

4-
import unittest # XXX: RUSTPYTHON; importing to be able to skip tests
5-
64

75
class BadBool:
86
def __bool__(self):
@@ -84,7 +82,6 @@ def test_unsortable_keys(self):
8482
with self.assertRaises(TypeError):
8583
self.json.encoder.JSONEncoder(sort_keys=True).encode({'a': 1, 1: 'a'})
8684

87-
@unittest.expectedFailure # TODO: RUSTPYTHON; TypeError: 'NoneType' object is not callable
8885
def test_current_indent_level(self):
8986
enc = self.json.encoder.c_make_encoder(
9087
markers=None,

‎crates/stdlib/src/json.rs‎

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -809,34 +809,44 @@ mod _json {
809809
markers: crate::vm::common::lock::PyMutex<HashSet<usize>>,
810810
}
811811

812+
#[derive(FromArgs)]
813+
struct EncoderArgs {
814+
#[pyarg(any)]
815+
markers: PyObjectRef,
816+
#[pyarg(any)]
817+
default: PyObjectRef,
818+
#[pyarg(any)]
819+
encoder: PyObjectRef,
820+
#[pyarg(any)]
821+
indent: PyObjectRef,
822+
#[pyarg(any)]
823+
key_separator: PyStrRef,
824+
#[pyarg(any)]
825+
item_separator: PyStrRef,
826+
#[pyarg(any)]
827+
sort_keys: PyObjectRef,
828+
#[pyarg(any)]
829+
skipkeys: PyObjectRef,
830+
#[pyarg(any)]
831+
allow_nan: PyObjectRef,
832+
}
833+
812834
impl Constructor for JsonEncoder {
813-
// markers, default, encoder, indent, key_separator, item_separator,
814-
// sort_keys, skipkeys, allow_nan -- exactly as `encoder.py` calls
815-
// `c_make_encoder`.
816-
// Nested tuple: `FromArgs` is only implemented up to 8-tuples, and
817-
// nested tuples count as a single top-level slot while still
818-
// consuming their own positional arguments in order.
819-
type Args = (
820-
PyObjectRef,
821-
PyObjectRef,
822-
PyObjectRef,
823-
PyObjectRef,
824-
PyStrRef,
825-
PyStrRef,
826-
(PyObjectRef, PyObjectRef, PyObjectRef),
827-
);
835+
type Args = EncoderArgs;
828836

829837
fn py_new(
830838
_cls: &Py<PyType>,
831-
(
839+
EncoderArgs {
832840
markers,
833841
default,
834842
encoder,
835843
indent,
836844
key_separator,
837845
item_separator,
838-
(sort_keys, skipkeys, allow_nan),
839-
): Self::Args,
846+
sort_keys,
847+
skipkeys,
848+
allow_nan,
849+
}: Self::Args,
840850
vm: &VirtualMachine,
841851
) -> PyResult<Self> {
842852
let check_circular = if vm.is_none(&markers) {
@@ -1334,11 +1344,29 @@ mod _json {
13341344
}
13351345
}
13361346

1337-
impl Callable for JsonEncoder {
1338-
type Args = (PyObjectRef, PyObjectRef);
1347+
#[derive(FromArgs)]
1348+
struct EncoderCallArgs {
1349+
#[pyarg(any)]
1350+
obj: PyObjectRef,
1351+
#[pyarg(any)]
1352+
_current_indent_level: PyObjectRef,
1353+
}
13391354

1340-
fn call(zelf: &Py<Self>, (obj, indent_level): Self::Args, vm: &VirtualMachine) -> PyResult {
1341-
let level: isize = indent_level.try_index(vm)?.try_to_primitive(vm)?;
1355+
impl Callable for JsonEncoder {
1356+
type Args = EncoderCallArgs;
1357+
1358+
fn call(
1359+
zelf: &Py<Self>,
1360+
EncoderCallArgs {
1361+
obj,
1362+
_current_indent_level,
1363+
}: Self::Args,
1364+
vm: &VirtualMachine,
1365+
) -> PyResult {
1366+
let level: isize = _current_indent_level.try_index(vm)?.try_to_primitive(vm)?;
1367+
// CPython starts its indent cache with indent * initial_level;
1368+
// negative string repetition produces the same prefix as zero.
1369+
let level = level.max(0);
13421370
let mut out = Wtf8Buf::new();
13431371
zelf.encode_value(&obj, level, &mut out, vm)?;
13441372
Ok(vm.new_tuple((out,)).into())

0 commit comments

Comments
 (0)