picklebuffer.rst
weakref.rst
capsule.rst
+ sentinel.rst
frame.rst
gen.rst
coro.rst
--- /dev/null
+.. highlight:: c
+
+.. _sentinelobjects:
+
+Sentinel objects
+----------------
+
+.. c:var:: PyTypeObject PySentinel_Type
+
+ This instance of :c:type:`PyTypeObject` represents the Python
+ :class:`sentinel` type. This is the same object as :class:`sentinel`.
+
+ .. versionadded:: next
+
+.. c:function:: int PySentinel_Check(PyObject *o)
+
+ Return true if *o* is a :class:`sentinel` object. The :class:`sentinel` type
+ does not allow subclasses, so this check is exact.
+
+ .. versionadded:: next
+
+.. c:function:: PyObject* PySentinel_New(const char *name, const char *module_name)
+
+ Return a new :class:`sentinel` object with :attr:`~sentinel.__name__` set to
+ *name* and :attr:`~sentinel.__module__` set to *module_name*.
+ *name* must not be ``NULL``. If *module_name* is ``NULL``, :attr:`~sentinel.__module__`
+ is set to ``None``.
+ Return ``NULL`` with an exception set on failure.
+
+ For pickling to work, *module_name* must be the name of an importable
+ module, and the sentinel must be accessible from that module under a
+ path matching *name*. Pickle treats *name* as a global variable name
+ in *module_name* (see :meth:`object.__reduce__`).
+
+ .. versionadded:: next
PySeqIter_New:PyObject*::+1:
PySeqIter_New:PyObject*:seq:0:
+PySentinel_New:PyObject*::+1:
+PySentinel_New:const char*:name::
+PySentinel_New:const char*:module_name::
+
PySequence_Check:int:::
PySequence_Check:PyObject*:o:0:
| | :func:`ascii` | | :func:`filter` | | :func:`map` | | **S** |
| | | | :func:`float` | | :func:`max` | | |func-set|_ |
| | **B** | | :func:`format` | | |func-memoryview|_ | | :func:`setattr` |
-| | :func:`bin` | | |func-frozenset|_ | | :func:`min` | | :func:`slice` |
-| | :func:`bool` | | | | | | :func:`sorted` |
-| | :func:`breakpoint` | | **G** | | **N** | | :func:`staticmethod` |
-| | |func-bytearray|_ | | :func:`getattr` | | :func:`next` | | |func-str|_ |
-| | |func-bytes|_ | | :func:`globals` | | | | :func:`sum` |
-| | | | | | **O** | | :func:`super` |
-| | **C** | | **H** | | :func:`object` | | |
+| | :func:`bin` | | |func-frozenset|_ | | :func:`min` | | :func:`sentinel` |
+| | :func:`bool` | | | | | | :func:`slice` |
+| | :func:`breakpoint` | | **G** | | **N** | | :func:`sorted` |
+| | |func-bytearray|_ | | :func:`getattr` | | :func:`next` | | :func:`staticmethod` |
+| | |func-bytes|_ | | :func:`globals` | | | | |func-str|_ |
+| | | | | | **O** | | :func:`sum` |
+| | **C** | | **H** | | :func:`object` | | :func:`super` |
| | :func:`callable` | | :func:`hasattr` | | :func:`oct` | | **T** |
| | :func:`chr` | | :func:`hash` | | :func:`open` | | |func-tuple|_ |
| | :func:`classmethod` | | :func:`help` | | :func:`ord` | | :func:`type` |
:func:`setattr`.
+.. class:: sentinel(name, /)
+
+ Return a new unique sentinel object. *name* must be a :class:`str`, and is
+ used as the returned object's representation::
+
+ >>> MISSING = sentinel("MISSING")
+ >>> MISSING
+ MISSING
+
+ Sentinel objects are truthy and compare equal only to themselves. They are
+ intended to be compared with the :keyword:`is` operator.
+
+ Shallow and deep copies of a sentinel object return the object itself.
+
+ Sentinels are conventionally assigned to a variable with a matching name.
+ Sentinels defined in this way can be used in :term:`type hints <type hint>`::
+
+ MISSING = sentinel("MISSING")
+
+ def next_value(default: int | MISSING = MISSING):
+ ...
+
+ Sentinel objects support the :ref:`| <bitwise>` operator for use in type expressions.
+
+ :mod:`Pickling <pickle>` is supported for sentinel objects that are
+ placed in the global scope of a module under a name matching the sentinel's
+ name, and for sentinels placed in class scopes with a name matching the
+ :term:`qualified name` of the sentinel. Other sentinels, such as those
+ defined in a function scope, are not picklable. The identity of the sentinel is preserved
+ after pickling::
+
+ import pickle
+
+ PICKLABLE = sentinel("PICKLABLE")
+
+ assert pickle.loads(pickle.dumps(PICKLABLE)) is PICKLABLE
+
+ class Cls:
+ PICKLABLE = sentinel("Cls.PICKLABLE")
+
+ assert pickle.loads(pickle.dumps(Cls.PICKLABLE)) is Cls.PICKLABLE
+
+ Sentinel objects have the following attributes:
+
+ .. attribute:: __name__
+
+ The sentinel's name.
+
+ .. attribute:: __module__
+
+ The name of the module where the sentinel was created.
+
+ .. versionadded:: next
+
+
.. class:: slice(stop, /)
slice(start, stop, step=None, /)
<whatsnew315-lazy-imports>`
* :pep:`814`: :ref:`Add frozendict built-in type
<whatsnew315-frozendict>`
+* :pep:`661`: :ref:`Add sentinel built-in type
+ <whatsnew315-sentinel>`
* :pep:`799`: :ref:`A dedicated profiling package for organizing Python
profiling tools <whatsnew315-profiling-package>`
* :pep:`799`: :ref:`Tachyon: High frequency statistical sampling profiler
(Contributed by Victor Stinner and Donghee Na in :gh:`141510`.)
+.. _whatsnew315-sentinel:
+
+:pep:`661`: Add sentinel built-in type
+--------------------------------------
+
+A new :class:`sentinel` type is added to the :mod:`builtins` module for
+creating unique sentinel values with a concise representation. Sentinel
+objects preserve identity when copied, support use in type expressions with
+the ``|`` operator, and can be pickled when they are importable by module and
+name.
+
+(PEP by Tal Einat; contributed by Jelle Zijlstra in :gh:`148829`.)
+
+
.. _whatsnew315-profiling-package:
:pep:`799`: A dedicated profiling package
#include "cpython/genobject.h"
#include "descrobject.h"
#include "genericaliasobject.h"
+#include "sentinelobject.h"
#include "warnings.h"
#include "weakrefobject.h"
#include "structseq.h"
--- /dev/null
+/* Sentinel object interface */
+
+#ifndef Py_SENTINELOBJECT_H
+#define Py_SENTINELOBJECT_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef Py_LIMITED_API
+PyAPI_DATA(PyTypeObject) PySentinel_Type;
+
+#define PySentinel_Check(op) Py_IS_TYPE((op), &PySentinel_Type)
+
+PyAPI_FUNC(PyObject *) PySentinel_New(
+ const char *name,
+ const char *module_name);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_SENTINELOBJECT_H */
'BuiltinImporter': (3, 3),
'str': (3, 4), # not interoperable with Python < 3.4
'frozendict': (3, 15),
+ 'sentinel': (3, 15),
}
for t in builtins.__dict__.values():
if isinstance(t, type) and not issubclass(t, BaseException):
import builtins
import collections
import contextlib
+import copy
import decimal
import fractions
import gc
import typing
import unittest
import warnings
+import weakref
from contextlib import ExitStack
from functools import partial
from inspect import CO_COROUTINE
# used as proof of globals being used
A_GLOBAL_VALUE = 123
+A_SENTINEL = sentinel("A_SENTINEL")
+
+class SentinelContainer:
+ CLASS_SENTINEL = sentinel("SentinelContainer.CLASS_SENTINEL")
class Squares:
__repr__ = None
self.assertRaises(TypeError, repr, C())
+ def test_sentinel(self):
+ missing = sentinel("MISSING")
+ other = sentinel("MISSING")
+
+ self.assertIsInstance(missing, sentinel)
+ self.assertIs(type(missing), sentinel)
+ self.assertEqual(missing.__name__, "MISSING")
+ self.assertEqual(missing.__module__, __name__)
+ self.assertIsNot(missing, other)
+ self.assertEqual(repr(missing), "MISSING")
+ self.assertTrue(missing)
+ self.assertIs(copy.copy(missing), missing)
+ self.assertIs(copy.deepcopy(missing), missing)
+ self.assertEqual(missing, missing)
+ self.assertNotEqual(missing, other)
+ self.assertRaises(TypeError, sentinel)
+ self.assertRaises(TypeError, sentinel, "MISSING", "EXTRA")
+ self.assertRaises(TypeError, sentinel, name="MISSING")
+ with self.assertRaisesRegex(TypeError, "must be str"):
+ sentinel(1)
+ self.assertTrue(sentinel.__flags__ & support._TPFLAGS_IMMUTABLETYPE)
+ self.assertTrue(sentinel.__flags__ & support._TPFLAGS_HAVE_GC)
+ self.assertFalse(sentinel.__flags__ & support._TPFLAGS_BASETYPE)
+ with self.assertRaises(TypeError):
+ class SubSentinel(sentinel):
+ pass
+ with self.assertRaises(TypeError):
+ sentinel.attribute = "value"
+ with self.assertRaises(AttributeError):
+ missing.__name__ = "CHANGED"
+ with self.assertRaises(AttributeError):
+ missing.__module__ = "changed"
+ with self.assertRaises(AttributeError):
+ del missing.__name__
+ with self.assertRaises(AttributeError):
+ del missing.__module__
+
+ def test_sentinel_pickle(self):
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ with self.subTest(protocol=proto):
+ self.assertIs(
+ pickle.loads(pickle.dumps(A_SENTINEL, protocol=proto)),
+ A_SENTINEL)
+ self.assertIs(
+ pickle.loads(pickle.dumps(
+ SentinelContainer.CLASS_SENTINEL, protocol=proto)),
+ SentinelContainer.CLASS_SENTINEL)
+
+ missing = sentinel("MISSING")
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ with self.subTest(protocol=proto):
+ with self.assertRaises(pickle.PicklingError):
+ pickle.dumps(missing, protocol=proto)
+
+ def test_sentinel_str_subclass_name_cycle(self):
+ class Name(str):
+ pass
+
+ name = Name("MISSING")
+ missing = sentinel(name)
+ self.assertIs(missing.__name__, name)
+ self.assertTrue(gc.is_tracked(missing))
+
+ name.missing = missing
+ ref = weakref.ref(name)
+ del name, missing
+ support.gc_collect()
+ self.assertIsNone(ref())
+
+ def test_sentinel_union(self):
+ missing = sentinel("MISSING")
+
+ self.assertIsInstance(missing | int, typing.Union)
+ self.assertEqual((missing | int).__args__, (missing, int))
+ self.assertIsInstance(int | missing, typing.Union)
+ self.assertEqual((int | missing).__args__, (int, missing))
+ self.assertIs(missing | missing, missing)
+ self.assertEqual(repr(int | missing), "int | MISSING")
+ self.assertIsInstance(missing | None, typing.Union)
+ self.assertEqual((missing | None).__args__, (missing, type(None)))
+ self.assertIsInstance(None | missing, typing.Union)
+ self.assertEqual((None | missing).__args__, (type(None), missing))
+ self.assertIsInstance(missing | list[int], typing.Union)
+ self.assertEqual((missing | list[int]).__args__, (missing, list[int]))
+ self.assertIsInstance(missing | (int | str), typing.Union)
+ self.assertEqual((missing | (int | str)).__args__, (missing, int, str))
+
+ with self.assertRaises(TypeError):
+ missing | 1
+ with self.assertRaises(TypeError):
+ 1 | missing
+
def test_round(self):
self.assertEqual(round(0.0), 0.0)
self.assertEqual(type(round(0.0)), int)
import enum
import os
+import pickle
import sys
import textwrap
import unittest
self.check_get_constant(_testlimitedcapi.get_constant_borrowed)
+class SentinelTest(unittest.TestCase):
+
+ def test_pysentinel_new(self):
+ marker = _testcapi.pysentinel_new("CAPI_SENTINEL", __name__)
+ self.assertIs(type(marker), sentinel)
+ self.assertTrue(_testcapi.pysentinel_check(marker))
+ self.assertFalse(_testcapi.pysentinel_check(object()))
+ self.assertEqual(marker.__name__, "CAPI_SENTINEL")
+ self.assertEqual(marker.__module__, __name__)
+ self.assertEqual(repr(marker), "CAPI_SENTINEL")
+
+ no_module = _testcapi.pysentinel_new("NO_MODULE")
+ self.assertIs(type(no_module), sentinel)
+ self.assertEqual(no_module.__name__, "NO_MODULE")
+ self.assertIs(no_module.__module__, None)
+
+ globals()["CAPI_SENTINEL"] = marker
+ self.addCleanup(globals().pop, "CAPI_SENTINEL", None)
+ self.assertIs(pickle.loads(pickle.dumps(marker)), marker)
+
+
class PrintTest(unittest.TestCase):
def testPyObjectPrintObject(self):
NamedTuple.__mro_entries__ = _namedtuple_mro_entries
-class _SingletonMeta(type):
- def __setattr__(cls, attr, value):
- # TypeError is consistent with the behavior of NoneType
- raise TypeError(
- f"cannot set {attr!r} attribute of immutable type {cls.__name__!r}"
- )
-
-
-class _NoExtraItemsType(metaclass=_SingletonMeta):
- """The type of the NoExtraItems singleton."""
-
- __slots__ = ()
-
- def __new__(cls):
- return globals().get("NoExtraItems") or object.__new__(cls)
-
- def __repr__(self):
- return 'typing.NoExtraItems'
-
- def __reduce__(self):
- return 'NoExtraItems'
-
-NoExtraItems = _NoExtraItemsType()
-del _NoExtraItemsType
-del _SingletonMeta
+NoExtraItems = sentinel("NoExtraItems")
def _get_typeddict_qualifiers(annotation_type):
Objects/obmalloc.o \
Objects/picklebufobject.o \
Objects/rangeobject.o \
+ Objects/sentinelobject.o \
Objects/setobject.o \
Objects/sliceobject.o \
Objects/structseq.o \
$(srcdir)/Include/pytypedefs.h \
$(srcdir)/Include/rangeobject.h \
$(srcdir)/Include/refcount.h \
+ $(srcdir)/Include/sentinelobject.h \
$(srcdir)/Include/setobject.h \
$(srcdir)/Include/sliceobject.h \
$(srcdir)/Include/structmember.h \
--- /dev/null
+Add :class:`sentinel`, implementing :pep:`661`. PEP by Tal Einat; patch by
+Jelle Zijlstra.
Py_RETURN_NONE;
}
+static PyObject *
+pysentinel_new(PyObject *self, PyObject *args)
+{
+ const char *name;
+ const char *module_name = NULL;
+ if (!PyArg_ParseTuple(args, "s|s", &name, &module_name)) {
+ return NULL;
+ }
+ return PySentinel_New(name, module_name);
+}
+
+static PyObject *
+pysentinel_check(PyObject *self, PyObject *obj)
+{
+ return PyBool_FromLong(PySentinel_Check(obj));
+}
+
static PyMethodDef test_methods[] = {
{"call_pyobject_print", call_pyobject_print, METH_VARARGS},
{"clear_managed_dict", clear_managed_dict, METH_O, NULL},
{"is_uniquely_referenced", is_uniquely_referenced, METH_O},
{"pyobject_dump", pyobject_dump, METH_VARARGS},
+ {"pysentinel_new", pysentinel_new, METH_VARARGS},
+ {"pysentinel_check", pysentinel_check, METH_O},
{NULL},
};
--- /dev/null
+/*[clinic input]
+preserve
+[clinic start generated code]*/
+
+#include "pycore_modsupport.h" // _PyArg_CheckPositional()
+
+static PyObject *
+sentinel_new_impl(PyTypeObject *type, PyObject *name);
+
+static PyObject *
+sentinel_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ PyObject *return_value = NULL;
+ PyTypeObject *base_tp = &PySentinel_Type;
+ PyObject *name;
+
+ if ((type == base_tp || type->tp_init == base_tp->tp_init) &&
+ !_PyArg_NoKeywords("sentinel", kwargs)) {
+ goto exit;
+ }
+ if (!_PyArg_CheckPositional("sentinel", PyTuple_GET_SIZE(args), 1, 1)) {
+ goto exit;
+ }
+ if (!PyUnicode_Check(PyTuple_GET_ITEM(args, 0))) {
+ _PyArg_BadArgument("sentinel", "argument 1", "str", PyTuple_GET_ITEM(args, 0));
+ goto exit;
+ }
+ name = PyTuple_GET_ITEM(args, 0);
+ return_value = sentinel_new_impl(type, name);
+
+exit:
+ return return_value;
+}
+/*[clinic end generated code: output=7f28fc0bf0259cba input=a9049054013a1b77]*/
&PyRange_Type,
&PyReversed_Type,
&PySTEntry_Type,
+ &PySentinel_Type,
&PySeqIter_Type,
&PySetIter_Type,
&PySet_Type,
--- /dev/null
+/* Sentinel object implementation */
+
+#include "Python.h"
+#include "descrobject.h" // PyMemberDef
+#include "pycore_ceval.h" // _PyThreadState_GET()
+#include "pycore_interpframe.h" // _PyFrame_IsIncomplete()
+#include "pycore_object.h" // _PyObject_GC_TRACK/UNTRACK()
+#include "pycore_stackref.h" // PyStackRef_AsPyObjectBorrow()
+#include "pycore_tuple.h" // _PyTuple_FromPair
+#include "pycore_typeobject.h" // _Py_BaseObject_RichCompare()
+#include "pycore_unionobject.h" // _Py_union_type_or()
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *name;
+ PyObject *module;
+} sentinelobject;
+
+#define sentinelobject_CAST(op) \
+ (assert(PySentinel_Check(op)), _Py_CAST(sentinelobject *, (op)))
+
+/*[clinic input]
+class sentinel "sentinelobject *" "&PySentinel_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=8b88f8268d3b5775]*/
+
+#include "clinic/sentinelobject.c.h"
+
+
+static PyObject *
+caller(void)
+{
+ _PyInterpreterFrame *f = _PyThreadState_GET()->current_frame;
+ if (f == NULL || PyStackRef_IsNull(f->f_funcobj)) {
+ assert(!PyErr_Occurred());
+ Py_RETURN_NONE;
+ }
+ PyFunctionObject *func = _PyFrame_GetFunction(f);
+ assert(PyFunction_Check(func));
+ PyObject *r = PyFunction_GetModule((PyObject *)func);
+ if (!r) {
+ assert(!PyErr_Occurred());
+ Py_RETURN_NONE;
+ }
+ return Py_NewRef(r);
+}
+
+static PyObject *
+sentinel_new_with_module(PyTypeObject *type, PyObject *name, PyObject *module)
+{
+ assert(PyUnicode_Check(name));
+
+ sentinelobject *self = PyObject_GC_New(sentinelobject, type);
+ if (self == NULL) {
+ return NULL;
+ }
+ self->name = Py_NewRef(name);
+ self->module = Py_NewRef(module);
+ _PyObject_GC_TRACK(self);
+ return (PyObject *)self;
+}
+
+/*[clinic input]
+@classmethod
+sentinel.__new__ as sentinel_new
+
+ name: object(subclass_of='&PyUnicode_Type')
+ /
+[clinic start generated code]*/
+
+static PyObject *
+sentinel_new_impl(PyTypeObject *type, PyObject *name)
+/*[clinic end generated code: output=4af55c6048bed30d input=3ab75704f39c119c]*/
+{
+ PyObject *module = caller();
+ PyObject *self = sentinel_new_with_module(type, name, module);
+ Py_DECREF(module);
+ return self;
+}
+
+PyObject *
+PySentinel_New(const char *name, const char *module_name)
+{
+ PyObject *name_obj = PyUnicode_FromString(name);
+ if (name_obj == NULL) {
+ return NULL;
+ }
+ PyObject *module_obj = module_name == NULL
+ ? Py_None
+ : PyUnicode_FromString(module_name);
+ if (module_obj == NULL) {
+ Py_DECREF(name_obj);
+ return NULL;
+ }
+
+ PyObject *sentinel = sentinel_new_with_module(
+ &PySentinel_Type, name_obj, module_obj);
+ Py_DECREF(module_obj);
+ Py_DECREF(name_obj);
+ return sentinel;
+}
+
+static int
+sentinel_clear(PyObject *op)
+{
+ sentinelobject *self = sentinelobject_CAST(op);
+ Py_CLEAR(self->name);
+ Py_CLEAR(self->module);
+ return 0;
+}
+
+static void
+sentinel_dealloc(PyObject *op)
+{
+ _PyObject_GC_UNTRACK(op);
+ (void)sentinel_clear(op);
+ Py_TYPE(op)->tp_free(op);
+}
+
+static int
+sentinel_traverse(PyObject *op, visitproc visit, void *arg)
+{
+ sentinelobject *self = sentinelobject_CAST(op);
+ Py_VISIT(self->name);
+ Py_VISIT(self->module);
+ return 0;
+}
+
+static PyObject *
+sentinel_repr(PyObject *op)
+{
+ sentinelobject *self = sentinelobject_CAST(op);
+ return Py_NewRef(self->name);
+}
+
+static PyObject *
+sentinel_copy(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+ return Py_NewRef(self);
+}
+
+static PyObject *
+sentinel_deepcopy(PyObject *self, PyObject *Py_UNUSED(memo))
+{
+ return Py_NewRef(self);
+}
+
+static PyObject *
+sentinel_reduce(PyObject *op, PyObject *Py_UNUSED(ignored))
+{
+ sentinelobject *self = sentinelobject_CAST(op);
+ return Py_NewRef(self->name);
+}
+
+static PyMethodDef sentinel_methods[] = {
+ {"__copy__", sentinel_copy, METH_NOARGS, NULL},
+ {"__deepcopy__", sentinel_deepcopy, METH_O, NULL},
+ {"__reduce__", sentinel_reduce, METH_NOARGS, NULL},
+ {NULL, NULL}
+};
+
+static PyMemberDef sentinel_members[] = {
+ {"__name__", Py_T_OBJECT_EX, offsetof(sentinelobject, name), Py_READONLY},
+ {"__module__", Py_T_OBJECT_EX, offsetof(sentinelobject, module), Py_READONLY},
+ {NULL}
+};
+
+static PyNumberMethods sentinel_as_number = {
+ .nb_or = _Py_union_type_or,
+};
+
+PyDoc_STRVAR(sentinel_doc,
+"sentinel(name, /)\n"
+"--\n\n"
+"Create a unique sentinel object with the given name.");
+
+PyTypeObject PySentinel_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ .tp_name = "sentinel",
+ .tp_basicsize = sizeof(sentinelobject),
+ .tp_dealloc = sentinel_dealloc,
+ .tp_repr = sentinel_repr,
+ .tp_as_number = &sentinel_as_number,
+ .tp_hash = PyObject_GenericHash,
+ .tp_getattro = PyObject_GenericGetAttr,
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE
+ | Py_TPFLAGS_HAVE_GC,
+ .tp_doc = sentinel_doc,
+ .tp_traverse = sentinel_traverse,
+ .tp_clear = sentinel_clear,
+ .tp_richcompare = _Py_BaseObject_RichCompare,
+ .tp_methods = sentinel_methods,
+ .tp_members = sentinel_members,
+ .tp_new = sentinel_new,
+ .tp_free = PyObject_GC_Del,
+};
{
if (obj == Py_None ||
PyType_Check(obj) ||
+ PySentinel_Check(obj) ||
_PyGenericAlias_Check(obj) ||
_PyUnion_Check(obj) ||
Py_IS_TYPE(obj, &_PyTypeAlias_Type)) {
<ClCompile Include="..\Objects\odictobject.c" />
<ClCompile Include="..\Objects\picklebufobject.c" />
<ClCompile Include="..\Objects\rangeobject.c" />
+ <ClCompile Include="..\Objects\sentinelobject.c" />
<ClCompile Include="..\Objects\setobject.c" />
<ClCompile Include="..\Objects\sliceobject.c" />
<ClCompile Include="..\Objects\structseq.c" />
<ClCompile Include="..\Objects\rangeobject.c">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\Objects\sentinelobject.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="..\Objects\setobject.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClInclude Include="..\Include\pytypedefs.h" />
<ClInclude Include="..\Include\rangeobject.h" />
<ClInclude Include="..\Include\refcount.h" />
+ <ClInclude Include="..\Include\sentinelobject.h" />
<ClInclude Include="..\Include\setobject.h" />
<ClInclude Include="..\Include\sliceobject.h" />
<ClInclude Include="..\Include\structmember.h" />
<ClCompile Include="..\Objects\odictobject.c" />
<ClCompile Include="..\Objects\picklebufobject.c" />
<ClCompile Include="..\Objects\rangeobject.c" />
+ <ClCompile Include="..\Objects\sentinelobject.c" />
<ClCompile Include="..\Objects\setobject.c" />
<ClCompile Include="..\Objects\sliceobject.c" />
<ClCompile Include="..\Objects\structseq.c" />
<ClInclude Include="..\Include\runtime_structs.h">
<Filter>Include</Filter>
</ClInclude>
+ <ClInclude Include="..\Include\sentinelobject.h">
+ <Filter>Include</Filter>
+ </ClInclude>
<ClInclude Include="..\Include\setobject.h">
<Filter>Include</Filter>
</ClInclude>
<ClCompile Include="..\Objects\rangeobject.c">
<Filter>Objects</Filter>
</ClCompile>
+ <ClCompile Include="..\Objects\sentinelobject.c">
+ <Filter>Objects</Filter>
+ </ClCompile>
<ClCompile Include="..\Objects\setobject.c">
<Filter>Objects</Filter>
</ClCompile>
SETBUILTIN("object", &PyBaseObject_Type);
SETBUILTIN("range", &PyRange_Type);
SETBUILTIN("reversed", &PyReversed_Type);
+ SETBUILTIN("sentinel", &PySentinel_Type);
SETBUILTIN("set", &PySet_Type);
SETBUILTIN("slice", &PySlice_Type);
SETBUILTIN("staticmethod", &PyStaticMethod_Type);
Objects/rangeobject.c - PyLongRangeIter_Type -
Objects/rangeobject.c - PyRangeIter_Type -
Objects/rangeobject.c - PyRange_Type -
+Objects/sentinelobject.c - PySentinel_Type -
Objects/setobject.c - PyFrozenSet_Type -
Objects/setobject.c - PySetIter_Type -
Objects/setobject.c - PySet_Type -