diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -292,7 +292,7 @@ in various ways. There is a separate er documentation. There is no C API for warning control. -.. c:function:: int PyErr_WarnExplicit(PyObject *category, const char *message, const char *filename, int lineno, const char *module, PyObject *registry) +.. c:function:: int PyErr_WarnExplicitObject(PyObject *category, PyObject *message, PyObject *filename, int lineno, PyObject *module, PyObject *registry) Issue a warning message with explicit control over all warning attributes. This is a straightforward wrapper around the Python function @@ -302,6 +302,15 @@ in various ways. There is a separate er *filename* is decoded from the filesystem encoding (:func:`sys.getfilesystemencoding`). + .. versionadded:: 3.3 + + +.. c:function:: int PyErr_WarnExplicit(PyObject *category, const char *message, const char *filename, int lineno, const char *module, PyObject *registry) + + Similar to :c:func:`PyErr_WarnExplicitObject` except that *message* and + *module* are UTF-8 encoded strings, and *filename* is decoded from the + filesystem encoding (:func:`sys.getfilesystemencoding`). + .. c:function:: int PyErr_WarnFormat(PyObject *category, Py_ssize_t stack_level, const char *format, ...) diff --git a/Include/pyerrors.h b/Include/pyerrors.h --- a/Include/pyerrors.h +++ b/Include/pyerrors.h @@ -266,6 +266,9 @@ PyAPI_FUNC(void) PyErr_SyntaxLocationEx( PyAPI_FUNC(PyObject *) PyErr_ProgramText( const char *filename, /* decoded from the filesystem encoding */ int lineno); +PyAPI_FUNC(PyObject *) PyErr_ProgramTextObject( + PyObject *filename, + int lineno); /* The following functions are used to create and modify unicode exceptions from C */ diff --git a/Include/warnings.h b/Include/warnings.h --- a/Include/warnings.h +++ b/Include/warnings.h @@ -17,6 +17,13 @@ PyAPI_FUNC(int) PyErr_WarnFormat( Py_ssize_t stack_level, const char *format, /* ASCII-encoded string */ ...); +PyAPI_FUNC(int) PyErr_WarnExplicitObject( + PyObject *category, + PyObject *message, + PyObject *filename, + int lineno, + PyObject *module, + PyObject *registry); PyAPI_FUNC(int) PyErr_WarnExplicit( PyObject *category, const char *message, /* UTF-8 encoded string */ @@ -25,6 +32,7 @@ PyAPI_FUNC(int) PyErr_WarnExplicit( const char *module, /* UTF-8 encoded string */ PyObject *registry); + /* DEPRECATED: Use PyErr_WarnEx() instead. */ #ifndef Py_LIMITED_API #define PyErr_Warn(category, msg) PyErr_WarnEx(category, msg, 1) diff --git a/Python/_warnings.c b/Python/_warnings.c --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -698,14 +698,14 @@ warnings_warn_explicit(PyObject *self, P /* Handle the warning. */ returned = warn_explicit(category, message, filename, lineno, module, - registry, source_line); + registry, source_line); Py_DECREF(source_list); return returned; } standard_call: return warn_explicit(category, message, filename, lineno, module, - registry, NULL); + registry, NULL); } @@ -777,11 +777,26 @@ PyErr_Warn(PyObject *category, char *tex /* Warning with explicit origin */ int +PyErr_WarnExplicitObject(PyObject *category, PyObject *message, + PyObject *filename, int lineno, + PyObject *module, PyObject *registry) +{ + PyObject *res; + if (category == NULL) + category = PyExc_RuntimeWarning; + res = warn_explicit(category, message, filename, lineno, + module, registry, NULL); + if (res == NULL) + return -1; + Py_DECREF(res); + return 0; +} + +int PyErr_WarnExplicit(PyObject *category, const char *text, const char *filename_str, int lineno, const char *module_str, PyObject *registry) { - PyObject *res; PyObject *message = PyUnicode_FromString(text); PyObject *filename = PyUnicode_DecodeFSDefault(filename_str); PyObject *module = NULL; @@ -795,14 +810,8 @@ PyErr_WarnExplicit(PyObject *category, c goto exit; } - if (category == NULL) - category = PyExc_RuntimeWarning; - res = warn_explicit(category, message, filename, lineno, module, registry, - NULL); - if (res == NULL) - goto exit; - Py_DECREF(res); - ret = 0; + ret = PyErr_WarnExplicitObject(category, message, filename, lineno, + module, registry); exit: Py_XDECREF(message); diff --git a/Python/compile.c b/Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -134,7 +134,7 @@ managed by compiler_enter_scope() and co */ struct compiler { - const char *c_filename; + PyObject *filename; struct symtable *c_st; PyFutureFeatures *c_future; /* pointer to module's __future__ */ PyCompilerFlags *c_flags; @@ -271,7 +271,9 @@ PyAST_CompileEx(mod_ty mod, const char * if (!compiler_init(&c)) return NULL; - c.c_filename = filename; + c.filename = PyUnicode_DecodeFSDefault(filename); + if (c.filename == NULL) + goto finally; c.c_arena = arena; c.c_future = PyFuture_FromAST(mod, filename); if (c.c_future == NULL) @@ -325,6 +327,7 @@ compiler_free(struct compiler *c) if (c->c_future) PyObject_Free(c->c_future); Py_DECREF(c->c_stack); + Py_XDECREF(c->filename); } static PyObject * @@ -1220,12 +1223,11 @@ get_ref_type(struct compiler *c, PyObjec if (scope == 0) { char buf[350]; PyOS_snprintf(buf, sizeof(buf), - "unknown scope for %.100s in %.100s(%s) in %s\n" + "unknown scope for %.100s in %.100s(%s)\n" "symbols: %s\nlocals: %s\nglobals: %s", PyBytes_AS_STRING(name), PyBytes_AS_STRING(c->u->u_name), PyObject_REPR(c->u->u_ste->ste_id), - c->c_filename, PyObject_REPR(c->u->u_ste->ste_symbols), PyObject_REPR(c->u->u_varnames), PyObject_REPR(c->u->u_names) @@ -2212,6 +2214,7 @@ compiler_assert(struct compiler *c, stmt { static PyObject *assertion_error = NULL; basicblock *end; + PyObject* msg; if (c->c_optimize) return 1; @@ -2222,11 +2225,17 @@ compiler_assert(struct compiler *c, stmt } if (s->v.Assert.test->kind == Tuple_kind && asdl_seq_LEN(s->v.Assert.test->v.Tuple.elts) > 0) { - const char* msg = - "assertion is always true, perhaps remove parentheses?"; - if (PyErr_WarnExplicit(PyExc_SyntaxWarning, msg, c->c_filename, - c->u->u_lineno, NULL, NULL) == -1) + msg = PyUnicode_FromString("assertion is always true, " + "perhaps remove parentheses?"); + if (msg == NULL) return 0; + if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg, + c->filename, c->u->u_lineno, + NULL, NULL) == -1) { + Py_DECREF(msg); + return 0; + } + Py_DECREF(msg); } VISIT(c, expr, s->v.Assert.test); end = compiler_new_block(c); @@ -3361,24 +3370,15 @@ compiler_in_loop(struct compiler *c) { static int compiler_error(struct compiler *c, const char *errstr) { - PyObject *loc, *filename; + PyObject *loc; PyObject *u = NULL, *v = NULL; - loc = PyErr_ProgramText(c->c_filename, c->u->u_lineno); + loc = PyErr_ProgramTextObject(c->filename, c->u->u_lineno); if (!loc) { Py_INCREF(Py_None); loc = Py_None; } - if (c->c_filename != NULL) { - filename = PyUnicode_DecodeFSDefault(c->c_filename); - if (!filename) - goto exit; - } - else { - Py_INCREF(Py_None); - filename = Py_None; - } - u = Py_BuildValue("(NiiO)", filename, c->u->u_lineno, + u = Py_BuildValue("(OiiO)", c->filename, c->u->u_lineno, c->u->u_col_offset, loc); if (!u) goto exit; @@ -3927,7 +3927,6 @@ makecode(struct compiler *c, struct asse PyObject *consts = NULL; PyObject *names = NULL; PyObject *varnames = NULL; - PyObject *filename = NULL; PyObject *name = NULL; PyObject *freevars = NULL; PyObject *cellvars = NULL; @@ -3951,9 +3950,6 @@ makecode(struct compiler *c, struct asse freevars = dict_keys_inorder(c->u->u_freevars, PyTuple_Size(cellvars)); if (!freevars) goto error; - filename = PyUnicode_DecodeFSDefault(c->c_filename); - if (!filename) - goto error; nlocals = PyDict_Size(c->u->u_varnames); flags = compute_code_flags(c); @@ -3974,14 +3970,13 @@ makecode(struct compiler *c, struct asse nlocals, stackdepth(c), flags, bytecode, consts, names, varnames, freevars, cellvars, - filename, c->u->u_name, + c->filename, c->u->u_name, c->u->u_firstlineno, a->a_lnotab); error: Py_XDECREF(consts); Py_XDECREF(names); Py_XDECREF(varnames); - Py_XDECREF(filename); Py_XDECREF(name); Py_XDECREF(freevars); Py_XDECREF(cellvars); diff --git a/Python/errors.c b/Python/errors.c --- a/Python/errors.c +++ b/Python/errors.c @@ -845,15 +845,11 @@ PyErr_SyntaxLocationEx(const char *filen functionality in tb_displayline() in traceback.c. */ PyObject * -PyErr_ProgramText(const char *filename, int lineno) +err_programtext(FILE *fp, int lineno) { - FILE *fp; int i; char linebuf[1000]; - if (filename == NULL || *filename == '\0' || lineno <= 0) - return NULL; - fp = fopen(filename, "r" PY_STDIOTEXTMODE); if (fp == NULL) return NULL; for (i = 0; i < lineno; i++) { @@ -884,6 +880,26 @@ PyErr_ProgramText(const char *filename, return NULL; } +PyObject * +PyErr_ProgramText(const char *filename, int lineno) +{ + FILE *fp; + if (filename == NULL || *filename == '\0' || lineno <= 0) + return NULL; + fp = fopen(filename, "r" PY_STDIOTEXTMODE); + return err_programtext(fp, lineno); +} + +PyObject * +PyErr_ProgramTextObject(PyObject *filename, int lineno) +{ + FILE *fp; + if (filename == NULL || lineno <= 0) + return NULL; + fp = _Py_fopen(filename, "r" PY_STDIOTEXTMODE); + return err_programtext(fp, lineno); +} + #ifdef __cplusplus } #endif