python / cpython

The Python programming language
https://www.python.org
Other
63.13k stars 30.22k forks source link

Additions to the C API #34901

Closed 1d332e54-3b86-44a9-8fc6-e0c6e60d2a36 closed 22 years ago

1d332e54-3b86-44a9-8fc6-e0c6e60d2a36 commented 23 years ago
BPO 448305
Nosy @gvanrossum, @loewis, @warsaw
Files
  • api.cdiff: concatenation of two patch files
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields: ```python assignee = 'https://github.com/gvanrossum' closed_at = created_at = labels = ['interpreter-core'] title = 'Additions to the C API' updated_at = user = 'https://bugs.python.org/giacometti' ``` bugs.python.org fields: ```python activity = actor = 'gvanrossum' assignee = 'gvanrossum' closed = True closed_date = None closer = None components = ['Interpreter Core'] creation = creator = 'giacometti' dependencies = [] files = ['3491'] hgrepos = [] issue_num = 448305 keywords = ['patch'] message_count = 10.0 messages = ['37180', '37181', '37182', '37183', '37184', '37185', '37186', '37187', '37188', '37189'] nosy_count = 4.0 nosy_names = ['gvanrossum', 'loewis', 'barry', 'giacometti'] pr_nums = [] priority = 'low' resolution = 'rejected' stage = None status = 'closed' superseder = None type = None url = 'https://bugs.python.org/issue448305' versions = [] ```

    1d332e54-3b86-44a9-8fc6-e0c6e60d2a36 commented 23 years ago

    I'm not sure a PEP is required for this patch, but these functions are pre-requisiste for two other PEP in the pipe...

    I have not always had easy access to news posting, so I'll be the happier this can go through without all the PEP overhead, otherwise, I'll try to follow up the PEP.

    I'm submitting this as a PEP in the same time, to the Director of PEP Affairs, as indicated in the PEP meta PEP-000 (barry), with a reference to this patch (file attached).

    Frederic Giacometti

    ---------------------------

    PEP XXX: Additions to the C API

    fred@arakne.com (Frederic Giacometti)

    Abstract

    This PEP defines a couple of C functions.

    The first two functions are for raising exceptions with multiple arguments; the third one is for calling a method when an arg tuple is given; and the other ones programmatically define sys.path and the optimization level in embedded python context, before initialization of the global Python engine.

    Copyright: This document is published under the Open Publication License.

    Specification:

    PyObject* PyErr_RaiseArgs( PyObject* exctype, PyObject* args)

    Raise the exception created by applying args to exctype. This is equivalent to the Python expression raise apply( exctype, args). Always set the error state and return NULL.

    PyObject* PyErr_Raise( PyObject* exctype, char const* format, ...)

    This function is similar to PyErr_RaiseArgs(), but defines the arguments using the same convention as Py_BuildValue(). Always set the error state and return NULL.

    PyObject* PyObject_CallMethodArgs( PyObject* o,
                                   char const* method, PyObject* args)
      Call the method named 'method' with arguments given by the tuple args,
      using for args the same convention as PyObject_CallObject().
      This is the equivalent of the Python expression
      o.method( args).
      Note that special method names, such as __add__(),
      __getitem__(), and so on are not supported.  The specific
      abstract-object routines for these must be used.
    
    void Py_SetPythonPath( char const* path)

    This function should be called before Py_Initialize() is called for the first time, if it is called at all. It defines the PYTHONPATH value to be used by the interpreter. Calling Py_SetPythonPath() will override the PYTHONPATH value from the environment. The argument should be NULL, or point to a zero-terminated character string which will not change for the duration of the program's execution.

    char const* Py_GetPythonPath()

      If Py_SetPythonPath()
      was never called, getenv( "PYTHONPATH") is returned,
      otherwise the argument of Py_SetPythonPath() is returned.
      The returned string points into static storage.
    
    void Py_SetOptimizeLevel( int level)
      This function should be called before
      Py_Initialize()
      is called for the first time.
      Legal optimization levels are listed below.
      \begin{tableii}{c|l}{character}{Character}{Meaning}
        \lineii{0}{No optimization (use \code{.pyc} files by default)}
        \lineii{1}{Same as \code{python -O}}
        \lineii{2}{Same as \code{python -OO}}
      \end{tableii}
    
    int Py_GetOptimizeLevel()
      Return the interpreter optimization level.

    Reference Implementation:

    See attached patch (concatenation of 2 patch files).

    61337411-43fc-4a9c-b8d5-4060aede66d0 commented 23 years ago

    Logged In: YES user_id=21627

    It seems that your patch is somewhat confused: It contains fragments of the SetPythonPath code, but fails to include the implementation of PyErr_Raise[Args].

    I think the patch should also identify the places in the code that could make use of the offered simplifications (and change them to the new API), to get an impression of how general this API is. I'm +1 on the _Raise functions and -0 on the CallMethodArgs (why does it not support keyword arguments?).

    1d332e54-3b86-44a9-8fc6-e0c6e60d2a36 commented 23 years ago

    Logged In: YES user_id=93657

    1) Patch for PyErr_Raise:

    I manually edited the patch file, since I had the ImportNotFound changes with it.

    The entire patch is in cdiff file attached to http://sourceforge.net/tracker/?func=detail&atid=305470&aid=448488&group_id=5470

    Meanwhile, I'm pasting below the missing section.

    2) I'm going to make a quick search on the existing base for replacement opportunities.

    3) CallMethodArgs vs. CallMethodArgs with keywords:

    The main reason is that the implementation relies on the exsiting PyObject_CallObject function, with does not take keyword args... However, your remark is relevant, and two other functions would be needed to complete the call interface: PyObject_CallObjectWithKW and PyObject_CallMethodArgsWithKW... I'd say that use of keyword arg from the C API is unusual; since I've never needed them, I haven't implemented them...

    Index: Python/errors.c \=================================================================== RCS file: /cvs/python/Python/Python/errors.c,v retrieving revision 1.1.1.1 diff -c -r1.1.1.1 errors.c *** Python/errors.c 2001/05/27 15:36:36 1.1.1.1 --- Python/errors.c 2001/06/05 16:11:16


    * 514,519 ** --- 514,571 ---- }

    + PyObject PyErr_RaiseArgs( PyObject exctype, PyObject args) + { + PyObject exception; + exception = PyObject_CallObject( exctype, args); + if (! exception) return NULL; + PyErr_SetObject( exctype, exception); + return NULL; + } + + PyObject PyErr_Raise( PyObject exctype, char const format, ...) + { + PyObject args = NULL, *result = NULL; + va_list va; + + va_start( va, format); + args = format ? Py_VaBuildValue( (char)format, va) : PyTuple_New(0); + va_end(va); + + if (! args) goto Finally; + if (! PyTuple_Check( args)) { + PyObject newargs; + newargs = PyTuple_New( 1); + if (! newargs) goto Finally; + PyTuple_SET_ITEM( newargs, 0, args); + args = newargs; + } + + result = PyErr_RaiseArgs( exctype, args); + Finally: + Py_XDECREF(args); + return result; + } +

    PyObject * PyErr_NewException(char *name, PyObject *base, PyObject *dict) {

    1d332e54-3b86-44a9-8fc6-e0c6e60d2a36 commented 23 years ago

    Logged In: YES user_id=93657

    A) Direct code replacement. Here is a non-exhaustive list of occurences:

    pythonrun.c-2.1:1242
        w = Py_BuildValue("(sO)", msg, v);
        Py_XDECREF(v);
        PyErr_SetObject(errtype, w);
        Py_XDECREF(w);
    --> PyErr_Raise( errtype, "sO", msg, v); Py_XDECREF( v);
    
    errors.c:towards 303 and 350:
        if (filename != NULL)
            v = Py_BuildValue("(iss)", err, s, filename);
        else
            v = Py_BuildValue("(is)", err, s);
        if (v != NULL) {
            PyErr_SetObject(PyExc_WindowsError, v);
            Py_DECREF(v);
    --> if (filename) PyErr_Raise( Pyexc_WindowsError, "iss", err, s, filename) else PyErr_Raise( ..., "is", err, s);
    
    compile.c: 421
        w = Py_BuildValue("(OO)", v, t);
        if (w == NULL)
            goto exit;
        PyErr_SetObject(exc, w);
    --> PyErr_Raise( exc, "OO", v, t)
    
    Modules/socketmodules.c:361
                v = Py_BuildValue("(is)", myerrorcode, outbuf);
                if (v != NULL) {
                    PyErr_SetObject(PySocket_Error, v);
                    Py_DECREF(v);
                }
                return NULL;
    --> return PyErr_Raise( PySocketError, "is", myerrorcode, outbuf);
    
    posixmodule.c:441
        v = Py_BuildValue("(is)", code, text);
        if (v != NULL) {
            PyErr_SetObject(PyExc_OSError, v);
            Py_DECREF(v);
        }
        return NULL; /* Signal to Python that an Exception is Pending */
    --> return PyErr_Raise( PyExc_OSError, "is", code, text);

    .....

    B) Other use of PyErr_Raise* in the current code base: ----------------------------------------------

    As of today, there are 3 functions for raising a new exception:

    PyErr_Raise( exctype, "O", obj) would replace PyErr_SetObject( exctype, obj) PyErr_Raise( exctype, "s", msg) would replace PyErr_SetString( exctype, msg)

    PyErr_SetObject and PyErr_SetString could then both be deprecated, in cases the arg is not already an instance of the exception... Here is some explaination:

    Historically, Python was first working with string exceptions, only. Structured object-oriented exceptions were introduced only towards the 1.5 releases, I think (very approximately - I've only used python 1.5.1 or later...).

    It is not also also how the current API works with exception whose __init require more than two args, and process them. If you want to raise an exception with an __init that has to or more args, there is presently no clear way of doing it; this is where i created the PyErrRaise* functions. There is also the case where one would define an exception which does not accept a string object as \_init__ argument... PyErr_SetString would create problem there too.

    Furthermore, the exact semantics and workings of PyErr_Object are not clear, with regard to the type of the object passed (this is fine when the object is already an instance of the exception class, but when it is not an instance of the exception class, huum). Use of PyErr_Raise would clarify this...

    warsaw commented 23 years ago

    Logged In: YES user_id=12800

    It's not clear to me that adding a couple of C API functions requires a PEP. I'm assigning to Guido for BDFL pronouncement. Guido should probably also decide on the patches themselves.

    gvanrossum commented 23 years ago

    Logged In: YES user_id=6380

    Given Frederic's attitude elsewhere, I'm closing this; it's unlikely that we'll ever get a reasonable patch.

    1d332e54-3b86-44a9-8fc6-e0c6e60d2a36 commented 23 years ago

    Logged In: YES user_id=93657

    Too bad Guido gets personal here against me. This was certainly a very reasonable and pertinent patch, without anything in it than its intent.

    gvanrossum commented 23 years ago

    Logged In: YES user_id=6380

    Reopened - this patch looks chaotic, but I think all pieces are actually there.

    Feedback:

    General: it would have been better to submit separate patches for each feature. I also wish you would upload a fixed patch rather than include patches in comments.

    PyError_RaiseArgs - This doesn't differ enough from PyErr_SetObject, if it differs at all -- it just instantiates the exception earlier. I don't think that the PyErr_Raise API provides sufficient added benefits to warrant deprecating the old calls. Also, it's a *feature\ that the exception isn't instantiated right away -- this saves time when it is caught and thrown away in C code later, as often happens.

    PyError_Raise - this may be useful, we're just considering something like this.

    PyErr_SetPythonPath, Py_GetPythonPath - why can't you just use setenv()?

    Py_Set/GetOptimizeLevel - IMO these are not needed, you can just set the global variable Py_OptimizeFlag yourself.

    gvanrossum commented 23 years ago

    Logged In: YES user_id=6380

    lowering the priority -- Frederic hasn't replied in two weeks.

    gvanrossum commented 22 years ago

    Logged In: YES user_id=6380

    Closing now for lack of feedback to my latest round of comments. I really don't have time to clean this patch up myself.