Kaydet (Commit) 393661d1 authored tarafından Guido van Rossum's avatar Guido van Rossum

Add warning mode for classic division, almost exactly as specified in

PEP 238.  Changes:

- add a new flag variable Py_DivisionWarningFlag, declared in
  pydebug.h, defined in object.c, set in main.c, and used in
  {int,long,float,complex}object.c.  When this flag is set, the
  classic division operator issues a DeprecationWarning message.

- add a new API PyRun_SimpleStringFlags() to match
  PyRun_SimpleString().  The main() function calls this so that
  commands run with -c can also benefit from -Dnew.

- While I was at it, I changed the usage message in main() somewhat:
  alphabetized the options, split it in *four* parts to fit in under
  512 bytes (not that I still believe this is necessary -- doc strings
  elsewhere are much longer), and perhaps most visibly, don't display
  the full list of options on each command line error.  Instead, the
  full list is only displayed when -h is used, and otherwise a brief
  reminder of -h is displayed.  When -h is used, write to stdout so
  that you can do `python -h | more'.

Notes:

- I don't want to use the -W option to control whether the classic
  division warning is issued or not, because the machinery to decide
  whether to display the warning or not is very expensive (it involves
  calling into the warnings.py module).  You can use -Werror to turn
  the warnings into exceptions though.

- The -Dnew option doesn't select future division for all of the
  program -- only for the __main__ module.  I don't know if I'll ever
  change this -- it would require changes to the .pyc file magic
  number to do it right, and a more global notion of compiler flags.

- You can usefully combine -Dwarn and -Dnew: this gives the __main__
  module new division, and warns about classic division everywhere
  else.
üst 29d55a38
...@@ -15,6 +15,7 @@ extern DL_IMPORT(int) Py_FrozenFlag; ...@@ -15,6 +15,7 @@ extern DL_IMPORT(int) Py_FrozenFlag;
extern DL_IMPORT(int) Py_TabcheckFlag; extern DL_IMPORT(int) Py_TabcheckFlag;
extern DL_IMPORT(int) Py_UnicodeFlag; extern DL_IMPORT(int) Py_UnicodeFlag;
extern DL_IMPORT(int) Py_IgnoreEnvironmentFlag; extern DL_IMPORT(int) Py_IgnoreEnvironmentFlag;
extern DL_IMPORT(int) Py_DivisionWarningFlag;
/* this is a wrapper around getenv() that pays attention to /* this is a wrapper around getenv() that pays attention to
Py_IgnoreEnvironmentFlag. It should be used for getting variables like Py_IgnoreEnvironmentFlag. It should be used for getting variables like
......
...@@ -33,6 +33,7 @@ DL_IMPORT(int) PyRun_AnyFileFlags(FILE *, char *, PyCompilerFlags *); ...@@ -33,6 +33,7 @@ DL_IMPORT(int) PyRun_AnyFileFlags(FILE *, char *, PyCompilerFlags *);
DL_IMPORT(int) PyRun_AnyFileExFlags(FILE *, char *, int, PyCompilerFlags *); DL_IMPORT(int) PyRun_AnyFileExFlags(FILE *, char *, int, PyCompilerFlags *);
DL_IMPORT(int) PyRun_SimpleString(char *); DL_IMPORT(int) PyRun_SimpleString(char *);
DL_IMPORT(int) PyRun_SimpleStringFlags(char *, PyCompilerFlags *);
DL_IMPORT(int) PyRun_SimpleFile(FILE *, char *); DL_IMPORT(int) PyRun_SimpleFile(FILE *, char *);
DL_IMPORT(int) PyRun_SimpleFileEx(FILE *, char *, int); DL_IMPORT(int) PyRun_SimpleFileEx(FILE *, char *, int);
DL_IMPORT(int) PyRun_SimpleFileExFlags(FILE *, char *, int, PyCompilerFlags *); DL_IMPORT(int) PyRun_SimpleFileExFlags(FILE *, char *, int, PyCompilerFlags *);
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#include "Python.h" #include "Python.h"
#include "osdefs.h" #include "osdefs.h"
#include "compile.h" /* For CO_FUTURE_DIVISION */
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
#include <unistd.h> #include <unistd.h>
...@@ -28,7 +29,7 @@ static char **orig_argv; ...@@ -28,7 +29,7 @@ static char **orig_argv;
static int orig_argc; static int orig_argc;
/* command line options */ /* command line options */
#define BASE_OPTS "c:diOSEtuUvxXhVW:" #define BASE_OPTS "c:dD:EhiOStuUvVWxX:"
#ifndef RISCOS #ifndef RISCOS
#define PROGRAM_OPTS BASE_OPTS #define PROGRAM_OPTS BASE_OPTS
...@@ -45,30 +46,33 @@ static char *usage_line = ...@@ -45,30 +46,33 @@ static char *usage_line =
"usage: %s [option] ... [-c cmd | file | -] [arg] ...\n"; "usage: %s [option] ... [-c cmd | file | -] [arg] ...\n";
/* Long usage message, split into parts < 512 bytes */ /* Long usage message, split into parts < 512 bytes */
static char *usage_top = "\ static char *usage_1 = "\
Options and arguments (and corresponding environment variables):\n\ Options and arguments (and corresponding environment variables):\n\
-c cmd : program passed in as string (terminates option list)\n\
-d : debug output from parser (also PYTHONDEBUG=x)\n\ -d : debug output from parser (also PYTHONDEBUG=x)\n\
-D arg : division options: -Dold (default), -Dwarn, -Dnew\n\
-E : ignore environment variables (such as PYTHONPATH)\n\
-h : print this help message and exit\n\
";
static char *usage_2 = "\
-i : inspect interactively after running script, (also PYTHONINSPECT=x)\n\ -i : inspect interactively after running script, (also PYTHONINSPECT=x)\n\
and force prompts, even if stdin does not appear to be a terminal\n\ and force prompts, even if stdin does not appear to be a terminal\n\
-O : optimize generated bytecode (a tad; also PYTHONOPTIMIZE=x)\n\ -O : optimize generated bytecode (a tad; also PYTHONOPTIMIZE=x)\n\
-OO : remove doc-strings in addition to the -O optimizations\n\ -OO : remove doc-strings in addition to the -O optimizations\n\
-S : don't imply 'import site' on initialization\n\ -S : don't imply 'import site' on initialization\n\
-E : ignore environment variables (such as PYTHONPATH)\n\
-t : issue warnings about inconsistent tab usage (-tt: issue errors)\n\ -t : issue warnings about inconsistent tab usage (-tt: issue errors)\n\
";
static char *usage_mid = "\
-u : unbuffered binary stdout and stderr (also PYTHONUNBUFFERED=x)\n\ -u : unbuffered binary stdout and stderr (also PYTHONUNBUFFERED=x)\n\
";
static char *usage_3 = "\
-U : Unicode literals: treats '...' literals like u'...'\n\ -U : Unicode literals: treats '...' literals like u'...'\n\
-v : verbose (trace import statements) (also PYTHONVERBOSE=x)\n\ -v : verbose (trace import statements) (also PYTHONVERBOSE=x)\n\
-x : skip first line of source, allowing use of non-Unix forms of #!cmd\n\
-h : print this help message and exit\n\
-V : print the Python version number and exit\n\ -V : print the Python version number and exit\n\
-W arg : warning control (arg is action:message:category:module:lineno)\n\ -W arg : warning control (arg is action:message:category:module:lineno)\n\
-c cmd : program passed in as string (terminates option list)\n\ -x : skip first line of source, allowing use of non-Unix forms of #!cmd\n\
file : program read from script file\n\ file : program read from script file\n\
- : program read from stdin (default; interactive mode if a tty)\n\ - : program read from stdin (default; interactive mode if a tty)\n\
"; ";
static char *usage_bot = "\ static char *usage_4 = "\
arg ...: arguments passed to program in sys.argv[1:]\n\ arg ...: arguments passed to program in sys.argv[1:]\n\
Other environment variables:\n\ Other environment variables:\n\
PYTHONSTARTUP: file executed on interactive startup (no default)\n\ PYTHONSTARTUP: file executed on interactive startup (no default)\n\
...@@ -83,10 +87,17 @@ PYTHONCASEOK : ignore case in 'import' statements (Windows).\n\ ...@@ -83,10 +87,17 @@ PYTHONCASEOK : ignore case in 'import' statements (Windows).\n\
static void static void
usage(int exitcode, char* program) usage(int exitcode, char* program)
{ {
fprintf(stderr, usage_line, program); FILE *f = exitcode ? stderr : stdout;
fprintf(stderr, usage_top);
fprintf(stderr, usage_mid); fprintf(f, usage_line, program);
fprintf(stderr, usage_bot, DELIM, DELIM, PYTHONHOMEHELP); if (exitcode)
fprintf(f, "Try `python -h' for more information.\n");
else {
fprintf(f, usage_1);
fprintf(f, usage_2);
fprintf(f, usage_3);
fprintf(f, usage_4, DELIM, DELIM, PYTHONHOMEHELP);
}
exit(exitcode); exit(exitcode);
/*NOTREACHED*/ /*NOTREACHED*/
} }
...@@ -113,6 +124,8 @@ Py_Main(int argc, char **argv) ...@@ -113,6 +124,8 @@ Py_Main(int argc, char **argv)
int saw_unbuffered_flag = 0; int saw_unbuffered_flag = 0;
PyCompilerFlags cf; PyCompilerFlags cf;
cf.cf_flags = 0;
orig_argc = argc; /* For Py_GetArgcArgv() */ orig_argc = argc; /* For Py_GetArgcArgv() */
orig_argv = argv; orig_argv = argv;
...@@ -135,13 +148,33 @@ Py_Main(int argc, char **argv) ...@@ -135,13 +148,33 @@ Py_Main(int argc, char **argv)
strcat(command, "\n"); strcat(command, "\n");
break; break;
} }
switch (c) { switch (c) {
case 'd': case 'd':
Py_DebugFlag++; Py_DebugFlag++;
break; break;
case 'D':
if (strcmp(_PyOS_optarg, "old") == 0) {
Py_DivisionWarningFlag = 0;
break;
}
if (strcmp(_PyOS_optarg, "warn") == 0) {
Py_DivisionWarningFlag++;
break;
}
if (strcmp(_PyOS_optarg, "new") == 0) {
/* XXX This only affects __main__ */
cf.cf_flags |= CO_FUTURE_DIVISION;
break;
}
fprintf(stderr,
"-D option should be "
"`-Dold', `-Dwarn' or `-Dnew' only\n");
usage(2, argv[0]);
/* NOTREACHED */
case 'i': case 'i':
inspect++; inspect++;
saw_inspect_flag = 1; saw_inspect_flag = 1;
...@@ -290,8 +323,7 @@ Py_Main(int argc, char **argv) ...@@ -290,8 +323,7 @@ Py_Main(int argc, char **argv)
(command == NULL && filename == NULL && stdin_is_interactive)) (command == NULL && filename == NULL && stdin_is_interactive))
fprintf(stderr, "Python %s on %s\n%s\n", fprintf(stderr, "Python %s on %s\n%s\n",
Py_GetVersion(), Py_GetPlatform(), COPYRIGHT); Py_GetVersion(), Py_GetPlatform(), COPYRIGHT);
if (command != NULL) { if (command != NULL) {
/* Backup _PyOS_optind and force sys.argv[0] = '-c' */ /* Backup _PyOS_optind and force sys.argv[0] = '-c' */
_PyOS_optind--; _PyOS_optind--;
...@@ -310,10 +342,8 @@ Py_Main(int argc, char **argv) ...@@ -310,10 +342,8 @@ Py_Main(int argc, char **argv)
Py_DECREF(v); Py_DECREF(v);
} }
cf.cf_flags = 0;
if (command) { if (command) {
sts = PyRun_SimpleString(command) != 0; sts = PyRun_SimpleStringFlags(command, &cf) != 0;
free(command); free(command);
} }
else { else {
......
...@@ -372,6 +372,27 @@ complex_div(PyComplexObject *v, PyComplexObject *w) ...@@ -372,6 +372,27 @@ complex_div(PyComplexObject *v, PyComplexObject *w)
return PyComplex_FromCComplex(quot); return PyComplex_FromCComplex(quot);
} }
static PyObject *
complex_classic_div(PyComplexObject *v, PyComplexObject *w)
{
Py_complex quot;
if (Py_DivisionWarningFlag &&
PyErr_Warn(PyExc_DeprecationWarning,
"classic complex division") < 0)
return NULL;
PyFPE_START_PROTECT("complex_classic_div", return 0)
errno = 0;
quot = c_quot(v->cval,w->cval);
PyFPE_END_PROTECT(quot)
if (errno == EDOM) {
PyErr_SetString(PyExc_ZeroDivisionError, "complex division");
return NULL;
}
return PyComplex_FromCComplex(quot);
}
static PyObject * static PyObject *
complex_remainder(PyComplexObject *v, PyComplexObject *w) complex_remainder(PyComplexObject *v, PyComplexObject *w)
{ {
...@@ -854,7 +875,7 @@ static PyNumberMethods complex_as_number = { ...@@ -854,7 +875,7 @@ static PyNumberMethods complex_as_number = {
(binaryfunc)complex_add, /* nb_add */ (binaryfunc)complex_add, /* nb_add */
(binaryfunc)complex_sub, /* nb_subtract */ (binaryfunc)complex_sub, /* nb_subtract */
(binaryfunc)complex_mul, /* nb_multiply */ (binaryfunc)complex_mul, /* nb_multiply */
(binaryfunc)complex_div, /* nb_divide */ (binaryfunc)complex_classic_div, /* nb_divide */
(binaryfunc)complex_remainder, /* nb_remainder */ (binaryfunc)complex_remainder, /* nb_remainder */
(binaryfunc)complex_divmod, /* nb_divmod */ (binaryfunc)complex_divmod, /* nb_divmod */
(ternaryfunc)complex_pow, /* nb_power */ (ternaryfunc)complex_pow, /* nb_power */
......
...@@ -413,6 +413,25 @@ float_div(PyObject *v, PyObject *w) ...@@ -413,6 +413,25 @@ float_div(PyObject *v, PyObject *w)
return PyFloat_FromDouble(a); return PyFloat_FromDouble(a);
} }
static PyObject *
float_classic_div(PyObject *v, PyObject *w)
{
double a,b;
CONVERT_TO_DOUBLE(v, a);
CONVERT_TO_DOUBLE(w, b);
if (Py_DivisionWarningFlag &&
PyErr_Warn(PyExc_DeprecationWarning, "classic float division") < 0)
return NULL;
if (b == 0.0) {
PyErr_SetString(PyExc_ZeroDivisionError, "float division");
return NULL;
}
PyFPE_START_PROTECT("divide", return 0)
a = a / b;
PyFPE_END_PROTECT(a)
return PyFloat_FromDouble(a);
}
static PyObject * static PyObject *
float_rem(PyObject *v, PyObject *w) float_rem(PyObject *v, PyObject *w)
{ {
...@@ -677,7 +696,7 @@ static PyNumberMethods float_as_number = { ...@@ -677,7 +696,7 @@ static PyNumberMethods float_as_number = {
(binaryfunc)float_add, /*nb_add*/ (binaryfunc)float_add, /*nb_add*/
(binaryfunc)float_sub, /*nb_subtract*/ (binaryfunc)float_sub, /*nb_subtract*/
(binaryfunc)float_mul, /*nb_multiply*/ (binaryfunc)float_mul, /*nb_multiply*/
(binaryfunc)float_div, /*nb_divide*/ (binaryfunc)float_classic_div, /*nb_divide*/
(binaryfunc)float_rem, /*nb_remainder*/ (binaryfunc)float_rem, /*nb_remainder*/
(binaryfunc)float_divmod, /*nb_divmod*/ (binaryfunc)float_divmod, /*nb_divmod*/
(ternaryfunc)float_pow, /*nb_power*/ (ternaryfunc)float_pow, /*nb_power*/
......
...@@ -511,6 +511,27 @@ int_div(PyIntObject *x, PyIntObject *y) ...@@ -511,6 +511,27 @@ int_div(PyIntObject *x, PyIntObject *y)
} }
} }
static PyObject *
int_classic_div(PyIntObject *x, PyIntObject *y)
{
long xi, yi;
long d, m;
CONVERT_TO_LONG(x, xi);
CONVERT_TO_LONG(y, yi);
if (Py_DivisionWarningFlag &&
PyErr_Warn(PyExc_DeprecationWarning, "classic int division") < 0)
return NULL;
switch (i_divmod(xi, yi, &d, &m)) {
case DIVMOD_OK:
return PyInt_FromLong(d);
case DIVMOD_OVERFLOW:
return PyLong_Type.tp_as_number->nb_divide((PyObject *)x,
(PyObject *)y);
default:
return NULL;
}
}
static PyObject * static PyObject *
int_mod(PyIntObject *x, PyIntObject *y) int_mod(PyIntObject *x, PyIntObject *y)
{ {
...@@ -744,7 +765,7 @@ int_or(PyIntObject *v, PyIntObject *w) ...@@ -744,7 +765,7 @@ int_or(PyIntObject *v, PyIntObject *w)
static PyObject * static PyObject *
int_true_divide(PyObject *v, PyObject *w) int_true_divide(PyObject *v, PyObject *w)
{ {
return PyFloat_Type.tp_as_number->nb_divide(v, w); return PyFloat_Type.tp_as_number->nb_true_divide(v, w);
} }
static PyObject * static PyObject *
...@@ -855,7 +876,7 @@ static PyNumberMethods int_as_number = { ...@@ -855,7 +876,7 @@ static PyNumberMethods int_as_number = {
(binaryfunc)int_add, /*nb_add*/ (binaryfunc)int_add, /*nb_add*/
(binaryfunc)int_sub, /*nb_subtract*/ (binaryfunc)int_sub, /*nb_subtract*/
(binaryfunc)int_mul, /*nb_multiply*/ (binaryfunc)int_mul, /*nb_multiply*/
(binaryfunc)int_div, /*nb_divide*/ (binaryfunc)int_classic_div, /*nb_divide*/
(binaryfunc)int_mod, /*nb_remainder*/ (binaryfunc)int_mod, /*nb_remainder*/
(binaryfunc)int_divmod, /*nb_divmod*/ (binaryfunc)int_divmod, /*nb_divmod*/
(ternaryfunc)int_pow, /*nb_power*/ (ternaryfunc)int_pow, /*nb_power*/
......
...@@ -1508,6 +1508,26 @@ long_div(PyObject *v, PyObject *w) ...@@ -1508,6 +1508,26 @@ long_div(PyObject *v, PyObject *w)
return (PyObject *)div; return (PyObject *)div;
} }
static PyObject *
long_classic_div(PyObject *v, PyObject *w)
{
PyLongObject *a, *b, *div, *mod;
CONVERT_BINOP(v, w, &a, &b);
if (Py_DivisionWarningFlag &&
PyErr_Warn(PyExc_DeprecationWarning, "classic long division") < 0)
div = NULL;
else if (l_divmod(a, b, &div, &mod) < 0)
div = NULL;
else
Py_DECREF(mod);
Py_DECREF(a);
Py_DECREF(b);
return (PyObject *)div;
}
static PyObject * static PyObject *
long_mod(PyObject *v, PyObject *w) long_mod(PyObject *v, PyObject *w)
{ {
...@@ -2115,7 +2135,7 @@ static PyNumberMethods long_as_number = { ...@@ -2115,7 +2135,7 @@ static PyNumberMethods long_as_number = {
(binaryfunc) long_add, /*nb_add*/ (binaryfunc) long_add, /*nb_add*/
(binaryfunc) long_sub, /*nb_subtract*/ (binaryfunc) long_sub, /*nb_subtract*/
(binaryfunc) long_mul, /*nb_multiply*/ (binaryfunc) long_mul, /*nb_multiply*/
(binaryfunc) long_div, /*nb_divide*/ (binaryfunc) long_classic_div, /*nb_divide*/
(binaryfunc) long_mod, /*nb_remainder*/ (binaryfunc) long_mod, /*nb_remainder*/
(binaryfunc) long_divmod, /*nb_divmod*/ (binaryfunc) long_divmod, /*nb_divmod*/
(ternaryfunc) long_pow, /*nb_power*/ (ternaryfunc) long_pow, /*nb_power*/
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
DL_IMPORT(long) _Py_RefTotal; DL_IMPORT(long) _Py_RefTotal;
#endif #endif
DL_IMPORT(int) Py_DivisionWarningFlag;
/* Object allocation routines used by NEWOBJ and NEWVAROBJ macros. /* Object allocation routines used by NEWOBJ and NEWVAROBJ macros.
These are used by the individual routines for object creation. These are used by the individual routines for object creation.
Do not call them otherwise, they do not initialize the object! */ Do not call them otherwise, they do not initialize the object! */
......
...@@ -686,13 +686,19 @@ PyRun_SimpleFileExFlags(FILE *fp, char *filename, int closeit, ...@@ -686,13 +686,19 @@ PyRun_SimpleFileExFlags(FILE *fp, char *filename, int closeit,
int int
PyRun_SimpleString(char *command) PyRun_SimpleString(char *command)
{
return PyRun_SimpleStringFlags(command, NULL);
}
int
PyRun_SimpleStringFlags(char *command, PyCompilerFlags *flags)
{ {
PyObject *m, *d, *v; PyObject *m, *d, *v;
m = PyImport_AddModule("__main__"); m = PyImport_AddModule("__main__");
if (m == NULL) if (m == NULL)
return -1; return -1;
d = PyModule_GetDict(m); d = PyModule_GetDict(m);
v = PyRun_String(command, Py_file_input, d, d); v = PyRun_StringFlags(command, Py_file_input, d, d, flags);
if (v == NULL) { if (v == NULL) {
PyErr_Print(); PyErr_Print();
return -1; return -1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment