diff --git a/src/Base/PyWrapParseTupleAndKeywords.h b/src/Base/PyWrapParseTupleAndKeywords.h
new file mode 100644
index 0000000000..3b1d151b9b
--- /dev/null
+++ b/src/Base/PyWrapParseTupleAndKeywords.h
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/****************************************************************************
+ * *
+ * Copyright (c) 2023 The FreeCAD Project Association *
+ * *
+ * This file is part of FreeCAD. *
+ * *
+ * FreeCAD is free software: you can redistribute it and/or modify it *
+ * under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation, either version 2.1 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * FreeCAD is distributed in the hope that it will be useful, but *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with FreeCAD. If not, see *
+ * . *
+ * *
+ ***************************************************************************/
+
+#ifndef FREECAD_PYWRAPPARSETUPLEANDKEYWORDS_H
+#define FREECAD_PYWRAPPARSETUPLEANDKEYWORDS_H
+
+#include
+#include
+#include
+
+namespace Base {
+
+ /// A thin C++ wrapper around PyArg_ParseTupleAndKeywords providing const-correctness for the keywords argument
+ /// \arg args The Python args object
+ /// \arg kw The Python kw object
+ /// \arg format The format string describing the expected arguments
+ /// \arg keywords A std::array of keywords, terminated by a nullptr (required by CPython)
+ /// \arg (variadic) Pointers to the storage locations for the parameters
+ /// \returns boolean true on success, or false on failure
+ template
+ bool Wrapped_ParseTupleAndKeywords(PyObject *args,
+ PyObject *kw,
+ const char *format,
+ const std::array keywords,
+ ...)
+ {
+ // NOTE: This code is from getargs.c in the Python source code (modified to use the public interface at
+ // PyArg_VaParseTupleAndKeywords and to return a bool).
+ va_list va; // NOLINT
+
+ if ((args == nullptr || !PyTuple_Check(args)) ||
+ (kw != nullptr && !PyDict_Check(kw)) ||
+ format == nullptr ||
+ keywords.empty() || // It must at least have a single nullptr in it (TODO: compilation error instead)
+ keywords.back() != nullptr) // It must END with a nullptr
+ {
+ PyErr_BadInternalCall();
+ return false;
+ }
+
+ va_start(va, keywords);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
+ int retval = PyArg_VaParseTupleAndKeywords(args, kw, format, const_cast(keywords.data()), va);
+ va_end(va);
+ return retval != 0; // Convert to a true C++ boolean
+ }
+
+}
+
+#endif //FREECAD_PYWRAPPARSETUPLEANDKEYWORDS_H