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

Larry Hastings larry at hastings.org
Tue Jan 21 08:19:11 CET 2014


On 01/20/2014 06:44 PM, Nikolaus Rath wrote:
> All in all, I'm still not sure how I'm supposed to proceed. I see the
> following options (and I'm fine with all of them):
>
> 1. Use the option group with a custom converter. This means a time(NULL)
>     call even if the caller passed a parameter.
>
> 2. Declare the _impl parameter as PyObject* instead of time_t, and
>     explicitly call a C conversion function.
>     
> 3. Patch clinic.py to only evaluate the C default if the caller does not
>     pass a parameter. This seemest cleanest, but I don't know if the
>     design of clinic.py actually allows that.

clinic.py is not flexible enough to allow initialization code after the 
call to the converter.

A comment on your approach so far: I'm very much against giving 
"default" a default value in the constructor.  I realize that hack saves 
you having to say "= NULL" in a lot of places.  But explicit is better 
than implicit, and we're going to read these signatures a lot more often 
than we write them, and I want Clinic signatures to be easy to read at 
first glance.

Anyway, you're right, the converter function is not called if a value is 
not passed in to convert it.  I think this is more complicated than you 
suspect, because PyArg_ParseWhatnot doesn't tell you whether or not it 
processed a parameter.  You have to detect it yourself, generally 
through a clever choice of a default value in C.  But there are no 
illegal values of time_t.

All is not lost!  What follows is rough pseudo-C code, hopefully you can 
take it from here.

    typedef struct {
       int set;
       time_t when;
    } clinic_time_t;

    #define DEFAULT_CLINIC_TIME_T {0, 0}

    static int
    parse_clinic_time_t_arg(PyObject *arg, clinic_time_t *ct)
    {
         if (arg == NULL)
             return 1;
         if (arg == Py_None)
             return 0;
         if (_PyTime_ObjectToTime_t(arg, &ct->when) == -1) {
             set = 1;
             return 0;
         }
         return 1;
    }

    static int post_parse_clinic_time_t(clinic_time_t *ct) {
         if (ct->set)
             return 0;
         ct->when = time(NULL);
         return 0;
    }

    /*[python input]
    class clinic_time_t_converter(CConverter):
         type = 'clinic_time_t'
         converter = 'parse_clinic_time_t'
         c_default = 'DEFAULT_CLINIC_TIME_T'
    [python start generated code]*/
    /*[python end generated code: checksum=...]*/

Now you can use clinic_time_t.  Parameters declared clinic_time_t can be 
required, or they can be optional; if they're optional give them a 
default value of None.  You'll have to call post_parse_clinic_time_t() 
by hand in your impl function; I'll see if I can extend Clinic so 
converters can emit code after a successful call to the parse function 
but before the call to the impl.  Also, the converter probably isn't 
quite right, you'll have to play with "impl_by_reference" and 
"parse_by_reference" and add and remove asterisks and ampersands to make 
sure the code is 100% correct.  Examine the implementation of path_t in 
Modules/posixmodule.c, as that does about the same thing.

And of course clinic_time_t is a poor name, perhaps you can come up with 
a better one.

That should work,


//arry/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20140120/314529f1/attachment.html>


More information about the Python-Dev mailing list