[neon/forks/sip6/Neon/release] /: New upstream version 6.7.7+dfsg

Dmitry Shachnev null at kde.org
Sun Feb 19 03:56:41 GMT 2023


Git commit d7431734eb9145d03cdae87b8dfd1bf996b44edc by Dmitry Shachnev.
Committed on 06/02/2023 at 13:17.
Pushed by carlosdem into branch 'Neon/release'.

New upstream version 6.7.7+dfsg

M  +58   -0    ChangeLog
M  +3    -0    NEWS
M  +1    -1    PKG-INFO
M  +6    -16   code_generator/gencode.c
M  +2    -8    code_generator/py2c.c
M  +2    -5    code_generator/sip.h
M  +1    -1    sip.egg-info/PKG-INFO
M  +2    -2    sipbuild/bindings.py
M  +20   -13   sipbuild/generator/outputs/formatters/argument.py
M  +10   -7    sipbuild/generator/outputs/formatters/value_list.py
M  +4    -4    sipbuild/generator/outputs/pyi.py
M  +34   -13   sipbuild/generator/outputs/type_hints.py
M  +10   -5    sipbuild/generator/outputs/xml.py
M  +4    -3    sipbuild/generator/parser/parser.py
M  +39   -51   sipbuild/generator/parser/parser_manager.py
M  +10   -19   sipbuild/generator/parser/rules.py
M  +4    -7    sipbuild/generator/specification.py
M  +2    -2    sipbuild/version.py

https://invent.kde.org/neon/forks/sip6/commit/d7431734eb9145d03cdae87b8dfd1bf996b44edc

diff --git a/ChangeLog b/ChangeLog
index d8122e9..68fc975 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,63 @@
+2023-02-04  Phil Thompson  <phil at riverbankcomputing.com>
+
+	* sipbuild/generator/outputs/pyi.py:
+	In .pyi files generate implict imports as well as explicit imports.
+	[2d5cad50e879] [6.7.7] <6.7-maint>
+
+	* NEWS, sipbuild/generator/outputs/pyi.py:
+	Fixed the 'pyqtsignal' typo in generated .pyi files.
+	[48117db2851d] <6.7-maint>
+
+2023-02-02  Phil Thompson  <phil at riverbankcomputing.com>
+
+	* NEWS, sipbuild/generator/outputs/type_hints.py:
+	Use the standard Sphinx directive to reference voidptr.
+	[2c334836f75f] <6.7-maint>
+
+2023-02-01  Phil Thompson  <phil at riverbankcomputing.com>
+
+	* sipbuild/generator/outputs/formatters/argument.py,
+	sipbuild/generator/outputs/type_hints.py,
+	sipbuild/generator/outputs/xml.py:
+	Ensure voidptr is rendered consistently and as a reST reference
+	where appropriate.
+	[3b892deb8c1b] <6.7-maint>
+
+	* sipbuild/generator/outputs/formatters/argument.py,
+	sipbuild/generator/outputs/formatters/value_list.py,
+	sipbuild/generator/outputs/xml.py:
+	Changes to the XML generation to reduce differences to earlier
+	versions.
+	[41dc32eadb62] <6.7-maint>
+
+2023-01-31  Phil Thompson  <phil at riverbankcomputing.com>
+
+	* NEWS, code_generator/gencode.c, code_generator/py2c.c,
+	code_generator/sip.h, sipbuild/bindings.py,
+	sipbuild/generator/outputs/pyi.py,
+	sipbuild/generator/parser/parser_manager.py,
+	sipbuild/generator/parser/rules.py,
+	sipbuild/generator/specification.py:
+	Refactored the handling of composite classes so that they are
+	populated properly.
+	[0afab92347b6] <6.7-maint>
+
+2023-01-28  Phil Thompson  <phil at riverbankcomputing.com>
+
+	* sipbuild/generator/outputs/xml.py:
+	Fixes for regressions in the XML generation.
+	[77ebbacae72e] <6.7-maint>
+
+	* NEWS, sipbuild/generator/parser/parser.py:
+	Fixed an incorrect API comment.
+	[febcfb71804d] <6.7-maint>
+
 2023-01-25  Phil Thompson  <phil at riverbankcomputing.com>
 
+	* .hgtags:
+	Added tag 6.7.6 for changeset 67273f43bdbf
+	[fe69fc6295b7] <6.7-maint>
+
 	* NEWS, code_generator/py2c.c:
 	Reduce the use of the heap when converting from Python to C data
 	structures.
diff --git a/NEWS b/NEWS
index c2803b9..7ebca32 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,6 @@
+v6.7.7 4th February 2023
+  - Bug fixes.
+
 v6.7.6 25th January 2023
   - The latest version of ABI v13 is v13.4.1.
   - The latest version of ABI v12 is v12.11.1.
diff --git a/PKG-INFO b/PKG-INFO
index d6b037b..17f093d 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: sip
-Version: 6.7.6
+Version: 6.7.7
 Summary: A Python bindings generator for C/C++ libraries
 Home-page: https://www.riverbankcomputing.com/software/sip/
 Author: Riverbank Computing Limited
diff --git a/code_generator/gencode.c b/code_generator/gencode.c
index 9fc917c..ad83fa1 100644
--- a/code_generator/gencode.c
+++ b/code_generator/gencode.c
@@ -1,7 +1,7 @@
 /*
  * The code generator module for SIP.
  *
- * Copyright (c) 2022 Riverbank Computing Limited <info at riverbankcomputing.com>
+ * Copyright (c) 2023 Riverbank Computing Limited <info at riverbankcomputing.com>
  *
  * This file is part of SIP.
  *
@@ -342,7 +342,7 @@ stringList *generateCode(sipSpec *pt, char *codeDir, const char *srcSuffix,
     if (srcSuffix == NULL)
         srcSuffix = (generating_c ? ".c" : ".cpp");
 
-    if (isComposite(pt->module))
+    if (pt->is_composite)
     {
         if (generateCompositeCpp(pt, codeDir, &generated, py_debug) < 0)
             return NULL;
@@ -1098,10 +1098,9 @@ static int generateCompositeCpp(sipSpec *pt, const char *codeDir,
         );
 
     for (mld = pt->module->allimports; mld != NULL; mld = mld->next)
-        if (mld->module->container == pt->module)
-            prcode(fp,
+        prcode(fp,
 "    sip_import_component_module(sipModuleDict, \"%s\");\n"
-                , mld->module->fullname->text);
+            , mld->module->fullname->text);
 
     prcode(fp,
 "\n"
@@ -1229,8 +1228,7 @@ static const char *generateCpp(sipSpec *pt, moduleDef *mod,
             );
 
     /* Define the names. */
-    if (mod->container == NULL)
-        generateNameCache(pt, fp);
+    generateNameCache(pt, fp);
 
     /* Generate the C++ code blocks. */
     generateCppCodeBlock(mod->cppcode, fp);
@@ -2047,15 +2045,7 @@ static const char *generateCpp(sipSpec *pt, moduleDef *mod,
             , mname);
 
     /* Generate the Python module initialisation function. */
-
-    if (mod->container == pt->module)
-        prcode(fp,
-"\n"
-"PyObject *sip_init_%s()\n"
-"{\n"
-            , mname);
-    else
-        generateModInitStart(pt->module, generating_c, fp);
+    generateModInitStart(pt->module, generating_c, fp);
 
     /* Generate the global functions. */
 
diff --git a/code_generator/py2c.c b/code_generator/py2c.c
index 2e6b3f3..fc78fd8 100644
--- a/code_generator/py2c.c
+++ b/code_generator/py2c.c
@@ -2,7 +2,7 @@
  * The transitional conversion from the output of the Python-based parser to
  * that required by the rest of the C-based code generator.
  *
- * Copyright (c) 2022 Riverbank Computing Limited <info at riverbankcomputing.com>
+ * Copyright (c) 2023 Riverbank Computing Limited <info at riverbankcomputing.com>
  *
  * This file is part of SIP.
  *
@@ -417,6 +417,7 @@ sipSpec *py2c(PyObject *spec, const char *encoding)
     pt->exptypehintcode = codeblock_list_attr(spec, "exported_type_hint_code",
             encoding);
     pt->genc = bool_attr(spec, "c_bindings");
+    pt->is_composite = bool_attr(spec, "is_composite");
     pt->plugins = str_list_attr(spec, "plugins", encoding);
     pt->nrvirthandlers = int_attr(spec, "nr_virtual_handlers");
     pt->qobject_cd = class_attr(pt, spec, "pyqt_qobject", encoding);
@@ -1654,12 +1655,6 @@ static moduleDef *module(sipSpec *pt, PyObject *obj, const char *encoding)
     if (bool_attr(obj, "has_delayed_dtors"))
         setHasDelayedDtors(value);
 
-    if (bool_attr(obj, "is_composite"))
-    {
-        setIsComposite(value);
-        value->modflags &= ~MOD_SUPER_INIT_MASK;
-    }
-
     if (bool_attr(obj, "use_arg_names"))
         setUseArgNames(value);
 
@@ -1699,7 +1694,6 @@ static moduleDef *module(sipSpec *pt, PyObject *obj, const char *encoding)
     value->next_key = int_attr(obj, "next_key");
     value->license = license_attr(obj, "license", encoding);
     value->proxies = class_list_attr(pt, obj, "proxies", encoding);
-    value->container = module_attr(pt, obj, "composite", encoding);
     value->used = ifacefilelist_attr(pt, obj, "used", encoding);
     value->imports = modulelist_attr(pt, obj, "imports", encoding);
     value->allimports = modulelist_attr(pt, obj, "all_imports", encoding);
diff --git a/code_generator/sip.h b/code_generator/sip.h
index 23b3f49..cc427b0 100644
--- a/code_generator/sip.h
+++ b/code_generator/sip.h
@@ -1,7 +1,7 @@
 /*
  * The main header file for SIP.
  *
- * Copyright (c) 2022 Riverbank Computing Limited <info at riverbankcomputing.com>
+ * Copyright (c) 2023 Riverbank Computing Limited <info at riverbankcomputing.com>
  *
  * This file is part of SIP.
  *
@@ -72,7 +72,6 @@
 
 #define MOD_HAS_DELAYED_DTORS   0x0001  /* It has a class with a delayed dtor. */
 #define MOD_IS_UNUSED           0x0002  /* This flag is unused. */
-#define MOD_IS_COMPOSITE        0x0004  /* It is a composite module. */
 #define MOD_IS_TRANSFORMED      0x0008  /* It's types have been transformed. */
 #define MOD_USE_ARG_NAMES       0x0010  /* Use real argument names. */
 #define MOD_USE_LIMITED_API     0x0020  /* Use the limited API. */
@@ -85,8 +84,6 @@
 
 #define hasDelayedDtors(m)  ((m)->modflags & MOD_HAS_DELAYED_DTORS)
 #define setHasDelayedDtors(m)   ((m)->modflags |= MOD_HAS_DELAYED_DTORS)
-#define isComposite(m)      ((m)->modflags & MOD_IS_COMPOSITE)
-#define setIsComposite(m)   ((m)->modflags |= MOD_IS_COMPOSITE)
 #define setIsTransformed(m) ((m)->modflags |= MOD_IS_TRANSFORMED)
 #define isTransformed(m)    ((m)->modflags & MOD_IS_TRANSFORMED)
 #define setUseArgNames(m)   ((m)->modflags |= MOD_USE_ARG_NAMES)
@@ -954,7 +951,6 @@ typedef struct _moduleDef {
     int next_key;                       /* The next key to allocate. */
     licenseDef *license;                /* The software license. */
     struct _classDef *proxies;          /* The list of proxy classes. */
-    struct _moduleDef *container;       /* The container module, if any. */
     struct _ifaceFileList *used;        /* Interface files used. */
     struct _moduleListDef *allimports;  /* The list of all imports. */
     struct _moduleListDef *imports;     /* The list of direct imports. */
@@ -1274,6 +1270,7 @@ typedef struct {
     codeBlockList *exptypehintcode;     /* Exported type hint code. */
     classDef *qobject_cd;               /* QObject class, NULL if none. */
     int genc;                           /* Set if we are generating C code. */
+    int is_composite;                   /* Set if the main module is composite. */
     struct _stringList *plugins;        /* The list of plugins. */
     struct _extractDef *extracts;       /* The list of extracts. */
 } sipSpec;
diff --git a/sip.egg-info/PKG-INFO b/sip.egg-info/PKG-INFO
index d6b037b..17f093d 100644
--- a/sip.egg-info/PKG-INFO
+++ b/sip.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: sip
-Version: 6.7.6
+Version: 6.7.7
 Summary: A Python bindings generator for C/C++ libraries
 Home-page: https://www.riverbankcomputing.com/software/sip/
 Author: Riverbank Computing Limited
diff --git a/sipbuild/bindings.py b/sipbuild/bindings.py
index a2346c7..29758bd 100644
--- a/sipbuild/bindings.py
+++ b/sipbuild/bindings.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2022, Riverbank Computing Limited
+# Copyright (c) 2023, Riverbank Computing Limited
 # All rights reserved.
 #
 # This copy of SIP is licensed for use under the terms of the SIP License
@@ -175,7 +175,7 @@ class Bindings(Configurable):
 
         module = spec.module
 
-        uses_limited_api = module.use_limited_api or module.is_composite
+        uses_limited_api = module.use_limited_api or spec.is_composite
 
         # The details of things that will have been generated.  Note that we
         # don't include anything for .api files or generic extracts as the
diff --git a/sipbuild/generator/outputs/formatters/argument.py b/sipbuild/generator/outputs/formatters/argument.py
index f060e85..22e637c 100644
--- a/sipbuild/generator/outputs/formatters/argument.py
+++ b/sipbuild/generator/outputs/formatters/argument.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2022, Riverbank Computing Limited
+# Copyright (c) 2023, Riverbank Computing Limited
 # All rights reserved.
 #
 # This copy of SIP is licensed for use under the terms of the SIP License
@@ -24,7 +24,7 @@
 from ...scoped_name import STRIP_NONE
 from ...specification import ArgumentType, ArrayArgument, ClassKey, ValueType
 
-from ..type_hints import TypeHintManager
+from ..type_hints import format_voidptr, TypeHintManager
 
 from .base_formatter import BaseFormatter
 from .utils import format_scoped_py_name
@@ -213,7 +213,13 @@ class ArgumentFormatter(BaseFormatter):
 
         return s
 
-    def py_default_value(self, embedded=False):
+    # The types that are implicitly pointers.
+    _IMPLICIT_POINTERS = (ArgumentType.PYOBJECT, ArgumentType.PYTUPLE,
+        ArgumentType.PYLIST, ArgumentType.PYDICT, ArgumentType.PYCALLABLE,
+        ArgumentType.PYSLICE, ArgumentType.PYTYPE, ArgumentType.CAPSULE,
+        ArgumentType.PYBUFFER, ArgumentType.PYENUM)
+
+    def py_default_value(self, type_name, embedded=False, as_xml=False):
         """ Return the Python representation of the argument's default value.
         """
 
@@ -229,21 +235,21 @@ class ArgumentFormatter(BaseFormatter):
         if len(arg.default_value) == 1 and arg.default_value[0].value_type is ValueType.NUMERIC:
             value = arg.default_value[0].value
 
-            if len(arg.derefs) > 0 and value == 0:
+            if value == 0 and ('voidptr' in type_name or len(arg.derefs) > 0 or arg.type in self._IMPLICIT_POINTERS):
                 return 'None'
 
             if arg.type in (ArgumentType.BOOL, ArgumentType.CBOOL):
                 return 'True' if value else 'False'
 
         return ValueListFormatter(self.spec, arg.default_value).py_expression(
-                embedded=embedded)
+                embedded=embedded, as_xml=as_xml)
 
-    def as_py_type(self, pep484=False, default_value=False):
+    def as_py_type(self, pep484=False, default_value=False, as_xml=False):
         """ Return the argument as a Python type. """
 
         arg = self.object
 
-        scope, name = self._py_arg(pep484)
+        scope, name = self._py_arg(pep484, as_xml)
 
         s = format_scoped_py_name(scope, name)
 
@@ -251,11 +257,11 @@ class ArgumentFormatter(BaseFormatter):
             if arg.name is not None:
                 s += ' ' + arg.name.name
 
-            s += '=' + self.py_default_value()
+            s += '=' + self.py_default_value(name)
 
         return s
 
-    def as_rest_ref(self, out):
+    def as_rest_ref(self, out, as_xml=False):
         """ Return the argument as a reST reference. """
 
         arg = self.object
@@ -280,9 +286,10 @@ class ArgumentFormatter(BaseFormatter):
                 # There would normally be a type hint.
                 s += "unknown-type"
             else:
-                s += self.as_py_type()
+                s += self.as_py_type(as_xml=as_xml)
         else:
-            s += TypeHintManager(self.spec).as_rest_ref(hint, out)
+            s += TypeHintManager(self.spec).as_rest_ref(hint, out,
+                    as_xml=as_xml)
 
         return s
 
@@ -337,7 +344,7 @@ class ArgumentFormatter(BaseFormatter):
 
         return hint
 
-    def _py_arg(self, pep484):
+    def _py_arg(self, pep484, as_xml):
         """ Return an argument as a 2-tuple of scope and name. """
 
         type = self.object.type
@@ -369,7 +376,7 @@ class ArgumentFormatter(BaseFormatter):
             name = definition.base_name
 
         elif type in (ArgumentType.STRUCT, ArgumentType.UNION, ArgumentType.VOID):
-            name = sip_module + '.voidptr'
+            name = format_voidptr(self.spec, pep484, as_xml)
 
         elif type in (ArgumentType.STRING, ArgumentType.SSTRING, ArgumentType.USTRING):
             name = 'bytes'
diff --git a/sipbuild/generator/outputs/formatters/value_list.py b/sipbuild/generator/outputs/formatters/value_list.py
index 0de7314..93f759f 100644
--- a/sipbuild/generator/outputs/formatters/value_list.py
+++ b/sipbuild/generator/outputs/formatters/value_list.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2022, Riverbank Computing Limited
+# Copyright (c) 2023, Riverbank Computing Limited
 # All rights reserved.
 #
 # This copy of SIP is licensed for use under the terms of the SIP License
@@ -38,12 +38,13 @@ class ValueListFormatter(BaseFormatter):
 
         return self._expression()
 
-    def py_expression(self, embedded=False):
+    def py_expression(self, embedded=False, as_xml=False):
         """ The Python representation of the value list as an expression. """
 
-        return self._expression(as_python=True, embedded=embedded)
+        return self._expression(as_python=True, embedded=embedded,
+                as_xml=as_xml)
 
-    def as_rest_ref(self):
+    def as_rest_ref(self, as_xml=False):
         """ Return the Python representation of the value list as a reST
         reference.
         """
@@ -90,7 +91,7 @@ class ValueListFormatter(BaseFormatter):
 
         return None
 
-    def _expression(self, as_python=False, embedded=False):
+    def _expression(self, as_python=False, embedded=False, as_xml=False):
         """ The representation of the value list as an expression. """
 
         s = ''
@@ -155,10 +156,12 @@ class ValueListFormatter(BaseFormatter):
                     s += arg_formatter.cpp_type()
 
                 args = [ValueListFormatter(self.spec, a)._expression(
-                                as_python=as_python, embedded=embedded)
+                                as_python=as_python, embedded=embedded,
+                                as_xml=as_xml)
                         for a in value.value.args]
 
-                s += '(' + ', '.join(args) + ')'
+                separator = ',' if as_xml else ', '
+                s += '(' + separator.join(args) + ')'
 
             elif value.value_type is ValueType.EMPTY:
                 s += '{}'
diff --git a/sipbuild/generator/outputs/pyi.py b/sipbuild/generator/outputs/pyi.py
index b554366..5f90773 100644
--- a/sipbuild/generator/outputs/pyi.py
+++ b/sipbuild/generator/outputs/pyi.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2022, Riverbank Computing Limited
+# Copyright (c) 2023, Riverbank Computing Limited
 # All rights reserved.
 #
 # This copy of SIP is licensed for use under the terms of the SIP License
@@ -49,7 +49,7 @@ f'''# The PEP 484 type hints stub file for the {module.py_name} module.
 
 ''')
 
-        if module.is_composite:
+        if spec.is_composite:
             _composite_module(pf, spec, module)
         else:
             _module(pf, spec, module)
@@ -79,7 +79,7 @@ import {spec.sip_module}
 
     imports = []
 
-    for mod in module.imports:
+    for mod in module.all_imports:
         parts = mod.fq_py_name.name.split('.')
 
         if mod.fq_py_name.name == mod.py_name:
@@ -460,7 +460,7 @@ def _callable(pf, spec, module, member, overloads, is_method, defined,
             scope = '' if module.py_name == 'QtCore' else 'QtCore.'
 
             s = _indent(indent)
-            s += f'{overload.common.py_name.name}: typing.ClassVar[{scope}pyqtsignal]\n'
+            s += f'{overload.common.py_name.name}: typing.ClassVar[{scope}pyqtSignal]\n'
             pf.write(s)
 
             return
diff --git a/sipbuild/generator/outputs/type_hints.py b/sipbuild/generator/outputs/type_hints.py
index 9a702dc..3ca02fd 100644
--- a/sipbuild/generator/outputs/type_hints.py
+++ b/sipbuild/generator/outputs/type_hints.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2022, Riverbank Computing Limited
+# Copyright (c) 2023, Riverbank Computing Limited
 # All rights reserved.
 #
 # This copy of SIP is licensed for use under the terms of the SIP License
@@ -132,7 +132,7 @@ class TypeHintManager:
 
         return managed_type_hint.as_docstring
 
-    def as_rest_ref(self, type_hint, out):
+    def as_rest_ref(self, type_hint, out, as_xml=False):
         """ Return the type hint with appropriate reST references. """
 
         managed_type_hint = self._get_managed_type_hint(type_hint, out)
@@ -140,7 +140,7 @@ class TypeHintManager:
         # See if it needs rendering.
         if managed_type_hint.as_rest_ref is None:
             managed_type_hint.as_rest_ref = self._render(managed_type_hint,
-                    out, rest_ref=True)
+                    out, rest_ref=True, as_xml=as_xml)
 
         return managed_type_hint.as_rest_ref
 
@@ -276,21 +276,22 @@ class TypeHintManager:
         return node
 
     def _render(self, managed_type_hint, out, pep484=False, rest_ref=False,
-            module=None, defined=None):
+            module=None, defined=None, as_xml=False):
         """ Return a rendered type hint. """
 
         self._parse(managed_type_hint, out)
 
         if managed_type_hint.root is not None:
             s = self._render_node(managed_type_hint.root, out, pep484,
-                    rest_ref, module, defined)
+                    rest_ref, module, defined, as_xml)
         else:
-            s = self._maybe_any_object(managed_type_hint.type_hint,
-                    pep484=pep484)
+            s = self._maybe_any_object(managed_type_hint.type_hint, pep484,
+                    as_xml)
 
         return s
 
-    def _render_node(self, node, out, pep484, rest_ref, module, defined):
+    def _render_node(self, node, out, pep484, rest_ref, module, defined,
+            as_xml):
         """ Render a single node. """
 
         if node.type is NodeType.TYPING:
@@ -303,7 +304,7 @@ class TypeHintManager:
 
             if node.children is not None:
                 children = [self._render_node(c, out, pep484, rest_ref, module,
-                        defined) for c in node.children]
+                        defined, as_xml) for c in node.children]
 
                 s += '[' + ', '.join(children) + ']'
 
@@ -332,7 +333,7 @@ class TypeHintManager:
                 s = formatter.fq_py_name
 
         else:
-            s = self._maybe_any_object(node.definition, pep484)
+            s = self._maybe_any_object(node.definition, pep484, as_xml)
 
         return s
 
@@ -462,13 +463,19 @@ class TypeHintManager:
         # Nothing was found.
         return TypeHintNode(NodeType.OTHER, definition=name)
 
-    @classmethod
-    def _maybe_any_object(cls, hint, pep484):
+    def _maybe_any_object(self, hint, pep484, as_xml):
         """ Return a hint taking into account that it may be any sort of
         object.
         """
 
-        return hint if hint != 'Any' else cls._any_object(pep484)
+        if hint == 'Any':
+            return cls._any_object(pep484)
+
+        # Don't worry if the voidptr name is qualified in any way.
+        if hint.endswith('voidptr'):
+            return format_voidptr(self._spec, pep484, as_xml)
+
+        return hint
 
     @staticmethod
     def _any_object(pep484):
@@ -495,3 +502,17 @@ class TypeHintManager:
             end -= 1
 
         return end
+
+
+def format_voidptr(spec, pep484, as_xml):
+    """ Return the representation of a voidptr in the context of either a type
+    hint, XML or a docstring.
+    """
+
+    if pep484:
+        return spec.sip_module + '.voidptr'
+
+    if as_xml:
+        return f':py:class:`~{spec.sip_module}.voidptr`'
+
+    return 'voidptr'
diff --git a/sipbuild/generator/outputs/xml.py b/sipbuild/generator/outputs/xml.py
index b92a848..c3cfc73 100644
--- a/sipbuild/generator/outputs/xml.py
+++ b/sipbuild/generator/outputs/xml.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2022, Riverbank Computing Limited
+# Copyright (c) 2023, Riverbank Computing Limited
 # All rights reserved.
 #
 # This copy of SIP is licensed for use under the terms of the SIP License
@@ -42,14 +42,16 @@ def output_xml(spec, module_name):
 
     # Note that we don't yet handle mapped types, templates or exceptions.
 
-    if spec.module.py_name != module_name:
+    module = spec.module
+
+    if module.py_name != module_name:
         return None
 
     root = Element('Module', version=_XML_VERSION_NR, name=module.py_name)
 
     for klass in spec.classes:
         if klass.iface_file.module is module and not klass.external:
-            _xml_class(root, spec, module, klass)
+            _class(root, spec, module, klass)
 
     for klass in module.proxies:
         _class(root, spec, module, klass)
@@ -375,7 +377,9 @@ def _typename(spec, arg, kw_args=KwArgs.NONE, out=False):
         if kw_args is KwArgs.ALL or (kw_args is KwArgs.OPTIONAL and arg.default_value is not None):
             s += arg.name.name + ': '
 
-    s += ArgumentFormatter(spec, arg).as_rest_ref(out)
+    arg_formatter = ArgumentFormatter(spec, arg)
+    arg_rest_ref = arg_formatter.as_rest_ref(out, as_xml=True)
+    s += arg_rest_ref
 
     if not out and arg.name is not None and arg.default_value is not None:
         s += ' = '
@@ -384,7 +388,8 @@ def _typename(spec, arg, kw_args=KwArgs.NONE, out=False):
         # hard but will get most cases.
         rest_ref = ValueListFormatter(spec, arg.default_value).as_rest_ref()
         if rest_ref is None:
-            rest_ref = formatter.py_default_value()
+            rest_ref = arg_formatter.py_default_value(arg_rest_ref,
+                    as_xml=True)
 
         s += rest_ref
 
diff --git a/sipbuild/generator/parser/parser.py b/sipbuild/generator/parser/parser.py
index 54e613f..9a15259 100644
--- a/sipbuild/generator/parser/parser.py
+++ b/sipbuild/generator/parser/parser.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2022, Riverbank Computing Limited
+# Copyright (c) 2023, Riverbank Computing Limited
 # All rights reserved.
 #
 # This copy of SIP is licensed for use under the terms of the SIP License
@@ -27,8 +27,9 @@ from .parser_manager import ParserManager
 def parse(sip_file, hex_version, encoding, abi_version, tags,
         disabled_features, protected_is_public, include_dirs, sip_module,
         is_strict=True):
-    """ Parse a .sip specification file returning a corresponding Specification
-    object and a list of the .sip files that define the module to be generated.
+    """ Parse a .sip file and return a 3-tuple of a Specification object, a
+    list of Module objects and a list of the .sip files that specify the module
+    to be generated.  A UserException is raised if there was an error.
     """
 
     return ParserManager(
diff --git a/sipbuild/generator/parser/parser_manager.py b/sipbuild/generator/parser/parser_manager.py
index 6608f75..b09504d 100644
--- a/sipbuild/generator/parser/parser_manager.py
+++ b/sipbuild/generator/parser/parser_manager.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2022, Riverbank Computing Limited
+# Copyright (c) 2023, Riverbank Computing Limited
 # All rights reserved.
 #
 # This copy of SIP is licensed for use under the terms of the SIP License
@@ -87,7 +87,6 @@ class ParserManager:
         self.c_bindings = None
         self.code_block = None
         self.module_state = None
-        self.module_states = []
         self.paren_depth = 0
         self.parsing_template = False
         self.parsing_virtual = False
@@ -1205,14 +1204,9 @@ class ParserManager:
         sip_file, raw_sip_file, input, lineno, lexpos, module_state = self._file_stack.pop()
 
         if module_state is None:
+            self._import_module(self._sip_file)
             module_state = self.module_state
 
-            # The current file was %Included so create a new Module and
-            # ModuleState as if it had been %Imported.
-            module = Module()
-            self.modules.append(module)
-            self.module_state = ModuleState(module, self._sip_file, self)
-
         self._file_stack.append(
                 (sip_file, raw_sip_file, input, lineno, lexpos, module_state))
 
@@ -1459,9 +1453,7 @@ class ParserManager:
         code will be generated for.
         """
 
-        module = self.module_state.module
-
-        return module is self.spec.module or module.composite is not None
+        return self.module_state.module is self.spec.module
 
     def instantiate_class_template(self, p, symbol, fq_cpp_name, template,
             py_name, no_type_name, docstring):
@@ -1503,7 +1495,7 @@ class ParserManager:
         raw_sip_file = sip_file
         sip_file = os.path.abspath(sip_file)
 
-        self.module_state = ModuleState(self.spec.module, sip_file, self)
+        self.module_state = ModuleState(self.spec.module, sip_file)
 
         try:
             self._parser.parse(self._read(sip_file, raw_sip_file),
@@ -1637,47 +1629,17 @@ class ParserManager:
                         "'{0}' is being read recursively".format(sip_file))
                 return
 
-        if new_module:
-            importing_from = self.module_state.module
-
-            # Create a new module if it has not already been defined.
-            for module_state in self.module_states:
-                if module_state.sip_file == sip_file:
-                    module = module_state.module
-                    break
-            else:
-                module = Module()
-                self.modules.append(module)
-
-                module.default_exception = self.module_state.module.default_exception
-                old_module_state = self.module_state
-                self.module_state = ModuleState(module, sip_file, self)
-
-                # Get the configuration of the new module.
-                mod_tags, mod_disabled = get_bindings_configuration(
-                        self.spec.abi_version[0], sip_file, self._include_dirs)
-
-                for tag in mod_tags:
-                    if tag not in self.tags:
-                        self.tags.append(tag)
-
-                for feature in mod_disabled:
-                    if feature not in self._disabled_features:
-                        self._disabled_features.append(feature)
+        # Ignore the file if we have already read it.
+        if sip_file in self._all_sip_files:
+            return
 
-            # Add the new import unless it has already been imported.
-            if module not in importing_from.imports:
-                importing_from.imports.insert(0, module)
+        if new_module:
+            old_module_state = self.module_state
+            self._import_module(sip_file)
         else:
             # This means that the file was %Included rather than %Imported.
             old_module_state = None
 
-        # Ignore the file if we have already read it. This replicates the
-        # behaviour of the old parser but shouldn't be required for a well
-        # specified project.
-        if sip_file in self._all_sip_files:
-            return
-
         # Save the state of the current .sip file.
         self._file_stack.append(
                 (self._sip_file, self.raw_sip_file, self._input,
@@ -2116,6 +2078,34 @@ class ParserManager:
         # call_super_init defaults to False if it wasn't specified.
         module.call_super_init = bool(module_state.call_super_init)
 
+    def _import_module(self, sip_file):
+        """ Create a new Module object and corresponding ModuleState object for
+        a .sip file and make it current.
+        """
+
+        importing_from = self.module_state.module
+
+        module = Module()
+        self.modules.append(module)
+
+        module.default_exception = self.module_state.module.default_exception
+        self.module_state = ModuleState(module, sip_file)
+
+        # Get the configuration of the new module.
+        mod_tags, mod_disabled = get_bindings_configuration(
+                self.spec.abi_version[0], sip_file, self._include_dirs)
+
+        for tag in mod_tags:
+            if tag not in self.tags:
+                self.tags.append(tag)
+
+        for feature in mod_disabled:
+            if feature not in self._disabled_features:
+                self._disabled_features.append(feature)
+
+        # Add the new import.
+        importing_from.imports.append(module)
+
     def _read(self, sip_file, raw_sip_file):
         """ Return the contents of the current .sip file. """
 
@@ -2149,7 +2139,7 @@ class ParserManager:
 class ModuleState:
     """ Encapsulate the parser-related state for a module. """
 
-    def __init__(self, module, sip_file, pm):
+    def __init__(self, module, sip_file):
         """ Initialise the state. """
 
         self.module = module
@@ -2162,8 +2152,6 @@ class ModuleState:
         self.kw_args = KwArgs.NONE
         self.nr_timelines = 0
 
-        pm.module_states.append(self)
-
 
 class ScopeState:
     """ Encapsulate the parser-related state for a scope. """
diff --git a/sipbuild/generator/parser/rules.py b/sipbuild/generator/parser/rules.py
index 0c3ad03..9c804e0 100644
--- a/sipbuild/generator/parser/rules.py
+++ b/sipbuild/generator/parser/rules.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2022, Riverbank Computing Limited
+# Copyright (c) 2023, Riverbank Computing Limited
 # All rights reserved.
 #
 # This copy of SIP is licensed for use under the terms of the SIP License
@@ -201,6 +201,12 @@ def p_composite_module(p):
     if pm.skipping:
         return
 
+    # A composite module must be the first one in the specification.
+    if not pm.in_main_module:
+        pm.parser_error(p, 1, "a %CompositeModule cannot be %Imported")
+
+    pm.spec.is_composite = True
+
     if len(p) == 4:
         name = p[2]
         body = p[3]
@@ -210,15 +216,7 @@ def p_composite_module(p):
 
     module = pm.module_state.module
 
-    if module is not pm.modules[0]:
-        pm.parser_error(p, 1, "a %CompositeModule cannot be %Imported")
-
-    if module.fq_py_name is not None:
-        pm.parser_error(p, 1,
-                "%CompositeModule must appear before any %Module directive")
-
     module.fq_py_name = cached_name(pm.spec, str(name))
-    module.is_composite = True
 
     for directive in body:
         if isinstance(directive, Docstring):
@@ -1035,22 +1033,15 @@ def p_module(p):
     if pm.skipping:
         return
 
-    module_state = pm.module_state
-    module = module_state.module
-
     # See if this %Module is part of a %CompositeModule.
-    if module.is_composite or module.composite is not None:
+    if pm.spec.is_composite:
         # Historically we %Include modules although conceptually we actually
         # %Import them.  Ensure that the scopes etc. are correct in either
         # case.
         pm.ensure_import()
 
-        # The module state may have changed.
-        module_state = pm.module_state
-
-        module_state.module.composite = module if module.is_composite else module.composite
-
-        module = module_state.module
+    module_state = pm.module_state
+    module = module_state.module
 
     if module.fq_py_name is not None:
         pm.parser_error(p, 1, "%Module has already been specified")
diff --git a/sipbuild/generator/specification.py b/sipbuild/generator/specification.py
index eecaaab..05a2dfb 100644
--- a/sipbuild/generator/specification.py
+++ b/sipbuild/generator/specification.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2022, Riverbank Computing Limited
+# Copyright (c) 2023, Riverbank Computing Limited
 # All rights reserved.
 #
 # This copy of SIP is licensed for use under the terms of the SIP License
@@ -979,9 +979,6 @@ class Module:
     # Set if wrapped ctors should support cooperative multi-inheritance.
     call_super_init: bool = False
 
-    # The containing composite module.
-    composite: Optional['Module'] = None
-
     # The text specified by any %Copying directives.
     copying: List[CodeBlock] = field(default_factory=list)
 
@@ -1023,9 +1020,6 @@ class Module:
     # The code specified by any %InitialisationCode directives.
     initialisation_code: List[CodeBlock] = field(default_factory=list)
 
-    # Set if the module is a composite module.
-    is_composite: bool = False
-
     # The software license.
     license: Optional[License] = None
 
@@ -1316,6 +1310,9 @@ class Specification:
     # The interface files.
     iface_files: List[IfaceFile] = field(default_factory=list)
 
+    # Set if the specification is for a composite module.
+    is_composite: bool = False
+
     # The mapped type templates.
     mapped_type_templates: List[MappedTypeTemplate] = field(default_factory=list)
 
diff --git a/sipbuild/version.py b/sipbuild/version.py
index 4755178..2978308 100644
--- a/sipbuild/version.py
+++ b/sipbuild/version.py
@@ -1,2 +1,2 @@
-SIP_VERSION = 0x060706
-SIP_VERSION_STR = '6.7.6'
+SIP_VERSION = 0x060707
+SIP_VERSION_STR = '6.7.7'



More information about the Neon-commits mailing list