diff -r 4d2ef8f3c424 Include/sliceobject.h --- a/Include/sliceobject.h Wed Jun 03 19:04:42 2015 -0700 +++ b/Include/sliceobject.h Thu Jun 04 01:53:59 2015 -0400 @@ -4,11 +4,13 @@ extern "C" { #endif -/* The unique ellipsis object "..." */ +/* The unique ellipsis object "..." and sliceliteral*/ PyAPI_DATA(PyObject) _Py_EllipsisObject; /* Don't use this directly */ +PyAPI_DATA(PyObject) _Py_SliceLiteralObject; /* Don't use this directly */ #define Py_Ellipsis (&_Py_EllipsisObject) +#define _Py_SliceLiteral (&_Py_SliceLiteralObject) /* Slice object interface */ @@ -27,6 +29,7 @@ PyAPI_DATA(PyTypeObject) PySlice_Type; PyAPI_DATA(PyTypeObject) PyEllipsis_Type; +PyAPI_DATA(PyTypeObject) PySliceLiteral_Type; #define PySlice_Check(op) (Py_TYPE(op) == &PySlice_Type) diff -r 4d2ef8f3c424 Lib/test/test_slice.py --- a/Lib/test/test_slice.py Wed Jun 03 19:04:42 2015 -0700 +++ b/Lib/test/test_slice.py Thu Jun 04 01:53:59 2015 -0400 @@ -240,5 +240,33 @@ self.assertEqual(s.indices(15), t.indices(15)) self.assertNotEqual(id(s), id(t)) + +class SliceLiteralTest(unittest.TestCase): + def test_literal_syntax(self): + pairs = ( + (slice(1, 1, 1), slice.literal[1:1:1]), + (slice(1, 1, None), slice.literal[1:1]), + (slice(1, 1, None), slice.literal[1:1:]), + (slice(1, None, 1), slice.literal[1::1]), + (slice(1, None, None), slice.literal[1:]), + (slice(1, None, None), slice.literal[1::]), + (slice(None, 1, 1), slice.literal[:1:1]), + (slice(None, 1, None), slice.literal[:1]), + (slice(None, 1, None), slice.literal[:1:]), + (slice(None, None, None), slice.literal[:]), + (slice(None, None, None), slice.literal[::]), + ) + for call, literal in pairs: + self.assertEqual(call, literal) + + def test_singleton(self): + self.assertIs(type(slice.literal)(), slice.literal) + + def test_pickle(self): + s = slice.literal + for protocol in (0, 1, 2): + t = loads(dumps(s, protocol)) + self.assertIs(t, s) + if __name__ == "__main__": unittest.main() diff -r 4d2ef8f3c424 Objects/object.c --- a/Objects/object.c Wed Jun 03 19:04:42 2015 -0700 +++ b/Objects/object.c Thu Jun 04 01:53:59 2015 -0400 @@ -1697,6 +1697,10 @@ if (PyType_Ready(&PyEllipsis_Type) < 0) Py_FatalError("Can't initialize ellipsis type"); + if ((PyType_Ready(&PySlice_Type) < 0) || + PyDict_SetItemString(PySlice_Type.tp_dict, "literal", _Py_SliceLiteral)) + Py_FatalError("Can't initialize slice type"); + if (PyType_Ready(&PyMemberDescr_Type) < 0) Py_FatalError("Can't initialize member descriptor type"); diff -r 4d2ef8f3c424 Objects/sliceobject.c --- a/Objects/sliceobject.c Wed Jun 03 19:04:42 2015 -0700 +++ b/Objects/sliceobject.c Thu Jun 04 01:53:59 2015 -0400 @@ -90,6 +90,90 @@ 1, &PyEllipsis_Type }; +/* Forward decleration for use in slice.literal. */ +PyObject *PySlice_New(PyObject*, PyObject*, PyObject*); + +static PyObject * +sliceliteral_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + if (PyTuple_GET_SIZE(args) || (kwargs && PyDict_Size(kwargs))) { + PyErr_SetString(PyExc_TypeError, "SliceLiteralType takes no arguments"); + return NULL; + } + Py_INCREF(_Py_SliceLiteral); + return _Py_SliceLiteral; +} + +static PyObject * +sliceliteral_reduce(PyObject *op) +{ + return PyUnicode_FromString("slice.literal"); +} + +static PyObject * +sliceliteral_getitem(PyObject *self, PyObject *key) +{ + Py_INCREF(key); + return key; +} + +static PyMappingMethods sliceliteral_as_mapping = { + NULL, + (binaryfunc)sliceliteral_getitem, + NULL, +}; + +static PyMethodDef sliceliteral_methods[] = { + {"__getitem__", (PyCFunction)sliceliteral_getitem, METH_O, NULL}, + {"__reduce__", (PyCFunction)sliceliteral_reduce, METH_NOARGS, NULL}, + {NULL, NULL} +}; + +PyTypeObject PySliceLiteral_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "sliceliteral", /* tp_name */ + 0, /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /*never called*/ /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + &sliceliteral_as_mapping, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + sliceliteral_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + (newfunc)sliceliteral_new, /* tp_new */ +}; + +PyObject _Py_SliceLiteralObject = { + _PyObject_EXTRA_INIT + 1, &PySliceLiteral_Type +}; /* Slice object implementation */ @@ -300,7 +384,62 @@ static PyObject * slice_repr(PySliceObject *r) { - return PyUnicode_FromFormat("slice(%R, %R, %R)", r->start, r->stop, r->step); + PyObject *repred; + PyObject *start; + PyObject *stop; + PyObject *step; + PyObject *ret; + + if (r->start == Py_None) { + if (!(start = PyUnicode_FromString(":"))) { + return NULL; + } + } + else { + if (!(repred = PyObject_Repr(r->start))) { + return NULL; + } + start = PyUnicode_FromFormat("%U:", repred); + Py_DECREF(repred); + if (!start) { + return NULL; + } + } + if (r->stop == Py_None) { + if (!(stop = PyUnicode_FromString(""))) { + Py_DECREF(start); + return NULL; + } + } + else { + if (!(stop = PyObject_Repr(r->stop))) { + Py_DECREF(start); + return NULL; + } + } + if (r->step == Py_None) { + if (!(step = PyUnicode_FromString(""))) { + Py_DECREF(start); + Py_DECREF(stop); + return NULL; + } + } + else { + if (!(repred = PyObject_Repr(r->step))) { + return NULL; + } + step = PyUnicode_FromFormat(":%U", repred); + Py_DECREF(repred); + if (!step) { + return NULL; + } + } + + ret = PyUnicode_FromFormat("slice.literal[%U%U%U]", start, stop, step); + Py_DECREF(start); + Py_DECREF(stop); + Py_DECREF(step); + return ret; } static PyMemberDef slice_members[] = {