Commit Graph

3 Commits

Author SHA1 Message Date
William S Fulton f06d86749c [Python] Fix empty classes and imported bases in .pyi files
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)
2026-08-04 23:41:57 +01:00
William S Fulton afc39844b4 [Python] Add %pythonstubcode and %pythonstubbegin directives
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)
2026-08-04 23:41:57 +01:00
William S Fulton 43ca691f0f [Python] Fix -pyi stub generation, rename option, add docs and test
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)
2026-07-29 18:58:46 +01:00