[neon/forks/sip6/Neon/release] /: New upstream version 6.15.1
Dmitry Shachnev
null at kde.org
Mon Jul 27 12:04:48 BST 2026
Git commit 7a192e315ca3e15f7497d060558e9c97dbff5f2a by Dmitry Shachnev.
Committed on 21/12/2025 at 09:09.
Pushed by carlosdem into branch 'Neon/release'.
New upstream version 6.15.1
M +3 -3 .git_archival.txt
M +1 -1 docs/conf.py
M +14 -0 docs/releases.md
M +9 -8 sipbuild/generator/indexed_lists.py
M +34 -7 sipbuild/generator/outputs/code/backends/v12v13.py
M +6 -30 sipbuild/generator/outputs/code/snippets.py
M +6 -2 sipbuild/generator/parser/parser_manager.py
M +3 -0 sipbuild/generator/parser/rules.py
M +6 -1 sipbuild/generator/resolver/resolver.py
A +34 -0 test/issue-99/issue_99_module.sip
A +10 -0 test/issue-99/test_issue_99.py
https://invent.kde.org/neon/forks/sip6/-/commit/7a192e315ca3e15f7497d060558e9c97dbff5f2a
diff --git a/.git_archival.txt b/.git_archival.txt
index 148366b..85a7bbb 100644
--- a/.git_archival.txt
+++ b/.git_archival.txt
@@ -1,3 +1,3 @@
-node: 7378531efd3500f1dc8a0c3a1219fdc239ae3dfb
-node-date: 2025-12-06T12:06:53Z
-describe-name: 6.15.0
+node: 4884efc25d98c9b2cf734adf43695ab3192f8dcc
+node-date: 2025-12-20T13:46:07Z
+describe-name: 6.15.1
diff --git a/docs/conf.py b/docs/conf.py
index fbe76a5..032cbee 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -13,7 +13,7 @@ project = 'sip'
copyright = '{0} Phil Thompson <phil at riverbankcomputing.com>'.format(
date.today().year)
author = 'Phil Thompson'
-version = 'v6.15.0'
+version = 'v6.15.1'
# -- General configuration ---------------------------------------------------
diff --git a/docs/releases.md b/docs/releases.md
index e46d911..fad429b 100644
--- a/docs/releases.md
+++ b/docs/releases.md
@@ -1,5 +1,19 @@
# Release Notes
+## v6.15.1
+
+### Bug fixes
+
+- A super-class of a disabled class was not ignored if it was disabled itself.
+- Fixed a regression in the generation of class definitions when using old ABI
+ versions that don't support arrays.
+- Fixed a regression in the checking if a name clashed with the name of a class
+ in the same scope. Resolves
+ [#99](https://github.com/Python-SIP/sip/issues/99)
+- Fixed a regression in the code generated for static functions defined in
+ hidden namespaces.
+
+
## v6.15.0
### Removal of support for Python v3.9
diff --git a/sipbuild/generator/indexed_lists.py b/sipbuild/generator/indexed_lists.py
index 01109f9..5505f56 100644
--- a/sipbuild/generator/indexed_lists.py
+++ b/sipbuild/generator/indexed_lists.py
@@ -108,30 +108,27 @@ class IndexedClassList(IndexedList['WrappedClass']):
"""
A list of WrappedClasss keeping the following indices:
- classes by fq_cpp_name
- - classes by scope and py_name
"""
+
def _index_clear(self):
"""Set up indices. See IndexedList._index_clear()."""
+
self._by_cppname = defaultdict(list)
- self._by_scope_pyname = defaultdict(list)
def _index_add(self, klass):
"""Add element to indices. See IndexedList._index_add()."""
+
self._by_cppname[klass.iface_file.fq_cpp_name].append(klass)
- self._by_scope_pyname[klass.scope, str(klass.py_name)].append(klass)
def _index_remove(self, klass):
"""Remove element from indices. See IndexedList._index_add()."""
+
self._by_cppname[klass.iface_file.fq_cpp_name].remove(klass)
- del self._by_scope_pyname[klass.scope, str(klass.py_name)]
def by_fq_cpp_name(self, name):
"""Find WrappedClasses by their .iface_file.fq_cpp_name."""
- return self._by_cppname[name]
- def by_scope_and_py_name(self, scope, name):
- """Find WrappedClasses by their .scope and .py_name."""
- return self._by_scope_pyname[scope, str(name)]
+ return self._by_cppname[name]
class IndexedEnumList(IndexedList['WrappedEnum']):
@@ -153,9 +150,11 @@ class IndexedEnumList(IndexedList['WrappedEnum']):
if enum.fq_cpp_name:
assert enum.fq_cpp_name not in self._by_cppname, f"Duplicate enum: {enum.fq_cpp_name}"
self._by_cppname[enum.fq_cpp_name] = enum
+
if enum.py_name:
assert (enum.scope, str(enum.py_name)) not in self._by_scope_pyname
self._by_scope_pyname[enum.scope, str(enum.py_name)] = enum
+
if not enum.is_scoped:
for member in enum.members:
assert (enum.scope, str(member.py_name)) not in self._unscoped_by_scope_member, f"Duplicate enum member: {member.py_name.name}"
@@ -165,8 +164,10 @@ class IndexedEnumList(IndexedList['WrappedEnum']):
"""Remove WrappedEnum from indices. See IndexedList._index_add()."""
if enum.fq_cpp_name:
del self._by_cppname[enum.fq_cpp_name]
+
if enum.py_name:
del self._by_scope_pyname[enum.scope, enum.py_name.name]
+
if not enum.is_scoped:
for member in enum.members:
del self._unscoped_by_scope_member[(enum.scope, str(member.py_name))]
diff --git a/sipbuild/generator/outputs/code/backends/v12v13.py b/sipbuild/generator/outputs/code/backends/v12v13.py
index 23c758f..eccbae4 100644
--- a/sipbuild/generator/outputs/code/backends/v12v13.py
+++ b/sipbuild/generator/outputs/code/backends/v12v13.py
@@ -12,8 +12,7 @@ from ...formatters import fmt_argument_as_cpp_type
from ..snippets import (g_class_docstring, g_class_method_table,
g_enum_member_table, g_module_docstring, g_type_init_body,
- g_module_init_start, g_pyqt_class_plugin, g_pyqt_helper_defns,
- g_pyqt_helper_init)
+ g_pyqt_class_plugin, g_pyqt_helper_defns, g_pyqt_helper_init)
from ..utils import (get_class_flags, get_const_cast, get_docstring_text,
get_encoded_type, get_enum_member, get_named_value_decl,
get_normalised_cached_name, get_optional_ptr, get_use_in_code,
@@ -159,7 +158,7 @@ const sipAPIDef *sipAPI_{module_name};
''')
g_pyqt_helper_defns(sf, spec)
- g_module_init_start(sf, spec)
+ self.g_module_init_start(sf)
has_module_functions = self.g_module_functions_table(sf, bindings,
module)
self.g_module_definition(sf, has_module_functions=has_module_functions)
@@ -274,6 +273,33 @@ f''' static PyModuleDef sip_module_def = {{
return True
+ def g_module_init_start(self, sf):
+ """ Generate the start of the Python module initialisation function.
+ """
+
+ spec = self.spec
+
+ if spec.is_composite or spec.c_bindings:
+ extern_c = ''
+ arg_type = 'void'
+ else:
+ extern_c = 'extern "C" '
+ arg_type = ''
+
+ module_name = spec.module.py_name
+
+ sf.write(
+f'''
+
+/* The Python module initialisation function. */
+#if defined(SIP_STATIC_MODULE)
+{extern_c}PyObject *PyInit_{module_name}({arg_type})
+#else
+PyMODINIT_FUNC PyInit_{module_name}({arg_type})
+#endif
+{{
+''')
+
def g_py_method_table(self, sf, bindings, members, scope):
""" Generate a Python method table for a class or mapped type and
return the number of entries.
@@ -875,10 +901,11 @@ static sipPySlotDef slots_{klass_name}[] = {{
(spec.c_bindings or klass.needs_array_helper),
'array_delete', klass_name))
- if klass.can_create:
- class_fields.append(f'sizeof ({scoped_class_name(spec, klass)})')
- else:
- class_fields.append('0')
+ if klass.can_create:
+ class_fields.append(
+ f'sizeof ({scoped_class_name(spec, klass)})')
+ else:
+ class_fields.append('0')
base_fields = ',\n '.join(base_fields)
container_fields = ',\n '.join(container_fields)
diff --git a/sipbuild/generator/outputs/code/snippets.py b/sipbuild/generator/outputs/code/snippets.py
index 20da422..f469950 100644
--- a/sipbuild/generator/outputs/code/snippets.py
+++ b/sipbuild/generator/outputs/code/snippets.py
@@ -96,7 +96,7 @@ static void sip_import_component_module(PyObject *d, const char *name)
''')
g_module_docstring(sf, module)
- g_module_init_start(sf, spec)
+ backend.g_module_init_start(sf)
backend.g_module_definition(sf)
sf.write(
@@ -931,31 +931,6 @@ def g_type_init_body(backend, sf, bindings, klass):
''')
-def g_module_init_start(sf, spec):
- """ Generate the start of the Python module initialisation function. """
-
- if spec.is_composite or spec.c_bindings:
- extern_c = ''
- arg_type = 'void'
- else:
- extern_c = 'extern "C" '
- arg_type = ''
-
- module_name = spec.module.py_name
-
- sf.write(
-f'''
-
-/* The Python module initialisation function. */
-#if defined(SIP_STATIC_MODULE)
-{extern_c}PyObject *PyInit_{module_name}({arg_type})
-#else
-PyMODINIT_FUNC PyInit_{module_name}({arg_type})
-#endif
-{{
-''')
-
-
def g_pyqt_class_plugin(backend, sf, bindings, klass):
""" Generate any extended class definition data for PyQt. Return True if
anything was generated.
@@ -2677,12 +2652,13 @@ def _static_function(backend, sf, bindings, member, scope=None):
if scope is None:
overloads = spec.module.overloads
+ scope_py = None
else:
overloads = scope.overloads
- scope = py_scope(scope)
+ scope_py = py_scope(scope)
- if scope is not None:
- member_name = scope.iface_file.fq_cpp_name.as_word + '_' + member_name
+ if scope_py is not None:
+ member_name = scope_py.iface_file.fq_cpp_name.as_word + '_' + member_name
sf.write('\n\n')
@@ -2701,7 +2677,7 @@ def _static_function(backend, sf, bindings, member, scope=None):
else:
kw_fw_decl = kw_decl = ''
- if scope is None:
+ if scope_py is None:
if not spec.c_bindings:
sf.write(f'extern "C" {{static PyObject *func_{member_name}({backend.get_py_method_args(is_impl=False, is_module_fn=True)}{kw_fw_decl});}}\n')
diff --git a/sipbuild/generator/parser/parser_manager.py b/sipbuild/generator/parser/parser_manager.py
index f94fca6..36c11b1 100644
--- a/sipbuild/generator/parser/parser_manager.py
+++ b/sipbuild/generator/parser/parser_manager.py
@@ -1056,7 +1056,10 @@ class ParserManager:
break
# Check the classes.
- for cd in self.spec.classes.by_scope_and_py_name(self.scope, py_name):
+ for cd in self.spec.classes:
+ if cd.scope is not self.scope:
+ continue
+
# A class will have already been added to the scope and this will
# tell us to ignore it.
if cd is ignore:
@@ -1065,7 +1068,8 @@ class ParserManager:
if cd.external:
continue
- clash("a class or namespace")
+ if cd.py_name.name == py_name:
+ clash("a class or namespace")
if self.scope is None:
# Check the exceptions.
diff --git a/sipbuild/generator/parser/rules.py b/sipbuild/generator/parser/rules.py
index 8b9b429..7f3993d 100644
--- a/sipbuild/generator/parser/rules.py
+++ b/sipbuild/generator/parser/rules.py
@@ -1986,6 +1986,9 @@ def p_simple_superclass(p):
pm = p.parser.pm
+ if pm.skipping:
+ return
+
# Handle templates.
if len(p) == 5:
if pm.parsing_template:
diff --git a/sipbuild/generator/resolver/resolver.py b/sipbuild/generator/resolver/resolver.py
index cc8a780..c226801 100644
--- a/sipbuild/generator/resolver/resolver.py
+++ b/sipbuild/generator/resolver/resolver.py
@@ -2162,8 +2162,13 @@ def _create_sorted_numbered_types(spec, mod, error_log):
if mod is spec.module or klass.iface_file.needed:
if not klass.is_hidden_namespace:
+ # For ABI v14 and later the sip module searches this table
+ # using the Python name (as part of attribute lookup). For
+ # earlier versions it uses the C/C++ name (for sipFindType()).
+ key_name = klass.py_name if spec.target_abi >= (14, 0) else klass.iface_file.cpp_name
+
mod.needed_types.append(Argument(ArgumentType.CLASS,
- definition=klass, name=klass.iface_file.cpp_name))
+ definition=klass, name=key_name))
for mapped_type in spec.mapped_types:
if mapped_type.iface_file.module is not mod:
diff --git a/test/issue-99/issue_99_module.sip b/test/issue-99/issue_99_module.sip
new file mode 100644
index 0000000..a88dc82
--- /dev/null
+++ b/test/issue-99/issue_99_module.sip
@@ -0,0 +1,34 @@
+// The SIP implementation of the issue_99_module test module. Note that the
+// issue meant that this module wouldn't build. We also test the correct
+// behaviour once built.
+
+
+%Module(name=issue_99_module)
+
+
+%ModuleHeaderCode
+class KlassA
+{
+public:
+ static const char *get_cpp_name() {return "KlassA";}
+};
+
+class KlassB
+{
+public:
+ static const char *get_cpp_name() {return "KlassB";}
+};
+%End
+
+
+class KlassA /PyName=KlassC/
+{
+public:
+ static const char *get_cpp_name();
+};
+
+class KlassB /PyName=KlassA/
+{
+public:
+ static const char *get_cpp_name();
+};
diff --git a/test/issue-99/test_issue_99.py b/test/issue-99/test_issue_99.py
new file mode 100644
index 0000000..6fb5f5d
--- /dev/null
+++ b/test/issue-99/test_issue_99.py
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: BSD-2-Clause
+
+# Copyright (c) 2025 Phil Thompson <phil at riverbankcomputing.com>
+
+
+def test_class_pyname(module):
+ assert module.KlassC.get_cpp_name() == b'KlassA'
+
+def test_class_pyname_using_existing_cpp_name(module):
+ assert module.KlassA.get_cpp_name() == b'KlassB'
More information about the Neon-commits
mailing list