diff --git a/Include/cpython/object.h b/Include/cpython/object.h
index 5f8b1f7c195501..489b2eecd32991 100644
--- a/Include/cpython/object.h
+++ b/Include/cpython/object.h
@@ -19,43 +19,6 @@ PyAPI_FUNC(Py_ssize_t) _PyInterpreterState_GetRefTotal(PyInterpreterState *);
#endif
-/********************* String Literals ****************************************/
-/* This structure helps managing static strings. The basic usage goes like this:
- Instead of doing
-
- r = PyObject_CallMethod(o, "foo", "args", ...);
-
- do
-
- _Py_IDENTIFIER(foo);
- ...
- r = _PyObject_CallMethodId(o, &PyId_foo, "args", ...);
-
- PyId_foo is a static variable, either on block level or file level. On first
- usage, the string "foo" is interned, and the structures are linked. On interpreter
- shutdown, all strings are released.
-
- Alternatively, _Py_static_string allows choosing the variable name.
- _PyUnicode_FromId returns a borrowed reference to the interned string.
- _PyObject_{Get,Set,Has}AttrId are __getattr__ versions using _Py_Identifier*.
-*/
-typedef struct _Py_Identifier {
- const char* string;
- // Index in PyInterpreterState.unicode.ids.array. It is process-wide
- // unique and must be initialized to -1.
- Py_ssize_t index;
-} _Py_Identifier;
-
-#ifndef Py_BUILD_CORE
-// For now we are keeping _Py_IDENTIFIER for continued use
-// in non-builtin extensions (and naughty PyPI modules).
-
-#define _Py_static_string_init(value) { .string = (value), .index = -1 }
-#define _Py_static_string(varname, value) static _Py_Identifier varname = _Py_static_string_init(value)
-#define _Py_IDENTIFIER(varname) _Py_static_string(PyId_##varname, #varname)
-
-#endif /* !Py_BUILD_CORE */
-
typedef struct {
/* Number implementations must check *both*
arguments for proper type and implement the necessary conversions
@@ -273,8 +236,6 @@ typedef struct _heaptypeobject {
PyAPI_FUNC(const char *) _PyType_Name(PyTypeObject *);
PyAPI_FUNC(PyObject *) _PyType_Lookup(PyTypeObject *, PyObject *);
-PyAPI_FUNC(PyObject *) _PyType_LookupId(PyTypeObject *, _Py_Identifier *);
-PyAPI_FUNC(PyObject *) _PyObject_LookupSpecialId(PyObject *, _Py_Identifier *);
PyAPI_FUNC(PyObject *) PyType_GetModuleByDef(PyTypeObject *, PyModuleDef *);
PyAPI_FUNC(PyObject *) PyType_GetDict(PyTypeObject *);
@@ -282,9 +243,6 @@ PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int);
PyAPI_FUNC(void) _Py_BreakPoint(void);
PyAPI_FUNC(void) _PyObject_Dump(PyObject *);
-PyAPI_FUNC(PyObject *) _PyObject_GetAttrId(PyObject *, _Py_Identifier *);
-PyAPI_FUNC(int) _PyObject_SetAttrId(PyObject *, _Py_Identifier *, PyObject *);
-
PyAPI_FUNC(PyObject **) _PyObject_GetDictPtr(PyObject *);
PyAPI_FUNC(void) PyObject_CallFinalizer(PyObject *);
PyAPI_FUNC(int) PyObject_CallFinalizerFromDealloc(PyObject *);
diff --git a/Include/internal/pycore_call.h b/Include/internal/pycore_call.h
index db719234e05bf3..8846155b38defb 100644
--- a/Include/internal/pycore_call.h
+++ b/Include/internal/pycore_call.h
@@ -8,6 +8,7 @@ extern "C" {
# error "this header requires Py_BUILD_CORE define"
#endif
+#include "pycore_identifier.h" // _Py_Identifier
#include "pycore_pystate.h" // _PyThreadState_GET()
/* Suggested size (number of positional arguments) for arrays of PyObject*
diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h
index e79fb207cf75b1..47b5948f66343a 100644
--- a/Include/internal/pycore_dict.h
+++ b/Include/internal/pycore_dict.h
@@ -9,6 +9,7 @@ extern "C" {
# error "this header requires Py_BUILD_CORE define"
#endif
+#include "pycore_identifier.h" // _Py_Identifier
#include "pycore_object.h" // PyDictOrValues
// Unsafe flavor of PyDict_GetItemWithError(): no error checking
diff --git a/Include/internal/pycore_identifier.h b/Include/internal/pycore_identifier.h
new file mode 100644
index 00000000000000..0e015a40c831f4
--- /dev/null
+++ b/Include/internal/pycore_identifier.h
@@ -0,0 +1,54 @@
+/* String Literals: _Py_Identifier API */
+
+#ifndef Py_INTERNAL_IDENTIFIER_H
+#define Py_INTERNAL_IDENTIFIER_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef Py_BUILD_CORE
+# error "this header requires Py_BUILD_CORE define"
+#endif
+
+/* This structure helps managing static strings. The basic usage goes like this:
+ Instead of doing
+
+ r = PyObject_CallMethod(o, "foo", "args", ...);
+
+ do
+
+ _Py_IDENTIFIER(foo);
+ ...
+ r = _PyObject_CallMethodId(o, &PyId_foo, "args", ...);
+
+ PyId_foo is a static variable, either on block level or file level. On first
+ usage, the string "foo" is interned, and the structures are linked. On interpreter
+ shutdown, all strings are released.
+
+ Alternatively, _Py_static_string allows choosing the variable name.
+ _PyUnicode_FromId returns a borrowed reference to the interned string.
+ _PyObject_{Get,Set,Has}AttrId are __getattr__ versions using _Py_Identifier*.
+*/
+typedef struct _Py_Identifier {
+ const char* string;
+ // Index in PyInterpreterState.unicode.ids.array. It is process-wide
+ // unique and must be initialized to -1.
+ Py_ssize_t index;
+} _Py_Identifier;
+
+// For now we are keeping _Py_IDENTIFIER for continued use
+// in non-builtin extensions (and naughty PyPI modules).
+
+#define _Py_static_string_init(value) { .string = (value), .index = -1 }
+#define _Py_static_string(varname, value) static _Py_Identifier varname = _Py_static_string_init(value)
+#define _Py_IDENTIFIER(varname) _Py_static_string(PyId_##varname, #varname)
+
+extern PyObject* _PyType_LookupId(PyTypeObject *, _Py_Identifier *);
+extern PyObject* _PyObject_LookupSpecialId(PyObject *, _Py_Identifier *);
+extern PyObject* _PyObject_GetAttrId(PyObject *, _Py_Identifier *);
+extern int _PyObject_SetAttrId(PyObject *, _Py_Identifier *, PyObject *);
+
+#ifdef __cplusplus
+}
+#endif
+#endif // !Py_INTERNAL_IDENTIFIER_H
diff --git a/Include/internal/pycore_unicodeobject.h b/Include/internal/pycore_unicodeobject.h
index 08c3dfec93bf05..360a9e1819f8e8 100644
--- a/Include/internal/pycore_unicodeobject.h
+++ b/Include/internal/pycore_unicodeobject.h
@@ -9,6 +9,7 @@ extern "C" {
#endif
#include "pycore_fileutils.h" // _Py_error_handler
+#include "pycore_identifier.h" // _Py_Identifier
#include "pycore_ucnhash.h" // _PyUnicode_Name_CAPI
/* --- Characters Type APIs ----------------------------------------------- */
diff --git a/Makefile.pre.in b/Makefile.pre.in
index 54b64e123cd7bc..62a55bb2478fe4 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -1769,6 +1769,7 @@ PYTHON_HEADERS= \
$(srcdir)/Include/internal/pycore_global_objects_fini_generated.h \
$(srcdir)/Include/internal/pycore_hamt.h \
$(srcdir)/Include/internal/pycore_hashtable.h \
+ $(srcdir)/Include/internal/pycore_identifier.h \
$(srcdir)/Include/internal/pycore_import.h \
$(srcdir)/Include/internal/pycore_initconfig.h \
$(srcdir)/Include/internal/pycore_interp.h \
diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj
index b0e62864421e17..bc1250f63957e2 100644
--- a/PCbuild/pythoncore.vcxproj
+++ b/PCbuild/pythoncore.vcxproj
@@ -235,6 +235,7 @@
+
@@ -248,7 +249,7 @@
-
+
@@ -280,7 +281,7 @@
-
+
diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters
index d5f61e9c5d7c89..a8a11d3b8b83b1 100644
--- a/PCbuild/pythoncore.vcxproj.filters
+++ b/PCbuild/pythoncore.vcxproj.filters
@@ -609,6 +609,9 @@
Include\internal
+
+ Include\internal
+
Include\internal
@@ -650,7 +653,7 @@
Include\internal
-
+
Include\internal
@@ -737,7 +740,7 @@
Include\internal
-
+
Modules\zlib