<div dir="ltr"><p dir="ltr">Ah yes, my apologies, I was thrown off by the first converter declaration in your class and didn't spot the second, so didn't realize what you were up to.</p><p>I still advise you not to use this solution. time() is a system call on many operating systems, and so it can be a heavier operation than you'd think. Best to avoid it unless it's needed (on FreeBSD it seems to add about 15% overhead to localtime(), for instance).</p>
<p>As for why you're getting that exception, it definitely looks like a bug in Argument Clinic. I spotted another bug that would have bitten you while I was looking for this one, so I've opened bugs on both issues, and put you on the nosy list for them.</p>
</div><div class="gmail_extra"><br><br><div class="gmail_quote">On Sat, Jan 18, 2014 at 7:42 PM, Nikolaus Rath <span dir="ltr"><<a href="mailto:Nikolaus@rath.org" target="_blank">Nikolaus@rath.org</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi Ryan,<br>
<div class="im"><br>
<br>
Ryan Smith-Roberts <<a href="mailto:rmsr@lab.net">rmsr@lab.net</a>> writes:<br>
> Hi Nikolaus. I also started a conversion of timemodule, but dropped it when<br>
> I saw in the issue that you had taken over that conversion. I also tried to<br>
> turn parse_time_t_args into a converter. However, it won't work. The<br>
> problem is that parse_time_t_args must be called whether or not the user<br>
> supplies an argument to the function, but an Argument Clinic converter only<br>
> gets called if the user actually supplies something, and not on the default<br>
> value.<br>
<br>
</div>I don't quite follow. My approach was to drop parse_time_t_args()<br>
completely and use _PyTime_ObjectToTime_t() as the conversion function<br>
(which only needs to be called if the user supplied something).<br>
<br>
In other words, I would have expected<br>
<div class="im"><br>
>> ,----<br>
>> | /*[python input]<br>
>> | class time_t_converter(CConverter):<br>
>> |     type = 'time_t'<br>
>> |     converter = 'time_t_converter'<br>
>> |     default = None<br>
>> |     py_default = 'None'<br>
>> |     c_default = 'time(NULL)'<br>
>> |     converter = '_PyTime_ObjectToTime_t'<br>
>> | [python start generated code]*/<br>
>> |<br>
>> | /*[clinic input]<br>
>> | time.localtime<br>
>> |<br>
>> |     seconds: time_t<br>
>> |     /<br>
>> |<br>
>> | bla.<br>
>> | [clinic start generated code]*/<br>
>> `----<br>
<br>
</div>to produce something like this:<br>
<div class="im"><br>
static PyObject *<br>
time_localtime(PyObject *self, PyObject *args)<br>
{<br>
</div>     PyObject *obj = NULL;<br>
     time_t seconds;<br>
     struct tm buf;<br>
<br>
     if (!PyArg_ParseTuple(args, "|O:localtime", &obj))<br>
         return NULL;<br>
     if (obj == NULL || obj == Py_None)<br>
         seconds = time(NULL);<br>
     else {<br>
         if (_PyTime_ObjectToTime_t(obj, &seconds) == -1)<br>
             return NULL;<br>
     }<br>
     return time_localtime_impl(self, seconds);<br>
}<br>
<br>
<br>
Apart from getting an error from clinic.py, it seems to me that this<br>
should in principle be possible.<br>
<br>
Best,<br>
Nikolaus<br>
<div class="HOEnZb"><div class="h5"><br>
<br>
><br>
> So, the best idea is to<br>
><br>
> * Remove the PyArgs_ParseTuple code from parse_time_t_args<br>
> * Declare seconds as a plain object in Argument Clinic<br>
> * Call the modified parse_time_t_args on seconds first thing in the _impl<br>
> functions<br>
><br>
><br>
> On Sat, Jan 18, 2014 at 4:56 PM, Nikolaus Rath <<a href="mailto:Nikolaus@rath.org">Nikolaus@rath.org</a>> wrote:<br>
><br>
>> Hello,<br>
>><br>
>> I'm trying to convert functions using parse_time_t_args() (from<br>
>> timemodule.c) for argument parsing to argument clinic.<br>
>><br>
>> The function is defined as:<br>
>><br>
>> ,----<br>
>> | static int<br>
>> | parse_time_t_args(PyObject *args, char *format, time_t *pwhen)<br>
>> | {<br>
>> |     PyObject *ot = NULL;<br>
>> |     time_t whent;<br>
>> |<br>
>> |     if (!PyArg_ParseTuple(args, format, &ot))<br>
>> |         return 0;<br>
>> |     if (ot == NULL || ot == Py_None) {<br>
>> |         whent = time(NULL);<br>
>> |     }<br>
>> |     else {<br>
>> |         if (_PyTime_ObjectToTime_t(ot, &whent) == -1)<br>
>> |             return 0;<br>
>> |     }<br>
>> |     *pwhen = whent;<br>
>> |     return 1;<br>
>> | }<br>
>> `----<br>
>><br>
>> and used like this:<br>
>><br>
>> ,----<br>
>> | static PyObject *<br>
>> | time_localtime(PyObject *self, PyObject *args)<br>
>> | {<br>
>> |     time_t when;<br>
>> |     struct tm buf;<br>
>> |<br>
>> |     if (!parse_time_t_args(args, "|O:localtime", &when))<br>
>> |         return NULL;<br>
>> |     if (pylocaltime(&when, &buf) == -1)<br>
>> |         return NULL;<br>
>> |     return tmtotuple(&buf);<br>
>> | }<br>
>> `----<br>
>><br>
>> In other words, if any Python object is passed to it, it calls<br>
>> _PyTime_ObjectToTime_t on it to convert it to time_t, and otherwise uses<br>
>> time(NULL) as the default value.<br>
>><br>
>> May first attempt to implement something similar in argument clinic was:<br>
>><br>
>> ,----<br>
>> | /*[python input]<br>
>> | class time_t_converter(CConverter):<br>
>> |     type = 'time_t'<br>
>> |     converter = 'time_t_converter'<br>
>> |     default = None<br>
>> |     py_default = 'None'<br>
>> |     c_default = 'time(NULL)'<br>
>> |     converter = '_PyTime_ObjectToTime_t'<br>
>> | [python start generated code]*/<br>
>> |<br>
>> | /*[clinic input]<br>
>> | time.localtime<br>
>> |<br>
>> |     seconds: time_t<br>
>> |     /<br>
>> |<br>
>> | bla.<br>
>> | [clinic start generated code]*/<br>
>> `----<br>
>><br>
>> However, running clinic.py on this file gives:<br>
>><br>
>> ,----<br>
>> | $ Tools/clinic/clinic.py Modules/timemodule.c<br>
>> | Error in file "Modules/timemodule.c" on line 529:<br>
>> | Exception raised during parsing:<br>
>> | Traceback (most recent call last):<br>
>> |   File "Tools/clinic/clinic.py", line 1445, in parse<br>
>> |     parser.parse(block)<br>
>> |   File "Tools/clinic/clinic.py", line 2738, in parse<br>
>> |     self.state(None)<br>
>> |   File "Tools/clinic/clinic.py", line 3468, in state_terminal<br>
>> |     self.function.docstring = self.format_docstring()<br>
>> |   File "Tools/clinic/clinic.py", line 3344, in format_docstring<br>
>> |     s += "".join(a)<br>
>> | TypeError: sequence item 2: expected str instance, NoneType found<br>
>> `----<br>
>><br>
>> What am I doing wrong?<br>
>><br>
>><br>
>> Best,<br>
>> Nikolaus<br>
>><br>
>> --<br>
>> Encrypted emails preferred.<br>
>> PGP fingerprint: 5B93 61F8 4EA2 E279 ABF6  02CF A9AD B7F8 AE4E 425C<br>
>><br>
>>              »Time flies like an arrow, fruit flies like a Banana.«<br>
>> _______________________________________________<br>
>> Python-Dev mailing list<br>
>> <a href="mailto:Python-Dev@python.org">Python-Dev@python.org</a><br>
>> <a href="https://mail.python.org/mailman/listinfo/python-dev" target="_blank">https://mail.python.org/mailman/listinfo/python-dev</a><br>
>> Unsubscribe:<br>
>> <a href="https://mail.python.org/mailman/options/python-dev/rmsr%40lab.net" target="_blank">https://mail.python.org/mailman/options/python-dev/rmsr%40lab.net</a><br>
>><br>
<br>
<br>
--<br>
Encrypted emails preferred.<br>
PGP fingerprint: 5B93 61F8 4EA2 E279 ABF6  02CF A9AD B7F8 AE4E 425C<br>
<br>
             »Time flies like an arrow, fruit flies like a Banana.«<br>
_______________________________________________<br>
Python-Dev mailing list<br>
<a href="mailto:Python-Dev@python.org">Python-Dev@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-dev" target="_blank">https://mail.python.org/mailman/listinfo/python-dev</a><br>
Unsubscribe: <a href="https://mail.python.org/mailman/options/python-dev/rmsr%40lab.net" target="_blank">https://mail.python.org/mailman/options/python-dev/rmsr%40lab.net</a><br>
</div></div></blockquote></div><br></div>