[PyQt] Possible small bug in docstring generation

Shaheed Haque srhaque at theiet.org
Thu Jun 15 19:58:12 BST 2017


Attached is a patch that converts this SIP:

===========
        virtual void
openDialogIncidenceCreated(Akonadi::ITIPHandlerDialogDelegate::Recipient
recipient, const QString &question,
Akonadi::ITIPHandlerDialogDelegate::Action action =
Akonadi::ITIPHandlerDialogDelegate::ActionAsk, const KGuiItem
&buttonYes = KGuiItem(i18nc("@action:button dialog positive
answer","Send Email")), const KGuiItem &buttonNo =
KGuiItem(i18nc("@action:button dialog negative answer","Do Not
Send")));
============

into this C++ code:

============
PyDoc_STRVAR(doc_Akonadi_ITIPHandlerDialogDelegate_openDialogIncidenceCreated,
"openDialogIncidenceCreated(self,
Akonadi.ITIPHandlerDialogDelegate.Recipient, str,
Akonadi.ITIPHandlerDialogDelegate.Action =
Akonadi.ITIPHandlerDialogDelegate.ActionAsk, KGuiItem =
KGuiItem(i18nc(\"@action:button dialog positive answer\",\"Send
Email\")), KGuiItem = KGuiItem(i18nc(\"@action:button dialog negative
answer\",\"Do Not Send\")))");
.
.
.
    {
         ::Akonadi::ITIPHandlerDialogDelegate::Recipient a0;
        const  ::QString* a1;
        int a1State = 0;
         ::Akonadi::ITIPHandlerDialogDelegate::Action a2 =
Akonadi::ITIPHandlerDialogDelegate::ActionAsk;
        const  ::KGuiItem& a3def = KGuiItem(i18nc("@action:button
dialog positive answer","Send Email"));
        const  ::KGuiItem* a3 = &a3def;
        const  ::KGuiItem& a4def = KGuiItem(i18nc("@action:button
dialog negative answer","Do Not Send"));
============

As you can see, the PyDoc_STRVAR has the quotes escaped, but a3def and
a4def do not. Now, the patch as-is is slightly overkill in the sense
that it introduces a %q format code for prcode, which I expected would
be needed for cases like:

     ..., QString bar = "worst \"stri\\ng ever", ...

to generate:

     ..., QString bar = \"worst \\\"stri\\\\ng ever\", ...

However, it seems that SIP's lexer does not like the escapes. I did
not feel comfortable patching that here and now, so as I say, that
make the %q arguably overkill.

Please consider the patch, which is against sip-4.19.3.dev1706101519,
with or without the %q stuff.

Thanks, Shaheed


On 14 June 2017 at 19:34, Shaheed Haque <srhaque at theiet.org> wrote:
> Hi Phil,
>
> Is it possible this fell through the cracks? I don't see it in the
> changelog for the latest snapshot...or going back for a bit.
>
> If you like, I could try to create a patch (I was thinking a "q"
> format string specifier for prcode?).
>
>
>
> On 20 March 2017 at 21:45, Phil Thompson <phil at riverbankcomputing.com> wrote:
>> On 20 Mar 2017, at 7:50 pm, Shaheed Haque <srhaque at theiet.org> wrote:
>>>
>>> Hi Phil,
>>>
>>> With sip 4.18.1, I noticed this function:
>>>
>>> KMIME_EXPORT bool parseGenericQuotedString(const char *&scursor,
>>>        const char *const send,
>>>        QString &result, bool isCRLF,
>>>        const char openChar = '"',
>>>        const char closeChar = '"');
>>>
>>> ends up generating a docstring as follows, which of course is missing
>>> any escaping of the quotes...
>>>
>>> PyDoc_STRVAR(doc_KMime_HeaderParsing_parseGenericQuotedString,
>>> "parseGenericQuotedString(str, str, str, bool, str = '"', str = '"')
>>> -> bool");
>>>
>>>
>>> I'm not sure if this is fixed in a more recent release, but I thought
>>> it worth mentioning...
>>
>> I doubt it has been fixed. I'll add it to the TODO list for the next release.
>>
>> Thanks,
>> Phil
-------------- next part --------------
--- gencode.c.orig	2017-06-12 03:30:05.000000000 +0200
+++ gencode.c	2017-06-15 20:41:26.255649661 +0200
@@ -148,7 +148,7 @@
         FILE *);
 static void generateOrdinaryFunction(sipSpec *pt, moduleDef *mod,
         classDef *c_scope, mappedTypeDef *mt_scope, memberDef *md, FILE *fp);
-static void generateSimpleFunctionCall(fcallDef *, FILE *);
+static void generateSimpleFunctionCall(fcallDef *, FILE *, int);
 static int generateResultVar(ifaceFileDef *scope, overDef *od, argDef *res,
         const char *indent, FILE *fp);
 static void generateFunctionCall(classDef *c_scope, mappedTypeDef *mt_scope,
@@ -474,9 +474,10 @@
 
         case string_value:
             {
-                const char *quote = (in_str ? "\\\"" : "\"");
+                const char *quote = (in_str ? "\\\"" :  "\"" );
+                const char *fmt = (in_str ? "%s%q%s" : "%s%q%s");
 
-                prcode(fp,"%s%s%s", quote, vd->u.vstr, quote);
+                prcode(fp, fmt, quote, vd->u.vstr, quote);
             }
 
             break;
@@ -498,7 +499,7 @@
             break;
 
         case fcall_value:
-            generateSimpleFunctionCall(vd->u.fcd,fp);
+            generateSimpleFunctionCall(vd->u.fcd,fp,in_str);
             break;
         }
  
@@ -9728,7 +9729,7 @@
 /*
  * Generate a simple function call.
  */
-static void generateSimpleFunctionCall(fcallDef *fcd,FILE *fp)
+static void generateSimpleFunctionCall(fcallDef *fcd,FILE *fp,int in_str)
 {
     int i;
 
@@ -9739,7 +9740,7 @@
         if (i > 0)
             prcode(fp,",");
 
-        generateExpression(fcd->args[i], FALSE, fp);
+        generateExpression(fcd->args[i], in_str, fp);
     }
 
     prcode(fp,")");
@@ -14256,6 +14257,28 @@
 
                     break;
                 }
+
+            case 'q':
+                {
+                    /*
+                     * 'q' is the same as 's' except that the '"' is escaped with a '\'.
+                     * And that then suggests that a '\' must also be escaped.
+                     */
+                    const char *cp = va_arg(ap,const char *);
+
+                    while (*cp != '\0')
+                    {
+                        if (*cp == '\n')
+                            ++currentLineNr;
+                        else if ((*cp == '"') || (*cp == '\\'))
+                            fputc('\\',fp);
+
+                        fputc(*cp,fp);
+                        ++cp;
+                    }
+
+                    break;
+                }
 
             case 's':
                 {


More information about the PyQt mailing list