[Python-Dev] Using argument clinic to replace timemodule.c:parse_time_t_args() (original) (raw)

Ryan Smith-Roberts rmsr at lab.net
Mon Jan 20 21:00:13 CET 2014


The trick you're missing is that any time you have an optional argument with a custom converter[1], PyArg_ParseTuple only calls the converter function in the case that the user actually supplies some value. This is a basic property of an optional argument. Another property is that the c_default is evaluated every time, as it is set before the call to PyArg_ParseTuple. Are these the best ways to do things? Maybe not, but it's how they are.

Please do not use a custom converter for this case. It can't work. Please do what I outlined earlier (untested, somewhat verbose code follows):

static int parse_time_t_arg(PyObject *arg, time_t *when) { if (arg == NULL || arg == Py_None) { *when = time(NULL); return 1; } if (_PyTime_ObjectToTime_t(arg, when) == -1) return 0; return 1; }

/[clinic input] time.gmtime seconds: object = None [clinic start generated code]/ { time_t when;

if (0 == parse_time_t_arg(seconds, &when))
    return NULL;

...

[1] If you set a default value, or put it in brackets as Serhiy later recommends, it works the same.

On Sun, Jan 19, 2014 at 8:19 PM, Nikolaus Rath <Nikolaus at rath.org> wrote:

Larry Hastings <larry at hastings.org> writes: > On 01/18/2014 09:52 PM, Ryan Smith-Roberts wrote: >> >> 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). >> > > I agree. Converting to Argument Clinic should not cause a performance > regression. Please don't add new calls to time() for the sake of > making code more generic. > > A better choice would be to write a converter function in C, then use > a custom converter that called it. Nikolaus: Is that something you're > comfortable doing?

I think I'll need some help. I don't know how to handle the case where the user is not passing anything. Here's my attempt: ,---- | /* C Converter for argument clinic | If obj is NULL or PyNone, return current time. Otherwise, | convert Python object to timet. | */ | static int | PyObjecttotimet(PyObject *obj, timet *stamp) | { | if (obj == NULL || obj == PyNone) { | *stamp = time(NULL); | } | else { | if (PyTimeObjectToTimet(obj, stamp) == -1) | return 0; | } | return 1; | } | | /*[python input] | class timetconverter(CConverter): | type = 'timet' | converter = 'PyObjecttotimet' | default = None | [python start generated code]*/ | /*[python end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ | | | /*[clinic input] | time.gmtime | | seconds: timet | / | | [clinic start generated code]*/ ----_ _but this results in the following code:_ _,----_ _| static PyObject *_ _| timegmtime(PyModuleDef *module, PyObject *args)_ _| {_ _| PyObject *returnvalue = NULL;_ _| timet seconds;_ _|_ _| if (!PyArgParseTuple(args,_ _| "|O&:gmtime",_ _| PyObjecttotimet, &seconds))_ _| goto exit;_ _| returnvalue = timegmtimeimpl(module, seconds);_ _|_ _| exit:_ _| return returnvalue;_ _| }_ _---- This works if the user calls time.gmtime(None), but it fails for time.gmtime(). It seems that in that case my C converter function is never called. What's the trick that I'm missing?

Thanks! -Nikolaus -- Encrypted emails preferred. PGP fingerprint: 5B93 61F8 4EA2 E279 ABF6 02CF A9AD B7F8 AE4E 425C »Time flies like an arrow, fruit flies like a Banana.«


Python-Dev mailing list Python-Dev at python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/rmsr%40lab.net -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.python.org/pipermail/python-dev/attachments/20140120/48e448a8/attachment-0001.html>



More information about the Python-Dev mailing list