Commit Graph

11 Commits

Author SHA1 Message Date
Nerixyz 5b13fbf23e [Python] Support multi-argument argout typing
Match pytyping against the full wrapper parameter list so a
multi-argument argout typemap supplies one return type.

See #3469.
2026-08-04 23:41:13 +01:00
William S Fulton 7458ea361a [Python] Fix annotations for multiple outputs
Build PEP 484 annotations from every Python output value, including a
native return that is not void. Use typing.List[typing.Union[...]] for
multiple results.

See #3469.

Assisted-by: Codex (GPT-5.6 Sol)
2026-08-04 23:41:13 +01:00
William S Fulton a0da96aff8 [Python] #3390 Add $pytypename special variable for pytyping typemaps
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)
2026-07-27 23:40:48 +01:00
William S Fulton c6d16a0bd8 Python: follow-up fixes for $pytypename PEP 484 annotations
- HTML doc cleanup/edits.
- Drop a stray Printf argument in emitIncompleteClass; the format string
  has no conversion for it.
- Take ownership of the getProxyClassLocalName() result directly instead
  of copying it, fixing a small string leak.
- Use SwigType_lstr instead of SwigType_str for the opaque class docstring
  so the shown type matches the mangled SWIGTYPE_ name - short &, short *
  and short[] all resolve to "short *" for SWIGTYPE_p_short.
- Emit the generated SWIGTYPE_ type wrapper classes inside an
  'if typing.TYPE_CHECKING' block instead of as real runtime classes. They
  exist only to give the PEP 484 annotations a named type to refer to, so
  declaring them for static type checkers only keeps them out of the runtime
  module namespace. A preceding comment replaces the previous per-class
  "only used for type annotations ..." docstring line.
- Quote the type in the type wrapper docstrings with single quotes rather
  than reStructuredText double backticks as this is the SWIG convention
  and the tools that would actually render RST docstrings — Sphinx autodoc,
  help()/pydoc (to inspect runtime objects) wouldn't even see them as
  they inspect runtime objects.
- Replace the "is this always correct?" FIXME in the enum branch of
  substituteTypenameSpecialVariable with a comment describing when it is
  reached and why int is correct. The default 'enum SWIGTYPE' typemap maps
  straight to "int" without substituting, so enums only reach this branch
  when a pytyping typemap uses $pytypename on an enum type; int is right
  because Python wraps enums as ints. Add a test that exercises this via a
  custom typemap (without it the type would wrongly resolve to an opaque
  SWIGTYPE_ class).
- Assert in the python_annotations_typing_runme test that the SWIGTYPE_
  type wrapper classes are not present at runtime, confirming they are
  declared for type checkers only.

Assisted-by: Claude Code (Opus 4.8)
2026-07-27 23:39:31 +01:00
Nerixyz 7a38effaac Python: Show class typenames in PEP 484 annotations 2026-07-27 23:39:31 +01:00
William S Fulton 50df6ced1f [Python] Only define pytyping typemaps where in typemaps are defined
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)
2026-07-23 17:30:59 +01:00
Nerixyz 42942f4cae Python: Map more primitives for PEP 484 annotations
Co-authored-by: William S Fulton <wsf@fultondesigns.co.uk>
2026-07-23 17:30:59 +01:00
William S Fulton 79f7a2b7cb Python: Remove Python 2 compatibility macros
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)
2026-07-06 23:50:31 +01:00
William S Fulton 5f7ee3121d Correction in custom typemap in python_annotations_typing test
Fix visual c++ warning C4244: '=': conversion from 'Py_ssize_t' to 'int', possible loss of data
2026-06-20 07:29:52 +01:00
Nerixyz ddb72429fb Python: Support multi-argument typemaps for pytyping 2026-06-04 23:48:53 +01:00
Nerixyz 5c35726a8d
Python: Add PEP 484 annotations for simple types 2026-03-24 14:56:16 +01:00