gh-148829: Implement PEP 661 (#148831)

Co-authored-by: Victorien <65306057+Viicos@users.noreply.github.com>
Co-authored-by: Pieter Eendebak <pieter.eendebak@gmail.com>
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
This commit is contained in:
Jelle Zijlstra 2026-04-27 19:28:30 -07:00 committed by GitHub
parent 0efd679a6c
commit 29a92abb60
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 532 additions and 32 deletions

View file

@ -112,6 +112,7 @@ Other Objects
picklebuffer.rst
weakref.rst
capsule.rst
sentinel.rst
frame.rst
gen.rst
coro.rst

35
Doc/c-api/sentinel.rst Normal file
View file

@ -0,0 +1,35 @@
.. 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

View file

@ -2037,6 +2037,10 @@ PySeqIter_Check:PyObject *:op:0:
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:

View file

@ -19,13 +19,13 @@ are always available. They are listed here in alphabetical order.
| | :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` |
@ -1827,6 +1827,61 @@ are always available. They are listed here in alphabetical order.
: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, /)

View file

@ -69,6 +69,8 @@ Summary -- Release highlights
<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
@ -247,6 +249,20 @@ to accept also other mapping types such as :class:`~types.MappingProxyType`.
(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

View file

@ -117,6 +117,7 @@ __pragma(warning(disable: 4201))
#include "cpython/genobject.h"
#include "descrobject.h"
#include "genericaliasobject.h"
#include "sentinelobject.h"
#include "warnings.h"
#include "weakrefobject.h"
#include "structseq.h"

22
Include/sentinelobject.h Normal file
View file

@ -0,0 +1,22 @@
/* 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 */

View file

@ -3244,6 +3244,7 @@ def test_builtin_types(self):
'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):

View file

@ -4,6 +4,7 @@
import builtins
import collections
import contextlib
import copy
import decimal
import fractions
import gc
@ -21,6 +22,7 @@
import typing
import unittest
import warnings
import weakref
from contextlib import ExitStack
from functools import partial
from inspect import CO_COROUTINE
@ -52,6 +54,10 @@
# 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:
@ -1903,6 +1909,98 @@ class C:
__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)

View file

@ -1,5 +1,6 @@
import enum
import os
import pickle
import sys
import textwrap
import unittest
@ -63,6 +64,27 @@ def test_get_constant_borrowed(self):
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):

View file

@ -3150,31 +3150,7 @@ def _namedtuple_mro_entries(bases):
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):

View file

@ -560,6 +560,7 @@ OBJECT_OBJS= \
Objects/obmalloc.o \
Objects/picklebufobject.o \
Objects/rangeobject.o \
Objects/sentinelobject.o \
Objects/setobject.o \
Objects/sliceobject.o \
Objects/structseq.o \
@ -1240,6 +1241,7 @@ PYTHON_HEADERS= \
$(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 \

View file

@ -0,0 +1,2 @@
Add :class:`sentinel`, implementing :pep:`661`. PEP by Tal Einat; patch by
Jelle Zijlstra.

View file

@ -555,6 +555,23 @@ pyobject_dump(PyObject *self, PyObject *args)
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},
@ -585,6 +602,8 @@ static PyMethodDef test_methods[] = {
{"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},
};

34
Objects/clinic/sentinelobject.c.h generated Normal file
View file

@ -0,0 +1,34 @@
/*[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]*/

View file

@ -2597,6 +2597,7 @@ static PyTypeObject* static_types[] = {
&PyRange_Type,
&PyReversed_Type,
&PySTEntry_Type,
&PySentinel_Type,
&PySeqIter_Type,
&PySetIter_Type,
&PySet_Type,

196
Objects/sentinelobject.c Normal file
View file

@ -0,0 +1,196 @@
/* 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,
};

View file

@ -245,6 +245,7 @@ is_unionable(PyObject *obj)
{
if (obj == Py_None ||
PyType_Check(obj) ||
PySentinel_Check(obj) ||
_PyGenericAlias_Check(obj) ||
_PyUnion_Check(obj) ||
Py_IS_TYPE(obj, &_PyTypeAlias_Type)) {

View file

@ -158,6 +158,7 @@
<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" />

View file

@ -400,6 +400,9 @@
<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>

View file

@ -384,6 +384,7 @@
<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" />
@ -561,6 +562,7 @@
<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" />

View file

@ -222,6 +222,9 @@
<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>
@ -1274,6 +1277,9 @@
<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>

View file

@ -3555,6 +3555,7 @@ _PyBuiltin_Init(PyInterpreterState *interp)
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);

View file

@ -83,6 +83,7 @@ Objects/picklebufobject.c - PyPickleBuffer_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 -

Can't render this file because it has a wrong number of fields in line 4.