[Python-Dev] Changing Clinic's output

Brett Cannon brett at python.org
Wed Jan 8 16:33:33 CET 2014


On Tue, Jan 7, 2014 at 7:07 PM, Larry Hastings <larry at hastings.org> wrote:

>
>
> On 01/07/2014 03:38 PM, Brett Cannon wrote:
>
> On Tue, Jan 7, 2014 at 6:24 PM, Larry Hastings <larry at hastings.org> wrote:
>
>>  For what it's worth, if we use the "accumulator" approach I propose
>> that the generated code doesn't go at the very end of the file.  Instead, I
>> suggest they should go *near* the end, below the implementations of the
>> module / class methods, but above the methoddef/type structures and the
>> module init function.
>>
>
>  If it is accumulated in a single location should it just be a single
> block for everything towards the end? Then forward declarations would go
> away (you could still have it as a comment to copy-and-paste where you
> define the implementation) and you can have a single macro for the
> PyMethodDef values, each class, etc. If you accumulated the PyMethodDef
> values into a single macro it would help make up for the convenience lost
> of converting a function by just cutting the old call signature up to the
> new *_impl() function.
>
>
> I *think* that would complicate some use cases.  People occasionally call
> these parsing functions from other functions, or spread their methoddef /
> typeobject structures throughout the file rather than putting them all at
> the end.
>
> I'm proposing that the blob of text immediately between the Clinic input
> and the body of the impl contain (newlines added here for clarity):
>
> static char *parsing_function_doc;
>
> static PyObject *
> parsing_function(...);
>
> #define PARSING_FUNCTION_METHODDEF \
>     { ... }
>
> static PyObject *
> parsing_function_impl(...)
>
> Then the "accumulator" would get the text of the docstring and the
> definition of the parsing_function.
>
>
> On the other hand, if we wanted to take this opportunity to force everyone
> to standardize (all methoddefs and typeobjects go at the end!) we could
> probably make it work with one giant block near the end.
>
> Or I could make it flexible on what went into the accumulator and what
> went into the normal output block, and the default could be
> everything-in-the-accumulator.  Making the common easy and the uncommon
> possible and all that.  Yeah, that seems best.
>

So let's make this idea concrete to focus a possible discussion. Using the
example from the Clinic HOWTO and converting to how I see it working:

####################

/*[clinic input]
pickle.Pickler.dump

    obj: 'O'
        The object to be pickled.
    /

Write a pickled representation of obj to the open file.
[clinic start generated code]*/

static PyObject *
pickle_Pickler_dump_impl(PyObject *self, PyObject *obj)
/*[clinic end generated code:
checksum=3bd30745bf206a48f8b576a1da3d90f55a0a4187]*/
{
    /* Check whether the Pickler was initialized correctly (issue3664).
       Developers often forget to call __init__() in their subclasses, which
       would trigger a segfault without this check. */
    if (self->write == NULL) {
        PyErr_Format(PicklingError,
                     "Pickler.__init__() was not called by %s.__init__()",
                     Py_TYPE(self)->tp_name);
        return NULL;
    }

    if (_Pickler_ClearBuffer(self) < 0)
        return NULL
    ...
}

...

/*[clinic accumulate]*/
PyDoc_STRVAR(pickle_Pickler_dump__doc__,
"Write a pickled representation of obj to the open file.\n"
"\n"

static PyObject *
_pickle_Pickler_dump(PyObject *args)
{
  ...
  return pickle_Pickler_dump_impl(...);
}

#define _PICKLE_PICKLER_DUMP_METHODDEF    \
{"dump", (PyCFunction)_pickle_Pickler_dump, METH_O,
_pickle_Pickler_dump__doc__},

... any other pickler.Pickler Clinic stuff that does not directly involve
the the impl function ...

#define _PICKLE_PICKLER_METHODDEF_ACCUMULATED  \
  _PICKLE_PICKLER_DUMP_METHODDEF  \
  ... any other MethodDef entries for pickle.Pickler

/*[clinic end accumulate: checksum=0123456789]*/

... pickle.Pickler struct where _PICKLE_PICKLER_METHODDEF_ACCUMULATED is
all that is needed for the non-magical class methods ...


###########################


Another potential perk of doing a gathering of Clinic output is that if we
take it to it's logical conclusion, then you can start to do things like
define a method like pickle.Pickler.__init__, etc., have Clinic handle
docstrings for modules and classes, and then it can end up spitting out the
type struct entirely for you, negating the typical need to do all of that
by hand (I don't know about the rest of you but I always just copy and
paste that struct anyway, so having a tool slot in the right method names
for the right positions would save me busy work). It could then go as far
as then spit out the module initialization function definition line and
then all you would need to do is fill that in; Clinic could handle all
other module-level details for you in the very common case.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20140108/8d3c5f3e/attachment.html>


More information about the Python-Dev mailing list