A generated stub class with no wrapped members had an empty suite, which
is invalid Python syntax. Stubs could also refer to base classes from
%imported modules without importing the corresponding Python proxy
module, leaving those names unresolved.
Track whether each stub class emits a member and use an ellipsis when
its body would otherwise be empty. Collect modules referenced through
%import and emit them before declarations, using the same package and
relative import rules as the generated Python proxy.
Keep annotation tests active with -pyi by parsing annotations from the
generated stub instead of expecting them on runtime objects. Include
each generated .pyi file in multi-module Pyrefly checks.
Add Python 3.14 Linux CI configurations for -pyi -typehints with and
without -builtin.
See #3473.
Assisted-by: Codex (GPT-5.6 Sol)
Remove generated .pyi files alongside Python proxy files during
test-suite and example cleanup. Use .py* patterns so stubs produced
with SWIG_FEATURES=-pyi and other Python sidecar files are covered by
the existing clean rules.
Add -typehints to enable PEP 484 annotations for a whole interface.
Run Pyrefly on generated wrappers in the Python examples and test suite
with SWIG_FEATURES=-typehints.
Keep C/C++ annotation tests in their original mode, and add a Python
3.14 Linux CI build that runs with -typehints.
See #735.
Assisted-by: Codex (GPT-5.6 Sol)
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)
Fixes and finishes off the -pyi-stub feature (generates a .pyi PEP 484
stub file alongside the wrapped module):
- printClassHeader() called _swig_add_metaclass, a runtime helper that
no longer exists, which would raise a NameError for any class using
%feature("python:nondynamic"). Switched to the current metaclass=
keyword-argument approach used elsewhere in this file.
- classHandler() called addSymbol() unconditionally, so plain -noproxy
builds (unrelated to -pyi) could fail with spurious "multiply
defined" errors. Gated back to (shadow || pyi_stub).
- The opaque SWIGTYPE_* wrapper classes are now emitted into the .pyi
stub too, not just the .py file, so $pytypename annotations falling
back to an opaque type resolve to a name actually defined in the stub.
- Unannotated variables/constants were emitted into the .pyi as a bare
name with nothing else on the line, which is not a valid attribute
declaration. Falls back to ": typing.Any".
- Regular instance methods and static methods were both silently
missing from the .pyi under -builtin (the option's primary intended
use case), because two separate code paths never reached the shared
pyi_stub emission logic.
- Renamed the command line option from -pyi-stub to -pyi, and improved
the -help text with the PYI ("Python Interface") acronym.
- Added header comment blocks to the new helper methods, matching the
file's existing convention.
- Documented -pyi in the manual with a worked, verified example, and
marked the pytyping/-pyi work as experimental/still evolving in
CHANGES.current.
- Added a python test-suite case (python_pyi.i) built with -builtin
-pyi, covering a constructor, regular method, static method, member
variable and an opaque-type fallback in one go. Clean up generated
.pyi files in the Makefiles the same way .py files already are.
Assisted-by: Claude Code (Sonnet 5)
Finalises the PR keeping the $pytypename mechanism but leaving the default
pytyping SWIGTYPE typemaps as typing.Any. The special variables are exercised
only through explicit typemaps; the default annotation change and the
library-wide pytyping sweep are left for a follow-up.
python.cxx:
- getProxyClassLocalName() uses import_name_string() so a class from an
imported module gets its fully qualified, package-aware name, as in
classDeclaration().
- Guard substitutePytypingVars() against a null typemap and skip work when
there is no special variable to substitute.
- Error when $*pytypename is applied to a non-pointer type instead of
emitting the literal.
- Remove the _swig_python_version_info >= (3, 5) guards; SWIG supports Python
3.5 and later, so import typing unconditionally and use a bare
if typing.TYPE_CHECKING.
- Fix two leaks (SwigType_manglestr, SwigType_typedef_resolve_all).
Doc/Manual/Python.html: correct the feature value pytyping to typing and
document the new special variables with valid HTML.
Tests: python_annotations_typing opts in to proxy-name annotations via explicit
typemaps and covers $*pytypename, class-typed member variables, a class-typed
%constant, and the opaque fallback for a forward-declared class; add
python_annotations_import for the cross-module module-qualified name.
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)
%nokwargs (and %feature("kwargs", "0")) on an individual function was
silently ignored when the -keyword command line option was set, because
check_kwargs() used GetFlag() which cannot distinguish "feature unset"
from feature value "0". Honour the explicit feature value when set
instead of OR-ing it with use_kw.
Visible under -builtin where the affected function's wrapper now uses
METH_VARARGS instead of METH_VARARGS|METH_KEYWORDS, so calling with
kwargs raises TypeError as expected. Without -builtin, the generated
Python proxy accepts named arguments and forwards them positionally,
masking the C wrapper level rejection - the runmes therefore gate the
TypeError assertions on is_python_builtin().
Add regression test python_nokwargs_keyword (built with -keyword) that
fails on the unfixed code, plus a parallel python_nokwargs_feature that
exercises the same opt-out behaviour via a module-wide %feature("kwargs").
Both cover constructors, instance methods, static methods, and global
functions.
Assisted-by: Claude Opus 4.7
- Add changes entry for new Lua shared_ptr support.
- Rename director_smartptr test to director_shared_ptr.
- Reimplement cpp11_shared_ptr test cases so that they are run by all
languages (in common.mk instead of being in chosen language's Makefile.in files).
This makes sure missing tests are run by all languages that support
shared_ptr.
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
For Python < 3.9 the tp_as_buffer member is set explicitly if the
interface has a bf_getbuffer slot defined. This fixes#3211.
Enabled buffer interface for non-builtin test.
This only works with Python >= 3.12, where methods __buffer__ and
__release_buffer__ were added. Unfortunately it's not practical for
these methods to reuse the slot methods (or vice versa).
Disable Py_LIMITED_API if below 3.11. The Py_buffer struct and
associated functions are not defined in earlier stable API versions.
Closes#3211
These changes add a weakreflist member to SwigPyObject, and set
tp_weaklistoffset to its offset. This fixes#1792.
The Py_TPFLAGS_MANAGED_WEAKREF introduced in Python 3.12 requires
Py_TPFLAGS_HAVE_GC to be set as well, which it currently isn't for
SwigPyObjectType. (See https://github.com/python/cpython/issues/134786).
Add SWIG_PyType_GetFullyQualifiedName which is just a wrapper around
PyType_GetFullyQualifiedName, but is only available in python-3.13.
Code up the equivalent for earlier versions - loosely based on the
python-3.13 implementation.
PyType_GetFullyQualifiedName is recommended in PEP-737 for getting the
fully qualified type name of a type.
Simplify implementation for -builtin, which does not need a fallback to
use strcmp as PyType_IsSubtype() 'just works' even when using multiple
modules (I think perhaps because SwigPyObject_stype->clientdata->pytype is
common across modules due to the implementation in SwigPyObject_Type()).
In the non-builtin case SwigPyObject is not a base type and usage is
different and when multiple modules are being used, SwigPyObject_Type()
returns two implementations of SwigPyObject which is solved in a hacky
way by comparing the types as strings when the pointer comparison fails.
Add import_callback test - tests %import and %callback to exercise
all of SwigPyPacked_Check(). Python only - the main callback example is
not widely tested and needs work in most of the other languages.
I tried with -Werror but observed the warning messages disappearing
and tests not failing - probably because the wrapper code is swallowing
warnings and catching the resulting error. Seen in python_overload_simple_cast_runme.py
on Linux (not Windows!). Also when the warning is turned into an error
just a seg fault can occur without the warning message. All round better
to actually see the warning.
A different approach is taken for supporting casting smart pointers up the
inheritance hierarchy. We no longer try to replace the underlying pointer type,
provided in the 'feature:smartptr', with the base class type. Such as morphing
'std::shared_ptr<(Derived)>' into 'std::shared_ptr<(Base)>'. Instead, we simply
use 'feature:smartptr' from the base class. This is more reliable than trying to
pattern match the pointer type in the feature. The base class must of course
also have the 'feature:smartptr' set, and this is still checked for as before.
The feature is now parsed in one place and stored in the parse tree in the
new 'smart' attribute for handling by the target languages.
Fix also improves the handling of the type parsed in 'feature:smartptr' in that
the type is now normalized and resolved in the scope of the class it is attached
to.
Closes#2768
* std_filesystem_python:
Add <type_traits> fragment for traits usage in std::filesystem
Correct const std::filesystem & typemaps
Fix memory leak wrapping const std::filesystem&
std::filesystem pointer handling correction
Python std::filesystem cleanup
Cosmetic whitespace corrections
Try to use wstring/wchar_t on windows
Reformat
Rename the helpers within the fragment to be more uniquely named
Make CI rerun (and output all failed cases for the specialPath)
Address review comments
Need to see which assert is failing on mingw
Verbose assert to try and see the failure on mingw
path::string() returns a copy not a const ref.
Remove cpp17_std_filesystem from common.mk, only defined for Python for now
Extend roundtrip test
Address review comment by @degasus on #1999 originally
Had trouble getting the test to be properly ignored. If I wrap the inline line 35 in #if __cplusplus the wrapper code isn't generated
Tweak tests setup
Cherry pick from yasamoka/master
Conflicts:
CHANGES.current
Fix when variable override contains a pointer dereference ->.
This enables use of $1.x as a variable override value as SWIG
replaces $1.x with a pointer dereference expression, such as
(&arg1)->x.
Added a testcase showing how Python typemaps could alternatively
be written using $typemap() instead of using C++ templates as used in
the UTL. I'm not convinced this is fully reliable or even a good idea,
so the variable replacements in $typemap() remain undocumented.
Support running testcases conditional on the compiler supporting
a each language version, like we already handle C++11.
Currently no testcases are actually run in this way for these
newer language versions.
Move HAVE_CXX11 into makefiles so that running test-suite
from top level directory or in the language's test-suite directory
is consistent. For example, running 'make check-java-test-suite'
behaves the same as 'cd Examples/test-suite/java && make check'.
* feature/python-builtin-separate-runtime-data:
Rework swig_and_compile_multi_cpp makefile helper
Different capsule names for builtin changes entry
Use different capsule names with and without -builtin
Conflicts:
CHANGES.current
Types generated with and without -builtin are not compatible. Mixing
them in a common type list leads to crashes. Avoid this by using
different capsule names: "type_pointer_capsule" without -builtin and
"type_pointer_capsule_builtin" with.
See #1684
Both function annotations and variable annotations are turned on using the
"python:annotations" feature. Example:
%feature("python:annotations", "c");
struct V {
float val;
};
The generated code contains a variable annotation containing the C float type:
class V(object):
val: "float" = property(_example.V_val_get, _example.V_val_set)
...
Python 3.5 and earlier do not support variable annotations, so variable
annotations can be turned off with a "python:annotations:novar" feature flag.
Example turning on function annotations but not variable annotations globally:
%feature("python:annotations", "c");
%feature("python:annotations:novar");
or via the command line:
-features python:annotations=c,python:annotations:novar
Closes#1951
Python function annotations containing C/C++ types are no longer
generated when using the -py3 option. Function annotations support
has been moved to a feature to provide finer grained control.
It can be turned on globally by adding:
%feature("python:annotations", "c");
or by using the command line argument:
-features python:annotations=c
The implementation is designed to be expandable to support different
annotations implementations. Future implementations could implement
something like the following for generating pure Python types:
%feature("python:annotations", "python");
or typing module types to conform to PEP-484:
%feature("python:annotations", "typing");
Closes#1561
Issue #735
template_typedef_cplx2 files are generated by the template_typedef_import.multicpptest
but can also be cleaned by the template_typedef_cplx2.cpptest target.