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 <nikol...@rath.org> wrote:

> Larry Hastings <la...@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 Py_None, return current time. Otherwise,
> |    convert Python object to time_t.
> | */
> | static int
> | PyObject_to_time_t(PyObject *obj, time_t *stamp)
> | {
> |     if (obj == NULL || obj == Py_None) {
> |         *stamp = time(NULL);
> |     }
> |     else {
> |         if (_PyTime_ObjectToTime_t(obj, stamp) == -1)
> |             return 0;
> |     }
> |     return 1;
> | }
> |
> | /*[python input]
> | class time_t_converter(CConverter):
> |     type = 'time_t'
> |     converter = 'PyObject_to_time_t'
> |     default = None
> | [python start generated code]*/
> | /*[python end generated code:
> checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/
> |
> |
> | /*[clinic input]
> | time.gmtime
> |
> |     seconds: time_t
> |     /
> |
> | [clinic start generated code]*/
> `----
>
> but this results in the following code:
>
> ,----
> | static PyObject *
> | time_gmtime(PyModuleDef *module, PyObject *args)
> | {
> |     PyObject *return_value = NULL;
> |     time_t seconds;
> |
> |     if (!PyArg_ParseTuple(args,
> |         "|O&:gmtime",
> |         PyObject_to_time_t, &seconds))
> |         goto exit;
> |     return_value = time_gmtime_impl(module, seconds);
> |
> | exit:
> |     return return_value;
> | }
> `----
>
> 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@python.org
> https://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe:
> https://mail.python.org/mailman/options/python-dev/rmsr%40lab.net
>
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to