These are the .pyi stub file equivalents of %pythoncode and %pythonbegin,
for adding Python code to the stub file generated by the -pyi and -pyifile
options. They do nothing unless a stub file is being generated.
%pythonstubcode inserts the code at the point the directive appears,
indenting it into the class body when used inside a class. %pythonstubbegin
inserts the code just after the SWIG banner, before any real code.
The stub file is generated independently of the .py file, so code added with
%pythoncode or %pythonbegin does not appear in it. Classes configured with
%pythonabc use names from collections.abc as generated base classes and
pyabc.i imports this module into the .py file, but a separately generated
stub had no import, leaving its base class unresolved. Add the equivalent
%pythonstubcode block to pyabc.i.
Extend the python_pyi test with a collections.abc base class and blocks
exercising both new directives.
See #3473.
Assisted-by: Claude Code (Opus 5)
There is a directorin typemap for SWIG_Object but none for
SWIG_Object const &, so the const reference form fell through to the
generic SWIGTYPE *const& typemap and was wrapped as an opaque proxy
object instead of being passed through unchanged. Affects every
language defining both SWIG_Object and SWIG_DIRECTOR_TYPEMAPS, that is
Python, Ruby, Perl and Octave. For Ruby the generated code did not even
compile, as SWIG_as_voidptr cannot cast a VALUE to void *.
For Python this also covers swig::SwigPtr_PyObject const& and
swig::SwigVar_PyObject const&, which are %applied from PyObject *const&.
Additionally fix a reference count leak for a swig::SwigVar_PyObject
director method argument passed by value. Assigning it into the
SwigVar_PyObject wrapper variable selects the implicitly declared copy
assignment operator, which adds a reference of its own, so the typemap's
SWIG_Py_XINCREF was a second increment against a single decrement on
scope exit. Casting to PyObject * selects
SwigVar_PyObject::operator=(PyObject *), which does not adjust the
count, making the SWIG_Py_XINCREF the one and only increment for every
argument type the typemap handles.
The existing python_director_pyobject test did not catch the leak
because its C++ caller built the SwigVar_PyObject from a borrowed raw
pointer, so the temporary stole a reference and cancelled it out. The
callers are now reference count neutral, the const reference forms are
covered, and the test checks that the object arriving in Python is the
object passed from C++, not just that the count is stable.
Assisted-by: Claude Code (Opus 5)
Follow on fixes to the previous commit:
Use SWIG_Py_XINCREF instead of Py_INCREF. Py_INCREF crashes on a null
PyObject * argument, which a C++ caller may legitimately pass, turning
what was a recoverable director error into a segfault. SWIG_Py_XINCREF
also honours the stable ABI, where it expands to Py_IncRef, and matches
the macros used elsewhere in pyclasses.swg.
Declare the typemap before the %apply directives in pyclasses.swg. %apply
copies the typemaps that exist at the point it appears, so a directorin
typemap declared after them was never propagated to swig::SwigPtr_PyObject
or swig::SwigVar_PyObject, which suffered from the same underflow. Passing
a swig::SwigPtr_PyObject by value was worse, as the wrapper variable stole
the reference held by the argument.
Rename the test to python_director_pyobject following the naming used for
the other Python only tests, and extend it to cover swig::SwigPtr_PyObject,
swig::SwigVar_PyObject and a null argument. Remove the unused variable and
the no-op if from the runme file, check the reference count after the
garbage collection loop and drop the success message, as the tests are
silent when they pass.
Add the CHANGES.current entry.
Assisted-by: Claude Code (Opus 5)
Each director upcall for a method taking PyObject* created a
SwigVar_PyObject, assigned the C++ parameter (a borrowed reference)
to it, then let the SwigVar_PyObject destructor DECREF it on scope
exit -- with no matching INCREF. After enough calls the object's
reference count underflowed, the object was freed prematurely, and
the next call crashed with 'deletion of interned string failed'.
Fix: add a %typemap(directorin,noblock=1) for PyObject* that INCREFs
the parameter after assignment, balancing the destructor's DECREF.
Fixes#2015.
Assisted-by: opencode (deepseek-v4-flash)
A bare #define at the start of a line in a brace delimited %fragment body is
consumed by the SWIG preprocessor and never reaches the generated wrapper. The
macro therefore only exists at SWIG level and code that SWIG does not macro
expand, such as a typemap delimited with %{ ... %}, is left referring to an
undefined name. Use %#define so the definition is emitted for the C compiler.
Fixes SWIG_FromCharPtrAndSize for Python, SWIG_FromBinaryCharPtrAndSize for
Octave, Perl, R and Ruby, SWIG_ToUint8Array and SWIG_FromUint8Array for
JavaScript, and the SWIG_AsVal_* and SWIG_From_* macros in the Scilab char,
short, signed char, unsigned char, unsigned long and long long files.
Lib/scilab/scipointer.swg is deliberately left alone. Its fragments are never
requested by any typemap, so they are only emitted as SWIG preprocessor
definitions; switching them to %#define drops SWIG_ConvertPtr and
SWIG_NewPointerObj from the generated code entirely. Fixing those needs the
definitions moving to a runtime insert, as the other target languages do.
Add a common test case charptr_fragment. It uses a %{ ... %} delimited typemap
so the macro name survives into the wrapper, which only compiles when the
library defines the macro for the C compiler. The target languages without
these macros wrap the same functions using their default typemaps. Verified
that the generated Python module fails to load before this change with an
undefined symbol for SWIG_FromCharPtrAndSize.
Follows on from #3522.
Assisted-by: Claude Code (Opus 5)
Follow up fixes to #3408.
A pytyping typemap must be defined alongside the in and out typemaps for the
type, otherwise a type wrapped as a pointer to an opaque type is annotated as
though it were a native Python type. Move the remaining pytyping typemaps that
were defined by default but whose in typemaps are not:
wchar_t and wchar_t * to pywstrings.swg, which is included by wchar.i,
cwstring.i and std_wstring.i
float _Complex, double _Complex and _Complex to ccomplex.i
Delete the long double pytyping typemap from pytyping.swg. Unlike the types
above there is no library file to move it to, as long double has no in and out
typemaps anywhere in the SWIG library. It is always wrapped as a pointer to an
opaque type and a Python float is never accepted for it, so annotating it as
float was always wrong. It now falls back to the SWIGTYPE default typing.Any.
Include pytyping.swg from pytypemaps.swg before the Unified Typemap Library
instead of from python.swg after it. A %apply in the library, such as
%apply size_t { std::size_t } in typemaps/misctypes.swg, only copies the
typemaps defined at that point, so std::size_t and std::ptrdiff_t now pick up
the pytyping typemaps instead of having to be listed again.
Also fix the const long double & annotation which was wrongly changed to float.
Add the CHANGES.current entry, correct the PEP 484 example in the Python
documentation for the char * annotation change, and align the indentation of
the char typemap with the other grouped typemaps.
Assisted-by: Claude Code (Opus 4.8)
The SwigPyObjectType metaclass and SwigPyStaticVar type created via
PyType_FromSpec in the heap types path of builtin.swg were allocated as
distinct heap type instances in each compiled module's copy of the
TypeOnce functions. When a class inherited from types defined in
different SWIG extension modules -- such as a director class from
module A and a non-director class from module B -- PyType_FromSpecWithBases
detected incompatible metaclasses and raised:
TypeError: metaclass conflict
Both TypeOnce functions now check the shared runtime data module for an
existing instance before creating a new one, so all modules share a
single metaclass. This regression was introduced when SWIG_HEAPTYPES
was enabled by default (SWIG 4.4) and only manifests on Python 3.12+.
Fixes#3315.
Assisted-by: opencode (deepseek-v4-flash)
Remove the Python 2 C API compatibility macros from pyhead.swg (PyClass_Check,
PyInt_*, PyString_*, Py_TPFLAGS_HAVE_CLASS, _PyLong_FromSsize_t) and the SWIG
string helper macros SWIG_Python_str_FromFormat and SWIG_Python_str_FromChar.
These mapped Python 2 names onto the Python 3 C API and were kept only for user
typemaps, which should now call the Python 3 C API directly.
SWIG_Python_str_FromChar was still used internally, so its call sites now use
PyUnicode_FromString directly.
Also remove the dead SWIG_PYTHON_SLOW_GETSET_THIS "fast getset" code in
pyrun.swg. That macro was unconditionally defined for Python 3, so the guarded
Python 2 paths (using PyInstance_Check) were never compiled; only the slow
getset path is kept.
Update the python_annotations_typing test typemap, which used PyString_Check
and PyString_AsString, to use PyBytes_Check and PyBytes_AsString.
Assisted-by: Claude Code (Opus 4.8)
Follow-up work on top of the initial Python 2.x removal: it finishes the
removal and fixes several issues found while reviewing the change.
Correctness fixes:
- pyrun.swg: SwigPyPacked_str passed the type name straight to
PyUnicode_FromFormat as its format string, so a type name containing a
'%' would be misinterpreted. Use PyUnicode_FromString instead.
- Doc/Manual/Varargs.html: the (...) varargs freearg typemap example lost
its free() loop when the surrounding Python 2 guard was removed, leaking
the memory the in typemap allocates. Restore the loop, now unconditional.
- Doc/Manual/Typemaps.html: the PyInt_Check to PyLong_Check substitution
left two typecheck excerpts reading PyLong_Check || PyLong_Check; collapse
each back to a single check.
Code generator (Source/Modules/python.cxx):
- Emit the native class X(..., metaclass=_SwigNonDynamicMeta) form for
nondynamic classes in all three base-list branches (object, Exception and
explicit bases), and drop the Python 2 _swig_add_metaclass helper.
- Emit a plain import builtins as __builtin__ instead of the Python 2
try/except import fallback.
- Update a stale Python 2.x comment.
Remove the deprecated embed.i library (it only ever worked with Python 2):
- Delete Lib/python/embed.i and the Lib/python/Makefile.in reference to it.
- Remove the python_static and python_static_cpp targets from
Examples/Makefile.in and the now-orphaned static: targets that used them
from the Examples/python example Makefiles.
- Remove the embed.i section from the manual.
Python test suite (Examples/test-suite/python):
- profiletest_runme.py: convert the Python 2 print statements to print().
- doxygen_constructors_runme.py: drop the dead sys.version_info < (3, 0)
branch, keeping the Python 3 super().__init__() form.
- li_cdata_bytes_runme.py and li_cdata_bytes_cpp_runme.py: drop the dead
exit-on-Python-2 version guard.
- file_test_runme.py and python_abstractbase_runme.py: drop the now-unused
import sys left behind by guard removal.
Documentation (Doc/Manual/Python.html):
- Drop the embed.i and SWIG_PYTHON_STRICT_UNICODE_WCHAR sections; the latter
macro was Python 2 only and no longer exists, wide strings are unicode-only
by default.
- De-duplicate the %pythonabc example and drop a stale collections.abc
compatibility note.
- Update the version support statement and other stale Python 2 mentions.
Other cleanups:
- Tools/mkdist.py: raise the minimum Python version check to Python 3.
- Reword stale Python 2 comments in pyrun.swg, pyiterators.swg and
pycontainer.swg, and fix a PyString_FromFormat left in a pyclasses.swg
doc comment.
- CHANGES.current: record that Python 2 support has been dropped.
Assisted-by: Claude Code (Opus 4.8)
The cdata.i (const void *BYTES, size_t LENGTH) typemap took LENGTH from
SWIG_AsCharPtrAndSize, whose psize includes a trailing NUL (data length
+ 1). When the destination buffer is sized exactly to the data, memmove
wrote one byte past the end. Confirmed with valgrind: "Invalid write of
size 1, 0 bytes after a block of size 512".
- Make SWIG_AsCharPtrAndSize binary aware in the languages that use the
generic Lib/cdata.i (Python, Perl, Ruby, Octave, R): when the caller
passes SWIG_BINARYSTR it now reports the exact byte count, not data
+ 1. Non cdata callers are unaffected as they never set the flag.
- Lua li_cdata_bytes tests looped to 0x99 instead of 0xff, verifying
only 154 of the 256 byte values; corrected to 0xff.
- Tcl cdata.i passed an int * to Tcl_GetSizeIntFromObj, which expects
a Tcl_Size * on Tcl 8.7 and 9; use Tcl_Size and reject values that
are not a byte.
- CHANGES.current: document the cdata type change and the overflow fix.
Assisted-by: Claude Opus 4.7
Use the full English word in the identifiers added by the previous
commit for cdata raw byte handling:
SWIG_BINSTR -> SWIG_BINARYSTR
SWIG_BINSTRMASK -> SWIG_BINARYSTRMASK
SWIG_AddBinMask -> SWIG_AddBinaryStrMask
SWIG_DelBinMask -> SWIG_DelBinaryStrMask
SWIG_IsBinStr -> SWIG_IsBinaryStr
SWIG_FromBinCharPtrAndSize -> SWIG_FromBinaryCharPtrAndSize
useBin (local variable) -> use_binary
Touches the constants in Lib/swigrun.swg, the SWIG_FromBinary*
macro defines in pystrings.swg, perlstrings.swg, rubystrings.swg,
octprimtypes.swg and rfragments.swg, and all call sites in
Lib/cdata.i and Lib/python/pystrings.swg.
Assisted-by: Claude Opus 4.7
Fix guile cdata.
Add SWIG_BINSTR flag
- Add SWIG_FromBinCharPtrAndSize with the new flag
To add languages that use Lib/cdata.i.
- python use binary string by using the new SWIG_BINSTR
in SWIG_AsCharPtrAndSize and SWIG_FromBinCharPtrAndSize.
Languages that were changed to uses list
- Tcl use list of integers.
- scilab use list of uint8.
And support passing list of numbers to C.
Add support to JavaScript
- use Uint8Array instead of strings.
- Add li_cdata_carrays. tests.
- Add li_cdata_bytes tests.
- Use Debian node-addon-api package location.
- napi folder location to Examples/test-suite/javascript/Makefile.in.
- Update documentation.
Update cdata.i documentation
This new cdata test focus on:
- Ensure we can receive proper data from C and pass proper data back to C.
- Use all possoble byte values , i.e. the full range of 0 to 255
and ensure values 128 to 255 do not pass Unicode transformation (UTF-8/16).
- Ensure zero is a valid value and not a string null termination
nor a modified UTF-8 which transform U+0000 to 0xC0 0x80.
- Check mutability of the cdata object.
Signed-off-by: Erez Geva <ErezGeva2@gmail.com>
- [Lua] Fix off-by-one when nil terminates the table early: use $1 = i
(not i + 1) to match the count of strings actually copied, and pop
the nil from the Lua stack before breaking.
- [Python] In SWIG_AsCharPtrAndSize (pystrings.swg) decref bytes / obj
on the SWIG_MemoryError early returns added by the previous commits,
so an allocation failure no longer leaks the temporary PyObject.
- [Octave, Python] In argcargv.i free already-allocated string entries
and the array itself before failing on a per-element OOM (Python uses
the existing break path so the freearg typemap performs the cleanup).
- [Perl, PHP, Tcl] Drop unreachable `goto fail` after SWIG_croak /
SWIG_PHP_Error / SWIG_exception_fail, all of which already invoke
SWIG_fail. Compilers warning on unreachable code complained.
- Standardise the OOM error wording across languages and fix the
3- and 5-space indentation introduced by the previous commits.
- Update Examples/perl5/xmlstring/xmlstring.i to the new
%typemaps_string signature (it picks up the missing WarningLeakMsg
argument too) and add a SWIG_NewCopyXMLChArray fragment.
- CHANGES.current: document the API breakages introduced by removing
%new_copy_array, removing %typemaps_string_alloc and extending
%typemaps_string, including the actual error text users will see.
Assisted-by: Claude Opus 4.7 <noreply@anthropic.com>
Add a SWIG_STRINGIFY to provide a generic stringize/stringify macro.
descriptor() implementation is simpler and better in case multiple threads are used.
The hardcoded string literal "swig::SwigPyIterator *" in descriptor() is
not expanded for per-module renames of SwigPyIterator. The change allows
the new name(s) to be passed into SWIG_TypeQuery().
A similar issue is described in #3189.
Add test for SwigPyIterator descriptor() with per-module rename
Closes#3365
* Python: Fix warnings about implicit type conversions
When compiling with -Wconversion -Wsign-conversion on
gcc, these places resulted in warnings.
Add explicit type casts to be clear to the compiler.
* new_copy_array casts size to size_t
This alleviates warnings when -Wconversion -Wsign-conversion
are enabled.
* Fix various conversions to correct integer signedness
len can be signed as is the case with python's size_t.
This casts it to size_t to avoid compilation warnings.
* Add -Wconversion and -Wsign-conversion compilation flags for tests
Use the Python C API to set the StopIteration as soon as possible in
and then use NULL return or PyErr_Occurred() to detect handle the
StopIteration once raised while still in C code. This removes the need
to thrown the stop_iteration C++ exception, which cannot be caught
across different shared objects on some operating
systems/compiler configurations.
Closes#3189
NULL is used as the return value for indicating that a Python exception
has been raised. Previously C Python API code could have been called,
but now execution is immediately returned to the Python interpreter.
Fix race condition in free-threading enabled Python interpreters, where SWIG_TypeQuery could segfault.
Given three threads, A B C:
1. thread A gets a cache miss from PyDict_GetItem and starts building a new PyCapsule
2. thread B also gets a cache miss and starts building its own PyCapsule
3. thread B calls PyDict_SetItem and decreases the reference counter on its local PyCapsule
4. thread C gets a cache hit from PyDict_GetItem, which returns the PyCapsule created by thread B
5. thread A calls PyDict_SetItem to set its own PyCapsule as the value. This overwrites the content of the cache, sending the reference counter for the PyCapsule created by thread B to 0.
6. thread C calls PyCapsule_GetPointer on an object that no longer exists and segfaults.
* Make SWIG_AsArgcArgv thread-safe in free-threading Python.
* Fix memory leak in case of invalid inputs, with and without GIL. e.g. mainv(["foo", 1]) raises TypeError; previously it would leak both a char *[3] and a char * for "foo".
* Improve test coverage.
* Add swig_test_utils.py to provide some useful testing utilities.
Partially revert issue #3137.
This change did nothing to improve thread safety.
e.g. to get an item from a list you can use:
- PyList_GET_ITEM - thread unsafe vs. list element swap due to borrowed references; thread unsafe against list shrinking; no bounds checking regardless of threading
- PyList_GetItem - thread unsafe vs. list element swap; unsure about thread safety vs. list shrinking; bounds checked. Slower than PyList_GET_ITEM.
- PyList_GetItemRef. Thread safe and bounds checked; slower than both of the above.
To clarify there is absolutely nothing wrong with using PyList_GET_ITEM or PyList_GetItem in free-threading Python, as long as you can guaranteed that either
- the list is private to the thread; or
- your code is protected by a critical section and is not going to be suspended within it; or
- your code is protected by a lock
Adds weakref support to the SwigPyObject class used as a base for all
builtin wrapper types defined as heap types (the default).
However, like __dictoffset__, the __weaklistoffset__ members slot is only
available in the limited API from python-3.9 onwards.
Document the previous commit which adds the bulk of the weakref support
to builtin wrappers.
- More robust implementation calling PyWeakref_GetRef.
- Remove check for PyWeakref_CheckProxy, it's been available since python-2.2.
- Remove redundant Py_LIMITED_API code (only called when SWIG_PYTHON_SLOW_GETSET_THIS is defined
which is only for python<3 and python-2 does not have a limited API.
SWIG_PYTHON_SLOW_GETSET_THIS code should be removed when python-2 support is removed.