Skip to content

Commit 310fe64

Browse files
authored
Preserve order for collections.OrderedDict (#1801)
1 parent d90cdd1 commit 310fe64

File tree

2 files changed

+31
-2
lines changed

2 files changed

+31
-2
lines changed

src/input/input_python.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -395,15 +395,17 @@ impl<'py> Input<'py> for Bound<'py, PyAny> {
395395
Self: 'a;
396396

397397
fn strict_dict<'a>(&'a self) -> ValResult<GenericPyMapping<'a, 'py>> {
398-
if let Ok(dict) = self.downcast::<PyDict>() {
398+
if let Ok(dict) = self.downcast_exact::<PyDict>() {
399399
Ok(GenericPyMapping::Dict(dict))
400+
} else if self.is_instance_of::<PyDict>() {
401+
Ok(GenericPyMapping::Mapping(self.downcast::<PyMapping>()?))
400402
} else {
401403
Err(ValError::new(ErrorTypeDefaults::DictType, self))
402404
}
403405
}
404406

405407
fn lax_dict<'a>(&'a self) -> ValResult<GenericPyMapping<'a, 'py>> {
406-
if let Ok(dict) = self.downcast::<PyDict>() {
408+
if let Ok(dict) = self.downcast_exact::<PyDict>() {
407409
Ok(GenericPyMapping::Dict(dict))
408410
} else if let Ok(mapping) = self.downcast::<PyMapping>() {
409411
Ok(GenericPyMapping::Mapping(mapping))

tests/validators/test_dict.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import re
2+
import sys
23
from collections import OrderedDict
34
from collections.abc import Mapping
45
from typing import Any
@@ -313,3 +314,29 @@ def test_dict_fail_fast(fail_fast, expected):
313314
v.validate_python({'a': 'b', 'c': 'd'})
314315

315316
assert exc_info.value.errors(include_url=False) == expected
317+
318+
319+
@pytest.mark.skipif(
320+
sys.implementation.name == 'graalpy',
321+
reason='GraalPy has a bug where PyMapping.items() does not preserve OrderedDict order. See: https://github.com/oracle/graalpython/issues/553',
322+
)
323+
@pytest.mark.parametrize('strict', [True, False])
324+
def test_ordered_dict_key_order_preservation(strict):
325+
# GH 12273
326+
v = SchemaValidator(cs.dict_schema(keys_schema=cs.str_schema(), values_schema=cs.int_schema()))
327+
328+
# Original issue
329+
foo = OrderedDict({'a': 1, 'b': 2})
330+
foo.move_to_end('a')
331+
332+
result = v.validate_python(foo, strict=strict)
333+
assert list(result.keys()) == list(foo.keys()) == ['b', 'a']
334+
assert result == {'b': 2, 'a': 1}
335+
336+
# More complex case
337+
foo2 = OrderedDict({'x': 1, 'y': 2, 'z': 3})
338+
foo2.move_to_end('x')
339+
340+
result2 = v.validate_python(foo2, strict=strict)
341+
assert list(result2.keys()) == list(foo2.keys()) == ['y', 'z', 'x']
342+
assert result2 == {'y': 2, 'z': 3, 'x': 1}

0 commit comments

Comments
 (0)