Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: python/cpython
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 3385b518af867918b657566339b8024bac85cc11
Choose a base ref
..
head repository: python/cpython
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: c5ccb709398dc8f67cb287f977bfa42df0dfb6d2
Choose a head ref
2 changes: 1 addition & 1 deletion Doc/library/argparse.rst
Original file line number Diff line number Diff line change
@@ -1867,7 +1867,7 @@ Sub-commands
...
>>> # create the top-level parser
>>> parser = argparse.ArgumentParser()
>>> subparsers = parser.add_subparsers()
>>> subparsers = parser.add_subparsers(required=True)
>>>
>>> # create the parser for the "foo" command
>>> parser_foo = subparsers.add_parser('foo')
2 changes: 1 addition & 1 deletion Doc/library/csv.rst
Original file line number Diff line number Diff line change
@@ -458,7 +458,7 @@ Reader objects have the following public attributes:

DictReader objects have the following public attribute:

.. attribute:: csvreader.fieldnames
.. attribute:: DictReader.fieldnames

If not passed as a parameter when creating the object, this attribute is
initialized upon first access or when the first record is read from the
3 changes: 3 additions & 0 deletions Doc/library/functions.rst
Original file line number Diff line number Diff line change
@@ -1635,6 +1635,9 @@ are always available. They are listed here in alphabetical order.
example: ``a[start:stop:step]`` or ``a[start:stop, i]``. See
:func:`itertools.islice` for an alternate version that returns an iterator.

.. versionchanged:: 3.12
Slice objects are now :term:`hashable` (provided :attr:`~slice.start`,
:attr:`~slice.stop`, and :attr:`~slice.step` are hashable).

.. function:: sorted(iterable, /, *, key=None, reverse=False)

7 changes: 1 addition & 6 deletions Lib/test/test_capi/test_misc.py
Original file line number Diff line number Diff line change
@@ -419,11 +419,6 @@ def __setitem__(self, index, value):
with self.assertRaises(TypeError):
_testcapi.sequence_set_slice(None, 1, 3, 'xy')

mapping = {1: 'a', 2: 'b', 3: 'c'}
with self.assertRaises(TypeError):
_testcapi.sequence_set_slice(mapping, 1, 3, 'xy')
self.assertEqual(mapping, {1: 'a', 2: 'b', 3: 'c'})

def test_sequence_del_slice(self):
# Correct case:
data = [1, 2, 3, 4, 5]
@@ -459,7 +454,7 @@ def __delitem__(self, index):
_testcapi.sequence_del_slice(None, 1, 3)

mapping = {1: 'a', 2: 'b', 3: 'c'}
with self.assertRaises(TypeError):
with self.assertRaises(KeyError):
_testcapi.sequence_del_slice(mapping, 1, 3)
self.assertEqual(mapping, {1: 'a', 2: 'b', 3: 'c'})

2 changes: 1 addition & 1 deletion Lib/test/test_doctest.py
Original file line number Diff line number Diff line change
@@ -707,7 +707,7 @@ def non_Python_modules(): r"""
>>> import builtins
>>> tests = doctest.DocTestFinder().find(builtins)
>>> 825 < len(tests) < 845 # approximate number of objects with docstrings
>>> 830 < len(tests) < 850 # approximate number of objects with docstrings
True
>>> real_tests = [t for t in tests if len(t.examples) > 0]
>>> len(real_tests) # objects that actually have doctests
12 changes: 9 additions & 3 deletions Lib/test/test_slice.py
Original file line number Diff line number Diff line change
@@ -80,10 +80,16 @@ def test_repr(self):
self.assertEqual(repr(slice(1, 2, 3)), "slice(1, 2, 3)")

def test_hash(self):
# Verify clearing of SF bug #800796
self.assertRaises(TypeError, hash, slice(5))
self.assertEqual(hash(slice(5)), slice(5).__hash__())
self.assertEqual(hash(slice(1, 2)), slice(1, 2).__hash__())
self.assertEqual(hash(slice(1, 2, 3)), slice(1, 2, 3).__hash__())
self.assertNotEqual(slice(5), slice(6))

with self.assertRaises(TypeError):
hash(slice(1, 2, []))

with self.assertRaises(TypeError):
slice(5).__hash__()
hash(slice(4, {}))

def test_cmp(self):
s1 = slice(1, 2, 3)
1 change: 1 addition & 0 deletions Makefile.pre.in
Original file line number Diff line number Diff line change
@@ -2076,6 +2076,7 @@ TESTSUBDIRS= idlelib/idle_test \
test/test_importlib/resources/data02 \
test/test_importlib/resources/data02/one \
test/test_importlib/resources/data02/subdirectory \
test/test_importlib/resources/data02/subdirectory/subsubdir \
test/test_importlib/resources/data02/two \
test/test_importlib/resources/data03 \
test/test_importlib/resources/data03/namespace \
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Make the slice object hashable.
38 changes: 37 additions & 1 deletion Objects/sliceobject.c
Original file line number Diff line number Diff line change
@@ -628,6 +628,42 @@ slice_traverse(PySliceObject *v, visitproc visit, void *arg)
return 0;
}

/* code based on tuplehash() of Objects/tupleobject.c */
#if SIZEOF_PY_UHASH_T > 4
#define _PyHASH_XXPRIME_1 ((Py_uhash_t)11400714785074694791ULL)
#define _PyHASH_XXPRIME_2 ((Py_uhash_t)14029467366897019727ULL)
#define _PyHASH_XXPRIME_5 ((Py_uhash_t)2870177450012600261ULL)
#define _PyHASH_XXROTATE(x) ((x << 31) | (x >> 33)) /* Rotate left 31 bits */
#else
#define _PyHASH_XXPRIME_1 ((Py_uhash_t)2654435761UL)
#define _PyHASH_XXPRIME_2 ((Py_uhash_t)2246822519UL)
#define _PyHASH_XXPRIME_5 ((Py_uhash_t)374761393UL)
#define _PyHASH_XXROTATE(x) ((x << 13) | (x >> 19)) /* Rotate left 13 bits */
#endif

static Py_hash_t
slicehash(PySliceObject *v)
{
Py_uhash_t acc = _PyHASH_XXPRIME_5;
#define _PyHASH_SLICE_PART(com) { \
Py_uhash_t lane = PyObject_Hash(v->com); \
if(lane == (Py_uhash_t)-1) { \
return -1; \
} \
acc += lane * _PyHASH_XXPRIME_2; \
acc = _PyHASH_XXROTATE(acc); \
acc *= _PyHASH_XXPRIME_1; \
}
_PyHASH_SLICE_PART(start);
_PyHASH_SLICE_PART(stop);
_PyHASH_SLICE_PART(step);
#undef _PyHASH_SLICE_PART
if(acc == (Py_uhash_t)-1) {
return 1546275796;
}
return acc;
}

PyTypeObject PySlice_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"slice", /* Name of this type */
@@ -642,7 +678,7 @@ PyTypeObject PySlice_Type = {
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
PyObject_HashNotImplemented, /* tp_hash */
(hashfunc)slicehash, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
2 changes: 1 addition & 1 deletion Objects/tupleobject.c
Original file line number Diff line number Diff line change
@@ -288,7 +288,7 @@ tuplerepr(PyTupleObject *v)

/* Hash for tuples. This is a slightly simplified version of the xxHash
non-cryptographic hash:
- we do not use any parallellism, there is only 1 accumulator.
- we do not use any parallelism, there is only 1 accumulator.
- we drop the final mixing since this is just a permutation of the
output space: it does not help against collisions.
- at the end, we mangle the length with a single constant.