From python-checkins at python.org Sun Jul 1 00:40:47 2012 From: python-checkins at python.org (matthias.klose) Date: Sun, 01 Jul 2012 00:40:47 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_-_Issue_=2314330=3A_Don=27t?= =?utf8?q?_derive_the_include_and_library_search_dirs?= Message-ID: http://hg.python.org/cpython/rev/7955d769fdf5 changeset: 77895:7955d769fdf5 parent: 77893:900cf4e7a62f user: doko at ubuntu.com date: Sun Jul 01 00:23:51 2012 +0200 summary: - Issue #14330: Don't derive the include and library search dirs from GCC for native builds files: Modules/_ctypes/libffi/aclocal.m4 | 10 +- Modules/_ctypes/libffi/configure | 305 +++++++++-------- setup.py | 16 +- 3 files changed, 167 insertions(+), 164 deletions(-) diff --git a/Modules/_ctypes/libffi/aclocal.m4 b/Modules/_ctypes/libffi/aclocal.m4 --- a/Modules/_ctypes/libffi/aclocal.m4 +++ b/Modules/_ctypes/libffi/aclocal.m4 @@ -1,4 +1,4 @@ -# generated automatically by aclocal 1.11.3 -*- Autoconf -*- +# generated automatically by aclocal 1.11.5 -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, @@ -14,8 +14,8 @@ m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.68],, -[m4_warning([this file was generated for autoconf 2.68. +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, +[m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically `autoreconf'.])]) @@ -38,7 +38,7 @@ [am__api_version='1.11' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.11.3], [], +m4_if([$1], [1.11.5], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) @@ -54,7 +54,7 @@ # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.11.3])dnl +[AM_AUTOMAKE_VERSION([1.11.5])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) diff --git a/Modules/_ctypes/libffi/configure b/Modules/_ctypes/libffi/configure --- a/Modules/_ctypes/libffi/configure +++ b/Modules/_ctypes/libffi/configure @@ -1,13 +1,11 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.68 for libffi 3.0.11. +# Generated by GNU Autoconf 2.69 for libffi 3.0.11. # # Report bugs to . # # -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, -# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software -# Foundation, Inc. +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation @@ -136,6 +134,31 @@ # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh @@ -169,7 +192,8 @@ else exitcode=1; echo positional parameters were not saved. fi -test x\$exitcode = x0 || exit 1" +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && @@ -222,21 +246,25 @@ if test "x$CONFIG_SHELL" != x; then : - # We cannot yet assume a decent shell, so we have to provide a - # neutralization value for shells without unset; and this also - # works around shells that cannot unset nonexistent variables. - # Preserve -v and -x to the replacement shell. - BASH_ENV=/dev/null - ENV=/dev/null - (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV - export CONFIG_SHELL - case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; - esac - exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 fi if test x$as_have_required = xno; then : @@ -339,6 +367,14 @@ } # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take @@ -460,6 +496,10 @@ chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). @@ -494,16 +534,16 @@ # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -p'. + # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -p' + as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else - as_ln_s='cp -p' - fi -else - as_ln_s='cp -p' + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null @@ -515,28 +555,8 @@ as_mkdir_p=false fi -if test -x / >/dev/null 2>&1; then - as_test_x='test -x' -else - if ls -dL / >/dev/null 2>&1; then - as_ls_L_option=L - else - as_ls_L_option= - fi - as_test_x=' - eval sh -c '\'' - if test -d "$1"; then - test -d "$1/."; - else - case $1 in #( - -*)set "./$1";; - esac; - case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( - ???[sx]*):;;*)false;;esac;fi - '\'' sh - ' -fi -as_executable_p=$as_test_x +as_test_x='test -x' +as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" @@ -1288,8 +1308,6 @@ if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe - $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. - If a cross compiler is detected then cross compile mode will be used" >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi @@ -1563,9 +1581,9 @@ if $ac_init_version; then cat <<\_ACEOF libffi configure 3.0.11 -generated by GNU Autoconf 2.68 - -Copyright (C) 2010 Free Software Foundation, Inc. +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1641,7 +1659,7 @@ test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext + test -x conftest$ac_exeext }; then : ac_retval=0 else @@ -1999,7 +2017,8 @@ main () { static int test_array [1 - 2 * !(($2) >= 0)]; -test_array [0] = 0 +test_array [0] = 0; +return test_array [0]; ; return 0; @@ -2015,7 +2034,8 @@ main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; -test_array [0] = 0 +test_array [0] = 0; +return test_array [0]; ; return 0; @@ -2041,7 +2061,8 @@ main () { static int test_array [1 - 2 * !(($2) < 0)]; -test_array [0] = 0 +test_array [0] = 0; +return test_array [0]; ; return 0; @@ -2057,7 +2078,8 @@ main () { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; -test_array [0] = 0 +test_array [0] = 0; +return test_array [0]; ; return 0; @@ -2091,7 +2113,8 @@ main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; -test_array [0] = 0 +test_array [0] = 0; +return test_array [0]; ; return 0; @@ -2164,7 +2187,7 @@ running configure, to aid debugging if configure makes a mistake. It was created by libffi $as_me 3.0.11, which was -generated by GNU Autoconf 2.68. Invocation command line was +generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2735,7 +2758,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ax_enable_builddir_sed="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -2801,7 +2824,7 @@ # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. @@ -2967,7 +2990,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3007,7 +3030,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3058,7 +3081,7 @@ test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do - { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue + as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ @@ -3111,7 +3134,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3270,7 +3293,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3310,7 +3333,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3363,7 +3386,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3404,7 +3427,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue @@ -3462,7 +3485,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3506,7 +3529,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3952,8 +3975,7 @@ /* end confdefs.h. */ #include #include -#include -#include +struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); @@ -4610,7 +4632,7 @@ for ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue + as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in @@ -4686,7 +4708,7 @@ for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue + as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in @@ -4752,7 +4774,7 @@ for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue + as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in @@ -4819,7 +4841,7 @@ for ac_prog in fgrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue + as_fn_executable_p "$ac_path_FGREP" || continue # Check for GNU ac_path_FGREP and select it if it is found. # Check for GNU $ac_path_FGREP case `"$ac_path_FGREP" --version 2>&1` in @@ -5075,7 +5097,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -5119,7 +5141,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -5543,7 +5565,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -5583,7 +5605,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OBJDUMP="objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -5889,7 +5911,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -5929,7 +5951,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DLLTOOL="dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -6033,7 +6055,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -6077,7 +6099,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -6202,7 +6224,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -6242,7 +6264,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -6301,7 +6323,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -6341,7 +6363,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -6990,7 +7012,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -7030,7 +7052,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -7110,7 +7132,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -7150,7 +7172,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -7202,7 +7224,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -7242,7 +7264,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_NMEDIT="nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -7294,7 +7316,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LIPO="${ac_tool_prefix}lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -7334,7 +7356,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_LIPO="lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -7386,7 +7408,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL="${ac_tool_prefix}otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -7426,7 +7448,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL="otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -7478,7 +7500,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -7518,7 +7540,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL64="otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -12554,7 +12576,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PRTDIAG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -13594,23 +13616,20 @@ /* end confdefs.h. */ $ac_includes_default int -find_stack_direction () -{ - static char *addr = 0; - auto char dummy; - if (addr == 0) - { - addr = &dummy; - return find_stack_direction (); - } - else - return (&dummy > addr) ? 1 : -1; +find_stack_direction (int *addr, int depth) +{ + int dir, dummy = 0; + if (! addr) + addr = &dummy; + *addr = addr < &dummy ? 1 : addr == &dummy ? 0 : -1; + dir = depth ? find_stack_direction (addr, depth - 1) : 0; + return dir + dummy; } int -main () -{ - return find_stack_direction () < 0; +main (int argc, char **argv) +{ + return find_stack_direction (0, argc + !argv + 20) < 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : @@ -14915,16 +14934,16 @@ # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -p'. + # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -p' + as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else - as_ln_s='cp -p' - fi -else - as_ln_s='cp -p' + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null @@ -14984,28 +15003,16 @@ as_mkdir_p=false fi -if test -x / >/dev/null 2>&1; then - as_test_x='test -x' -else - if ls -dL / >/dev/null 2>&1; then - as_ls_L_option=L - else - as_ls_L_option= - fi - as_test_x=' - eval sh -c '\'' - if test -d "$1"; then - test -d "$1/."; - else - case $1 in #( - -*)set "./$1";; - esac; - case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( - ???[sx]*):;;*)false;;esac;fi - '\'' sh - ' -fi -as_executable_p=$as_test_x + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" @@ -15027,7 +15034,7 @@ # values after options handling. ac_log=" This file was extended by libffi $as_me 3.0.11, which was -generated by GNU Autoconf 2.68. Invocation command line was +generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -15097,10 +15104,10 @@ ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ libffi config.status 3.0.11 -configured by $0, generated by GNU Autoconf 2.68, +configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" -Copyright (C) 2010 Free Software Foundation, Inc. +Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -15191,7 +15198,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then - set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -438,7 +438,9 @@ if not cross_compiling: add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib') add_dir_to_list(self.compiler.include_dirs, '/usr/local/include') - self.add_gcc_paths() + # only change this for cross builds for 3.3, issues on Mageia + if cross_compiling: + self.add_gcc_paths() self.add_multiarch_paths() # Add paths specified in the environment variables LDFLAGS and @@ -489,18 +491,12 @@ # lib_dirs and inc_dirs are used to search for files; # if a file is found in one of those directories, it can # be assumed that no additional -I,-L directives are needed. - inc_dirs = self.compiler.include_dirs[:] - lib_dirs = self.compiler.library_dirs[:] if not cross_compiling: - for d in ( - '/usr/include', - ): - add_dir_to_list(inc_dirs, d) - for d in ( + lib_dirs = self.compiler.library_dirs + [ '/lib64', '/usr/lib64', '/lib', '/usr/lib', - ): - add_dir_to_list(lib_dirs, d) + ] + inc_dirs = self.compiler.include_dirs + ['/usr/include'] exts = [] missing = [] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 1 00:40:47 2012 From: python-checkins at python.org (matthias.klose) Date: Sun, 01 Jul 2012 00:40:47 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_-_Issue_=2315194=3A_check_i?= =?utf8?q?n_the_missing_m4/ax=5Fcheck=5Fcompile=5Fflag=2Em4_file=2E?= Message-ID: http://hg.python.org/cpython/rev/989efaab9525 changeset: 77896:989efaab9525 user: doko at ubuntu.com date: Sun Jul 01 00:37:47 2012 +0200 summary: - Issue #15194: check in the missing m4/ax_check_compile_flag.m4 file. Regenerate aclocalm4 and configure. files: Modules/_ctypes/libffi/aclocal.m4 | 829 +++++++++- Modules/_ctypes/libffi/configure | 627 +++++-- Modules/_ctypes/libffi/m4/ax_check_compile_flag.m4 | 72 + 3 files changed, 1351 insertions(+), 177 deletions(-) diff --git a/Modules/_ctypes/libffi/aclocal.m4 b/Modules/_ctypes/libffi/aclocal.m4 --- a/Modules/_ctypes/libffi/aclocal.m4 +++ b/Modules/_ctypes/libffi/aclocal.m4 @@ -1,4 +1,4 @@ -# generated automatically by aclocal 1.11.5 -*- Autoconf -*- +# generated automatically by aclocal 1.11.3 -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, @@ -14,12 +14,830 @@ m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, -[m4_warning([this file was generated for autoconf 2.69. +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.68],, +[m4_warning([this file was generated for autoconf 2.68. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically `autoreconf'.])]) +# ltdl.m4 - Configure ltdl for the target system. -*-Autoconf-*- +# +# Copyright (C) 1999-2006, 2007, 2008, 2011 Free Software Foundation, Inc. +# Written by Thomas Tanner, 1999 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 18 LTDL_INIT + +# LT_CONFIG_LTDL_DIR(DIRECTORY, [LTDL-MODE]) +# ------------------------------------------ +# DIRECTORY contains the libltdl sources. It is okay to call this +# function multiple times, as long as the same DIRECTORY is always given. +AC_DEFUN([LT_CONFIG_LTDL_DIR], +[AC_BEFORE([$0], [LTDL_INIT]) +_$0($*) +])# LT_CONFIG_LTDL_DIR + +# We break this out into a separate macro, so that we can call it safely +# internally without being caught accidentally by the sed scan in libtoolize. +m4_defun([_LT_CONFIG_LTDL_DIR], +[dnl remove trailing slashes +m4_pushdef([_ARG_DIR], m4_bpatsubst([$1], [/*$])) +m4_case(_LTDL_DIR, + [], [dnl only set lt_ltdl_dir if _ARG_DIR is not simply `.' + m4_if(_ARG_DIR, [.], + [], + [m4_define([_LTDL_DIR], _ARG_DIR) + _LT_SHELL_INIT([lt_ltdl_dir=']_ARG_DIR['])])], + [m4_if(_ARG_DIR, _LTDL_DIR, + [], + [m4_fatal([multiple libltdl directories: `]_LTDL_DIR[', `]_ARG_DIR['])])]) +m4_popdef([_ARG_DIR]) +])# _LT_CONFIG_LTDL_DIR + +# Initialise: +m4_define([_LTDL_DIR], []) + + +# _LT_BUILD_PREFIX +# ---------------- +# If Autoconf is new enough, expand to `${top_build_prefix}', otherwise +# to `${top_builddir}/'. +m4_define([_LT_BUILD_PREFIX], +[m4_ifdef([AC_AUTOCONF_VERSION], + [m4_if(m4_version_compare(m4_defn([AC_AUTOCONF_VERSION]), [2.62]), + [-1], [m4_ifdef([_AC_HAVE_TOP_BUILD_PREFIX], + [${top_build_prefix}], + [${top_builddir}/])], + [${top_build_prefix}])], + [${top_builddir}/])[]dnl +]) + + +# LTDL_CONVENIENCE +# ---------------- +# sets LIBLTDL to the link flags for the libltdl convenience library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-convenience to the configure arguments. Note that +# AC_CONFIG_SUBDIRS is not called here. LIBLTDL will be prefixed with +# '${top_build_prefix}' if available, otherwise with '${top_builddir}/', +# and LTDLINCL will be prefixed with '${top_srcdir}/' (note the single +# quotes!). If your package is not flat and you're not using automake, +# define top_build_prefix, top_builddir, and top_srcdir appropriately +# in your Makefiles. +AC_DEFUN([LTDL_CONVENIENCE], +[AC_BEFORE([$0], [LTDL_INIT])dnl +dnl Although the argument is deprecated and no longer documented, +dnl LTDL_CONVENIENCE used to take a DIRECTORY orgument, if we have one +dnl here make sure it is the same as any other declaration of libltdl's +dnl location! This also ensures lt_ltdl_dir is set when configure.ac is +dnl not yet using an explicit LT_CONFIG_LTDL_DIR. +m4_ifval([$1], [_LT_CONFIG_LTDL_DIR([$1])])dnl +_$0() +])# LTDL_CONVENIENCE + +# AC_LIBLTDL_CONVENIENCE accepted a directory argument in older libtools, +# now we have LT_CONFIG_LTDL_DIR: +AU_DEFUN([AC_LIBLTDL_CONVENIENCE], +[_LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) +_LTDL_CONVENIENCE]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBLTDL_CONVENIENCE], []) + + +# _LTDL_CONVENIENCE +# ----------------- +# Code shared by LTDL_CONVENIENCE and LTDL_INIT([convenience]). +m4_defun([_LTDL_CONVENIENCE], +[case $enable_ltdl_convenience in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; +esac +LIBLTDL='_LT_BUILD_PREFIX'"${lt_ltdl_dir+$lt_ltdl_dir/}libltdlc.la" +LTDLDEPS=$LIBLTDL +LTDLINCL='-I${top_srcdir}'"${lt_ltdl_dir+/$lt_ltdl_dir}" + +AC_SUBST([LIBLTDL]) +AC_SUBST([LTDLDEPS]) +AC_SUBST([LTDLINCL]) + +# For backwards non-gettext consistent compatibility... +INCLTDL="$LTDLINCL" +AC_SUBST([INCLTDL]) +])# _LTDL_CONVENIENCE + + +# LTDL_INSTALLABLE +# ---------------- +# sets LIBLTDL to the link flags for the libltdl installable library +# and LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-install to the configure arguments. Note that +# AC_CONFIG_SUBDIRS is not called from here. If an installed libltdl +# is not found, LIBLTDL will be prefixed with '${top_build_prefix}' if +# available, otherwise with '${top_builddir}/', and LTDLINCL will be +# prefixed with '${top_srcdir}/' (note the single quotes!). If your +# package is not flat and you're not using automake, define top_build_prefix, +# top_builddir, and top_srcdir appropriately in your Makefiles. +# In the future, this macro may have to be called after LT_INIT. +AC_DEFUN([LTDL_INSTALLABLE], +[AC_BEFORE([$0], [LTDL_INIT])dnl +dnl Although the argument is deprecated and no longer documented, +dnl LTDL_INSTALLABLE used to take a DIRECTORY orgument, if we have one +dnl here make sure it is the same as any other declaration of libltdl's +dnl location! This also ensures lt_ltdl_dir is set when configure.ac is +dnl not yet using an explicit LT_CONFIG_LTDL_DIR. +m4_ifval([$1], [_LT_CONFIG_LTDL_DIR([$1])])dnl +_$0() +])# LTDL_INSTALLABLE + +# AC_LIBLTDL_INSTALLABLE accepted a directory argument in older libtools, +# now we have LT_CONFIG_LTDL_DIR: +AU_DEFUN([AC_LIBLTDL_INSTALLABLE], +[_LT_CONFIG_LTDL_DIR([m4_default([$1], [libltdl])]) +_LTDL_INSTALLABLE]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBLTDL_INSTALLABLE], []) + + +# _LTDL_INSTALLABLE +# ----------------- +# Code shared by LTDL_INSTALLABLE and LTDL_INIT([installable]). +m4_defun([_LTDL_INSTALLABLE], +[if test -f $prefix/lib/libltdl.la; then + lt_save_LDFLAGS="$LDFLAGS" + LDFLAGS="-L$prefix/lib $LDFLAGS" + AC_CHECK_LIB([ltdl], [lt_dlinit], [lt_lib_ltdl=yes]) + LDFLAGS="$lt_save_LDFLAGS" + if test x"${lt_lib_ltdl-no}" = xyes; then + if test x"$enable_ltdl_install" != xyes; then + # Don't overwrite $prefix/lib/libltdl.la without --enable-ltdl-install + AC_MSG_WARN([not overwriting libltdl at $prefix, force with `--enable-ltdl-install']) + enable_ltdl_install=no + fi + elif test x"$enable_ltdl_install" = xno; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + fi +fi + +# If configure.ac declared an installable ltdl, and the user didn't override +# with --disable-ltdl-install, we will install the shipped libltdl. +case $enable_ltdl_install in + no) ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL="-lltdl" + LTDLDEPS= + LTDLINCL= + ;; + *) enable_ltdl_install=yes + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='_LT_BUILD_PREFIX'"${lt_ltdl_dir+$lt_ltdl_dir/}libltdl.la" + LTDLDEPS=$LIBLTDL + LTDLINCL='-I${top_srcdir}'"${lt_ltdl_dir+/$lt_ltdl_dir}" + ;; +esac + +AC_SUBST([LIBLTDL]) +AC_SUBST([LTDLDEPS]) +AC_SUBST([LTDLINCL]) + +# For backwards non-gettext consistent compatibility... +INCLTDL="$LTDLINCL" +AC_SUBST([INCLTDL]) +])# LTDL_INSTALLABLE + + +# _LTDL_MODE_DISPATCH +# ------------------- +m4_define([_LTDL_MODE_DISPATCH], +[dnl If _LTDL_DIR is `.', then we are configuring libltdl itself: +m4_if(_LTDL_DIR, [], + [], + dnl if _LTDL_MODE was not set already, the default value is `subproject': + [m4_case(m4_default(_LTDL_MODE, [subproject]), + [subproject], [AC_CONFIG_SUBDIRS(_LTDL_DIR) + _LT_SHELL_INIT([lt_dlopen_dir="$lt_ltdl_dir"])], + [nonrecursive], [_LT_SHELL_INIT([lt_dlopen_dir="$lt_ltdl_dir"; lt_libobj_prefix="$lt_ltdl_dir/"])], + [recursive], [], + [m4_fatal([unknown libltdl mode: ]_LTDL_MODE)])])dnl +dnl Be careful not to expand twice: +m4_define([$0], []) +])# _LTDL_MODE_DISPATCH + + +# _LT_LIBOBJ(MODULE_NAME) +# ----------------------- +# Like AC_LIBOBJ, except that MODULE_NAME goes into _LT_LIBOBJS instead +# of into LIBOBJS. +AC_DEFUN([_LT_LIBOBJ], [ + m4_pattern_allow([^_LT_LIBOBJS$]) + _LT_LIBOBJS="$_LT_LIBOBJS $1.$ac_objext" +])# _LT_LIBOBJS + + +# LTDL_INIT([OPTIONS]) +# -------------------- +# Clients of libltdl can use this macro to allow the installer to +# choose between a shipped copy of the ltdl sources or a preinstalled +# version of the library. If the shipped ltdl sources are not in a +# subdirectory named libltdl, the directory name must be given by +# LT_CONFIG_LTDL_DIR. +AC_DEFUN([LTDL_INIT], +[dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +dnl We need to keep our own list of libobjs separate from our parent project, +dnl and the easiest way to do that is redefine the AC_LIBOBJs macro while +dnl we look for our own LIBOBJs. +m4_pushdef([AC_LIBOBJ], m4_defn([_LT_LIBOBJ])) +m4_pushdef([AC_LIBSOURCES]) + +dnl If not otherwise defined, default to the 1.5.x compatible subproject mode: +m4_if(_LTDL_MODE, [], + [m4_define([_LTDL_MODE], m4_default([$2], [subproject])) + m4_if([-1], [m4_bregexp(_LTDL_MODE, [\(subproject\|\(non\)?recursive\)])], + [m4_fatal([unknown libltdl mode: ]_LTDL_MODE)])]) + +AC_ARG_WITH([included_ltdl], + [AS_HELP_STRING([--with-included-ltdl], + [use the GNU ltdl sources included here])]) + +if test "x$with_included_ltdl" != xyes; then + # We are not being forced to use the included libltdl sources, so + # decide whether there is a useful installed version we can use. + AC_CHECK_HEADER([ltdl.h], + [AC_CHECK_DECL([lt_dlinterface_register], + [AC_CHECK_LIB([ltdl], [lt_dladvise_preload], + [with_included_ltdl=no], + [with_included_ltdl=yes])], + [with_included_ltdl=yes], + [AC_INCLUDES_DEFAULT + #include ])], + [with_included_ltdl=yes], + [AC_INCLUDES_DEFAULT] + ) +fi + +dnl If neither LT_CONFIG_LTDL_DIR, LTDL_CONVENIENCE nor LTDL_INSTALLABLE +dnl was called yet, then for old times' sake, we assume libltdl is in an +dnl eponymous directory: +AC_PROVIDE_IFELSE([LT_CONFIG_LTDL_DIR], [], [_LT_CONFIG_LTDL_DIR([libltdl])]) + +AC_ARG_WITH([ltdl_include], + [AS_HELP_STRING([--with-ltdl-include=DIR], + [use the ltdl headers installed in DIR])]) + +if test -n "$with_ltdl_include"; then + if test -f "$with_ltdl_include/ltdl.h"; then : + else + AC_MSG_ERROR([invalid ltdl include directory: `$with_ltdl_include']) + fi +else + with_ltdl_include=no +fi + +AC_ARG_WITH([ltdl_lib], + [AS_HELP_STRING([--with-ltdl-lib=DIR], + [use the libltdl.la installed in DIR])]) + +if test -n "$with_ltdl_lib"; then + if test -f "$with_ltdl_lib/libltdl.la"; then : + else + AC_MSG_ERROR([invalid ltdl library directory: `$with_ltdl_lib']) + fi +else + with_ltdl_lib=no +fi + +case ,$with_included_ltdl,$with_ltdl_include,$with_ltdl_lib, in + ,yes,no,no,) + m4_case(m4_default(_LTDL_TYPE, [convenience]), + [convenience], [_LTDL_CONVENIENCE], + [installable], [_LTDL_INSTALLABLE], + [m4_fatal([unknown libltdl build type: ]_LTDL_TYPE)]) + ;; + ,no,no,no,) + # If the included ltdl is not to be used, then use the + # preinstalled libltdl we found. + AC_DEFINE([HAVE_LTDL], [1], + [Define this if a modern libltdl is already installed]) + LIBLTDL=-lltdl + LTDLDEPS= + LTDLINCL= + ;; + ,no*,no,*) + AC_MSG_ERROR([`--with-ltdl-include' and `--with-ltdl-lib' options must be used together]) + ;; + *) with_included_ltdl=no + LIBLTDL="-L$with_ltdl_lib -lltdl" + LTDLDEPS= + LTDLINCL="-I$with_ltdl_include" + ;; +esac +INCLTDL="$LTDLINCL" + +# Report our decision... +AC_MSG_CHECKING([where to find libltdl headers]) +AC_MSG_RESULT([$LTDLINCL]) +AC_MSG_CHECKING([where to find libltdl library]) +AC_MSG_RESULT([$LIBLTDL]) + +_LTDL_SETUP + +dnl restore autoconf definition. +m4_popdef([AC_LIBOBJ]) +m4_popdef([AC_LIBSOURCES]) + +AC_CONFIG_COMMANDS_PRE([ + _ltdl_libobjs= + _ltdl_ltlibobjs= + if test -n "$_LT_LIBOBJS"; then + # Remove the extension. + _lt_sed_drop_objext='s/\.o$//;s/\.obj$//' + for i in `for i in $_LT_LIBOBJS; do echo "$i"; done | sed "$_lt_sed_drop_objext" | sort -u`; do + _ltdl_libobjs="$_ltdl_libobjs $lt_libobj_prefix$i.$ac_objext" + _ltdl_ltlibobjs="$_ltdl_ltlibobjs $lt_libobj_prefix$i.lo" + done + fi + AC_SUBST([ltdl_LIBOBJS], [$_ltdl_libobjs]) + AC_SUBST([ltdl_LTLIBOBJS], [$_ltdl_ltlibobjs]) +]) + +# Only expand once: +m4_define([LTDL_INIT]) +])# LTDL_INIT + +# Old names: +AU_DEFUN([AC_LIB_LTDL], [LTDL_INIT($@)]) +AU_DEFUN([AC_WITH_LTDL], [LTDL_INIT($@)]) +AU_DEFUN([LT_WITH_LTDL], [LTDL_INIT($@)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIB_LTDL], []) +dnl AC_DEFUN([AC_WITH_LTDL], []) +dnl AC_DEFUN([LT_WITH_LTDL], []) + + +# _LTDL_SETUP +# ----------- +# Perform all the checks necessary for compilation of the ltdl objects +# -- including compiler checks and header checks. This is a public +# interface mainly for the benefit of libltdl's own configure.ac, most +# other users should call LTDL_INIT instead. +AC_DEFUN([_LTDL_SETUP], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_SYS_MODULE_EXT])dnl +AC_REQUIRE([LT_SYS_MODULE_PATH])dnl +AC_REQUIRE([LT_SYS_DLSEARCH_PATH])dnl +AC_REQUIRE([LT_LIB_DLLOAD])dnl +AC_REQUIRE([LT_SYS_SYMBOL_USCORE])dnl +AC_REQUIRE([LT_FUNC_DLSYM_USCORE])dnl +AC_REQUIRE([LT_SYS_DLOPEN_DEPLIBS])dnl +AC_REQUIRE([gl_FUNC_ARGZ])dnl + +m4_require([_LT_CHECK_OBJDIR])dnl +m4_require([_LT_HEADER_DLFCN])dnl +m4_require([_LT_CHECK_DLPREOPEN])dnl +m4_require([_LT_DECL_SED])dnl + +dnl Don't require this, or it will be expanded earlier than the code +dnl that sets the variables it relies on: +_LT_ENABLE_INSTALL + +dnl _LTDL_MODE specific code must be called at least once: +_LTDL_MODE_DISPATCH + +# In order that ltdl.c can compile, find out the first AC_CONFIG_HEADERS +# the user used. This is so that ltdl.h can pick up the parent projects +# config.h file, The first file in AC_CONFIG_HEADERS must contain the +# definitions required by ltdl.c. +# FIXME: Remove use of undocumented AC_LIST_HEADERS (2.59 compatibility). +AC_CONFIG_COMMANDS_PRE([dnl +m4_pattern_allow([^LT_CONFIG_H$])dnl +m4_ifset([AH_HEADER], + [LT_CONFIG_H=AH_HEADER], + [m4_ifset([AC_LIST_HEADERS], + [LT_CONFIG_H=`echo "AC_LIST_HEADERS" | $SED 's,^[[ ]]*,,;s,[[ :]].*$,,'`], + [])])]) +AC_SUBST([LT_CONFIG_H]) + +AC_CHECK_HEADERS([unistd.h dl.h sys/dl.h dld.h mach-o/dyld.h dirent.h], + [], [], [AC_INCLUDES_DEFAULT]) + +AC_CHECK_FUNCS([closedir opendir readdir], [], [AC_LIBOBJ([lt__dirent])]) +AC_CHECK_FUNCS([strlcat strlcpy], [], [AC_LIBOBJ([lt__strl])]) + +m4_pattern_allow([LT_LIBEXT])dnl +AC_DEFINE_UNQUOTED([LT_LIBEXT],["$libext"],[The archive extension]) + +name= +eval "lt_libprefix=\"$libname_spec\"" +m4_pattern_allow([LT_LIBPREFIX])dnl +AC_DEFINE_UNQUOTED([LT_LIBPREFIX],["$lt_libprefix"],[The archive prefix]) + +name=ltdl +eval "LTDLOPEN=\"$libname_spec\"" +AC_SUBST([LTDLOPEN]) +])# _LTDL_SETUP + + +# _LT_ENABLE_INSTALL +# ------------------ +m4_define([_LT_ENABLE_INSTALL], +[AC_ARG_ENABLE([ltdl-install], + [AS_HELP_STRING([--enable-ltdl-install], [install libltdl])]) + +case ,${enable_ltdl_install},${enable_ltdl_convenience} in + *yes*) ;; + *) enable_ltdl_convenience=yes ;; +esac + +m4_ifdef([AM_CONDITIONAL], +[AM_CONDITIONAL(INSTALL_LTDL, test x"${enable_ltdl_install-no}" != xno) + AM_CONDITIONAL(CONVENIENCE_LTDL, test x"${enable_ltdl_convenience-no}" != xno)]) +])# _LT_ENABLE_INSTALL + + +# LT_SYS_DLOPEN_DEPLIBS +# --------------------- +AC_DEFUN([LT_SYS_DLOPEN_DEPLIBS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_CACHE_CHECK([whether deplibs are loaded by dlopen], + [lt_cv_sys_dlopen_deplibs], + [# PORTME does your system automatically load deplibs for dlopen? + # or its logical equivalent (e.g. shl_load for HP-UX < 11) + # For now, we just catch OSes we know something about -- in the + # future, we'll try test this programmatically. + lt_cv_sys_dlopen_deplibs=unknown + case $host_os in + aix3*|aix4.1.*|aix4.2.*) + # Unknown whether this is true for these versions of AIX, but + # we want this `case' here to explicitly catch those versions. + lt_cv_sys_dlopen_deplibs=unknown + ;; + aix[[4-9]]*) + lt_cv_sys_dlopen_deplibs=yes + ;; + amigaos*) + case $host_cpu in + powerpc) + lt_cv_sys_dlopen_deplibs=no + ;; + esac + ;; + darwin*) + # Assuming the user has installed a libdl from somewhere, this is true + # If you are looking for one http://www.opendarwin.org/projects/dlcompat + lt_cv_sys_dlopen_deplibs=yes + ;; + freebsd* | dragonfly*) + lt_cv_sys_dlopen_deplibs=yes + ;; + gnu* | linux* | k*bsd*-gnu | kopensolaris*-gnu) + # GNU and its variants, using gnu ld.so (Glibc) + lt_cv_sys_dlopen_deplibs=yes + ;; + hpux10*|hpux11*) + lt_cv_sys_dlopen_deplibs=yes + ;; + interix*) + lt_cv_sys_dlopen_deplibs=yes + ;; + irix[[12345]]*|irix6.[[01]]*) + # Catch all versions of IRIX before 6.2, and indicate that we don't + # know how it worked for any of those versions. + lt_cv_sys_dlopen_deplibs=unknown + ;; + irix*) + # The case above catches anything before 6.2, and it's known that + # at 6.2 and later dlopen does load deplibs. + lt_cv_sys_dlopen_deplibs=yes + ;; + netbsd* | netbsdelf*-gnu) + lt_cv_sys_dlopen_deplibs=yes + ;; + openbsd*) + lt_cv_sys_dlopen_deplibs=yes + ;; + osf[[1234]]*) + # dlopen did load deplibs (at least at 4.x), but until the 5.x series, + # it did *not* use an RPATH in a shared library to find objects the + # library depends on, so we explicitly say `no'. + lt_cv_sys_dlopen_deplibs=no + ;; + osf5.0|osf5.0a|osf5.1) + # dlopen *does* load deplibs and with the right loader patch applied + # it even uses RPATH in a shared library to search for shared objects + # that the library depends on, but there's no easy way to know if that + # patch is installed. Since this is the case, all we can really + # say is unknown -- it depends on the patch being installed. If + # it is, this changes to `yes'. Without it, it would be `no'. + lt_cv_sys_dlopen_deplibs=unknown + ;; + osf*) + # the two cases above should catch all versions of osf <= 5.1. Read + # the comments above for what we know about them. + # At > 5.1, deplibs are loaded *and* any RPATH in a shared library + # is used to find them so we can finally say `yes'. + lt_cv_sys_dlopen_deplibs=yes + ;; + qnx*) + lt_cv_sys_dlopen_deplibs=yes + ;; + solaris*) + lt_cv_sys_dlopen_deplibs=yes + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + esac + ]) +if test "$lt_cv_sys_dlopen_deplibs" != yes; then + AC_DEFINE([LTDL_DLOPEN_DEPLIBS], [1], + [Define if the OS needs help to load dependent libraries for dlopen().]) +fi +])# LT_SYS_DLOPEN_DEPLIBS + +# Old name: +AU_ALIAS([AC_LTDL_SYS_DLOPEN_DEPLIBS], [LT_SYS_DLOPEN_DEPLIBS]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_SYS_DLOPEN_DEPLIBS], []) + + +# LT_SYS_MODULE_EXT +# ----------------- +AC_DEFUN([LT_SYS_MODULE_EXT], +[m4_require([_LT_SYS_DYNAMIC_LINKER])dnl +AC_CACHE_CHECK([which extension is used for runtime loadable modules], + [libltdl_cv_shlibext], +[ +module=yes +eval libltdl_cv_shlibext=$shrext_cmds +module=no +eval libltdl_cv_shrext=$shrext_cmds + ]) +if test -n "$libltdl_cv_shlibext"; then + m4_pattern_allow([LT_MODULE_EXT])dnl + AC_DEFINE_UNQUOTED([LT_MODULE_EXT], ["$libltdl_cv_shlibext"], + [Define to the extension used for runtime loadable modules, say, ".so".]) +fi +if test "$libltdl_cv_shrext" != "$libltdl_cv_shlibext"; then + m4_pattern_allow([LT_SHARED_EXT])dnl + AC_DEFINE_UNQUOTED([LT_SHARED_EXT], ["$libltdl_cv_shrext"], + [Define to the shared library suffix, say, ".dylib".]) +fi +])# LT_SYS_MODULE_EXT + +# Old name: +AU_ALIAS([AC_LTDL_SHLIBEXT], [LT_SYS_MODULE_EXT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_SHLIBEXT], []) + + +# LT_SYS_MODULE_PATH +# ------------------ +AC_DEFUN([LT_SYS_MODULE_PATH], +[m4_require([_LT_SYS_DYNAMIC_LINKER])dnl +AC_CACHE_CHECK([which variable specifies run-time module search path], + [lt_cv_module_path_var], [lt_cv_module_path_var="$shlibpath_var"]) +if test -n "$lt_cv_module_path_var"; then + m4_pattern_allow([LT_MODULE_PATH_VAR])dnl + AC_DEFINE_UNQUOTED([LT_MODULE_PATH_VAR], ["$lt_cv_module_path_var"], + [Define to the name of the environment variable that determines the run-time module search path.]) +fi +])# LT_SYS_MODULE_PATH + +# Old name: +AU_ALIAS([AC_LTDL_SHLIBPATH], [LT_SYS_MODULE_PATH]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_SHLIBPATH], []) + + +# LT_SYS_DLSEARCH_PATH +# -------------------- +AC_DEFUN([LT_SYS_DLSEARCH_PATH], +[m4_require([_LT_SYS_DYNAMIC_LINKER])dnl +AC_CACHE_CHECK([for the default library search path], + [lt_cv_sys_dlsearch_path], + [lt_cv_sys_dlsearch_path="$sys_lib_dlsearch_path_spec"]) +if test -n "$lt_cv_sys_dlsearch_path"; then + sys_dlsearch_path= + for dir in $lt_cv_sys_dlsearch_path; do + if test -z "$sys_dlsearch_path"; then + sys_dlsearch_path="$dir" + else + sys_dlsearch_path="$sys_dlsearch_path$PATH_SEPARATOR$dir" + fi + done + m4_pattern_allow([LT_DLSEARCH_PATH])dnl + AC_DEFINE_UNQUOTED([LT_DLSEARCH_PATH], ["$sys_dlsearch_path"], + [Define to the system default library search path.]) +fi +])# LT_SYS_DLSEARCH_PATH + +# Old name: +AU_ALIAS([AC_LTDL_SYSSEARCHPATH], [LT_SYS_DLSEARCH_PATH]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_SYSSEARCHPATH], []) + + +# _LT_CHECK_DLPREOPEN +# ------------------- +m4_defun([_LT_CHECK_DLPREOPEN], +[m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +AC_CACHE_CHECK([whether libtool supports -dlopen/-dlpreopen], + [libltdl_cv_preloaded_symbols], + [if test -n "$lt_cv_sys_global_symbol_pipe"; then + libltdl_cv_preloaded_symbols=yes + else + libltdl_cv_preloaded_symbols=no + fi + ]) +if test x"$libltdl_cv_preloaded_symbols" = xyes; then + AC_DEFINE([HAVE_PRELOADED_SYMBOLS], [1], + [Define if libtool can extract symbol lists from object files.]) +fi +])# _LT_CHECK_DLPREOPEN + + +# LT_LIB_DLLOAD +# ------------- +AC_DEFUN([LT_LIB_DLLOAD], +[m4_pattern_allow([^LT_DLLOADERS$]) +LT_DLLOADERS= +AC_SUBST([LT_DLLOADERS]) + +AC_LANG_PUSH([C]) + +LIBADD_DLOPEN= +AC_SEARCH_LIBS([dlopen], [dl], + [AC_DEFINE([HAVE_LIBDL], [1], + [Define if you have the libdl library or equivalent.]) + if test "$ac_cv_search_dlopen" != "none required" ; then + LIBADD_DLOPEN="-ldl" + fi + libltdl_cv_lib_dl_dlopen="yes" + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#if HAVE_DLFCN_H +# include +#endif + ]], [[dlopen(0, 0);]])], + [AC_DEFINE([HAVE_LIBDL], [1], + [Define if you have the libdl library or equivalent.]) + libltdl_cv_func_dlopen="yes" + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"], + [AC_CHECK_LIB([svld], [dlopen], + [AC_DEFINE([HAVE_LIBDL], [1], + [Define if you have the libdl library or equivalent.]) + LIBADD_DLOPEN="-lsvld" libltdl_cv_func_dlopen="yes" + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dlopen.la"])])]) +if test x"$libltdl_cv_func_dlopen" = xyes || test x"$libltdl_cv_lib_dl_dlopen" = xyes +then + lt_save_LIBS="$LIBS" + LIBS="$LIBS $LIBADD_DLOPEN" + AC_CHECK_FUNCS([dlerror]) + LIBS="$lt_save_LIBS" +fi +AC_SUBST([LIBADD_DLOPEN]) + +LIBADD_SHL_LOAD= +AC_CHECK_FUNC([shl_load], + [AC_DEFINE([HAVE_SHL_LOAD], [1], + [Define if you have the shl_load function.]) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}shl_load.la"], + [AC_CHECK_LIB([dld], [shl_load], + [AC_DEFINE([HAVE_SHL_LOAD], [1], + [Define if you have the shl_load function.]) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}shl_load.la" + LIBADD_SHL_LOAD="-ldld"])]) +AC_SUBST([LIBADD_SHL_LOAD]) + +case $host_os in +darwin[[1567]].*) +# We only want this for pre-Mac OS X 10.4. + AC_CHECK_FUNC([_dyld_func_lookup], + [AC_DEFINE([HAVE_DYLD], [1], + [Define if you have the _dyld_func_lookup function.]) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dyld.la"]) + ;; +beos*) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}load_add_on.la" + ;; +cygwin* | mingw* | os2* | pw32*) + AC_CHECK_DECLS([cygwin_conv_path], [], [], [[#include ]]) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}loadlibrary.la" + ;; +esac + +AC_CHECK_LIB([dld], [dld_link], + [AC_DEFINE([HAVE_DLD], [1], + [Define if you have the GNU dld library.]) + LT_DLLOADERS="$LT_DLLOADERS ${lt_dlopen_dir+$lt_dlopen_dir/}dld_link.la"]) +AC_SUBST([LIBADD_DLD_LINK]) + +m4_pattern_allow([^LT_DLPREOPEN$]) +LT_DLPREOPEN= +if test -n "$LT_DLLOADERS" +then + for lt_loader in $LT_DLLOADERS; do + LT_DLPREOPEN="$LT_DLPREOPEN-dlpreopen $lt_loader " + done + AC_DEFINE([HAVE_LIBDLLOADER], [1], + [Define if libdlloader will be built on this platform]) +fi +AC_SUBST([LT_DLPREOPEN]) + +dnl This isn't used anymore, but set it for backwards compatibility +LIBADD_DL="$LIBADD_DLOPEN $LIBADD_SHL_LOAD" +AC_SUBST([LIBADD_DL]) + +AC_LANG_POP +])# LT_LIB_DLLOAD + +# Old name: +AU_ALIAS([AC_LTDL_DLLIB], [LT_LIB_DLLOAD]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_DLLIB], []) + + +# LT_SYS_SYMBOL_USCORE +# -------------------- +# does the compiler prefix global symbols with an underscore? +AC_DEFUN([LT_SYS_SYMBOL_USCORE], +[m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +AC_CACHE_CHECK([for _ prefix in compiled symbols], + [lt_cv_sys_symbol_underscore], + [lt_cv_sys_symbol_underscore=no + cat > conftest.$ac_ext <<_LT_EOF +void nm_test_func(){} +int main(){nm_test_func;return 0;} +_LT_EOF + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + ac_nlist=conftest.nm + if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $ac_nlist) && test -s "$ac_nlist"; then + # See whether the symbols have a leading underscore. + if grep '^. _nm_test_func' "$ac_nlist" >/dev/null; then + lt_cv_sys_symbol_underscore=yes + else + if grep '^. nm_test_func ' "$ac_nlist" >/dev/null; then + : + else + echo "configure: cannot find nm_test_func in $ac_nlist" >&AS_MESSAGE_LOG_FD + fi + fi + else + echo "configure: cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "configure: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.c >&AS_MESSAGE_LOG_FD + fi + rm -rf conftest* + ]) + sys_symbol_underscore=$lt_cv_sys_symbol_underscore + AC_SUBST([sys_symbol_underscore]) +])# LT_SYS_SYMBOL_USCORE + +# Old name: +AU_ALIAS([AC_LTDL_SYMBOL_USCORE], [LT_SYS_SYMBOL_USCORE]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_SYMBOL_USCORE], []) + + +# LT_FUNC_DLSYM_USCORE +# -------------------- +AC_DEFUN([LT_FUNC_DLSYM_USCORE], +[AC_REQUIRE([LT_SYS_SYMBOL_USCORE])dnl +if test x"$lt_cv_sys_symbol_underscore" = xyes; then + if test x"$libltdl_cv_func_dlopen" = xyes || + test x"$libltdl_cv_lib_dl_dlopen" = xyes ; then + AC_CACHE_CHECK([whether we have to add an underscore for dlsym], + [libltdl_cv_need_uscore], + [libltdl_cv_need_uscore=unknown + save_LIBS="$LIBS" + LIBS="$LIBS $LIBADD_DLOPEN" + _LT_TRY_DLOPEN_SELF( + [libltdl_cv_need_uscore=no], [libltdl_cv_need_uscore=yes], + [], [libltdl_cv_need_uscore=cross]) + LIBS="$save_LIBS" + ]) + fi +fi + +if test x"$libltdl_cv_need_uscore" = xyes; then + AC_DEFINE([NEED_USCORE], [1], + [Define if dlsym() requires a leading underscore in symbol names.]) +fi +])# LT_FUNC_DLSYM_USCORE + +# Old name: +AU_ALIAS([AC_LTDL_DLSYM_USCORE], [LT_FUNC_DLSYM_USCORE]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LTDL_DLSYM_USCORE], []) + # Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008, 2011 Free Software # Foundation, Inc. # @@ -38,7 +856,7 @@ [am__api_version='1.11' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.11.5], [], +m4_if([$1], [1.11.3], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) @@ -54,7 +872,7 @@ # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.11.5])dnl +[AM_AUTOMAKE_VERSION([1.11.3])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) @@ -1069,6 +1887,7 @@ m4_include([m4/asmcfi.m4]) m4_include([m4/ax_cc_maxopt.m4]) m4_include([m4/ax_cflags_warn_all.m4]) +m4_include([m4/ax_check_compile_flag.m4]) m4_include([m4/ax_compiler_vendor.m4]) m4_include([m4/ax_configure_args.m4]) m4_include([m4/ax_enable_builddir.m4]) diff --git a/Modules/_ctypes/libffi/configure b/Modules/_ctypes/libffi/configure --- a/Modules/_ctypes/libffi/configure +++ b/Modules/_ctypes/libffi/configure @@ -1,11 +1,13 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for libffi 3.0.11. +# Generated by GNU Autoconf 2.68 for libffi 3.0.11. # # Report bugs to . # # -# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software +# Foundation, Inc. # # # This configure script is free software; the Free Software Foundation @@ -134,31 +136,6 @@ # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH -# Use a proper internal environment variable to ensure we don't fall - # into an infinite loop, continuously re-executing ourselves. - if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then - _as_can_reexec=no; export _as_can_reexec; - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -as_fn_exit 255 - fi - # We don't want this to propagate to other subprocesses. - { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh @@ -192,8 +169,7 @@ else exitcode=1; echo positional parameters were not saved. fi -test x\$exitcode = x0 || exit 1 -test -x / || exit 1" +test x\$exitcode = x0 || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && @@ -246,25 +222,21 @@ if test "x$CONFIG_SHELL" != x; then : - export CONFIG_SHELL - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 + # We cannot yet assume a decent shell, so we have to provide a + # neutralization value for shells without unset; and this also + # works around shells that cannot unset nonexistent variables. + # Preserve -v and -x to the replacement shell. + BASH_ENV=/dev/null + ENV=/dev/null + (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV + export CONFIG_SHELL + case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; + esac + exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : @@ -367,14 +339,6 @@ } # as_fn_mkdir_p - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take @@ -496,10 +460,6 @@ chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } - # If we had to re-execute with $CONFIG_SHELL, we're ensured to have - # already done that, so ensure we don't try to do so again and fall - # in an infinite loop. This has already happened in practice. - _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). @@ -534,16 +494,16 @@ # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. + # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' + as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null @@ -555,8 +515,28 @@ as_mkdir_p=false fi -as_test_x='test -x' -as_executable_p=as_fn_executable_p +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" @@ -644,6 +624,7 @@ FFI_EXEC_TRAMPOLINE_TABLE FFI_EXEC_TRAMPOLINE_TABLE_FALSE FFI_EXEC_TRAMPOLINE_TABLE_TRUE +sys_symbol_underscore HAVE_LONG_DOUBLE ALLOCA PA64_HPUX_FALSE @@ -1308,6 +1289,8 @@ if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe + $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used" >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi @@ -1581,9 +1564,9 @@ if $ac_init_version; then cat <<\_ACEOF libffi configure 3.0.11 -generated by GNU Autoconf 2.69 - -Copyright (C) 2012 Free Software Foundation, Inc. +generated by GNU Autoconf 2.68 + +Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1659,7 +1642,7 @@ test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || - test -x conftest$ac_exeext + $as_test_x conftest$ac_exeext }; then : ac_retval=0 else @@ -2017,8 +2000,7 @@ main () { static int test_array [1 - 2 * !(($2) >= 0)]; -test_array [0] = 0; -return test_array [0]; +test_array [0] = 0 ; return 0; @@ -2034,8 +2016,7 @@ main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; -test_array [0] = 0; -return test_array [0]; +test_array [0] = 0 ; return 0; @@ -2061,8 +2042,7 @@ main () { static int test_array [1 - 2 * !(($2) < 0)]; -test_array [0] = 0; -return test_array [0]; +test_array [0] = 0 ; return 0; @@ -2078,8 +2058,7 @@ main () { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; -test_array [0] = 0; -return test_array [0]; +test_array [0] = 0 ; return 0; @@ -2113,8 +2092,7 @@ main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; -test_array [0] = 0; -return test_array [0]; +test_array [0] = 0 ; return 0; @@ -2187,7 +2165,7 @@ running configure, to aid debugging if configure makes a mistake. It was created by libffi $as_me 3.0.11, which was -generated by GNU Autoconf 2.69. Invocation command line was +generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ @@ -2758,7 +2736,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_ax_enable_builddir_sed="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -2824,7 +2802,7 @@ # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. @@ -2990,7 +2968,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3030,7 +3008,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3081,7 +3059,7 @@ test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do - as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue + { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ @@ -3134,7 +3112,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3293,7 +3271,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3333,7 +3311,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3386,7 +3364,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3427,7 +3405,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue @@ -3485,7 +3463,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3529,7 +3507,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3975,7 +3953,8 @@ /* end confdefs.h. */ #include #include -struct stat; +#include +#include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); @@ -4632,7 +4611,7 @@ for ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_SED" || continue + { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in @@ -4708,7 +4687,7 @@ for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in @@ -4774,7 +4753,7 @@ for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in @@ -4841,7 +4820,7 @@ for ac_prog in fgrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_FGREP" || continue + { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue # Check for GNU ac_path_FGREP and select it if it is found. # Check for GNU $ac_path_FGREP case `"$ac_path_FGREP" --version 2>&1` in @@ -5097,7 +5076,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -5141,7 +5120,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -5565,7 +5544,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -5605,7 +5584,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_OBJDUMP="objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -5911,7 +5890,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -5951,7 +5930,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_DLLTOOL="dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -6055,7 +6034,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AR="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -6099,7 +6078,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_AR="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -6224,7 +6203,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -6264,7 +6243,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -6323,7 +6302,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -6363,7 +6342,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -7012,7 +6991,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -7052,7 +7031,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -7132,7 +7111,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -7172,7 +7151,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -7224,7 +7203,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -7264,7 +7243,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_NMEDIT="nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -7316,7 +7295,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_LIPO="${ac_tool_prefix}lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -7356,7 +7335,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_LIPO="lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -7408,7 +7387,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_OTOOL="${ac_tool_prefix}otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -7448,7 +7427,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_OTOOL="otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -7500,7 +7479,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -7540,7 +7519,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_OTOOL64="otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -12138,9 +12117,41 @@ else xlc_opt="-qtune=auto" fi - AX_CHECK_COMPILE_FLAG($xlc_opt, - CFLAGS="-O3 -qansialias -w $xlc_opt", - CFLAGS="-O3 -qansialias -w" + as_CACHEVAR=`$as_echo "ax_cv_check_cflags__$xlc_opt" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts $xlc_opt" >&5 +$as_echo_n "checking whether C compiler accepts $xlc_opt... " >&6; } +if eval \${$as_CACHEVAR+:} false; then : + $as_echo_n "(cached) " >&6 +else + + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS $xlc_opt" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$as_CACHEVAR=yes" +else + eval "$as_CACHEVAR=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS=$ax_check_save_flags +fi +eval ac_res=\$$as_CACHEVAR + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if test x"`eval 'as_val=${'$as_CACHEVAR'};$as_echo "$as_val"'`" = xyes; then : + CFLAGS="-O3 -qansialias -w $xlc_opt" +else + CFLAGS="-O3 -qansialias -w" echo "******************************************************" echo "* You seem to have the IBM C compiler. It is *" echo "* recommended for best performance that you use: *" @@ -12150,7 +12161,9 @@ echo "* where xxx is pwr2, pwr3, 604, or whatever kind of *" echo "* CPU you have. (Set the CFLAGS environment var. *" echo "* and re-run configure.) For more info, man cc. *" - echo "******************************************************") + echo "******************************************************" +fi + ;; intel) CFLAGS="-O3 -ansi_alias" @@ -12281,7 +12294,43 @@ esac if test "x$icc_flags" != x; then for flag in $icc_flags; do - AX_CHECK_COMPILE_FLAG($flag, icc_archflag=$flag; break) + as_CACHEVAR=`$as_echo "ax_cv_check_cflags__$flag" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts $flag" >&5 +$as_echo_n "checking whether C compiler accepts $flag... " >&6; } +if eval \${$as_CACHEVAR+:} false; then : + $as_echo_n "(cached) " >&6 +else + + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS $flag" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$as_CACHEVAR=yes" +else + eval "$as_CACHEVAR=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS=$ax_check_save_flags +fi +eval ac_res=\$$as_CACHEVAR + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if test x"`eval 'as_val=${'$as_CACHEVAR'};$as_echo "$as_val"'`" = xyes; then : + icc_archflag=$flag; break +else + : +fi + done fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for icc architecture flag" >&5 @@ -12299,14 +12348,115 @@ CFLAGS="-O3 -fomit-frame-pointer" # -malign-double for x86 systems - AX_CHECK_COMPILE_FLAG(-malign-double, CFLAGS="$CFLAGS -malign-double") + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -malign-double" >&5 +$as_echo_n "checking whether C compiler accepts -malign-double... " >&6; } +if ${ax_cv_check_cflags___malign_double+:} false; then : + $as_echo_n "(cached) " >&6 +else + + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS -malign-double" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ax_cv_check_cflags___malign_double=yes +else + ax_cv_check_cflags___malign_double=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS=$ax_check_save_flags +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___malign_double" >&5 +$as_echo "$ax_cv_check_cflags___malign_double" >&6; } +if test x"$ax_cv_check_cflags___malign_double" = xyes; then : + CFLAGS="$CFLAGS -malign-double" +else + : +fi + # -fstrict-aliasing for gcc-2.95+ - AX_CHECK_COMPILE_FLAG(-fstrict-aliasing, - CFLAGS="$CFLAGS -fstrict-aliasing") + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -fstrict-aliasing" >&5 +$as_echo_n "checking whether C compiler accepts -fstrict-aliasing... " >&6; } +if ${ax_cv_check_cflags___fstrict_aliasing+:} false; then : + $as_echo_n "(cached) " >&6 +else + + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS -fstrict-aliasing" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ax_cv_check_cflags___fstrict_aliasing=yes +else + ax_cv_check_cflags___fstrict_aliasing=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS=$ax_check_save_flags +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___fstrict_aliasing" >&5 +$as_echo "$ax_cv_check_cflags___fstrict_aliasing" >&6; } +if test x"$ax_cv_check_cflags___fstrict_aliasing" = xyes; then : + CFLAGS="$CFLAGS -fstrict-aliasing" +else + : +fi + # note that we enable "unsafe" fp optimization with other compilers, too - AX_CHECK_COMPILE_FLAG(-ffast-math, CFLAGS="$CFLAGS -ffast-math") + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -ffast-math" >&5 +$as_echo_n "checking whether C compiler accepts -ffast-math... " >&6; } +if ${ax_cv_check_cflags___ffast_math+:} false; then : + $as_echo_n "(cached) " >&6 +else + + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS -ffast-math" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ax_cv_check_cflags___ffast_math=yes +else + ax_cv_check_cflags___ffast_math=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS=$ax_check_save_flags +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___ffast_math" >&5 +$as_echo "$ax_cv_check_cflags___ffast_math" >&6; } +if test x"$ax_cv_check_cflags___ffast_math" = xyes; then : + CFLAGS="$CFLAGS -ffast-math" +else + : +fi + @@ -12576,7 +12726,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_PRTDIAG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -12652,7 +12802,43 @@ flags="-march=$arch -mcpu=$arch -m$arch" fi for flag in $flags; do - AX_CHECK_COMPILE_FLAG($flag, ax_cv_gcc_archflag=$flag; break) + as_CACHEVAR=`$as_echo "ax_cv_check_cflags__$flag" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts $flag" >&5 +$as_echo_n "checking whether C compiler accepts $flag... " >&6; } +if eval \${$as_CACHEVAR+:} false; then : + $as_echo_n "(cached) " >&6 +else + + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS $flag" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$as_CACHEVAR=yes" +else + eval "$as_CACHEVAR=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS=$ax_check_save_flags +fi +eval ac_res=\$$as_CACHEVAR + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if test x"`eval 'as_val=${'$as_CACHEVAR'};$as_echo "$as_val"'`" = xyes; then : + ax_cv_gcc_archflag=$flag; break +else + : +fi + done test "x$ax_cv_gcc_archflag" = xunknown || break done @@ -12686,7 +12872,41 @@ CFLAGS="-O3" fi - AX_CHECK_COMPILE_FLAG($CFLAGS, , + as_CACHEVAR=`$as_echo "ax_cv_check_cflags__$CFLAGS" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts $CFLAGS" >&5 +$as_echo_n "checking whether C compiler accepts $CFLAGS... " >&6; } +if eval \${$as_CACHEVAR+:} false; then : + $as_echo_n "(cached) " >&6 +else + + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS $CFLAGS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$as_CACHEVAR=yes" +else + eval "$as_CACHEVAR=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS=$ax_check_save_flags +fi +eval ac_res=\$$as_CACHEVAR + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if test x"`eval 'as_val=${'$as_CACHEVAR'};$as_echo "$as_val"'`" = xyes; then : + : +else + echo "" echo "********************************************************" echo "* WARNING: The guessed CFLAGS don't seem to work with *" @@ -12695,7 +12915,9 @@ echo "********************************************************" echo "" CFLAGS="" - ) + +fi + fi @@ -13616,20 +13838,23 @@ /* end confdefs.h. */ $ac_includes_default int -find_stack_direction (int *addr, int depth) -{ - int dir, dummy = 0; - if (! addr) - addr = &dummy; - *addr = addr < &dummy ? 1 : addr == &dummy ? 0 : -1; - dir = depth ? find_stack_direction (addr, depth - 1) : 0; - return dir + dummy; -} - -int -main (int argc, char **argv) -{ - return find_stack_direction (0, argc + !argv + 20) < 0; +find_stack_direction () +{ + static char *addr = 0; + auto char dummy; + if (addr == 0) + { + addr = &dummy; + return find_stack_direction (); + } + else + return (&dummy > addr) ? 1 : -1; +} + +int +main () +{ + return find_stack_direction () < 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : @@ -14163,7 +14388,53 @@ fi if test x$TARGET = xX86_WIN64; then - LT_SYS_SYMBOL_USCORE + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _ prefix in compiled symbols" >&5 +$as_echo_n "checking for _ prefix in compiled symbols... " >&6; } +if ${lt_cv_sys_symbol_underscore+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_sys_symbol_underscore=no + cat > conftest.$ac_ext <<_LT_EOF +void nm_test_func(){} +int main(){nm_test_func;return 0;} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Now try to grab the symbols. + ac_nlist=conftest.nm + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $ac_nlist\""; } >&5 + (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $ac_nlist) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "$ac_nlist"; then + # See whether the symbols have a leading underscore. + if grep '^. _nm_test_func' "$ac_nlist" >/dev/null; then + lt_cv_sys_symbol_underscore=yes + else + if grep '^. nm_test_func ' "$ac_nlist" >/dev/null; then + : + else + echo "configure: cannot find nm_test_func in $ac_nlist" >&5 + fi + fi + else + echo "configure: cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "configure: failed program was:" >&5 + cat conftest.c >&5 + fi + rm -rf conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_symbol_underscore" >&5 +$as_echo "$lt_cv_sys_symbol_underscore" >&6; } + sys_symbol_underscore=$lt_cv_sys_symbol_underscore + + if test "x$sys_symbol_underscore" = xyes; then $as_echo "#define SYMBOL_UNDERSCORE 1" >>confdefs.h @@ -14934,16 +15205,16 @@ # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. + # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' + as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null @@ -15003,16 +15274,28 @@ as_mkdir_p=false fi - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -as_test_x='test -x' -as_executable_p=as_fn_executable_p +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" @@ -15034,7 +15317,7 @@ # values after options handling. ac_log=" This file was extended by libffi $as_me 3.0.11, which was -generated by GNU Autoconf 2.69. Invocation command line was +generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -15104,10 +15387,10 @@ ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ libffi config.status 3.0.11 -configured by $0, generated by GNU Autoconf 2.69, +configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" -Copyright (C) 2012 Free Software Foundation, Inc. +Copyright (C) 2010 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -15198,7 +15481,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then - set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' diff --git a/Modules/_ctypes/libffi/m4/ax_check_compile_flag.m4 b/Modules/_ctypes/libffi/m4/ax_check_compile_flag.m4 new file mode 100644 --- /dev/null +++ b/Modules/_ctypes/libffi/m4/ax_check_compile_flag.m4 @@ -0,0 +1,72 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the current language's compiler +# or gives an error. (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the current language's default +# flags (e.g. CFLAGS) when the check is done. The check is thus made with +# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to +# force the compiler to issue an error when a bad flag is given. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 2 + +AC_DEFUN([AX_CHECK_COMPILE_FLAG], +[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl +AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ + ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) +AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_COMPILE_FLAGS -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 1 00:40:48 2012 From: python-checkins at python.org (matthias.klose) Date: Sun, 01 Jul 2012 00:40:48 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_default_-=3E_default?= =?utf8?q?=29=3A_null_merge?= Message-ID: http://hg.python.org/cpython/rev/a3b3e60f36a5 changeset: 77897:a3b3e60f36a5 parent: 77896:989efaab9525 parent: 77894:1cbab581bf1e user: doko at ubuntu.com date: Sun Jul 01 00:38:34 2012 +0200 summary: null merge files: Lib/test/test_pep3151.py | 10 ++++++++++ Misc/NEWS | 3 +++ Objects/exceptions.c | 6 ++++++ 3 files changed, 19 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_pep3151.py b/Lib/test/test_pep3151.py --- a/Lib/test/test_pep3151.py +++ b/Lib/test/test_pep3151.py @@ -29,6 +29,10 @@ class SubOSErrorCombinedNewFirst(SubOSErrorWithNew, SubOSErrorWithInit): pass +class SubOSErrorWithStandaloneInit(OSError): + def __init__(self): + pass + class HierarchyTest(unittest.TestCase): @@ -193,6 +197,12 @@ self.assertEqual(e.baz, "baz") self.assertEqual(e.args, ("some message",)) + def test_init_standalone(self): + # __init__ doesn't propagate to OSError.__init__ (see issue #15229) + e = SubOSErrorWithStandaloneInit() + self.assertEqual(e.args, ()) + self.assertEqual(str(e), '') + def test_main(): support.run_unittest(__name__) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #15229: An OSError subclass whose __init__ doesn't call back + OSError.__init__ could produce incomplete instances, leading to crashes + when calling str() on them. Library ------- diff --git a/Objects/exceptions.c b/Objects/exceptions.c --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -834,6 +834,7 @@ #endif /* Steals the reference to args */ + Py_CLEAR(self->args); self->args = args; args = NULL; @@ -916,6 +917,11 @@ )) goto error; } + else { + self->args = PyTuple_New(0); + if (self->args == NULL) + goto error; + } return (PyObject *) self; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 1 01:10:31 2012 From: python-checkins at python.org (matthias.klose) Date: Sun, 01 Jul 2012 01:10:31 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_-_Issue_=2315194=3A_check_i?= =?utf8?q?n_the_missing_m4/ax=5Fappend=5Fflag=2Em4_file=2E?= Message-ID: http://hg.python.org/cpython/rev/6fe974b8056c changeset: 77898:6fe974b8056c user: doko at ubuntu.com date: Sun Jul 01 01:08:20 2012 +0200 summary: - Issue #15194: check in the missing m4/ax_append_flag.m4 file. Regenerate aclocalm4 and configure. files: Modules/_ctypes/libffi/aclocal.m4 | 1 + Modules/_ctypes/libffi/configure | 23 +++- Modules/_ctypes/libffi/m4/ax_append_flag.m4 | 69 ++++++++++ 3 files changed, 92 insertions(+), 1 deletions(-) diff --git a/Modules/_ctypes/libffi/aclocal.m4 b/Modules/_ctypes/libffi/aclocal.m4 --- a/Modules/_ctypes/libffi/aclocal.m4 +++ b/Modules/_ctypes/libffi/aclocal.m4 @@ -1885,6 +1885,7 @@ ]) # _AM_PROG_TAR m4_include([m4/asmcfi.m4]) +m4_include([m4/ax_append_flag.m4]) m4_include([m4/ax_cc_maxopt.m4]) m4_include([m4/ax_cflags_warn_all.m4]) m4_include([m4/ax_check_compile_flag.m4]) diff --git a/Modules/_ctypes/libffi/configure b/Modules/_ctypes/libffi/configure --- a/Modules/_ctypes/libffi/configure +++ b/Modules/_ctypes/libffi/configure @@ -12960,7 +12960,28 @@ case ".$ac_cv_cflags_warn_all" in .ok|.ok,*) ;; .|.no|.no,*) ;; - *) AX_APPEND_FLAG($VAR, ) ;; + *) if ${CFLAGS+:} false; then : + case " $CFLAGS " in + *" $ac_cv_cflags_warn_all "*) + { { $as_echo "$as_me:${as_lineno-$LINENO}: : CFLAGS already contains \$ac_cv_cflags_warn_all"; } >&5 + (: CFLAGS already contains $ac_cv_cflags_warn_all) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + ;; + *) + { { $as_echo "$as_me:${as_lineno-$LINENO}: : CFLAGS=\"\$CFLAGS \$ac_cv_cflags_warn_all\""; } >&5 + (: CFLAGS="$CFLAGS $ac_cv_cflags_warn_all") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + CFLAGS="$CFLAGS $ac_cv_cflags_warn_all" + ;; + esac +else + CFLAGS="$ac_cv_cflags_warn_all" +fi + ;; esac ac_ext=c diff --git a/Modules/_ctypes/libffi/m4/ax_append_flag.m4 b/Modules/_ctypes/libffi/m4/ax_append_flag.m4 new file mode 100644 --- /dev/null +++ b/Modules/_ctypes/libffi/m4/ax_append_flag.m4 @@ -0,0 +1,69 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_append_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE]) +# +# DESCRIPTION +# +# FLAG is appended to the FLAGS-VARIABLE shell variable, with a space +# added in between. +# +# If FLAGS-VARIABLE is not specified, the current language's flags (e.g. +# CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains +# FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly +# FLAG. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 2 + +AC_DEFUN([AX_APPEND_FLAG], +[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX +AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])dnl +AS_VAR_SET_IF(FLAGS, + [case " AS_VAR_GET(FLAGS) " in + *" $1 "*) + AC_RUN_LOG([: FLAGS already contains $1]) + ;; + *) + AC_RUN_LOG([: FLAGS="$FLAGS $1"]) + AS_VAR_SET(FLAGS, ["AS_VAR_GET(FLAGS) $1"]) + ;; + esac], + [AS_VAR_SET(FLAGS,["$1"])]) +AS_VAR_POPDEF([FLAGS])dnl +])dnl AX_APPEND_FLAG -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 1 01:58:39 2012 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 01 Jul 2012 01:58:39 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Add_syntax_highlighter_tool?= Message-ID: http://hg.python.org/cpython/rev/da4dd603030b changeset: 77899:da4dd603030b user: Raymond Hettinger date: Sat Jun 30 16:58:06 2012 -0700 summary: Add syntax highlighter tool files: Tools/scripts/pycolorize.py | 109 ++++++++++++++++++++++++ 1 files changed, 109 insertions(+), 0 deletions(-) diff --git a/Tools/scripts/pycolorize.py b/Tools/scripts/pycolorize.py new file mode 100755 --- /dev/null +++ b/Tools/scripts/pycolorize.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python3 +'Convert Python source code to HTML with colorized markup' + +__all__ = ['colorize', 'build_page', 'default_css', 'default_html'] + +import keyword, tokenize, cgi, functools + +def insert(s, i, text): + 'Insert text at position i in string s' + return s[:i] + text + s[i:] + +def is_builtin(s): + 'Return True if s is the name of a builtin' + return s in vars(__builtins__) + +def colorize(source): + 'Convert Python source code to an HTML fragment with colorized markup' + text = cgi.escape(source) + lines = text.splitlines(True) + readline = functools.partial(next, iter(lines), '') + actions = [] + kind = tok_str = '' + tok_type = tokenize.COMMENT + for tok in tokenize.generate_tokens(readline): + prev_tok_type, prev_tok_str = tok_type, tok_str + tok_type, tok_str, (srow, scol), (erow, ecol), logical_lineno = tok + kind, prev_kind = '', kind + if tok_type == tokenize.COMMENT: + kind = 'comment' + elif tok_type == tokenize.OP: + kind = 'operator' + elif tok_type == tokenize.STRING: + kind = 'string' + if prev_tok_type == tokenize.INDENT or scol==0: + kind = 'docstring' + elif tok_type == tokenize.NAME: + if tok_str in ('def', 'class', 'import', 'from'): + kind = 'definition' + elif prev_tok_str in ('def', 'class'): + kind = 'defname' + elif keyword.iskeyword(tok_str): + kind = 'keyword' + elif is_builtin(tok_str) and prev_tok_str != '.': + kind = 'builtin' + if kind: + actions.append(((srow, scol), (erow, ecol), kind)) + + for (srow, scol), (erow, ecol), kind in reversed(actions): + lines[erow-1] = insert(lines[erow-1], ecol, '') + lines[srow-1] = insert(lines[srow-1], scol, '' % kind) + + lines.insert(0, '
\n')
+    lines.append('
\n') + return ''.join(lines) + +default_css = { + '.comment': '{color: crimson;}', + '.string': '{color: forestgreen;}', + '.docstring': '{color: forestgreen; font-style:italic}', + '.keyword': '{color: darkorange;}', + '.builtin': '{color: purple;}', + '.definition': '{color: darkorange; font-weight:bold;}', + '.defname': '{color: blue;}', + '.operator': '{color: brown;}', +} + +default_html = '''\ + + +%s + +''' + +def build_page(source, html=default_html, css=default_css): + 'Create a complete HTML page with colorized Python source code' + css_str = ''.join(['%s %s\n' % item for item in default_css.items()]) + result = colorize(source) + return html % (css_str, result) + + +if __name__ == '__main__': + import sys, argparse, webbrowser, os + + parser = argparse.ArgumentParser( + description = 'Convert Python source code to colorized HTML') + parser.add_argument('sourcefile', metavar = 'SOURCEFILE', nargs = 1, + help = 'File containing Python sourcecode') + parser.add_argument('-b', '--browser', action = 'store_true', + help = 'launch a browser to show results') + parser.add_argument('-s', '--standalone', action = 'store_true', + help = 'show a standalone snippet rather than a complete webpage') + args = parser.parse_args() + if args.browser and args.standalone: + parser.error('The -s/--standalone option is incompatible with ' + 'the -b/--browser option') + + sourcefile = args.sourcefile[0] + with open(sourcefile) as f: + page = f.read() + html = colorize(page) if args.standalone else build_page(page) + if args.browser: + htmlfile = os.path.splitext(os.path.basename(sourcefile))[0] + '.html' + with open(htmlfile, 'w') as f: + f.write(html) + webbrowser.open('file://' + os.path.abspath(htmlfile)) + else: + sys.stdout.write(html) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 1 02:00:24 2012 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 01 Jul 2012 02:00:24 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Add_author_tag?= Message-ID: http://hg.python.org/cpython/rev/05a3ae2231f7 changeset: 77900:05a3ae2231f7 user: Raymond Hettinger date: Sat Jun 30 17:00:14 2012 -0700 summary: Add author tag files: Tools/scripts/pycolorize.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Tools/scripts/pycolorize.py b/Tools/scripts/pycolorize.py --- a/Tools/scripts/pycolorize.py +++ b/Tools/scripts/pycolorize.py @@ -2,6 +2,7 @@ 'Convert Python source code to HTML with colorized markup' __all__ = ['colorize', 'build_page', 'default_css', 'default_html'] +__author__ = 'Raymond Hettinger' import keyword, tokenize, cgi, functools -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 1 02:10:35 2012 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 01 Jul 2012 02:10:35 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_local_variable?= Message-ID: http://hg.python.org/cpython/rev/81bbd52695e0 changeset: 77901:81bbd52695e0 user: Raymond Hettinger date: Sat Jun 30 17:10:25 2012 -0700 summary: Fix local variable files: Tools/scripts/pycolorize.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Tools/scripts/pycolorize.py b/Tools/scripts/pycolorize.py --- a/Tools/scripts/pycolorize.py +++ b/Tools/scripts/pycolorize.py @@ -76,7 +76,7 @@ def build_page(source, html=default_html, css=default_css): 'Create a complete HTML page with colorized Python source code' - css_str = ''.join(['%s %s\n' % item for item in default_css.items()]) + css_str = ''.join(['%s %s\n' % item for item in css.items()]) result = colorize(source) return html % (css_str, result) -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sun Jul 1 06:03:35 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 01 Jul 2012 06:03:35 +0200 Subject: [Python-checkins] Daily reference leaks (81bbd52695e0): sum=-1 Message-ID: results for 81bbd52695e0 on branch "default" -------------------------------------------- test_support leaked [0, 0, -1] references, sum=-1 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogwA3mPw', '-x'] From python-checkins at python.org Sun Jul 1 07:19:15 2012 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 01 Jul 2012 07:19:15 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Small_cleanups?= Message-ID: http://hg.python.org/cpython/rev/d02588a26057 changeset: 77902:d02588a26057 user: Raymond Hettinger date: Sat Jun 30 22:19:04 2012 -0700 summary: Small cleanups files: Tools/scripts/README | 1 + Tools/scripts/pycolorize.py | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Tools/scripts/README b/Tools/scripts/README --- a/Tools/scripts/README +++ b/Tools/scripts/README @@ -47,6 +47,7 @@ pickle2db.py Load a pickle generated by db2pickle.py to a database pindent.py Indent Python code, giving block-closing comments ptags.py Create vi tags file for Python modules +pycolorize Python syntax highlighting with HTML output. pydoc3 Python documentation browser pysource.py Find Python source files redemo.py Basic regular expression demonstration facility diff --git a/Tools/scripts/pycolorize.py b/Tools/scripts/pycolorize.py --- a/Tools/scripts/pycolorize.py +++ b/Tools/scripts/pycolorize.py @@ -66,17 +66,25 @@ } default_html = '''\ - + + %s - + + ''' def build_page(source, html=default_html, css=default_css): 'Create a complete HTML page with colorized Python source code' - css_str = ''.join(['%s %s\n' % item for item in css.items()]) + css_str = '\n'.join(['%s %s' % item for item in css.items()]) result = colorize(source) return html % (css_str, result) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 1 08:19:40 2012 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 01 Jul 2012 08:19:40 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Set_title_to_the_source_fil?= =?utf8?q?ename?= Message-ID: http://hg.python.org/cpython/rev/21ca7f56e12c changeset: 77903:21ca7f56e12c user: Raymond Hettinger date: Sat Jun 30 23:19:30 2012 -0700 summary: Set title to the source filename files: Tools/scripts/pycolorize.py | 11 ++++++----- 1 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Tools/scripts/pycolorize.py b/Tools/scripts/pycolorize.py --- a/Tools/scripts/pycolorize.py +++ b/Tools/scripts/pycolorize.py @@ -2,7 +2,7 @@ 'Convert Python source code to HTML with colorized markup' __all__ = ['colorize', 'build_page', 'default_css', 'default_html'] -__author__ = 'Raymond Hettinger' +__author__ = 'Raymond Hettinger' import keyword, tokenize, cgi, functools @@ -71,7 +71,7 @@ - Python Code + %s @@ -82,11 +82,12 @@ ''' -def build_page(source, html=default_html, css=default_css): +def build_page(source, title='python', css=default_css, html=default_html): 'Create a complete HTML page with colorized Python source code' css_str = '\n'.join(['%s %s' % item for item in css.items()]) result = colorize(source) - return html % (css_str, result) + title = cgi.escape(title) + return html % (title, css_str, result) if __name__ == '__main__': @@ -108,7 +109,7 @@ sourcefile = args.sourcefile[0] with open(sourcefile) as f: page = f.read() - html = colorize(page) if args.standalone else build_page(page) + html = colorize(page) if args.standalone else build_page(page, title=sourcefile) if args.browser: htmlfile = os.path.splitext(os.path.basename(sourcefile))[0] + '.html' with open(htmlfile, 'w') as f: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 1 09:37:14 2012 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 01 Jul 2012 09:37:14 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Limit_which_operators_get_c?= =?utf8?q?olorized?= Message-ID: http://hg.python.org/cpython/rev/fae140c00954 changeset: 77904:fae140c00954 user: Raymond Hettinger date: Sun Jul 01 00:37:05 2012 -0700 summary: Limit which operators get colorized files: Tools/scripts/pycolorize.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Tools/scripts/pycolorize.py b/Tools/scripts/pycolorize.py --- a/Tools/scripts/pycolorize.py +++ b/Tools/scripts/pycolorize.py @@ -28,7 +28,7 @@ kind, prev_kind = '', kind if tok_type == tokenize.COMMENT: kind = 'comment' - elif tok_type == tokenize.OP: + elif tok_type == tokenize.OP and tok_str[:1] not in '{}[](),.:;': kind = 'operator' elif tok_type == tokenize.STRING: kind = 'string' -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 1 09:39:58 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 01 Jul 2012 09:39:58 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Remove_an_unnee?= =?utf8?q?ded_footnote=2E?= Message-ID: http://hg.python.org/cpython/rev/dd618635efb8 changeset: 77905:dd618635efb8 branch: 2.7 parent: 77884:97445ca895d5 user: Georg Brandl date: Sun Jul 01 09:40:16 2012 +0200 summary: Remove an unneeded footnote. files: Doc/library/profile.rst | 9 +++------ 1 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Doc/library/profile.rst b/Doc/library/profile.rst --- a/Doc/library/profile.rst +++ b/Doc/library/profile.rst @@ -607,13 +607,10 @@ best results with a custom timer, it might be necessary to hard-code it in the C source of the internal :mod:`_lsprof` module. + .. rubric:: Footnotes -.. [#] Updated and converted to LaTeX by Guido van Rossum. Further updated by Armin - Rigo to integrate the documentation for the new :mod:`cProfile` module of Python - 2.5. - -.. [#] Prior to Python 2.2, it was necessary to edit the profiler source code to embed - the bias as a literal number. You still can, but that method is no longer +.. [#] Prior to Python 2.2, it was necessary to edit the profiler source code to + embed the bias as a literal number. You still can, but that method is no longer described, because no longer needed. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 1 09:47:49 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 01 Jul 2012 09:47:49 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=282=2E7=29=3A_Make_call_of_os?= =?utf8?q?=2Egetppid=28=29_conditional=3A_it_is_not_available_on_Windows?= =?utf8?q?=2E?= Message-ID: http://hg.python.org/cpython/rev/65dd71ebf28f changeset: 77906:65dd71ebf28f branch: 2.7 user: Georg Brandl date: Sun Jul 01 09:47:54 2012 +0200 summary: Make call of os.getppid() conditional: it is not available on Windows. files: Doc/library/multiprocessing.rst | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -81,7 +81,8 @@ def info(title): print title print 'module name:', __name__ - print 'parent process:', os.getppid() + if hasattr(os, 'getppid'): # only available on Unix + print 'parent process:', os.getppid() print 'process id:', os.getpid() def f(name): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 1 09:49:26 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 01 Jul 2012 09:49:26 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Fix_inconsisten?= =?utf8?q?t_function_name_in_embedding_howto=2E?= Message-ID: http://hg.python.org/cpython/rev/275601fdc285 changeset: 77907:275601fdc285 branch: 3.2 parent: 77882:177f93f0f5b9 user: Georg Brandl date: Sun Jul 01 09:43:20 2012 +0200 summary: Fix inconsistent function name in embedding howto. files: Doc/extending/embedding.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/extending/embedding.rst b/Doc/extending/embedding.rst --- a/Doc/extending/embedding.rst +++ b/Doc/extending/embedding.rst @@ -155,13 +155,13 @@ interesting part with respect to embedding Python starts with :: Py_Initialize(); - pName = PyString_FromString(argv[1]); + pName = PyUnicode_FromString(argv[1]); /* Error checking of pName left out */ pModule = PyImport_Import(pName); After initializing the interpreter, the script is loaded using :c:func:`PyImport_Import`. This routine needs a Python string as its argument, -which is constructed using the :c:func:`PyString_FromString` data conversion +which is constructed using the :c:func:`PyUnicode_FromString` data conversion routine. :: pFunc = PyObject_GetAttrString(pModule, argv[2]); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 1 09:49:27 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 01 Jul 2012 09:49:27 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=283=2E2=29=3A_Make_call_of_os?= =?utf8?q?=2Egetppid=28=29_conditional=3A_it_is_not_available_on_Windows?= =?utf8?q?=2E?= Message-ID: http://hg.python.org/cpython/rev/031862264304 changeset: 77908:031862264304 branch: 3.2 user: Georg Brandl date: Sun Jul 01 09:47:54 2012 +0200 summary: Make call of os.getppid() conditional: it is not available on Windows. files: Doc/library/multiprocessing.rst | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -79,7 +79,8 @@ def info(title): print(title) print('module name:', __name__) - print('parent process:', os.getppid()) + if hasattr(os, 'getppid'): # only available on Unix + print('parent process:', os.getppid()) print('process id:', os.getpid()) def f(name): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 1 09:55:33 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 01 Jul 2012 09:55:33 +0200 Subject: [Python-checkins] =?utf8?q?cpython_=28merge_3=2E2_-=3E_default=29?= =?utf8?q?=3A_Merge_with_3=2E2=2E?= Message-ID: http://hg.python.org/cpython/rev/071bdd4a636b changeset: 77909:071bdd4a636b parent: 77904:fae140c00954 parent: 77908:031862264304 user: Georg Brandl date: Sun Jul 01 09:56:07 2012 +0200 summary: Merge with 3.2. files: Doc/extending/embedding.rst | 4 ++-- Doc/library/multiprocessing.rst | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Doc/extending/embedding.rst b/Doc/extending/embedding.rst --- a/Doc/extending/embedding.rst +++ b/Doc/extending/embedding.rst @@ -155,13 +155,13 @@ interesting part with respect to embedding Python starts with :: Py_Initialize(); - pName = PyString_FromString(argv[1]); + pName = PyUnicode_FromString(argv[1]); /* Error checking of pName left out */ pModule = PyImport_Import(pName); After initializing the interpreter, the script is loaded using :c:func:`PyImport_Import`. This routine needs a Python string as its argument, -which is constructed using the :c:func:`PyString_FromString` data conversion +which is constructed using the :c:func:`PyUnicode_FromString` data conversion routine. :: pFunc = PyObject_GetAttrString(pModule, argv[2]); diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -79,7 +79,8 @@ def info(title): print(title) print('module name:', __name__) - print('parent process:', os.getppid()) + if hasattr(os, 'getppid'): # only available on Unix + print('parent process:', os.getppid()) print('process id:', os.getpid()) def f(name): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 1 10:04:01 2012 From: python-checkins at python.org (georg.brandl) Date: Sun, 01 Jul 2012 10:04:01 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Fix_filename=2E?= Message-ID: http://hg.python.org/cpython/rev/b31fef9f65dc changeset: 77910:b31fef9f65dc user: Georg Brandl date: Sun Jul 01 10:04:35 2012 +0200 summary: Fix filename. files: Tools/scripts/README | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Tools/scripts/README b/Tools/scripts/README --- a/Tools/scripts/README +++ b/Tools/scripts/README @@ -47,7 +47,7 @@ pickle2db.py Load a pickle generated by db2pickle.py to a database pindent.py Indent Python code, giving block-closing comments ptags.py Create vi tags file for Python modules -pycolorize Python syntax highlighting with HTML output. +pycolorize.py Python syntax highlighting with HTML output pydoc3 Python documentation browser pysource.py Find Python source files redemo.py Basic regular expression demonstration facility -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 1 10:38:08 2012 From: python-checkins at python.org (matthias.klose) Date: Sun, 01 Jul 2012 10:38:08 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_-_Issue_=2315235=3A_Allow_B?= =?utf8?q?erkley_DB_versions_up_to_5=2E3_to_build_the_dbm_module=2E?= Message-ID: http://hg.python.org/cpython/rev/7be082d80b8a changeset: 77911:7be082d80b8a user: doko at ubuntu.com date: Sun Jul 01 10:35:54 2012 +0200 summary: - Issue #15235: Allow Berkley DB versions up to 5.3 to build the dbm module. files: Misc/NEWS | 2 ++ setup.py | 2 +- 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -51,6 +51,8 @@ - Issue #14330: For cross builds, don't use host python, use host search paths for host compiler. +- Issue #15235: Allow Berkley DB versions up to 5.3 to build the dbm module. + What's New in Python 3.3.0 Beta 1? ================================== diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -830,7 +830,7 @@ # a release. Most open source OSes come with one or more # versions of BerkeleyDB already installed. - max_db_ver = (5, 1) + max_db_ver = (5, 3) min_db_ver = (3, 3) db_setup_debug = False # verbose debug prints from this script? -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 1 12:25:14 2012 From: python-checkins at python.org (stefan.krah) Date: Sun, 01 Jul 2012 12:25:14 +0200 Subject: [Python-checkins] =?utf8?q?cpython=3A_Remove_ISSUES=2Etxt=2E?= Message-ID: http://hg.python.org/cpython/rev/a1c8302e6b27 changeset: 77912:a1c8302e6b27 user: Stefan Krah date: Sun Jul 01 12:24:20 2012 +0200 summary: Remove ISSUES.txt. files: Modules/_decimal/ISSUES.txt | 54 ------------------------- 1 files changed, 0 insertions(+), 54 deletions(-) diff --git a/Modules/_decimal/ISSUES.txt b/Modules/_decimal/ISSUES.txt deleted file mode 100644 --- a/Modules/_decimal/ISSUES.txt +++ /dev/null @@ -1,56 +0,0 @@ - - -Normal priority: ----------------- - -1) Add C-API importable as capsule. - -2) Add --with-system-libmpdec to ./configure. - -3) Use same default emin/emax on 32-bit (MAX_EMAX=425000000) and 64-bit - (MAX_EMAX=10**18-1). - -4) Order of arguments in Context(). - -5) Documentation. - -6) quantize() - - exp argument is misleading: - Decimal('0.321000e+2').quantize(exp=9) -> user might expect - that the result will have exp=9. - - watchexp - -7) Match the exception hierarchy of decimal.py: - - exceptions.ArithmeticError(exceptions.Exception) - DecimalException - Clamped - DivisionByZero(DecimalException, exceptions.ZeroDivisionError) - Inexact - Overflow(Inexact, Rounded) - Underflow(Inexact, Rounded, Subnormal) - InvalidOperation - Rounded - Subnormal - FloatOperation - - -Low priority: -------------- - -1) Convert tabs (wait until commit). - -2) Pre-ANSI compilers require '#' in the first column (should be done - for the whole Python source tree if we support such compilers). (?) - -3) FETCH_CURRENT_CONTEXT vs. CURRENT_CONTEXT? - -4) Justify remaining uses of exit on overflow in bignum arith. Short - answer: with correct context values the coefficients never get big - enough for that to happen. - -5) Justify remaining uses of abort() in mpdecimal: These uses are - for debug purposes and can't be reached when the library is used - correctly. - - -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 1 23:50:08 2012 From: python-checkins at python.org (local-hg) Date: Sun, 1 Jul 2012 23:50:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?hooks=3A_Fix_the_hooks_for_the_hg=2Ep?= =?utf-8?q?=2Eo_migration?= Message-ID: <3WQQHh0XCWzPKT@mail.python.org> http://hg.python.org/hooks/rev/bd04c6b37749 changeset: 82:bd04c6b37749 user: Antoine Pitrou date: Sun Jul 01 21:50:06 2012 +0000 summary: Fix the hooks for the hg.p.o migration files: hgbuildbot.py | 12 ++++++++++-- hgroundup.py | 4 +++- mail.py | 20 +++++++++++++++----- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/hgbuildbot.py b/hgbuildbot.py --- a/hgbuildbot.py +++ b/hgbuildbot.py @@ -59,8 +59,16 @@ elif isinstance(v, str): change[k] = v.decode('utf8', 'replace') d.addCallback(send, change) - d.addCallbacks(s.printSuccess, s.printFailure) - d.addBoth(s.stop) + + def printSuccess(res): + print "change(s) sent successfully" + + def printFailure(why): + print "change(s) NOT sent, something went wrong:" + print why + + d.addCallbacks(printSuccess, printFailure) + d.addBoth(lambda _: reactor.stop()) def hook(ui, repo, hooktype, node=None, source=None, **kwargs): diff --git a/hgroundup.py b/hgroundup.py --- a/hgroundup.py +++ b/hgroundup.py @@ -69,7 +69,9 @@ repourl = posixpath.join(ui.config('web', 'baseurl'), 'rev/') fromaddr = ui.config('hgroundup', 'fromaddr') toaddr = ui.config('hgroundup', 'toaddr') - mailrelay = ui.config('hgroundup', 'mailrelay', default='127.0.0.1') + mailrelay = ui.config('hgroundup', 'mailrelay', default='') + if not mailrelay: + mailrelay = ui.config('smtp', 'host', default='') for var in ('repourl', 'fromaddr', 'toaddr'): if not locals()[var]: raise RuntimeError( diff --git a/mail.py b/mail.py --- a/mail.py +++ b/mail.py @@ -2,6 +2,14 @@ Mercurial hook to send an email for each changeset to a specified address. For use as an "incoming" hook. + +To set the SMTP server to something other than localhost, add a [smtp] +section to your hgrc: + +[smtp] +host = mail.python.org +port = 25 + """ from email.header import Header @@ -20,16 +28,13 @@ CSET_URL = BASE + '%s/rev/%s' -def send(sub, sender, to, body): +def send(smtp, sub, sender, to, body): msg = MIMEMultipart() msg['Subject'] = Header(sub, 'utf8') msg['To'] = to msg['From'] = sender msg.attach(MIMEText(body, _subtype='plain', _charset='utf8')) - smtp = smtplib.SMTP() - smtp.connect() smtp.sendmail(sender, to, msg.as_string()) - smtp.close() def strip_bin_diffs(chunks): stripped = [] @@ -143,7 +148,12 @@ subj = prefixes + desc - send(subj, sender, to, '\n'.join(body) + '\n') + host = ui.config('smtp', 'host', '') + port = int(ui.config('smtp', 'port', 0)) + smtp = smtplib.SMTP(host, port) + send(smtp, subj, sender, to, '\n'.join(body) + '\n') + smtp.close() + ui.status('notified %s of incoming changeset %s\n' % (to, ctx)) return False -- Repository URL: http://hg.python.org/hooks From python-checkins at python.org Mon Jul 2 00:02:54 2012 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 2 Jul 2012 00:02:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE1MjEy?= =?utf-8?q?=3A_fix_typo_in_compiler_module_=28rename_SC=5FGLOBAL=5FEXPLICT?= =?utf-8?q?_to?= Message-ID: <3WQQZQ6CZNzPHN@mail.python.org> http://hg.python.org/cpython/rev/55130516d1d2 changeset: 77913:55130516d1d2 branch: 2.7 parent: 77906:65dd71ebf28f user: Antoine Pitrou date: Mon Jul 02 00:01:22 2012 +0200 summary: Issue #15212: fix typo in compiler module (rename SC_GLOBAL_EXPLICT to SC_GLOBAL_EXPLICIT). Patch by Arfrever. files: Lib/compiler/consts.py | 2 +- Lib/compiler/pycodegen.py | 4 ++-- Lib/compiler/symbols.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Lib/compiler/consts.py b/Lib/compiler/consts.py --- a/Lib/compiler/consts.py +++ b/Lib/compiler/consts.py @@ -5,7 +5,7 @@ SC_LOCAL = 1 SC_GLOBAL_IMPLICIT = 2 -SC_GLOBAL_EXPLICT = 3 +SC_GLOBAL_EXPLICIT = 3 SC_FREE = 4 SC_CELL = 5 SC_UNKNOWN = 6 diff --git a/Lib/compiler/pycodegen.py b/Lib/compiler/pycodegen.py --- a/Lib/compiler/pycodegen.py +++ b/Lib/compiler/pycodegen.py @@ -7,7 +7,7 @@ from compiler import ast, parse, walk, syntax from compiler import pyassem, misc, future, symbols -from compiler.consts import SC_LOCAL, SC_GLOBAL_IMPLICIT, SC_GLOBAL_EXPLICT, \ +from compiler.consts import SC_LOCAL, SC_GLOBAL_IMPLICIT, SC_GLOBAL_EXPLICIT, \ SC_FREE, SC_CELL from compiler.consts import (CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS, CO_NESTED, CO_GENERATOR, CO_FUTURE_DIVISION, @@ -283,7 +283,7 @@ self.emit(prefix + '_NAME', name) else: self.emit(prefix + '_FAST', name) - elif scope == SC_GLOBAL_EXPLICT: + elif scope == SC_GLOBAL_EXPLICIT: self.emit(prefix + '_GLOBAL', name) elif scope == SC_GLOBAL_IMPLICIT: if not self.optimized: diff --git a/Lib/compiler/symbols.py b/Lib/compiler/symbols.py --- a/Lib/compiler/symbols.py +++ b/Lib/compiler/symbols.py @@ -1,7 +1,7 @@ """Module symbol-table generator""" from compiler import ast -from compiler.consts import SC_LOCAL, SC_GLOBAL_IMPLICIT, SC_GLOBAL_EXPLICT, \ +from compiler.consts import SC_LOCAL, SC_GLOBAL_IMPLICIT, SC_GLOBAL_EXPLICIT, \ SC_FREE, SC_CELL, SC_UNKNOWN from compiler.misc import mangle import types @@ -90,7 +90,7 @@ The scope of a name could be LOCAL, GLOBAL, FREE, or CELL. """ if name in self.globals: - return SC_GLOBAL_EXPLICT + return SC_GLOBAL_EXPLICIT if name in self.cells: return SC_CELL if name in self.defs: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 2 05:00:22 2012 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 2 Jul 2012 05:00:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_The_StopIterat?= =?utf-8?q?ion_API_applies_to_both_tokenize=28=29_and_generate=5Ftokens=28?= =?utf-8?q?=29?= Message-ID: <3WQY9f2vqqzPMc@mail.python.org> http://hg.python.org/cpython/rev/366df7ba1616 changeset: 77914:366df7ba1616 branch: 2.7 user: Raymond Hettinger date: Sun Jul 01 20:00:09 2012 -0700 summary: The StopIteration API applies to both tokenize() and generate_tokens() files: Doc/library/tokenize.rst | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Doc/library/tokenize.rst b/Doc/library/tokenize.rst --- a/Doc/library/tokenize.rst +++ b/Doc/library/tokenize.rst @@ -29,7 +29,8 @@ which must be a callable object which provides the same interface as the :meth:`readline` method of built-in file objects (see section :ref:`bltin-file-objects`). Each call to the function should return one line - of input as a string. + of input as a string. Alternately, *readline* may be a callable object that + signals completion by raising :exc:`StopIteration`. The generator produces 5-tuples with these members: the token type; the token string; a 2-tuple ``(srow, scol)`` of ints specifying the row and column -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Mon Jul 2 06:01:23 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 02 Jul 2012 06:01:23 +0200 Subject: [Python-checkins] Daily reference leaks (a1c8302e6b27): sum=-1 Message-ID: results for a1c8302e6b27 on branch "default" -------------------------------------------- test_support leaked [0, 0, -1] references, sum=-1 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogRQIyRG', '-x'] From python-checkins at python.org Mon Jul 2 20:36:32 2012 From: python-checkins at python.org (brett.cannon) Date: Mon, 2 Jul 2012 20:36:32 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Closes_=2315030=3A_Make_im?= =?utf-8?q?portlib=2Eabc=2EPyPycLoader_respect_the_new_=2Epyc?= Message-ID: <3WQxxr4QhFzPHv@mail.python.org> http://hg.python.org/cpython/rev/b7463ec1980c changeset: 77915:b7463ec1980c parent: 77912:a1c8302e6b27 user: Brett Cannon date: Mon Jul 02 14:35:34 2012 -0400 summary: Closes #15030: Make importlib.abc.PyPycLoader respect the new .pyc file size header field. Thanks to Marc Abramowitz and Ronan Lamy for helping out with various parts of the patch. files: Doc/library/importlib.rst | 4 ++++ Lib/importlib/abc.py | 8 +++++++- Lib/importlib/test/source/test_abc_loader.py | 8 ++++++-- Misc/ACKS | 1 + Misc/NEWS | 3 +++ 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -455,6 +455,10 @@ :class:`PyLoader`. Do note that this solution will not support sourceless/bytecode-only loading; only source *and* bytecode loading. + .. versionchanged:: 3.3 + Updated to parse (but not use) the new source size field in bytecode + files when reading and to write out the field properly when writing. + .. method:: source_mtime(fullname) An abstract method which returns the modification time for the source diff --git a/Lib/importlib/abc.py b/Lib/importlib/abc.py --- a/Lib/importlib/abc.py +++ b/Lib/importlib/abc.py @@ -282,7 +282,12 @@ if len(raw_timestamp) < 4: raise EOFError("bad timestamp in {}".format(fullname)) pyc_timestamp = _bootstrap._r_long(raw_timestamp) - bytecode = data[8:] + raw_source_size = data[8:12] + if len(raw_source_size) != 4: + raise EOFError("bad file size in {}".format(fullname)) + # Source size is unused as the ABC does not provide a way to + # get the size of the source ahead of reading it. + bytecode = data[12:] # Verify that the magic number is valid. if imp.get_magic() != magic: raise ImportError( @@ -318,6 +323,7 @@ if not sys.dont_write_bytecode: data = bytearray(imp.get_magic()) data.extend(_bootstrap._w_long(source_timestamp)) + data.extend(_bootstrap._w_long(len(source) & 0xFFFFFFFF)) data.extend(marshal.dumps(code_object)) self.write_bytecode(fullname, data) return code_object diff --git a/Lib/importlib/test/source/test_abc_loader.py b/Lib/importlib/test/source/test_abc_loader.py --- a/Lib/importlib/test/source/test_abc_loader.py +++ b/Lib/importlib/test/source/test_abc_loader.py @@ -148,11 +148,12 @@ self.bytecode_to_path[name] = data['path'] magic = data.get('magic', imp.get_magic()) mtime = importlib._w_long(data.get('mtime', self.default_mtime)) + source_size = importlib._w_long(len(self.source) & 0xFFFFFFFF) if 'bc' in data: bc = data['bc'] else: bc = self.compile_bc(name) - self.module_bytecode[name] = magic + mtime + bc + self.module_bytecode[name] = magic + mtime + source_size + bc def compile_bc(self, name): source_path = self.module_paths.get(name, '') or '' @@ -344,7 +345,10 @@ self.assertEqual(magic, imp.get_magic()) mtime = importlib._r_long(mock.module_bytecode[name][4:8]) self.assertEqual(mtime, 1) - bc = mock.module_bytecode[name][8:] + source_size = mock.module_bytecode[name][8:12] + self.assertEqual(len(mock.source) & 0xFFFFFFFF, + importlib._r_long(source_size)) + bc = mock.module_bytecode[name][12:] self.assertEqual(bc, mock.compile_bc(name)) def test_module(self): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -587,6 +587,7 @@ Ross Lagerwall Cameron Laird Jean-Baptiste "Jiba" Lamy +Ronan Lamy Torsten Landschoff ?ukasz Langa Tino Lange diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -17,6 +17,9 @@ Library ------- +- Issue #15030: importlib.abc.PyPycLoader now supports the new source size + header field in .pyc files. + - Issue #5346: Preserve permissions of mbox, MMDF and Babyl mailbox files on flush(). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 2 20:53:15 2012 From: python-checkins at python.org (brett.cannon) Date: Mon, 2 Jul 2012 20:53:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315210=3A_If_=5Ffr?= =?utf-8?q?ozen=5Fimportlib_is_not_found_in_sys=2Emodules_by?= Message-ID: <3WQyK70dd5zPCD@mail.python.org> http://hg.python.org/cpython/rev/818db871d29a changeset: 77916:818db871d29a user: Brett Cannon date: Mon Jul 02 14:53:10 2012 -0400 summary: Issue #15210: If _frozen_importlib is not found in sys.modules by importlib.__init__, then catch the KeyError raised, not ImportError. files: Lib/importlib/__init__.py | 2 +- Lib/importlib/test/test_api.py | 23 +++++++++++++++++++++- Misc/NEWS | 3 ++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Lib/importlib/__init__.py b/Lib/importlib/__init__.py --- a/Lib/importlib/__init__.py +++ b/Lib/importlib/__init__.py @@ -7,7 +7,7 @@ try: _bootstrap = sys.modules['_frozen_importlib'] -except ImportError: +except KeyError: from . import _bootstrap _bootstrap._setup(sys, imp) else: diff --git a/Lib/importlib/test/test_api.py b/Lib/importlib/test/test_api.py --- a/Lib/importlib/test/test_api.py +++ b/Lib/importlib/test/test_api.py @@ -160,9 +160,30 @@ importlib.invalidate_caches() # Shouldn't trigger an exception. +class FrozenImportlibTests(unittest.TestCase): + + def test_no_frozen_importlib(self): + # Should be able to import w/o _frozen_importlib being defined. + modules = {} + for name in ('importlib', 'importlib.__init__', 'importlib._bootstrap', + '_frozen_importlib'): + try: + modules[name] = sys.modules[name] + del sys.modules[name] + except KeyError: + continue + modules['_frozen_importlib'] = None + import importlib + for name, module in modules.items(): + sys.modules[name] = module + + def test_main(): from test.support import run_unittest - run_unittest(ImportModuleTests, FindLoaderTests, InvalidateCacheTests) + run_unittest(ImportModuleTests, + FindLoaderTests, + InvalidateCacheTests, + FrozenImportlibTests) if __name__ == '__main__': diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -17,6 +17,9 @@ Library ------- +- Issue #15210: Catch KeyError when imprortlib.__init__ can't find + _frozen_importlib in sys.modules, not ImportError. + - Issue #15030: importlib.abc.PyPycLoader now supports the new source size header field in .pyc files. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 2 21:13:18 2012 From: python-checkins at python.org (brett.cannon) Date: Mon, 2 Jul 2012 21:13:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315166=3A_Re-imple?= =?utf-8?q?ment_imp=2Eget=5Ftag=28=29_using_sys=2Eimplementation=2E?= Message-ID: <3WQymG5zqqzNC6@mail.python.org> http://hg.python.org/cpython/rev/b36bed82c9d0 changeset: 77917:b36bed82c9d0 user: Brett Cannon date: Mon Jul 02 15:13:11 2012 -0400 summary: Issue #15166: Re-implement imp.get_tag() using sys.implementation. Also eliminates some C code in Python/import.c as well. Patch by Eric Snow with verification by comparing against another patch from Jeff Knupp. files: Lib/imp.py | 7 +- Lib/importlib/_bootstrap.py | 2 +- Misc/NEWS | 2 + Python/import.c | 38 +- Python/importlib.h | 340 ++++++++++++----------- 5 files changed, 194 insertions(+), 195 deletions(-) diff --git a/Lib/imp.py b/Lib/imp.py --- a/Lib/imp.py +++ b/Lib/imp.py @@ -11,7 +11,7 @@ init_builtin, init_frozen, is_builtin, is_frozen, _fix_co_filename, extension_suffixes) # Could move out of _imp, but not worth the code -from _imp import get_magic, get_tag +from _imp import get_magic from importlib._bootstrap import new_module from importlib._bootstrap import cache_from_source @@ -37,6 +37,11 @@ IMP_HOOK = 9 +def get_tag(): + """Return the magic tag for .pyc or .pyo files.""" + return sys.implementation.cache_tag + + def get_suffixes(): warnings.warn('imp.get_suffixes() is deprecated; use the constants ' 'defined on importlib.machinery instead', diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -1452,7 +1452,7 @@ # Constants setattr(self_module, '_relax_case', _make_relax_case()) setattr(self_module, '_MAGIC_NUMBER', _imp_module.get_magic()) - setattr(self_module, '_TAG', _imp.get_tag()) + setattr(self_module, '_TAG', sys.implementation.cache_tag) if builtin_os == 'nt': SOURCE_SUFFIXES.append('.pyw') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -17,6 +17,8 @@ Library ------- +- Issue #15166: Implement imp.get_tag() using sys.implementation.cache_tag. + - Issue #15210: Catch KeyError when imprortlib.__init__ can't find _frozen_importlib in sys.modules, not ImportError. diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -112,23 +112,11 @@ /* MAGIC must change whenever the bytecode emitted by the compiler may no longer be understood by older implementations of the eval loop (usually due to the addition of new opcodes) - TAG must change for each major Python release. The magic number will take - care of any bytecode changes that occur during development. */ -#define QUOTE(arg) #arg -#define STRIFY(name) QUOTE(name) -#define MAJOR STRIFY(PY_MAJOR_VERSION) -#define MINOR STRIFY(PY_MINOR_VERSION) #define MAGIC (3230 | ((long)'\r'<<16) | ((long)'\n'<<24)) -#define TAG "cpython-" MAJOR MINOR; #define CACHEDIR "__pycache__" /* Current magic word and string tag as globals. */ static long pyc_magic = MAGIC; -static const char *pyc_tag = TAG; -#undef QUOTE -#undef STRIFY -#undef MAJOR -#undef MINOR /* See _PyImport_FixupExtensionObject() below */ static PyObject *extensions = NULL; @@ -534,9 +522,22 @@ const char * PyImport_GetMagicTag(void) { - return pyc_tag; + PyObject *impl, *tag; + const char *raw_tag; + + /* We could also pull it from imp or importlib. */ + impl = PySys_GetObject("implementation"); + if (impl == NULL) + return NULL; + tag = PyObject_GetAttrString(impl, "cache_tag"); + if (tag == NULL) + return NULL; + raw_tag = PyUnicode_DATA(tag); + Py_DECREF(tag); + return raw_tag; } + /* Magic for extension modules (built-in as well as dynamically loaded). To prevent initializing an extension module more than once, we keep a static dictionary 'extensions' keyed by module name @@ -1847,12 +1848,6 @@ } static PyObject * -imp_get_tag(PyObject *self, PyObject *noargs) -{ - return PyUnicode_FromString(pyc_tag); -} - -static PyObject * imp_extension_suffixes(PyObject *self, PyObject *noargs) { PyObject *list; @@ -2002,10 +1997,6 @@ "get_magic() -> string\n\ Return the magic number for .pyc or .pyo files."); -PyDoc_STRVAR(doc_get_tag, -"get_tag() -> string\n\ -Return the magic tag for .pyc or .pyo files."); - PyDoc_STRVAR(doc_extension_suffixes, "extension_suffixes() -> list of strings\n\ Returns the list of file suffixes used to identify extension modules."); @@ -2029,7 +2020,6 @@ static PyMethodDef imp_methods[] = { {"get_magic", imp_get_magic, METH_NOARGS, doc_get_magic}, - {"get_tag", imp_get_tag, METH_NOARGS, doc_get_tag}, {"extension_suffixes", imp_extension_suffixes, METH_NOARGS, doc_extension_suffixes}, {"lock_held", imp_lock_held, METH_NOARGS, doc_lock_held}, diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: http://hg.python.org/cpython From brett at python.org Mon Jul 2 22:00:21 2012 From: brett at python.org (Brett Cannon) Date: Mon, 2 Jul 2012 16:00:21 -0400 Subject: [Python-checkins] cpython: Issue #15166: Re-implement imp.get_tag() using sys.implementation In-Reply-To: References: Message-ID: On Mon, Jul 2, 2012 at 3:34 PM, Amaury Forgeot d'Arc wrote: > > + tag = PyObject_GetAttrString(impl, "cache_tag"); > > + if (tag == NULL) > > + return NULL; > > + raw_tag = PyUnicode_DATA(tag); > > + Py_DECREF(tag); > > + return raw_tag; > > This code will crash if the tag is not a string, e.g. after > "sys.implementation.cache_tag = 42". > And I am a bit worried about the returned pointer. Is it borrowed from > the Python object? Can't the C caller keep the value? > Since this is a constant in sysmodule.c (the TAG macro there) it would probably be best to expose the const char * from there in some global value and just directly return it from this function. -------------- next part -------------- An HTML attachment was scrubbed... URL: From python-checkins at python.org Mon Jul 2 22:30:08 2012 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 2 Jul 2012 22:30:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Do_HTML_escaping_after_the?= =?utf-8?q?_tokenization_step=2E?= Message-ID: <3WR0Sw3dGczN3T@mail.python.org> http://hg.python.org/cpython/rev/671894ae19a2 changeset: 77918:671894ae19a2 user: Raymond Hettinger date: Mon Jul 02 13:29:57 2012 -0700 summary: Do HTML escaping after the tokenization step. files: Tools/scripts/pycolorize.py | 37 +++++++++++++++--------- 1 files changed, 23 insertions(+), 14 deletions(-) diff --git a/Tools/scripts/pycolorize.py b/Tools/scripts/pycolorize.py --- a/Tools/scripts/pycolorize.py +++ b/Tools/scripts/pycolorize.py @@ -6,22 +6,29 @@ import keyword, tokenize, cgi, functools -def insert(s, i, text): - 'Insert text at position i in string s' - return s[:i] + text + s[i:] - def is_builtin(s): 'Return True if s is the name of a builtin' return s in vars(__builtins__) +def escape_range(lines, start, end): + 'Return escaped content from a range of lines between start and end' + (srow, scol), (erow, ecol) = start, end + if srow == erow: + rows = [lines[srow-1][scol:ecol]] + else: + rows = [lines[srow-1][scol:]] + lines[srow: erow-1] + [lines[erow-1][:ecol]] + return cgi.escape(''.join(rows)), end + def colorize(source): 'Convert Python source code to an HTML fragment with colorized markup' - text = cgi.escape(source) - lines = text.splitlines(True) + lines = source.splitlines(True) + lines.append('') readline = functools.partial(next, iter(lines), '') actions = [] kind = tok_str = '' tok_type = tokenize.COMMENT + written = (1, 0) + result = [] for tok in tokenize.generate_tokens(readline): prev_tok_type, prev_tok_str = tok_type, tok_str tok_type, tok_str, (srow, scol), (erow, ecol), logical_lineno = tok @@ -44,15 +51,17 @@ elif is_builtin(tok_str) and prev_tok_str != '.': kind = 'builtin' if kind: - actions.append(((srow, scol), (erow, ecol), kind)) + line_upto_token, written = escape_range(lines, written, (srow, scol)) + line_thru_token, written = escape_range(lines, written, (erow, ecol)) + result += [line_upto_token, '' % kind, + line_thru_token, ''] + else: + line_thru_token, written = escape_range(lines, written, (erow, ecol)) + result += [line_thru_token] - for (srow, scol), (erow, ecol), kind in reversed(actions): - lines[erow-1] = insert(lines[erow-1], ecol, '
') - lines[srow-1] = insert(lines[srow-1], scol, '' % kind) - - lines.insert(0, '
\n')
-    lines.append('
\n') - return ''.join(lines) + result.insert(0, '
\n')
+    result.append('
\n') + return ''.join(result) default_css = { '.comment': '{color: crimson;}', -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 2 22:56:28 2012 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 2 Jul 2012 22:56:28 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Clean-up_unused_variable?= Message-ID: <3WR13J1HKQzPC8@mail.python.org> http://hg.python.org/cpython/rev/f0955d95ac02 changeset: 77919:f0955d95ac02 user: Raymond Hettinger date: Mon Jul 02 13:54:33 2012 -0700 summary: Clean-up unused variable files: Tools/scripts/pycolorize.py | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Tools/scripts/pycolorize.py b/Tools/scripts/pycolorize.py --- a/Tools/scripts/pycolorize.py +++ b/Tools/scripts/pycolorize.py @@ -24,7 +24,6 @@ lines = source.splitlines(True) lines.append('') readline = functools.partial(next, iter(lines), '') - actions = [] kind = tok_str = '' tok_type = tokenize.COMMENT written = (1, 0) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 3 02:17:35 2012 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 3 Jul 2012 02:17:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Use_new-style_string_forma?= =?utf-8?q?tting_for_the_HTML_template?= Message-ID: <3WR5WM5pVNzNX4@mail.python.org> http://hg.python.org/cpython/rev/2367ec12da2d changeset: 77920:2367ec12da2d user: Raymond Hettinger date: Mon Jul 02 17:17:16 2012 -0700 summary: Use new-style string formatting for the HTML template files: Tools/scripts/pycolorize.py | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Tools/scripts/pycolorize.py b/Tools/scripts/pycolorize.py --- a/Tools/scripts/pycolorize.py +++ b/Tools/scripts/pycolorize.py @@ -79,13 +79,13 @@ - %s + {title} -%s +{body} ''' @@ -95,7 +95,7 @@ css_str = '\n'.join(['%s %s' % item for item in css.items()]) result = colorize(source) title = cgi.escape(title) - return html % (title, css_str, result) + return html.format(title=title, css=css_str, body=result) if __name__ == '__main__': -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Tue Jul 3 05:54:42 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 03 Jul 2012 05:54:42 +0200 Subject: [Python-checkins] Daily reference leaks (2367ec12da2d): sum=0 Message-ID: results for 2367ec12da2d on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogWCGHZl', '-x'] From python-checkins at python.org Tue Jul 3 06:09:08 2012 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 3 Jul 2012 06:09:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Make_it_easier?= =?utf-8?q?_to_search_for_the_grouper=28=29_recipe=2E?= Message-ID: <3WRBfX2mWbzN2y@mail.python.org> http://hg.python.org/cpython/rev/d32f21d87363 changeset: 77921:d32f21d87363 branch: 2.7 parent: 77914:366df7ba1616 user: Raymond Hettinger date: Mon Jul 02 21:08:45 2012 -0700 summary: Make it easier to search for the grouper() recipe. files: Doc/library/itertools.rst | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -733,7 +733,8 @@ return izip(a, b) def grouper(n, iterable, fillvalue=None): - "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx" + "Collect data into fixed-length chunks or blocks" + # grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx" args = [iter(iterable)] * n return izip_longest(fillvalue=fillvalue, *args) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 3 07:14:02 2012 From: python-checkins at python.org (eric.araujo) Date: Tue, 3 Jul 2012 07:14:02 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Avoid_SyntaxEr?= =?utf-8?q?ror_in_script_using_print_function?= Message-ID: <3WRD5Q3rn2zN37@mail.python.org> http://hg.python.org/cpython/rev/9a57c9d4b0b4 changeset: 77922:9a57c9d4b0b4 branch: 2.7 parent: 77914:366df7ba1616 user: ?ric Araujo date: Mon Jul 02 17:45:10 2012 -0400 summary: Avoid SyntaxError in script using print function files: Tools/scripts/byext.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Tools/scripts/byext.py b/Tools/scripts/byext.py --- a/Tools/scripts/byext.py +++ b/Tools/scripts/byext.py @@ -2,6 +2,8 @@ """Show file statistics by extension.""" +from __future__ import print_function + import os import sys -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 3 07:14:05 2012 From: python-checkins at python.org (eric.araujo) Date: Tue, 3 Jul 2012 07:14:05 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Adapt_mentions?= =?utf-8?q?_of_future_changes_in_doc?= Message-ID: <3WRD5T0PdrzN3d@mail.python.org> http://hg.python.org/cpython/rev/c1945703c7cb changeset: 77923:c1945703c7cb branch: 2.7 user: ?ric Araujo date: Mon Jul 02 17:46:40 2012 -0400 summary: Adapt mentions of future changes in doc files: Doc/distutils/sourcedist.rst | 3 +-- Doc/library/csv.rst | 2 +- Doc/library/mailbox.rst | 2 +- Doc/library/parser.rst | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Doc/distutils/sourcedist.rst b/Doc/distutils/sourcedist.rst --- a/Doc/distutils/sourcedist.rst +++ b/Doc/distutils/sourcedist.rst @@ -51,8 +51,7 @@ of the standard Python library since Python 1.6) (4) - requires the :program:`compress` program. Notice that this format is now - pending for deprecation and will be removed in the future versions of Python. + requires the :program:`compress` program. When using any ``tar`` format (``gztar``, ``bztar``, ``ztar`` or ``tar``) under Unix, you can specify the ``owner`` and ``group`` names diff --git a/Doc/library/csv.rst b/Doc/library/csv.rst --- a/Doc/library/csv.rst +++ b/Doc/library/csv.rst @@ -40,7 +40,7 @@ This version of the :mod:`csv` module doesn't support Unicode input. Also, there are currently some issues regarding ASCII NUL characters. Accordingly, all input should be UTF-8 or printable ASCII to be safe; see the examples in - section :ref:`csv-examples`. These restrictions will be removed in the future. + section :ref:`csv-examples`. .. seealso:: diff --git a/Doc/library/mailbox.rst b/Doc/library/mailbox.rst --- a/Doc/library/mailbox.rst +++ b/Doc/library/mailbox.rst @@ -1513,7 +1513,7 @@ mailboxes, such as adding or removing message, and do not provide classes to represent format-specific message properties. For backward compatibility, the older mailbox classes are still available, but the newer classes should be used -in preference to them. The old classes will be removed in Python 3. +in preference to them. The old classes have been removed in Python 3. Older mailbox objects support only iteration and provide a single public method: diff --git a/Doc/library/parser.rst b/Doc/library/parser.rst --- a/Doc/library/parser.rst +++ b/Doc/library/parser.rst @@ -34,7 +34,7 @@ replaced by "ast"; this is a legacy from the time when there was no other AST and has nothing to do with the AST found in Python 2.5. This is also the reason for the functions' keyword arguments being called *ast*, not *st*. - The "ast" functions will be removed in Python 3. + The "ast" functions have been removed in Python 3. There are a few things to note about this module which are important to making use of the data structures created. This is not a tutorial on editing the parse -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 3 07:14:06 2012 From: python-checkins at python.org (eric.araujo) Date: Tue, 3 Jul 2012 07:14:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Use_source_rol?= =?utf-8?q?e_to_get_links_to_files?= Message-ID: <3WRD5V37NhzN7D@mail.python.org> http://hg.python.org/cpython/rev/6ccd4554fa48 changeset: 77924:6ccd4554fa48 branch: 2.7 user: ?ric Araujo date: Mon Jul 02 17:46:56 2012 -0400 summary: Use source role to get links to files files: Doc/library/fpectl.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/fpectl.rst b/Doc/library/fpectl.rst --- a/Doc/library/fpectl.rst +++ b/Doc/library/fpectl.rst @@ -113,8 +113,8 @@ .. seealso:: Some files in the source distribution may be interesting in learning more about - how this module operates. The include file :file:`Include/pyfpe.h` discusses the - implementation of this module at some length. :file:`Modules/fpetestmodule.c` + how this module operates. The include file :source:`Include/pyfpe.h` discusses the + implementation of this module at some length. :source:`Modules/fpetestmodule.c` gives several examples of use. Many additional examples can be found in - :file:`Objects/floatobject.c`. + :source:`Objects/floatobject.c`. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 3 07:14:08 2012 From: python-checkins at python.org (eric.araujo) Date: Tue, 3 Jul 2012 07:14:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSWdub3JlIC5uZnMq?= =?utf-8?q?_files_in_distutils_=28=237719=29=2E?= Message-ID: <3WRD5X0DxXzMxM@mail.python.org> http://hg.python.org/cpython/rev/a56cebff113a changeset: 77925:a56cebff113a branch: 2.7 user: ?ric Araujo date: Tue Jul 03 01:12:42 2012 -0400 summary: Ignore .nfs* files in distutils (#7719). These files are created by some NFS clients a file is edited and removed concurrently (see added link in doc for more info). If such a file is removed between distutils calls listdir and copy, it will get confused. Other special files are ignored in sdist (namely VCS directories), but this has to be filtered out earlier. files: Doc/distutils/apiref.rst | 8 +++++- Lib/distutils/dir_util.py | 4 +++ Lib/distutils/tests/test_dir_util.py | 18 ++++++++++++++++ Lib/distutils/tests/test_sdist.py | 7 +++-- Misc/ACKS | 1 + Misc/NEWS | 3 ++ 6 files changed, 36 insertions(+), 5 deletions(-) diff --git a/Doc/distutils/apiref.rst b/Doc/distutils/apiref.rst --- a/Doc/distutils/apiref.rst +++ b/Doc/distutils/apiref.rst @@ -973,8 +973,8 @@ Copy an entire directory tree *src* to a new location *dst*. Both *src* and *dst* must be directory names. If *src* is not a directory, raise :exc:`DistutilsFileError`. If *dst* does not exist, it is created with - :func:`mkpath`. The end result of the copy is that every file in *src* is - copied to *dst*, and directories under *src* are recursively copied to *dst*. + :func:`mkpath`. The end result of the copy is that every file in *src* is + copied to *dst*, and directories under *src* are recursively copied to *dst*. Return the list of files that were copied or might have been copied, using their output name. The return value is unaffected by *update* or *dry_run*: it is simply the list of all files under *src*, with the names changed to be under @@ -987,6 +987,10 @@ destination of the symlink will be copied. *update* and *verbose* are the same as for :func:`copy_file`. + Files in *src* that begin with :file:`.nfs` are skipped (more information on + these files is available in answer D2 of the `NFS FAQ page + `_. + .. function:: remove_tree(directory[, verbose=0, dry_run=0]) diff --git a/Lib/distutils/dir_util.py b/Lib/distutils/dir_util.py --- a/Lib/distutils/dir_util.py +++ b/Lib/distutils/dir_util.py @@ -144,6 +144,10 @@ src_name = os.path.join(src, n) dst_name = os.path.join(dst, n) + if n.startswith('.nfs'): + # skip NFS rename files + continue + if preserve_symlinks and os.path.islink(src_name): link_dest = os.readlink(src_name) if verbose >= 1: diff --git a/Lib/distutils/tests/test_dir_util.py b/Lib/distutils/tests/test_dir_util.py --- a/Lib/distutils/tests/test_dir_util.py +++ b/Lib/distutils/tests/test_dir_util.py @@ -101,6 +101,24 @@ remove_tree(self.root_target, verbose=0) remove_tree(self.target2, verbose=0) + def test_copy_tree_skips_nfs_temp_files(self): + mkpath(self.target, verbose=0) + + a_file = os.path.join(self.target, 'ok.txt') + nfs_file = os.path.join(self.target, '.nfs123abc') + for f in a_file, nfs_file: + fh = open(f, 'w') + try: + fh.write('some content') + finally: + fh.close() + + copy_tree(self.target, self.target2) + self.assertEqual(os.listdir(self.target2), ['ok.txt']) + + remove_tree(self.root_target, verbose=0) + remove_tree(self.target2, verbose=0) + def test_ensure_relative(self): if os.sep == '/': self.assertEqual(ensure_relative('/home/foo'), 'home/foo') diff --git a/Lib/distutils/tests/test_sdist.py b/Lib/distutils/tests/test_sdist.py --- a/Lib/distutils/tests/test_sdist.py +++ b/Lib/distutils/tests/test_sdist.py @@ -91,9 +91,8 @@ @unittest.skipUnless(zlib, "requires zlib") def test_prune_file_list(self): - # this test creates a package with some vcs dirs in it - # and launch sdist to make sure they get pruned - # on all systems + # this test creates a project with some VCS dirs and an NFS rename + # file, then launches sdist to check they get pruned on all systems # creating VCS directories with some files in them os.mkdir(join(self.tmp_dir, 'somecode', '.svn')) @@ -107,6 +106,8 @@ self.write_file((self.tmp_dir, 'somecode', '.git', 'ok'), 'xxx') + self.write_file((self.tmp_dir, 'somecode', '.nfs0001'), 'xxx') + # now building a sdist dist, cmd = self.get_cmd() diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -688,6 +688,7 @@ Brian Quinlan Anders Qvist Burton Radons +Jeff Ramnani Brodie Rao Antti Rasinen Sridhar Ratnakumar diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -14,6 +14,9 @@ longer raised due to a read system call returning EINTR from within these methods. +- Issue #7719: Make distutils ignore ``.nfs*`` files instead of choking later + on. Initial patch by SilentGhost and Jeff Ramnani. + - Issue #10053: Don't close FDs when FileIO.__init__ fails. Loosely based on the work by Hirokazu Yamamoto. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 3 07:14:09 2012 From: python-checkins at python.org (eric.araujo) Date: Tue, 3 Jul 2012 07:14:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMi43IC0+IDIuNyk6?= =?utf-8?q?_Branch_merge?= Message-ID: <3WRD5Y355rzMxl@mail.python.org> http://hg.python.org/cpython/rev/11fb5b7be8cd changeset: 77926:11fb5b7be8cd branch: 2.7 parent: 77925:a56cebff113a parent: 77921:d32f21d87363 user: ?ric Araujo date: Tue Jul 03 01:13:40 2012 -0400 summary: Branch merge files: Doc/library/itertools.rst | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -733,7 +733,8 @@ return izip(a, b) def grouper(n, iterable, fillvalue=None): - "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx" + "Collect data into fixed-length chunks or blocks" + # grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx" args = [iter(iterable)] * n return izip_longest(fillvalue=fillvalue, *args) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 3 07:23:54 2012 From: python-checkins at python.org (eric.araujo) Date: Tue, 3 Jul 2012 07:23:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogQ3JlYXRlIH4vLnB5?= =?utf-8?q?pirc_securely_=28=2313512=29=2E?= Message-ID: <3WRDJp1jQSzN7R@mail.python.org> http://hg.python.org/cpython/rev/f833e7ec4de1 changeset: 77927:f833e7ec4de1 branch: 2.7 user: ?ric Araujo date: Tue Jul 03 01:23:46 2012 -0400 summary: Create ~/.pypirc securely (#13512). There was a window between the write and the chmod where the user?s password would be exposed, depending on default permissions. Philip Jenvey?s patch fixes it. files: Lib/distutils/config.py | 2 +- Misc/ACKS | 1 + Misc/NEWS | 3 +++ 3 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Lib/distutils/config.py b/Lib/distutils/config.py --- a/Lib/distutils/config.py +++ b/Lib/distutils/config.py @@ -42,7 +42,7 @@ def _store_pypirc(self, username, password): """Creates a default .pypirc file.""" rc = self._get_rc_file() - f = open(rc, 'w') + f = os.fdopen(os.open(rc, os.O_CREAT | os.O_WRONLY, 0600), 'w') try: f.write(DEFAULT_PYPIRC % (username, password)) finally: diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -412,6 +412,7 @@ Thomas Jarosch Drew Jenkins Flemming Kj?r Jensen +Philip Jenvey Jiba Orjan Johansen Fredrik Johansson diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -14,6 +14,9 @@ longer raised due to a read system call returning EINTR from within these methods. +- Issue #13512: Create ~/.pypirc securely (CVE-2011-4944). Initial patch by + Philip Jenvey, tested by Mageia and Debian. + - Issue #7719: Make distutils ignore ``.nfs*`` files instead of choking later on. Initial patch by SilentGhost and Jeff Ramnani. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 3 09:12:50 2012 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 3 Jul 2012 09:12:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Minor_cleanups?= Message-ID: <3WRGkV3ZrFzMrq@mail.python.org> http://hg.python.org/cpython/rev/4d320cd4c6fe changeset: 77928:4d320cd4c6fe parent: 77920:2367ec12da2d user: Raymond Hettinger date: Tue Jul 03 00:12:27 2012 -0700 summary: Minor cleanups files: Tools/scripts/README | 2 +- Tools/scripts/pycolorize.py | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Tools/scripts/README b/Tools/scripts/README --- a/Tools/scripts/README +++ b/Tools/scripts/README @@ -28,6 +28,7 @@ google.py Open a webbrowser with Google gprof2html.py Transform gprof(1) output into useful HTML h2py.py Translate #define's into Python assignments +highlight.py Python syntax highlighting with HTML output idle3 Main program to start IDLE ifdef.py Remove #if(n)def groups from C sources lfcr.py Change LF line endings to CRLF (Unix to Windows) @@ -47,7 +48,6 @@ pickle2db.py Load a pickle generated by db2pickle.py to a database pindent.py Indent Python code, giving block-closing comments ptags.py Create vi tags file for Python modules -pycolorize.py Python syntax highlighting with HTML output pydoc3 Python documentation browser pysource.py Find Python source files redemo.py Basic regular expression demonstration facility diff --git a/Tools/scripts/pycolorize.py b/Tools/scripts/highlight.py rename from Tools/scripts/pycolorize.py rename to Tools/scripts/highlight.py --- a/Tools/scripts/pycolorize.py +++ b/Tools/scripts/highlight.py @@ -21,7 +21,7 @@ def colorize(source): 'Convert Python source code to an HTML fragment with colorized markup' - lines = source.splitlines(True) + lines = source.splitlines(keepends=True) lines.append('') readline = functools.partial(next, iter(lines), '') kind = tok_str = '' @@ -31,7 +31,7 @@ for tok in tokenize.generate_tokens(readline): prev_tok_type, prev_tok_str = tok_type, tok_str tok_type, tok_str, (srow, scol), (erow, ecol), logical_lineno = tok - kind, prev_kind = '', kind + kind = '' if tok_type == tokenize.COMMENT: kind = 'comment' elif tok_type == tokenize.OP and tok_str[:1] not in '{}[](),.:;': @@ -102,22 +102,22 @@ import sys, argparse, webbrowser, os parser = argparse.ArgumentParser( - description = 'Convert Python source code to colorized HTML') - parser.add_argument('sourcefile', metavar = 'SOURCEFILE', nargs = 1, + description = 'Convert Python source code to colorized HTML') + parser.add_argument('sourcefile', metavar = 'SOURCEFILE', help = 'File containing Python sourcecode') parser.add_argument('-b', '--browser', action = 'store_true', help = 'launch a browser to show results') - parser.add_argument('-s', '--standalone', action = 'store_true', - help = 'show a standalone snippet rather than a complete webpage') + parser.add_argument('-s', '--section', action = 'store_true', + help = 'show an HTML section rather than a complete webpage') args = parser.parse_args() - if args.browser and args.standalone: - parser.error('The -s/--standalone option is incompatible with ' + if args.browser and args.section: + parser.error('The -s/--section option is incompatible with ' 'the -b/--browser option') - sourcefile = args.sourcefile[0] + sourcefile = args.sourcefile with open(sourcefile) as f: page = f.read() - html = colorize(page) if args.standalone else build_page(page, title=sourcefile) + html = colorize(page) if args.section else build_page(page, title=sourcefile) if args.browser: htmlfile = os.path.splitext(os.path.basename(sourcefile))[0] + '.html' with open(htmlfile, 'w') as f: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 3 09:16:06 2012 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 3 Jul 2012 09:16:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_keyword_argument?= Message-ID: <3WRGpG3RbFzMrq@mail.python.org> http://hg.python.org/cpython/rev/d7bed032520b changeset: 77929:d7bed032520b user: Raymond Hettinger date: Tue Jul 03 00:15:59 2012 -0700 summary: Fix keyword argument files: Tools/scripts/highlight.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Tools/scripts/highlight.py b/Tools/scripts/highlight.py --- a/Tools/scripts/highlight.py +++ b/Tools/scripts/highlight.py @@ -21,7 +21,7 @@ def colorize(source): 'Convert Python source code to an HTML fragment with colorized markup' - lines = source.splitlines(keepends=True) + lines = source.splitlines(True) lines.append('') readline = functools.partial(next, iter(lines), '') kind = tok_str = '' -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 3 13:05:09 2012 From: python-checkins at python.org (jesus.cea) Date: Tue, 3 Jul 2012 13:05:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE2Njc6?= =?utf-8?q?_Unused_variable_warning_in_Non-Windows?= Message-ID: <3WRMtY5ZkczNdv@mail.python.org> http://hg.python.org/cpython/rev/7ccc2cea6969 changeset: 77930:7ccc2cea6969 branch: 2.7 parent: 77927:f833e7ec4de1 user: Jesus Cea date: Tue Jul 03 13:04:55 2012 +0200 summary: Issue #1667: Unused variable warning in Non-Windows files: Parser/myreadline.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Parser/myreadline.c b/Parser/myreadline.c --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -40,7 +40,10 @@ my_fgets(char *buf, int len, FILE *fp) { char *p; +#ifdef MS_WINDOWS int i; +#endif + while (1) { if (PyOS_InputHook != NULL) (void)(PyOS_InputHook)(); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 3 13:08:49 2012 From: python-checkins at python.org (jesus.cea) Date: Tue, 3 Jul 2012 13:08:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Backed_out_cha?= =?utf-8?q?ngeset_7ccc2cea6969?= Message-ID: <3WRMyn1jNtzNf1@mail.python.org> http://hg.python.org/cpython/rev/7da1951df27a changeset: 77931:7da1951df27a branch: 2.7 user: Jesus Cea date: Tue Jul 03 13:06:45 2012 +0200 summary: Backed out changeset 7ccc2cea6969 files: Parser/myreadline.c | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diff --git a/Parser/myreadline.c b/Parser/myreadline.c --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -40,10 +40,7 @@ my_fgets(char *buf, int len, FILE *fp) { char *p; -#ifdef MS_WINDOWS int i; -#endif - while (1) { if (PyOS_InputHook != NULL) (void)(PyOS_InputHook)(); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 3 13:08:51 2012 From: python-checkins at python.org (jesus.cea) Date: Tue, 3 Jul 2012 13:08:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE2Nzc6?= =?utf-8?q?_Unused_variable_warning_in_Non-Windows?= Message-ID: <3WRMyq09p5zNfs@mail.python.org> http://hg.python.org/cpython/rev/2de5c9ced464 changeset: 77932:2de5c9ced464 branch: 2.7 user: Jesus Cea date: Tue Jul 03 13:07:58 2012 +0200 summary: Issue #1677: Unused variable warning in Non-Windows files: Parser/myreadline.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Parser/myreadline.c b/Parser/myreadline.c --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -40,7 +40,10 @@ my_fgets(char *buf, int len, FILE *fp) { char *p; +#ifdef MS_WINDOWS int i; +#endif + while (1) { if (PyOS_InputHook != NULL) (void)(PyOS_InputHook)(); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 3 13:18:48 2012 From: python-checkins at python.org (jesus.cea) Date: Tue, 3 Jul 2012 13:18:48 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE2Nzc6?= =?utf-8?q?_Unused_variable_warning_in_Non-Windows?= Message-ID: <3WRNBJ1g37zMZK@mail.python.org> http://hg.python.org/cpython/rev/4de541fbdd58 changeset: 77933:4de541fbdd58 branch: 3.2 parent: 77908:031862264304 user: Jesus Cea date: Tue Jul 03 13:15:03 2012 +0200 summary: Issue #1677: Unused variable warning in Non-Windows files: Parser/myreadline.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Parser/myreadline.c b/Parser/myreadline.c --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -36,8 +36,11 @@ my_fgets(char *buf, int len, FILE *fp) { char *p; + int err; +#ifdef MS_WINDOWS int i; - int err; +#endif + while (1) { if (PyOS_InputHook != NULL) (void)(PyOS_InputHook)(); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 3 13:18:49 2012 From: python-checkins at python.org (jesus.cea) Date: Tue, 3 Jul 2012 13:18:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_NULL_MERGE=3A_Issue_=231677=3A_Unused_variable_warning_i?= =?utf-8?q?n_Non-Windows?= Message-ID: <3WRNBK5dbdzNHT@mail.python.org> http://hg.python.org/cpython/rev/7937aa6b7e92 changeset: 77934:7937aa6b7e92 parent: 77929:d7bed032520b parent: 77933:4de541fbdd58 user: Jesus Cea date: Tue Jul 03 13:18:30 2012 +0200 summary: NULL MERGE: Issue #1677: Unused variable warning in Non-Windows files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 3 17:34:23 2012 From: python-checkins at python.org (vinay.sajip) Date: Tue, 3 Jul 2012 17:34:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_15241=3A_Improved_si?= =?utf-8?q?te=2Epy_documentation_relating_to_venvs=2E?= Message-ID: <3WRTsC3SbxzNJV@mail.python.org> http://hg.python.org/cpython/rev/4a39ea2c1b11 changeset: 77935:4a39ea2c1b11 user: Vinay Sajip date: Tue Jul 03 16:33:57 2012 +0100 summary: Issue 15241: Improved site.py documentation relating to venvs. files: Doc/library/site.rst | 9 +++++++++ Lib/site.py | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Doc/library/site.rst b/Doc/library/site.rst --- a/Doc/library/site.rst +++ b/Doc/library/site.rst @@ -38,6 +38,15 @@ if it refers to an existing directory, and if so, adds it to ``sys.path`` and also inspects the newly added path for configuration files. +If a file named "pyvenv.cfg" exists one directory above sys.executable, +sys.prefix and sys.exec_prefix are set to that directory and +it is also checked for site-packages and site-python (sys.base_prefix and +sys.base_exec_prefix will always be the "real" prefixes of the Python +installation). If "pyvenv.cfg" (a bootstrap configuration file) contains +the key "include-system-site-packages" set to anything other than "false" +(case-insensitive), the system-level prefixes will still also be +searched for site-packages; otherwise they won't. + A path configuration file is a file whose name has the form :file:`{name}.pth` and exists in one of the four directories mentioned above; its contents are additional items (one per line) to be added to ``sys.path``. Non-existing items diff --git a/Lib/site.py b/Lib/site.py --- a/Lib/site.py +++ b/Lib/site.py @@ -15,8 +15,8 @@ If a file named "pyvenv.cfg" exists one directory above sys.executable, sys.prefix and sys.exec_prefix are set to that directory and -it is also checked for site-packages and site-python (sys.prefix and -sys.exec_prefix will always be the "real" prefixes of the Python +it is also checked for site-packages and site-python (sys.base_prefix and +sys.base_exec_prefix will always be the "real" prefixes of the Python installation). If "pyvenv.cfg" (a bootstrap configuration file) contains the key "include-system-site-packages" set to anything other than "false" (case-insensitive), the system-level prefixes will still also be -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 3 17:56:59 2012 From: python-checkins at python.org (vinay.sajip) Date: Tue, 3 Jul 2012 17:56:59 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315241=3A_Added_te?= =?utf-8?q?st_for_venv_prefixes=2E?= Message-ID: <3WRVMH1hxyzNZr@mail.python.org> http://hg.python.org/cpython/rev/18c2519b9114 changeset: 77936:18c2519b9114 user: Vinay Sajip date: Tue Jul 03 16:56:40 2012 +0100 summary: Issue #15241: Added test for venv prefixes. files: Lib/test/test_venv.py | 25 +++++++++++++++++++++++++ 1 files changed, 25 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -8,6 +8,7 @@ import os import os.path import shutil +import subprocess import sys import tempfile from test.support import (captured_stdout, captured_stderr, run_unittest, @@ -86,6 +87,30 @@ print(' %r' % os.listdir(bd)) self.assertTrue(os.path.exists(fn), 'File %r should exist.' % fn) + def test_prefixes(self): + """ + Test that the prefix values are as expected. + """ + #check our prefixes + self.assertEqual(sys.base_prefix, sys.prefix) + self.assertEqual(sys.base_exec_prefix, sys.exec_prefix) + + # check a venv's prefixes + shutil.rmtree(self.env_dir) + self.run_with_capture(venv.create, self.env_dir) + envpy = os.path.join(self.env_dir, self.bindir, self.exe) + cmd = [envpy, '-c', None] + for prefix, expected in ( + ('prefix', self.env_dir), + ('prefix', self.env_dir), + ('base_prefix', sys.prefix), + ('base_exec_prefix', sys.exec_prefix)): + cmd[2] = 'import sys; print(sys.%s)' % prefix + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + out, err = p.communicate() + self.assertEqual(out[:-1], expected.encode()) + def test_overwrite_existing(self): """ Test control of overwriting an existing environment directory. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 3 18:27:08 2012 From: python-checkins at python.org (vinay.sajip) Date: Tue, 3 Jul 2012 18:27:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Closes_=2315241=3A_Added_i?= =?utf-8?q?nformation_on_venv_prefixes_to_pyvenv_section=2E?= Message-ID: <3WRW2431Y2zNgx@mail.python.org> http://hg.python.org/cpython/rev/74fea1763d02 changeset: 77937:74fea1763d02 user: Vinay Sajip date: Tue Jul 03 17:26:55 2012 +0100 summary: Closes #15241: Added information on venv prefixes to pyvenv section. files: Doc/using/scripts.rst | 22 ++++++++++++++++++++++ 1 files changed, 22 insertions(+), 0 deletions(-) diff --git a/Doc/using/scripts.rst b/Doc/using/scripts.rst --- a/Doc/using/scripts.rst +++ b/Doc/using/scripts.rst @@ -63,3 +63,25 @@ virtualenv will be created, according to the given options, at each provided path. +.. note:: A virtual environment (also called a ``venv``) is a Python + environment such that the Python interpreter, libraries and scripts + installed into it are isolated from those installed in other virtual + environments, and (by default) any libraries installed in a "system" Python, + i.e. one which is installed as part of your operating system. + + A venv is a directory tree which contains Python executable files and + other files which indicate that it is a venv. + + Common installation tools such as ``distribute`` and ``pip`` work as + expected with venvs - i.e. when a venv is active, they install Python + packages into the venv without needing to be told to do so explicitly. + + When a venv is active (i.e. the venv's Python interpreter is running), the + attributes :attr:`sys.prefix` and :attr:`sys.exec_prefix` point to the base + directory of the venv, whereas :attr:`sys.base_prefix` and + :attr:`sys.base_exec_prefix` point to the non-venv Python installation + which was used to create the venv. If a venv is not active, then + :attr:`sys.prefix` is the same as :attr:`sys.base_prefix` and + :attr:`sys.exec_prefix` is the same as :attr:`sys.base_exec_prefix` (they + all point to a non-venv Python installation). + -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 3 22:14:06 2012 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 3 Jul 2012 22:14:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Refactor_to_isolate_HTML_e?= =?utf-8?q?ncoding_step_from_the_parsing_step=2E?= Message-ID: <3WRc3y4GcSzN1Y@mail.python.org> http://hg.python.org/cpython/rev/1f06fe5cd4da changeset: 77938:1f06fe5cd4da user: Raymond Hettinger date: Tue Jul 03 13:13:52 2012 -0700 summary: Refactor to isolate HTML encoding step from the parsing step. files: Tools/scripts/highlight.py | 37 ++++++++++++++----------- 1 files changed, 21 insertions(+), 16 deletions(-) diff --git a/Tools/scripts/highlight.py b/Tools/scripts/highlight.py --- a/Tools/scripts/highlight.py +++ b/Tools/scripts/highlight.py @@ -10,24 +10,23 @@ 'Return True if s is the name of a builtin' return s in vars(__builtins__) -def escape_range(lines, start, end): - 'Return escaped content from a range of lines between start and end' +def combine_range(lines, start, end): + 'Join content from a range of lines between start and end' (srow, scol), (erow, ecol) = start, end if srow == erow: rows = [lines[srow-1][scol:ecol]] else: rows = [lines[srow-1][scol:]] + lines[srow: erow-1] + [lines[erow-1][:ecol]] - return cgi.escape(''.join(rows)), end + return ''.join(rows), end -def colorize(source): - 'Convert Python source code to an HTML fragment with colorized markup' +def isolate_tokens(source): + 'Generate chunks of source and indentify chunks to be highlighted' lines = source.splitlines(True) lines.append('') readline = functools.partial(next, iter(lines), '') kind = tok_str = '' tok_type = tokenize.COMMENT written = (1, 0) - result = [] for tok in tokenize.generate_tokens(readline): prev_tok_type, prev_tok_str = tok_type, tok_str tok_type, tok_str, (srow, scol), (erow, ecol), logical_lineno = tok @@ -49,23 +48,29 @@ kind = 'keyword' elif is_builtin(tok_str) and prev_tok_str != '.': kind = 'builtin' + line_upto_token, written = combine_range(lines, written, (srow, scol)) + line_thru_token, written = combine_range(lines, written, (erow, ecol)) + yield kind, line_upto_token, line_thru_token + +def colorize(source): + 'Convert Python source code to an HTML fragment with colorized markup' + result = ['
\n']
+    for kind, line_upto_token, line_thru_token in isolate_tokens(source):
         if kind:
-            line_upto_token, written = escape_range(lines, written, (srow, scol))
-            line_thru_token, written = escape_range(lines, written, (erow, ecol))
-            result += [line_upto_token, '' % kind,
-                       line_thru_token, '']
+            result += [cgi.escape(line_upto_token),
+                       '' % kind,
+                       cgi.escape(line_thru_token),
+                       '']
         else:
-            line_thru_token, written = escape_range(lines, written, (erow, ecol))
-            result += [line_thru_token]
-
-    result.insert(0, '
\n')
-    result.append('
\n') + result += [cgi.escape(line_upto_token), + cgi.escape(line_thru_token)] + result += ['
\n'] return ''.join(result) default_css = { '.comment': '{color: crimson;}', '.string': '{color: forestgreen;}', - '.docstring': '{color: forestgreen; font-style:italic}', + '.docstring': '{color: forestgreen; font-style:italic;}', '.keyword': '{color: darkorange;}', '.builtin': '{color: purple;}', '.definition': '{color: darkorange; font-weight:bold;}', -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 3 22:36:59 2012 From: python-checkins at python.org (vinay.sajip) Date: Tue, 3 Jul 2012 22:36:59 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Closes_=2314902=3A_Fixed_t?= =?utf-8?q?imezone_conversion_of_a_date/time_in_the_past=2E_Thanks_to?= Message-ID: <3WRcZM2s9szN17@mail.python.org> http://hg.python.org/cpython/rev/56260d30985d changeset: 77939:56260d30985d user: Vinay Sajip date: Tue Jul 03 21:36:36 2012 +0100 summary: Closes #14902: Fixed timezone conversion of a date/time in the past. Thanks to Yuriy Syrovetskiy for the report and Juancarlo A?ez for the patch on which this fix is based. files: Lib/test/test_logging.py | 6 ++++-- Misc/ACKS | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -2899,8 +2899,10 @@ def test_time(self): r = self.get_record() - dt = datetime.datetime(1993,4,21,8,3,0,0,utc) - r.created = time.mktime(dt.timetuple()) - time.timezone + dt = datetime.datetime(1993, 4, 21, 8, 3, 0, 0, utc) + # We use None to indicate we want the local timezone + # We're essentially converting a UTC time to local time + r.created = time.mktime(dt.astimezone(None).timetuple()) r.msecs = 123 f = logging.Formatter('%(asctime)s %(message)s') f.converter = time.gmtime diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -33,6 +33,7 @@ Erik Anders?n Oliver Andrich Ross Andrus +Juancarlo A?ez J?r?my Anger Jon Anglin ?ric Araujo @@ -1167,3 +1168,4 @@ Kai Zhu Tarek Ziad? Peter ?strand + -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 3 23:11:49 2012 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 3 Jul 2012 23:11:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Add_support_for_ANSI_escap?= =?utf-8?q?e_sequences?= Message-ID: <3WRdLY2nYrzMlD@mail.python.org> http://hg.python.org/cpython/rev/980de5b47d0d changeset: 77940:980de5b47d0d user: Raymond Hettinger date: Tue Jul 03 14:11:40 2012 -0700 summary: Add support for ANSI escape sequences files: Tools/scripts/highlight.py | 52 ++++++++++++++++++++++---- 1 files changed, 44 insertions(+), 8 deletions(-) diff --git a/Tools/scripts/highlight.py b/Tools/scripts/highlight.py --- a/Tools/scripts/highlight.py +++ b/Tools/scripts/highlight.py @@ -1,7 +1,8 @@ #!/usr/bin/env python3 -'Convert Python source code to HTML with colorized markup' +'Add syntax highlighting to Python source code' -__all__ = ['colorize', 'build_page', 'default_css', 'default_html'] +__all__ = ['colorize', 'build_page', 'default_css', 'default_html', + 'ansi_colorize', 'default_ansi'] __author__ = 'Raymond Hettinger' import keyword, tokenize, cgi, functools @@ -52,7 +53,29 @@ line_thru_token, written = combine_range(lines, written, (erow, ecol)) yield kind, line_upto_token, line_thru_token -def colorize(source): +default_ansi = { + 'comment': '\033[0;31m', + 'string': '\033[0;32m', + 'docstring': '\033[0;32m', + 'keyword': '\033[0;33m', + 'builtin': '\033[0;35m', + 'definition': '\033[0;33m', + 'defname': '\033[0;34m', + 'operator': '\033[0;33m', +} + +def colorize_ansi(source, colors=default_ansi): + 'Add syntax highlighting to Python source code using ANSI escape sequences' + # http://en.wikipedia.org/wiki/ANSI_escape_code + result = [] + for kind, line_upto_token, line_thru_token in isolate_tokens(source): + if kind: + result += [line_upto_token, colors[kind], line_thru_token, '\033[0m'] + else: + result += [line_upto_token, line_thru_token] + return ''.join(result) + +def colorize_html(source): 'Convert Python source code to an HTML fragment with colorized markup' result = ['
\n']
     for kind, line_upto_token, line_thru_token in isolate_tokens(source):
@@ -98,7 +121,7 @@
 def build_page(source, title='python', css=default_css, html=default_html):
     'Create a complete HTML page with colorized Python source code'
     css_str = '\n'.join(['%s %s' % item for item in css.items()])
-    result = colorize(source)
+    result = colorize_html(source)
     title = cgi.escape(title)
     return html.format(title=title, css=css_str, body=result)
 
@@ -107,26 +130,39 @@
     import sys, argparse, webbrowser, os
 
     parser = argparse.ArgumentParser(
-            description = 'Convert Python source code to colorized HTML')
+            description = 'Add syntax highlighting to Python source')
     parser.add_argument('sourcefile', metavar = 'SOURCEFILE',
             help = 'File containing Python sourcecode')
+    parser.add_argument('-a', '--ansi', action = 'store_true',
+            help = 'emit ANSI escape highlighted source')
     parser.add_argument('-b', '--browser', action = 'store_true',
             help = 'launch a browser to show results')
     parser.add_argument('-s', '--section', action = 'store_true',
             help = 'show an HTML section rather than a complete webpage')
     args = parser.parse_args()
+
     if args.browser and args.section:
         parser.error('The -s/--section option is incompatible with '
                      'the -b/--browser option')
+    if args.ansi and (args.browser or args.section):
+        parser.error('The -a/--ansi option is incompatible with '
+                     'the -b/--browser and -s/--section options')
 
     sourcefile = args.sourcefile
     with open(sourcefile) as f:
         page = f.read()
-    html = colorize(page) if args.section else build_page(page, title=sourcefile)
+
+    if args.ansi:
+        encoded = colorize_ansi(page)
+    elif args.section:
+        encoded = colorize_html(page)
+    else:
+        encoded = build_page(page, title=sourcefile)
+
     if args.browser:
         htmlfile = os.path.splitext(os.path.basename(sourcefile))[0] + '.html'
         with open(htmlfile, 'w') as f:
-            f.write(html)
+            f.write(encoded)
         webbrowser.open('file://' + os.path.abspath(htmlfile))
     else:
-        sys.stdout.write(html)
+        sys.stdout.write(encoded)

-- 
Repository URL: http://hg.python.org/cpython

From python-checkins at python.org  Tue Jul  3 23:25:22 2012
From: python-checkins at python.org (raymond.hettinger)
Date: Tue,  3 Jul 2012 23:25:22 +0200 (CEST)
Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_spelling=2E?=
Message-ID: <3WRdfB0bPXzMvF@mail.python.org>

http://hg.python.org/cpython/rev/f9c8260da02d
changeset:   77941:f9c8260da02d
user:        Raymond Hettinger 
date:        Tue Jul 03 14:25:16 2012 -0700
summary:
  Fix spelling.

files:
  Tools/scripts/highlight.py |  2 +-
  1 files changed, 1 insertions(+), 1 deletions(-)


diff --git a/Tools/scripts/highlight.py b/Tools/scripts/highlight.py
--- a/Tools/scripts/highlight.py
+++ b/Tools/scripts/highlight.py
@@ -21,7 +21,7 @@
     return ''.join(rows), end
 
 def isolate_tokens(source):
-    'Generate chunks of source and indentify chunks to be highlighted'
+    'Generate chunks of source and identify chunks to be highlighted'
     lines = source.splitlines(True)
     lines.append('')
     readline = functools.partial(next, iter(lines), '')

-- 
Repository URL: http://hg.python.org/cpython

From python-checkins at python.org  Tue Jul  3 23:42:40 2012
From: python-checkins at python.org (raymond.hettinger)
Date: Tue,  3 Jul 2012 23:42:40 +0200 (CEST)
Subject: [Python-checkins] =?utf-8?q?cpython=3A_Add_examples_to_the_module?=
	=?utf-8?q?_docstring?=
Message-ID: <3WRf280X2SzM8G@mail.python.org>

http://hg.python.org/cpython/rev/1401ff261ced
changeset:   77942:1401ff261ced
user:        Raymond Hettinger 
date:        Tue Jul 03 14:42:33 2012 -0700
summary:
  Add examples to the module docstring

files:
  Tools/scripts/highlight.py |  26 +++++++++++++++++++++-----
  1 files changed, 21 insertions(+), 5 deletions(-)


diff --git a/Tools/scripts/highlight.py b/Tools/scripts/highlight.py
--- a/Tools/scripts/highlight.py
+++ b/Tools/scripts/highlight.py
@@ -1,5 +1,21 @@
 #!/usr/bin/env python3
-'Add syntax highlighting to Python source code'
+'''Add syntax highlighting to Python source code
+
+Example command-line calls:
+
+    # Show syntax highlighted code in the terminal window
+    $ ./highlight.py -a myfile.py
+
+    # Colorize myfile.py and display in a browser
+    $ ./highlight.py -b myfile.py
+
+    # Create an HTML section that can be embedded in an existing webpage
+    ./highlight.py -s myfile.py
+
+    # Create a complete HTML file
+    $ ./highlight.py myfile.py > myfile.html
+
+'''
 
 __all__ = ['colorize', 'build_page', 'default_css', 'default_html',
            'ansi_colorize', 'default_ansi']
@@ -150,14 +166,14 @@
 
     sourcefile = args.sourcefile
     with open(sourcefile) as f:
-        page = f.read()
+        source = f.read()
 
     if args.ansi:
-        encoded = colorize_ansi(page)
+        encoded = colorize_ansi(source)
     elif args.section:
-        encoded = colorize_html(page)
+        encoded = colorize_html(source)
     else:
-        encoded = build_page(page, title=sourcefile)
+        encoded = build_page(source, title=sourcefile)
 
     if args.browser:
         htmlfile = os.path.splitext(os.path.basename(sourcefile))[0] + '.html'

-- 
Repository URL: http://hg.python.org/cpython

From python-checkins at python.org  Wed Jul  4 02:55:30 2012
From: python-checkins at python.org (raymond.hettinger)
Date: Wed,  4 Jul 2012 02:55:30 +0200 (CEST)
Subject: [Python-checkins] =?utf-8?q?cpython=3A_Make_ANSI_the_default_outp?=
	=?utf-8?q?ut_style?=
Message-ID: <3WRkJf3ry7zN7r@mail.python.org>

http://hg.python.org/cpython/rev/9fe720fe6057
changeset:   77943:9fe720fe6057
user:        Raymond Hettinger 
date:        Tue Jul 03 17:55:23 2012 -0700
summary:
  Make ANSI the default output style

files:
  Tools/scripts/highlight.py |  21 +++++++++------------
  1 files changed, 9 insertions(+), 12 deletions(-)


diff --git a/Tools/scripts/highlight.py b/Tools/scripts/highlight.py
--- a/Tools/scripts/highlight.py
+++ b/Tools/scripts/highlight.py
@@ -4,7 +4,7 @@
 Example command-line calls:
 
     # Show syntax highlighted code in the terminal window
-    $ ./highlight.py -a myfile.py
+    $ ./highlight.py myfile.py
 
     # Colorize myfile.py and display in a browser
     $ ./highlight.py -b myfile.py
@@ -13,7 +13,7 @@
     ./highlight.py -s myfile.py
 
     # Create a complete HTML file
-    $ ./highlight.py myfile.py > myfile.html
+    $ ./highlight.py -c myfile.py > myfile.html
 
 '''
 
@@ -149,31 +149,28 @@
             description = 'Add syntax highlighting to Python source')
     parser.add_argument('sourcefile', metavar = 'SOURCEFILE',
             help = 'File containing Python sourcecode')
-    parser.add_argument('-a', '--ansi', action = 'store_true',
-            help = 'emit ANSI escape highlighted source')
     parser.add_argument('-b', '--browser', action = 'store_true',
             help = 'launch a browser to show results')
+    parser.add_argument('-c', '--complete', action = 'store_true',
+            help = 'build a complete html webpage')
     parser.add_argument('-s', '--section', action = 'store_true',
             help = 'show an HTML section rather than a complete webpage')
     args = parser.parse_args()
 
-    if args.browser and args.section:
+    if args.section and (args.browser or args.complete):
         parser.error('The -s/--section option is incompatible with '
-                     'the -b/--browser option')
-    if args.ansi and (args.browser or args.section):
-        parser.error('The -a/--ansi option is incompatible with '
-                     'the -b/--browser and -s/--section options')
+                     'the -b/--browser or -c/--complete options')
 
     sourcefile = args.sourcefile
     with open(sourcefile) as f:
         source = f.read()
 
-    if args.ansi:
-        encoded = colorize_ansi(source)
+    if args.complete or args.browser:
+        encoded = build_page(source, title=sourcefile)
     elif args.section:
         encoded = colorize_html(source)
     else:
-        encoded = build_page(source, title=sourcefile)
+        encoded = colorize_ansi(source)
 
     if args.browser:
         htmlfile = os.path.splitext(os.path.basename(sourcefile))[0] + '.html'

-- 
Repository URL: http://hg.python.org/cpython

From solipsis at pitrou.net  Wed Jul  4 06:04:46 2012
From: solipsis at pitrou.net (solipsis at pitrou.net)
Date: Wed, 04 Jul 2012 06:04:46 +0200
Subject: [Python-checkins] Daily reference leaks (9fe720fe6057): sum=0
Message-ID: 

results for 9fe720fe6057 on branch "default"
--------------------------------------------

test_support leaked [-1, 1, 0] references, sum=0


Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogc4o6qg', '-x']

From python-checkins at python.org  Wed Jul  4 11:07:57 2012
From: python-checkins at python.org (mark.dickinson)
Date: Wed,  4 Jul 2012 11:07:57 +0200 (CEST)
Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_undefined_names_in_=5F?=
	=?utf-8?b?X2FsbF9fLg==?=
Message-ID: <3WRxDs4wFczN8G@mail.python.org>

http://hg.python.org/cpython/rev/070977904889
changeset:   77944:070977904889
user:        Mark Dickinson 
date:        Wed Jul 04 11:07:06 2012 +0200
summary:
  Fix undefined names in __all__.

files:
  Tools/scripts/highlight.py |  4 ++--
  1 files changed, 2 insertions(+), 2 deletions(-)


diff --git a/Tools/scripts/highlight.py b/Tools/scripts/highlight.py
--- a/Tools/scripts/highlight.py
+++ b/Tools/scripts/highlight.py
@@ -17,8 +17,8 @@
 
 '''
 
-__all__ = ['colorize', 'build_page', 'default_css', 'default_html',
-           'ansi_colorize', 'default_ansi']
+__all__ = ['colorize_html', 'build_page', 'default_css', 'default_html',
+           'colorize_ansi', 'default_ansi']
 __author__ = 'Raymond Hettinger'
 
 import keyword, tokenize, cgi, functools

-- 
Repository URL: http://hg.python.org/cpython

From python-checkins at python.org  Wed Jul  4 20:03:50 2012
From: python-checkins at python.org (brett.cannon)
Date: Wed,  4 Jul 2012 20:03:50 +0200 (CEST)
Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315210=3A_Greatly_?=
 =?utf-8?q?simplify_the_test_for_supporting_importlib?=
Message-ID: <3WS97B0lrSzMkQ@mail.python.org>

http://hg.python.org/cpython/rev/906c69928049
changeset:   77945:906c69928049
user:        Brett Cannon 
date:        Wed Jul 04 14:03:40 2012 -0400
summary:
  Issue #15210: Greatly simplify the test for supporting importlib
working without _frozen_importlib by moving to an import over a direct
access in sys.modules.

files:
  Lib/importlib/__init__.py      |   4 ++--
  Lib/importlib/test/test_api.py |  17 +++++------------
  2 files changed, 7 insertions(+), 14 deletions(-)


diff --git a/Lib/importlib/__init__.py b/Lib/importlib/__init__.py
--- a/Lib/importlib/__init__.py
+++ b/Lib/importlib/__init__.py
@@ -6,8 +6,8 @@
 import sys
 
 try:
-    _bootstrap = sys.modules['_frozen_importlib']
-except KeyError:
+    import _frozen_importlib as _bootstrap
+except ImportError:
     from . import _bootstrap
     _bootstrap._setup(sys, imp)
 else:
diff --git a/Lib/importlib/test/test_api.py b/Lib/importlib/test/test_api.py
--- a/Lib/importlib/test/test_api.py
+++ b/Lib/importlib/test/test_api.py
@@ -1,7 +1,9 @@
 from . import util
 import imp
 import importlib
+from importlib import machinery
 import sys
+from test import support
 import unittest
 
 
@@ -164,18 +166,9 @@
 
     def test_no_frozen_importlib(self):
         # Should be able to import w/o _frozen_importlib being defined.
-        modules = {}
-        for name in ('importlib', 'importlib.__init__', 'importlib._bootstrap',
-                     '_frozen_importlib'):
-            try:
-                modules[name] = sys.modules[name]
-                del sys.modules[name]
-            except KeyError:
-                continue
-        modules['_frozen_importlib'] = None
-        import importlib
-        for name, module in modules.items():
-            sys.modules[name] = module
+        module = support.import_fresh_module('importlib', blocked=['_frozen_importlib'])
+        self.assertFalse(isinstance(module.__loader__,
+                                    machinery.FrozenImporter))
 
 
 def test_main():

-- 
Repository URL: http://hg.python.org/cpython

From python-checkins at python.org  Thu Jul  5 04:34:00 2012
From: python-checkins at python.org (senthil.kumaran)
Date: Thu,  5 Jul 2012 04:34:00 +0200 (CEST)
Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogRml4IGlzc3VlICMg?=
 =?utf-8?q?15033_-_Return_the_proper_exitcode_for_failure_when_modules_are?=
Message-ID: <3WSNRr6v07zNBB@mail.python.org>

http://hg.python.org/cpython/rev/fcbd3bda7c0f
changeset:   77946:fcbd3bda7c0f
branch:      3.2
parent:      77933:4de541fbdd58
user:        Senthil Kumaran 
date:        Wed Jul 04 19:28:16 2012 -0700
summary:
  Fix issue # 15033 - Return the proper exitcode for failure when modules are invoked using -m switch. Patch contributed by Jeff Knupp

files:
  Lib/test/test_cmd_line_script.py |  15 +++++++++++++++
  Misc/NEWS                        |   3 +++
  Modules/main.c                   |   2 +-
  3 files changed, 19 insertions(+), 1 deletions(-)


diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py
--- a/Lib/test/test_cmd_line_script.py
+++ b/Lib/test/test_cmd_line_script.py
@@ -279,6 +279,21 @@
                     self._check_output(script_name, rc, out,
                                       script_name, script_name, '', '')
 
+    def test_dash_m_error_code_is_one(self):
+        # If a module is invoked with the -m command line flag
+        # and results in an error that the return code to the
+        # shell is '1'
+        with temp_dir() as script_dir:
+            with support.temp_cwd(path=script_dir):
+                pkg_dir = os.path.join(script_dir, 'test_pkg')
+                make_pkg(pkg_dir)
+                script_name = _make_test_script(pkg_dir, 'other',
+                                                "if __name__ == '__main__': raise ValueError")
+                rc, out, err = assert_python_failure('-m', 'test_pkg.other', *example_args)
+                if verbose > 1:
+                    print(out)
+                self.assertEqual(rc, 1)
+
 def test_main():
     support.run_unittest(CmdLineTest)
     support.reap_children()
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@
 Core and Builtins
 -----------------
 
+- Issue #15033: Fix the exit status bug when modules invoked using -m swith,
+  return the proper failure return value (1). Patch contributed by Jeff Knupp.
+
 - Issue #12268: File readline, readlines and read() or readall() methods
   no longer lose data when an underlying read system call is interrupted.
   IOError is no longer raised due to a read system call returning EINTR
diff --git a/Modules/main.c b/Modules/main.c
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -673,7 +673,7 @@
         sts = run_command(command, &cf);
         free(command);
     } else if (module) {
-        sts = RunModule(module, 1);
+        sts = (RunModule(module, 1) != 0);
     }
     else {
 

-- 
Repository URL: http://hg.python.org/cpython

From python-checkins at python.org  Thu Jul  5 04:34:02 2012
From: python-checkins at python.org (senthil.kumaran)
Date: Thu,  5 Jul 2012 04:34:02 +0200 (CEST)
Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?=
 =?utf-8?q?=29=3A_Fix_issue_=23_15033_-_Return_the_proper_exitcode_for_fai?=
 =?utf-8?q?lure_when_modules_are?=
Message-ID: <3WSNRt3yJHzNDj@mail.python.org>

http://hg.python.org/cpython/rev/1186d68715cc
changeset:   77947:1186d68715cc
parent:      77945:906c69928049
parent:      77946:fcbd3bda7c0f
user:        Senthil Kumaran 
date:        Wed Jul 04 19:33:45 2012 -0700
summary:
  Fix issue # 15033 - Return the proper exitcode for failure when modules are invoked using -m switch. Patch contributed by Jeff Knupp

files:
  Lib/test/test_cmd_line_script.py |  15 +++++++++++++++
  Misc/NEWS                        |   3 +++
  Modules/main.c                   |   2 +-
  3 files changed, 19 insertions(+), 1 deletions(-)


diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py
--- a/Lib/test/test_cmd_line_script.py
+++ b/Lib/test/test_cmd_line_script.py
@@ -287,6 +287,21 @@
                     self._check_output(script_name, rc, out,
                                       script_name, script_name, '', '')
 
+    def test_dash_m_error_code_is_one(self):
+        # If a module is invoked with the -m command line flag
+        # and results in an error that the return code to the
+        # shell is '1'
+        with temp_dir() as script_dir:
+            with support.temp_cwd(path=script_dir):
+                pkg_dir = os.path.join(script_dir, 'test_pkg')
+                make_pkg(pkg_dir)
+                script_name = _make_test_script(pkg_dir, 'other',
+                                                "if __name__ == '__main__': raise ValueError")
+                rc, out, err = assert_python_failure('-m', 'test_pkg.other', *example_args)
+                if verbose > 1:
+                    print(out)
+                self.assertEqual(rc, 1)
+
     def test_pep_409_verbiage(self):
         # Make sure PEP 409 syntax properly suppresses
         # the context of an exception
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@
 Core and Builtins
 -----------------
 
+- Issue #15033: Fix the exit status bug when modules invoked using -m swith,
+  return the proper failure return value (1). Patch contributed by Jeff Knupp.
+
 - Issue #15229: An OSError subclass whose __init__ doesn't call back
   OSError.__init__ could produce incomplete instances, leading to crashes
   when calling str() on them.
diff --git a/Modules/main.c b/Modules/main.c
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -660,7 +660,7 @@
         sts = run_command(command, &cf);
         free(command);
     } else if (module) {
-        sts = RunModule(module, 1);
+        sts = (RunModule(module, 1) != 0);
     }
     else {
 

-- 
Repository URL: http://hg.python.org/cpython

From python-checkins at python.org  Thu Jul  5 04:50:45 2012
From: python-checkins at python.org (senthil.kumaran)
Date: Thu,  5 Jul 2012 04:50:45 +0200 (CEST)
Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fix_closes_iss?=
 =?utf-8?q?ue_=23_15033_-_Return_the_proper_exitcode_for_failure_when_modu?=
 =?utf-8?q?les?=
Message-ID: <3WSNq910hfzNCm@mail.python.org>

http://hg.python.org/cpython/rev/55b3de6d701e
changeset:   77948:55b3de6d701e
branch:      2.7
parent:      77932:2de5c9ced464
user:        Senthil Kumaran 
date:        Wed Jul 04 19:50:29 2012 -0700
summary:
  Fix closes issue # 15033 - Return the proper exitcode for failure when modules are invoked using -m switch. Patch contributed by Jeff Knupp

files:
  Lib/test/test_cmd_line_script.py |  18 +++++++++++++++++-
  Misc/NEWS                        |   3 +++
  Modules/main.c                   |   2 +-
  3 files changed, 21 insertions(+), 2 deletions(-)


diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py
--- a/Lib/test/test_cmd_line_script.py
+++ b/Lib/test/test_cmd_line_script.py
@@ -6,11 +6,14 @@
 import test.test_support
 from test.script_helper import (run_python,
                                 temp_dir, make_script, compile_script,
-                                make_pkg, make_zip_script, make_zip_pkg)
+                                assert_python_failure, make_pkg,
+                                make_zip_script, make_zip_pkg)
 
 verbose = test.test_support.verbose
 
 
+example_args = ['test1', 'test2', 'test3']
+
 test_source = """\
 # Script may be run with optimisation enabled, so don't rely on assert
 # statements being executed
@@ -204,6 +207,19 @@
             launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg')
             self._check_import_error(launch_name, msg)
 
+    def test_dash_m_error_code_is_one(self):
+        # If a module is invoked with the -m command line flag
+        # and results in an error that the return code to the
+        # shell is '1'
+        with temp_dir() as script_dir:
+            pkg_dir = os.path.join(script_dir, 'test_pkg')
+            make_pkg(pkg_dir)
+            script_name = _make_test_script(pkg_dir, 'other', "if __name__ == '__main__': raise ValueError")
+            rc, out, err = assert_python_failure('-m', 'test_pkg.other', *example_args)
+            if verbose > 1:
+                print(out)
+            self.assertEqual(rc, 1)
+
 
 def test_main():
     test.test_support.run_unittest(CmdLineTest)
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -9,6 +9,9 @@
 Core and Builtins
 -----------------
 
+- Issue #15033: Fix the exit status bug when modules invoked using -m swith,
+  return the proper failure return value (1). Patch contributed by Jeff Knupp.
+
 - Issue #12268: File readline, readlines and read() methods no longer lose
   data when an underlying read system call is interrupted.  IOError is no
   longer raised due to a read system call returning EINTR from within these
diff --git a/Modules/main.c b/Modules/main.c
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -583,7 +583,7 @@
         sts = PyRun_SimpleStringFlags(command, &cf) != 0;
         free(command);
     } else if (module) {
-        sts = RunModule(module, 1);
+        sts = (RunModule(module, 1) != 0);
         free(module);
     }
     else {

-- 
Repository URL: http://hg.python.org/cpython

From solipsis at pitrou.net  Thu Jul  5 06:07:32 2012
From: solipsis at pitrou.net (solipsis at pitrou.net)
Date: Thu, 05 Jul 2012 06:07:32 +0200
Subject: [Python-checkins] Daily reference leaks (906c69928049): sum=1
Message-ID: 

results for 906c69928049 on branch "default"
--------------------------------------------

test_support leaked [1, 0, 0] references, sum=1


Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogVOzGLJ', '-x']

From python-checkins at python.org  Thu Jul  5 20:59:30 2012
From: python-checkins at python.org (antoine.pitrou)
Date: Thu,  5 Jul 2012 20:59:30 +0200 (CEST)
Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE1MDIw?=
 =?utf-8?q?=3A_The_program_name_used_to_search_for_Python=27s_path_is_now?=
Message-ID: <3WSpJy5s4XzNQT@mail.python.org>

http://hg.python.org/cpython/rev/c97d78415f5a
changeset:   77949:c97d78415f5a
branch:      3.2
parent:      77946:fcbd3bda7c0f
user:        Antoine Pitrou 
date:        Thu Jul 05 20:56:30 2012 +0200
summary:
  Issue #15020: The program name used to search for Python's path is now "python3" under Unix, not "python".

files:
  Misc/NEWS          |  3 +++
  Python/pythonrun.c |  4 ++++
  2 files changed, 7 insertions(+), 0 deletions(-)


diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@
 Core and Builtins
 -----------------
 
+- Issue #15020: The program name used to search for Python's path is now
+  "python3" under Unix, not "python".
+
 - Issue #15033: Fix the exit status bug when modules invoked using -m swith,
   return the proper failure return value (1). Patch contributed by Jeff Knupp.
 
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -696,7 +696,11 @@
     PyInterpreterState_Delete(interp);
 }
 
+#ifdef MS_WINDOWS
 static wchar_t *progname = L"python";
+#else
+static wchar_t *progname = L"python3";
+#endif
 
 void
 Py_SetProgramName(wchar_t *pn)

-- 
Repository URL: http://hg.python.org/cpython

From python-checkins at python.org  Thu Jul  5 20:59:32 2012
From: python-checkins at python.org (antoine.pitrou)
Date: Thu,  5 Jul 2012 20:59:32 +0200 (CEST)
Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?=
 =?utf-8?q?=29=3A_Issue_=2315020=3A_The_program_name_used_to_search_for_Py?=
 =?utf-8?q?thon=27s_path_is_now_python3?=
Message-ID: <3WSpK03xqtzNQV@mail.python.org>

http://hg.python.org/cpython/rev/61e6ac40c816
changeset:   77950:61e6ac40c816
parent:      77947:1186d68715cc
parent:      77949:c97d78415f5a
user:        Antoine Pitrou 
date:        Thu Jul 05 20:57:33 2012 +0200
summary:
  Issue #15020: The program name used to search for Python's path is now python3 under Unix, not python.

files:
  Misc/NEWS          |  3 +++
  Python/pythonrun.c |  4 ++++
  2 files changed, 7 insertions(+), 0 deletions(-)


diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@
 Core and Builtins
 -----------------
 
+- Issue #15020: The program name used to search for Python's path is now
+  "python3" under Unix, not "python".
+
 - Issue #15033: Fix the exit status bug when modules invoked using -m swith,
   return the proper failure return value (1). Patch contributed by Jeff Knupp.
 
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -778,7 +778,11 @@
     PyInterpreterState_Delete(interp);
 }
 
+#ifdef MS_WINDOWS
 static wchar_t *progname = L"python";
+#else
+static wchar_t *progname = L"python3";
+#endif
 
 void
 Py_SetProgramName(wchar_t *pn)

-- 
Repository URL: http://hg.python.org/cpython

From solipsis at pitrou.net  Fri Jul  6 06:06:35 2012
From: solipsis at pitrou.net (solipsis at pitrou.net)
Date: Fri, 06 Jul 2012 06:06:35 +0200
Subject: [Python-checkins] Daily reference leaks (61e6ac40c816): sum=0
Message-ID: 

results for 61e6ac40c816 on branch "default"
--------------------------------------------



Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogZf7Tw5', '-x']

From python-checkins at python.org  Fri Jul  6 13:23:43 2012
From: python-checkins at python.org (richard.oudkerk)
Date: Fri,  6 Jul 2012 13:23:43 +0200 (CEST)
Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315261=3A_Stop_os?=
 =?utf-8?q?=2Estat=28fd=29_crashing_on_Windows_when_fd_not_open=2E?=
Message-ID: <3WTD8b2N3QzNH2@mail.python.org>

http://hg.python.org/cpython/rev/62b9bfbc3356
changeset:   77951:62b9bfbc3356
user:        Richard Oudkerk 
date:        Fri Jul 06 12:05:32 2012 +0100
summary:
  Issue #15261: Stop os.stat(fd) crashing on Windows when fd not open.

files:
  Doc/library/os.path.rst      |  11 ++++++++---
  Lib/test/test_genericpath.py |  10 ++++++++++
  Lib/test/test_os.py          |  13 +++++++++++++
  Misc/NEWS                    |   2 ++
  Modules/posixmodule.c        |   7 ++++---
  5 files changed, 37 insertions(+), 6 deletions(-)


diff --git a/Doc/library/os.path.rst b/Doc/library/os.path.rst
--- a/Doc/library/os.path.rst
+++ b/Doc/library/os.path.rst
@@ -70,11 +70,16 @@
 
 .. function:: exists(path)
 
-   Return ``True`` if *path* refers to an existing path.  Returns ``False`` for
-   broken symbolic links. On some platforms, this function may return ``False`` if
-   permission is not granted to execute :func:`os.stat` on the requested file, even
+   Return ``True`` if *path* refers to an existing path or an open
+   file descriptor.  Returns ``False`` for broken symbolic links.  On
+   some platforms, this function may return ``False`` if permission is
+   not granted to execute :func:`os.stat` on the requested file, even
    if the *path* physically exists.
 
+   .. versionchanged:: 3.3
+      *path* can now be an integer: ``True`` is returned if it is an
+       open file descriptor, ``False`` otherwise.
+
 
 .. function:: lexists(path)
 
diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py
--- a/Lib/test/test_genericpath.py
+++ b/Lib/test/test_genericpath.py
@@ -146,6 +146,16 @@
                 f.close()
             support.unlink(support.TESTFN)
 
+    @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()")
+    def test_exists_fd(self):
+        r, w = os.pipe()
+        try:
+            self.assertTrue(self.pathmodule.exists(r))
+        finally:
+            os.close(r)
+            os.close(w)
+        self.assertFalse(self.pathmodule.exists(r))
+
     def test_isdir(self):
         self.assertIs(self.pathmodule.isdir(support.TESTFN), False)
         f = open(support.TESTFN, "wb")
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -473,6 +473,19 @@
                     return
                 self.fail("Could not stat pagefile.sys")
 
+        @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()")
+        def test_15261(self):
+            # Verify that stat'ing a closed fd does not cause crash
+            r, w = os.pipe()
+            try:
+                os.stat(r)          # should not raise error
+            finally:
+                os.close(r)
+                os.close(w)
+            with self.assertRaises(OSError) as ctx:
+                os.stat(r)
+            self.assertEqual(ctx.exception.errno, errno.EBADF)
+
 from test import mapping_tests
 
 class EnvironTests(mapping_tests.BasicTestMappingProtocol):
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -23,6 +23,8 @@
 Library
 -------
 
+- Issue #15261: Stop os.stat(fd) crashing on Windows when fd not open.
+
 - Issue #15166: Implement imp.get_tag() using sys.implementation.cache_tag.
 
 - Issue #15210: Catch KeyError when imprortlib.__init__ can't find
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -1829,7 +1829,10 @@
     HANDLE h;
     int type;
 
-    h = (HANDLE)_get_osfhandle(file_number);
+    if (!_PyVerify_fd(file_number))
+        h = INVALID_HANDLE_VALUE;
+    else
+        h = (HANDLE)_get_osfhandle(file_number);
 
     /* Protocol violation: we explicitly clear errno, instead of
        setting it to a POSIX error. Callers should use GetLastError. */
@@ -8244,8 +8247,6 @@
     /* on OpenVMS we must ensure that all bytes are written to the file */
     fsync(fd);
 #endif
-    if (!_PyVerify_fd(fd))
-        return posix_error();
     Py_BEGIN_ALLOW_THREADS
     res = FSTAT(fd, &st);
     Py_END_ALLOW_THREADS

-- 
Repository URL: http://hg.python.org/cpython

From python-checkins at python.org  Fri Jul  6 16:36:05 2012
From: python-checkins at python.org (benjamin.peterson)
Date: Fri,  6 Jul 2012 16:36:05 +0200 (CEST)
Subject: [Python-checkins] =?utf-8?q?peps=3A_specify_Provides-Extra?=
Message-ID: <3WTJQY0ZPZzNND@mail.python.org>

http://hg.python.org/peps/rev/4dc72bbf9ed2
changeset:   4483:4dc72bbf9ed2
user:        Daniel Holth 
date:        Wed Jul 04 07:30:08 2012 -0400
summary:
  specify Provides-Extra

files:
  pep-0345.txt |  36 +++++++++++++++++++++++++++++++++++-
  1 files changed, 35 insertions(+), 1 deletions(-)


diff --git a/pep-0345.txt b/pep-0345.txt
--- a/pep-0345.txt
+++ b/pep-0345.txt
@@ -26,7 +26,7 @@
 Version 1.2 of the metadata format adds a number of optional fields
 designed to make third-party packaging of Python Software easier.
 These fields are "Requires-Python", "Requires-External", "Requires-Dist",
-"Provides-Dist", and "Obsoletes-Dist".  This version also changes the
+"Provides-Dist", "Provides-Extra", and "Obsoletes-Dist".  This version also changes the
 "Platform" field. Three new fields were also added: "Maintainer",
 "Maintainer-email" and "Project-URL".
 
@@ -395,6 +395,36 @@
 The label is a free text limited to 32 signs.
 
 
+Provides-Extra (multiple use)
+:::::::::::::::::::::::::::::
+
+A string containing the name of an optional feature. Must be a valid Python
+identifier. May be used to make a dependency conditional on whether the
+optional feature has been requested.
+
+Example::
+
+    Provides-Extra: pdf
+    Requires-Dist: reportlab; extra == 'pdf'
+
+A second distribution requires an optional dependency by placing it
+inside square brackets, and can request multiple features by separating
+them with a comma (,). The requirements are evaluated for each requested
+feature and added to the set of requirements for the distribution.
+
+Example::
+
+    Requires-Dist: beaglevote[pdf]
+    Requires-Dist: libexample[test, doc]
+
+Two feature names `test` and `doc` are reserved to mark dependencies that
+are needed for running automated tests and generating documentation,
+respectively.
+
+It is legal to specify `Provides-Extra:` without referencing it in any
+`Requires-Dist:`.
+
+
 Version Specifiers
 ==================
 
@@ -433,6 +463,8 @@
 
 - ``Requires-Dist: zope.interface (3.1)``: any version that starts with 3.1,
   excluding post or pre-releases.
+- ``Requires-Dist: zope.interface (==3.1)``: equivalent to ``Requires-Dist:
+  zope.interface (3.1)``.
 - ``Requires-Dist: zope.interface (3.1.0)``: any version that starts with
   3.1.0, excluding post or pre-releases. Since that particular project doesn't
   use more than 3 digits, it also means "only the 3.1.0 release".
@@ -485,6 +517,7 @@
 - platform.machine = platform.machine()
 - platform.python_implementation = platform.python_implementation()
 - a free string, like ``'2.4'``, or ``'win32'``
+- extra = (name of requested feature)
 
 Notice that ``in`` is restricted to strings, meaning that it is not possible
 to use other sequences like tuples or lists on the right side.
@@ -518,6 +551,7 @@
   - Requires-External
   - Requires-Dist
   - Provides-Dist
+  - Provides-Extra
   - Obsoletes-Dist
   - Project-URL
 

-- 
Repository URL: http://hg.python.org/peps

From python-checkins at python.org  Fri Jul  6 17:14:08 2012
From: python-checkins at python.org (nick.coghlan)
Date: Fri,  6 Jul 2012 17:14:08 +0200 (CEST)
Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_14814=3A_Better_hand?=
 =?utf-8?q?ling_of_cases_where_octet/hextet_parsing_fails=2C?=
Message-ID: <3WTKGS4tdTzNHq@mail.python.org>

http://hg.python.org/cpython/rev/b7cfdb48af62
changeset:   77952:b7cfdb48af62
user:        Nick Coghlan 
date:        Sat Jul 07 01:13:55 2012 +1000
summary:
  Issue 14814: Better handling of cases where octet/hextet parsing fails, including ensuring that tracebacks are still clean even when calling class constructors directly

files:
  Lib/ipaddress.py           |  10 ++-
  Lib/test/test_ipaddress.py |  77 +++++++++++++------------
  2 files changed, 48 insertions(+), 39 deletions(-)


diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py
--- a/Lib/ipaddress.py
+++ b/Lib/ipaddress.py
@@ -1024,7 +1024,7 @@
             try:
                 packed_ip = (packed_ip << 8) | self._parse_octet(oc)
             except ValueError:
-                raise AddressValueError(ip_str)
+                raise AddressValueError(ip_str) from None
         return packed_ip
 
     def _parse_octet(self, octet_str):
@@ -1041,6 +1041,7 @@
 
         """
         # Whitelist the characters, since int() allows a lot of bizarre stuff.
+        # Higher level wrappers convert these to more informative errors
         if not self._DECIMAL_DIGITS.issuperset(octet_str):
             raise ValueError
         octet_int = int(octet_str, 10)
@@ -1497,7 +1498,7 @@
                 [None])
         except ValueError:
             # Can't have more than one '::'
-            raise AddressValueError(ip_str)
+            raise AddressValueError(ip_str) from None
 
         # parts_hi is the number of parts to copy from above/before the '::'
         # parts_lo is the number of parts to copy from below/after the '::'
@@ -1538,7 +1539,7 @@
                 ip_int |= self._parse_hextet(parts[i])
             return ip_int
         except ValueError:
-            raise AddressValueError(ip_str)
+            raise AddressValueError(ip_str) from None
 
     def _parse_hextet(self, hextet_str):
         """Convert an IPv6 hextet string into an integer.
@@ -1555,8 +1556,11 @@
 
         """
         # Whitelist the characters, since int() allows a lot of bizarre stuff.
+        # Higher level wrappers convert these to more informative errors
         if not self._HEX_DIGITS.issuperset(hextet_str):
             raise ValueError
+        if len(hextet_str) > 4:
+            raise ValueError
         hextet_int = int(hextet_str, 16)
         if hextet_int > 0xFFFF:
             raise ValueError
diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py
--- a/Lib/test/test_ipaddress.py
+++ b/Lib/test/test_ipaddress.py
@@ -42,9 +42,20 @@
         self.assertEqual(ipaddress.IPv6Address('::ffff') - (2**16 - 2),
                          ipaddress.IPv6Address('::1'))
 
-    def testInvalidStrings(self):
+    def testInvalidIntToBytes(self):
+        self.assertRaises(ValueError, ipaddress.v4_int_to_packed, -1)
+        self.assertRaises(ValueError, ipaddress.v4_int_to_packed,
+                          2 ** ipaddress.IPV4LENGTH)
+        self.assertRaises(ValueError, ipaddress.v6_int_to_packed, -1)
+        self.assertRaises(ValueError, ipaddress.v6_int_to_packed,
+                          2 ** ipaddress.IPV6LENGTH)
+
+    def testInvalidStringsInAddressFactory(self):
         def AssertInvalidIP(ip_str):
-            self.assertRaises(ValueError, ipaddress.ip_address, ip_str)
+            with self.assertRaises(ValueError) as ex:
+                ipaddress.ip_address(ip_str)
+            self.assertIsNone(ex.exception.__context__)
+
         AssertInvalidIP("")
         AssertInvalidIP("016.016.016.016")
         AssertInvalidIP("016.016.016")
@@ -106,42 +117,36 @@
         AssertInvalidIP(":1:2:3:4:5:6:7")
         AssertInvalidIP("1:2:3:4:5:6:7:")
         AssertInvalidIP(":1:2:3:4:5:6:")
+        AssertInvalidIP("1000")
+        AssertInvalidIP("1000000000000000")
+        AssertInvalidIP("02001:db8::")
+        self.assertRaises(ValueError, ipaddress.ip_interface, 'bogus')
 
-        self.assertRaises(ipaddress.AddressValueError,
-                          ipaddress.IPv4Interface, '')
-        self.assertRaises(ipaddress.AddressValueError, ipaddress.IPv4Interface,
-                          'google.com')
-        self.assertRaises(ipaddress.AddressValueError, ipaddress.IPv4Interface,
-                          '::1.2.3.4')
-        self.assertRaises(ipaddress.AddressValueError,
-                          ipaddress.IPv6Interface, '')
-        self.assertRaises(ipaddress.AddressValueError, ipaddress.IPv6Interface,
-                          'google.com')
-        self.assertRaises(ipaddress.AddressValueError, ipaddress.IPv6Interface,
-                          '1.2.3.4')
-        self.assertRaises(ipaddress.AddressValueError, ipaddress.IPv6Interface,
-                          'cafe:cafe::/128/190')
-        self.assertRaises(ipaddress.AddressValueError, ipaddress.IPv6Interface,
-                          '1234:axy::b')
-        self.assertRaises(ipaddress.AddressValueError, ipaddress.IPv6Address,
-                          '1234:axy::b')
-        self.assertRaises(ipaddress.AddressValueError, ipaddress.IPv6Address,
-                          '2001:db8:::1')
-        self.assertRaises(ipaddress.AddressValueError, ipaddress.IPv6Address,
-                          '2001:888888::1')
-        self.assertRaises(ipaddress.AddressValueError,
-                          ipaddress.IPv4Address(1)._ip_int_from_string,
+    def testInvalidStringsInConstructors(self):
+        def AssertInvalidIP(ip_class, ip_str):
+            with self.assertRaises(ipaddress.AddressValueError) as ex:
+                ip_class(ip_str)
+            if ex.exception.__context__ is not None:
+                # Provide clean tracebacks by default
+                self.assertTrue(ex.exception.__suppress_context__)
+
+        AssertInvalidIP(ipaddress.IPv4Address, '127.0.0.1/32')
+        AssertInvalidIP(ipaddress.IPv4Address(1)._ip_int_from_string,
                           '1.a.2.3')
-        self.assertEqual(False, ipaddress.IPv4Interface(1)._is_hostmask(
-                '1.a.2.3'))
-        self.assertRaises(ValueError, ipaddress.ip_interface, 'bogus')
-        self.assertRaises(ValueError, ipaddress.IPv4Address, '127.0.0.1/32')
-        self.assertRaises(ValueError, ipaddress.v4_int_to_packed, -1)
-        self.assertRaises(ValueError, ipaddress.v4_int_to_packed,
-                          2 ** ipaddress.IPV4LENGTH)
-        self.assertRaises(ValueError, ipaddress.v6_int_to_packed, -1)
-        self.assertRaises(ValueError, ipaddress.v6_int_to_packed,
-                          2 ** ipaddress.IPV6LENGTH)
+        AssertInvalidIP(ipaddress.IPv4Interface, '')
+        AssertInvalidIP(ipaddress.IPv4Interface, 'google.com')
+        AssertInvalidIP(ipaddress.IPv6Address, '1234:axy::b')
+        AssertInvalidIP(ipaddress.IPv6Address, '2001:db8:::1')
+        AssertInvalidIP(ipaddress.IPv6Address, '2001:888888::1')
+        AssertInvalidIP(ipaddress.IPv4Interface, '::1.2.3.4')
+        AssertInvalidIP(ipaddress.IPv6Interface, '')
+        AssertInvalidIP(ipaddress.IPv6Interface, 'google.com')
+        AssertInvalidIP(ipaddress.IPv6Interface, '1.2.3.4')
+        AssertInvalidIP(ipaddress.IPv6Interface, 'cafe:cafe::/128/190')
+        AssertInvalidIP(ipaddress.IPv6Interface, '1234:axy::b')
+
+    def testInvalidHostmask(self):
+        self.assertFalse(ipaddress.IPv4Interface(1)._is_hostmask('1.a.2.3'))
 
     def testInternals(self):
         first, last = ipaddress._find_address_range([

-- 
Repository URL: http://hg.python.org/cpython

From python-checkins at python.org  Fri Jul  6 17:43:50 2012
From: python-checkins at python.org (nick.coghlan)
Date: Fri,  6 Jul 2012 17:43:50 +0200 (CEST)
Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_14814=3A_Eliminate_b?=
 =?utf-8?q?ytes_warnings_from_ipaddress_by_correctly_throwing_an?=
Message-ID: <3WTKwk6NJ3zNGs@mail.python.org>

http://hg.python.org/cpython/rev/30e8f2242190
changeset:   77953:30e8f2242190
user:        Nick Coghlan 
date:        Sat Jul 07 01:43:31 2012 +1000
summary:
  Issue 14814: Eliminate bytes warnings from ipaddress by correctly throwing an exception early when given bytes data of the wrong length. Also removes 2.x backwards compatibility code from associated tests.

files:
  Lib/ipaddress.py           |  16 +++++-
  Lib/test/test_ipaddress.py |  61 ++++++++++++++-----------
  2 files changed, 46 insertions(+), 31 deletions(-)


diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py
--- a/Lib/ipaddress.py
+++ b/Lib/ipaddress.py
@@ -1250,7 +1250,9 @@
             return
 
         # Constructing from a packed address
-        if isinstance(address, bytes) and len(address) == 4:
+        if isinstance(address, bytes):
+            if len(address) != 4:
+                raise AddressValueError(address)
             self._ip = struct.unpack('!I', address)[0]
             return
 
@@ -1379,7 +1381,9 @@
         _BaseNetwork.__init__(self, address)
 
         # Constructing from a packed address
-        if isinstance(address, bytes) and len(address) == 4:
+        if isinstance(address, bytes):
+            if len(address) != 4:
+                raise AddressValueError(address)
             self.network_address = IPv4Address(
                 struct.unpack('!I', address)[0])
             self._prefixlen = self._max_prefixlen
@@ -1864,7 +1868,9 @@
             return
 
         # Constructing from a packed address
-        if isinstance(address, bytes) and len(address) == 16:
+        if isinstance(address, bytes):
+            if len(address) != 16:
+                raise AddressValueError(address)
             tmp = struct.unpack('!QQ', address)
             self._ip = (tmp[0] << 64) | tmp[1]
             return
@@ -1996,7 +2002,9 @@
             return
 
         # Constructing from a packed address
-        if isinstance(address, bytes) and len(address) == 16:
+        if isinstance(address, bytes):
+            if len(address) != 16:
+                raise AddressValueError(address)
             tmp = struct.unpack('!QQ', address)
             self.network_address = IPv6Address((tmp[0] << 64) | tmp[1])
             self._prefixlen = self._max_prefixlen
diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py
--- a/Lib/test/test_ipaddress.py
+++ b/Lib/test/test_ipaddress.py
@@ -8,10 +8,6 @@
 import ipaddress
 
 
-# Compatibility function to cast str to bytes objects
-_cb = lambda bytestr: bytes(bytestr, 'charmap')
-
-
 class IpaddrUnitTest(unittest.TestCase):
 
     def setUp(self):
@@ -267,25 +263,36 @@
                          6)
 
     def testIpFromPacked(self):
-        ip = ipaddress.ip_network
-
+        address = ipaddress.ip_address
         self.assertEqual(self.ipv4_interface._ip,
-                         ipaddress.ip_interface(_cb('\x01\x02\x03\x04'))._ip)
-        self.assertEqual(ip('255.254.253.252'),
-                         ip(_cb('\xff\xfe\xfd\xfc')))
-        self.assertRaises(ValueError, ipaddress.ip_network, _cb('\x00' * 3))
-        self.assertRaises(ValueError, ipaddress.ip_network, _cb('\x00' * 5))
+                         ipaddress.ip_interface(b'\x01\x02\x03\x04')._ip)
+        self.assertEqual(address('255.254.253.252'),
+                         address(b'\xff\xfe\xfd\xfc'))
         self.assertEqual(self.ipv6_interface.ip,
                          ipaddress.ip_interface(
-                _cb('\x20\x01\x06\x58\x02\x2a\xca\xfe'
-                    '\x02\x00\x00\x00\x00\x00\x00\x01')).ip)
-        self.assertEqual(ip('ffff:2:3:4:ffff::'),
-                         ip(_cb('\xff\xff\x00\x02\x00\x03\x00\x04' +
-                                '\xff\xff' + '\x00' * 6)))
-        self.assertEqual(ip('::'),
-                         ip(_cb('\x00' * 16)))
-        self.assertRaises(ValueError, ip, _cb('\x00' * 15))
-        self.assertRaises(ValueError, ip, _cb('\x00' * 17))
+                    b'\x20\x01\x06\x58\x02\x2a\xca\xfe'
+                    b'\x02\x00\x00\x00\x00\x00\x00\x01').ip)
+        self.assertEqual(address('ffff:2:3:4:ffff::'),
+                         address(b'\xff\xff\x00\x02\x00\x03\x00\x04' +
+                            b'\xff\xff' + b'\x00' * 6))
+        self.assertEqual(address('::'),
+                         address(b'\x00' * 16))
+
+    def testIpFromPackedErrors(self):
+        def assertInvalidPackedAddress(f, length):
+            self.assertRaises(ValueError, f, b'\x00' * length)
+        assertInvalidPackedAddress(ipaddress.ip_address, 3)
+        assertInvalidPackedAddress(ipaddress.ip_address, 5)
+        assertInvalidPackedAddress(ipaddress.ip_address, 15)
+        assertInvalidPackedAddress(ipaddress.ip_address, 17)
+        assertInvalidPackedAddress(ipaddress.ip_interface, 3)
+        assertInvalidPackedAddress(ipaddress.ip_interface, 5)
+        assertInvalidPackedAddress(ipaddress.ip_interface, 15)
+        assertInvalidPackedAddress(ipaddress.ip_interface, 17)
+        assertInvalidPackedAddress(ipaddress.ip_network, 3)
+        assertInvalidPackedAddress(ipaddress.ip_network, 5)
+        assertInvalidPackedAddress(ipaddress.ip_network, 15)
+        assertInvalidPackedAddress(ipaddress.ip_network, 17)
 
     def testGetIp(self):
         self.assertEqual(int(self.ipv4_interface.ip), 16909060)
@@ -893,17 +900,17 @@
 
     def testPacked(self):
         self.assertEqual(self.ipv4_address.packed,
-                         _cb('\x01\x02\x03\x04'))
+                         b'\x01\x02\x03\x04')
         self.assertEqual(ipaddress.IPv4Interface('255.254.253.252').packed,
-                         _cb('\xff\xfe\xfd\xfc'))
+                         b'\xff\xfe\xfd\xfc')
         self.assertEqual(self.ipv6_address.packed,
-                         _cb('\x20\x01\x06\x58\x02\x2a\xca\xfe'
-                             '\x02\x00\x00\x00\x00\x00\x00\x01'))
+                         b'\x20\x01\x06\x58\x02\x2a\xca\xfe'
+                         b'\x02\x00\x00\x00\x00\x00\x00\x01')
         self.assertEqual(ipaddress.IPv6Interface('ffff:2:3:4:ffff::').packed,
-                         _cb('\xff\xff\x00\x02\x00\x03\x00\x04\xff\xff'
-                            + '\x00' * 6))
+                         b'\xff\xff\x00\x02\x00\x03\x00\x04\xff\xff'
+                            + b'\x00' * 6)
         self.assertEqual(ipaddress.IPv6Interface('::1:0:0:0:0').packed,
-                         _cb('\x00' * 6 + '\x00\x01' + '\x00' * 8))
+                         b'\x00' * 6 + b'\x00\x01' + b'\x00' * 8)
 
     def testIpStrFromPrefixlen(self):
         ipv4 = ipaddress.IPv4Interface('1.2.3.4/24')

-- 
Repository URL: http://hg.python.org/cpython

From python-checkins at python.org  Fri Jul  6 19:02:32 2012
From: python-checkins at python.org (antoine.pitrou)
Date: Fri,  6 Jul 2012 19:02:32 +0200 (CEST)
Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE1MjQ3?=
 =?utf-8?q?=3A_FileIO_now_raises_an_error_when_given_a_file_descriptor_poi?=
 =?utf-8?q?nting?=
Message-ID: <3WTMgX5kp5zMTk@mail.python.org>

http://hg.python.org/cpython/rev/9cf9527358a5
changeset:   77954:9cf9527358a5
branch:      3.2
parent:      77949:c97d78415f5a
user:        Antoine Pitrou 
date:        Fri Jul 06 18:48:24 2012 +0200
summary:
  Issue #15247: FileIO now raises an error when given a file descriptor pointing to a directory.

files:
  Lib/test/test_fileio.py |   8 ++++++++
  Misc/NEWS               |   3 +++
  Modules/_io/fileio.c    |  17 +++++------------
  3 files changed, 16 insertions(+), 12 deletions(-)


diff --git a/Lib/test/test_fileio.py b/Lib/test/test_fileio.py
--- a/Lib/test/test_fileio.py
+++ b/Lib/test/test_fileio.py
@@ -127,6 +127,14 @@
         else:
             self.fail("Should have raised IOError")
 
+    @unittest.skipIf(os.name == 'nt', "test only works on a POSIX-like system")
+    def testOpenDirFD(self):
+        fd = os.open('.', os.O_RDONLY)
+        with self.assertRaises(IOError) as cm:
+            _FileIO(fd, 'r')
+        os.close(fd)
+        self.assertEqual(cm.exception.errno, errno.EISDIR)
+
     #A set of functions testing that we get expected behaviour if someone has
     #manually closed the internal file descriptor.  First, a decorator:
     def ClosedFD(func):
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -87,6 +87,9 @@
 Library
 -------
 
+- Issue #15247: FileIO now raises an error when given a file descriptor
+  pointing to a directory.
+
 - Issue #5346: Preserve permissions of mbox, MMDF and Babyl mailbox
   files on flush().
 
diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c
--- a/Modules/_io/fileio.c
+++ b/Modules/_io/fileio.c
@@ -166,22 +166,15 @@
    directories, so we need a check.  */
 
 static int
-dircheck(fileio* self, const char *name)
+dircheck(fileio* self, PyObject *nameobj)
 {
 #if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR)
     struct stat buf;
     if (self->fd < 0)
         return 0;
     if (fstat(self->fd, &buf) == 0 && S_ISDIR(buf.st_mode)) {
-        char *msg = strerror(EISDIR);
-        PyObject *exc;
-        if (internal_close(self))
-            return -1;
-
-        exc = PyObject_CallFunction(PyExc_IOError, "(iss)",
-                                    EISDIR, msg, name);
-        PyErr_SetObject(PyExc_IOError, exc);
-        Py_XDECREF(exc);
+        errno = EISDIR;
+        PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, nameobj);
         return -1;
     }
 #endif
@@ -373,9 +366,9 @@
                 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
             goto error;
         }
-        if (dircheck(self, name) < 0)
-            goto error;
     }
+    if (dircheck(self, nameobj) < 0)
+        goto error;
 
 #if defined(MS_WINDOWS) || defined(__CYGWIN__)
     /* don't translate newlines (\r\n <=> \n) */

-- 
Repository URL: http://hg.python.org/cpython

From python-checkins at python.org  Fri Jul  6 19:02:34 2012
From: python-checkins at python.org (antoine.pitrou)
Date: Fri,  6 Jul 2012 19:02:34 +0200 (CEST)
Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?=
 =?utf-8?q?=29=3A_Issue_=2315247=3A_FileIO_now_raises_an_error_when_given_?=
 =?utf-8?q?a_file_descriptor_pointing?=
Message-ID: <3WTMgZ3Rr8zLtR@mail.python.org>

http://hg.python.org/cpython/rev/19bd61ed3b3b
changeset:   77955:19bd61ed3b3b
parent:      77953:30e8f2242190
parent:      77954:9cf9527358a5
user:        Antoine Pitrou 
date:        Fri Jul 06 18:52:58 2012 +0200
summary:
  Issue #15247: FileIO now raises an error when given a file descriptor pointing to a directory.

files:
  Lib/test/test_fileio.py |   8 ++++++++
  Misc/NEWS               |   3 +++
  Modules/_io/fileio.c    |  17 +++++------------
  3 files changed, 16 insertions(+), 12 deletions(-)


diff --git a/Lib/test/test_fileio.py b/Lib/test/test_fileio.py
--- a/Lib/test/test_fileio.py
+++ b/Lib/test/test_fileio.py
@@ -128,6 +128,14 @@
         else:
             self.fail("Should have raised IOError")
 
+    @unittest.skipIf(os.name == 'nt', "test only works on a POSIX-like system")
+    def testOpenDirFD(self):
+        fd = os.open('.', os.O_RDONLY)
+        with self.assertRaises(IOError) as cm:
+            _FileIO(fd, 'r')
+        os.close(fd)
+        self.assertEqual(cm.exception.errno, errno.EISDIR)
+
     #A set of functions testing that we get expected behaviour if someone has
     #manually closed the internal file descriptor.  First, a decorator:
     def ClosedFD(func):
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -23,6 +23,9 @@
 Library
 -------
 
+- Issue #15247: FileIO now raises an error when given a file descriptor
+  pointing to a directory.
+
 - Issue #15261: Stop os.stat(fd) crashing on Windows when fd not open.
 
 - Issue #15166: Implement imp.get_tag() using sys.implementation.cache_tag.
diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c
--- a/Modules/_io/fileio.c
+++ b/Modules/_io/fileio.c
@@ -169,22 +169,15 @@
    directories, so we need a check.  */
 
 static int
-dircheck(fileio* self, const char *name)
+dircheck(fileio* self, PyObject *nameobj)
 {
 #if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR)
     struct stat buf;
     if (self->fd < 0)
         return 0;
     if (fstat(self->fd, &buf) == 0 && S_ISDIR(buf.st_mode)) {
-        char *msg = strerror(EISDIR);
-        PyObject *exc;
-        if (internal_close(self))
-            return -1;
-
-        exc = PyObject_CallFunction(PyExc_IOError, "(iss)",
-                                    EISDIR, msg, name);
-        PyErr_SetObject(PyExc_IOError, exc);
-        Py_XDECREF(exc);
+        errno = EISDIR;
+        PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, nameobj);
         return -1;
     }
 #endif
@@ -406,9 +399,9 @@
                 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
             goto error;
         }
-        if (dircheck(self, name) < 0)
-            goto error;
     }
+    if (dircheck(self, nameobj) < 0)
+        goto error;
 
 #if defined(MS_WINDOWS) || defined(__CYGWIN__)
     /* don't translate newlines (\r\n <=> \n) */

-- 
Repository URL: http://hg.python.org/cpython

From python-checkins at python.org  Fri Jul  6 19:02:35 2012
From: python-checkins at python.org (antoine.pitrou)
Date: Fri,  6 Jul 2012 19:02:35 +0200 (CEST)
Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE1MjQ3?=
 =?utf-8?q?=3A_FileIO_now_raises_an_error_when_given_a_file_descriptor_poi?=
 =?utf-8?q?nting?=
Message-ID: <3WTMgb6nmHzMTk@mail.python.org>

http://hg.python.org/cpython/rev/d7040647d590
changeset:   77956:d7040647d590
branch:      2.7
parent:      77948:55b3de6d701e
user:        Antoine Pitrou 
date:        Fri Jul 06 18:48:24 2012 +0200
summary:
  Issue #15247: FileIO now raises an error when given a file descriptor pointing to a directory.

files:
  Lib/test/test_fileio.py |   8 ++++++++
  Misc/NEWS               |   3 +++
  Modules/_io/fileio.c    |  17 +++++------------
  3 files changed, 16 insertions(+), 12 deletions(-)


diff --git a/Lib/test/test_fileio.py b/Lib/test/test_fileio.py
--- a/Lib/test/test_fileio.py
+++ b/Lib/test/test_fileio.py
@@ -130,6 +130,14 @@
         else:
             self.fail("Should have raised IOError")
 
+    @unittest.skipIf(os.name == 'nt', "test only works on a POSIX-like system")
+    def testOpenDirFD(self):
+        fd = os.open('.', os.O_RDONLY)
+        with self.assertRaises(IOError) as cm:
+            _FileIO(fd, 'r')
+        os.close(fd)
+        self.assertEqual(cm.exception.errno, errno.EISDIR)
+
     #A set of functions testing that we get expected behaviour if someone has
     #manually closed the internal file descriptor.  First, a decorator:
     def ClosedFD(func):
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -84,6 +84,9 @@
 Library
 -------
 
+- Issue #15247: FileIO now raises an error when given a file descriptor
+  pointing to a directory.
+
 - Issue #14591: Fix bug in Random.jumpahead that could produce an invalid
   Mersenne Twister state on 64-bit machines.
 
diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c
--- a/Modules/_io/fileio.c
+++ b/Modules/_io/fileio.c
@@ -137,22 +137,15 @@
    directories, so we need a check.  */
 
 static int
-dircheck(fileio* self, const char *name)
+dircheck(fileio* self, PyObject *nameobj)
 {
 #if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR)
     struct stat buf;
     if (self->fd < 0)
         return 0;
     if (fstat(self->fd, &buf) == 0 && S_ISDIR(buf.st_mode)) {
-        char *msg = strerror(EISDIR);
-        PyObject *exc;
-        if (internal_close(self))
-            return -1;
-
-        exc = PyObject_CallFunction(PyExc_IOError, "(iss)",
-                                    EISDIR, msg, name);
-        PyErr_SetObject(PyExc_IOError, exc);
-        Py_XDECREF(exc);
+        errno = EISDIR;
+        PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, nameobj);
         return -1;
     }
 #endif
@@ -356,9 +349,9 @@
                 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
             goto error;
         }
-        if(dircheck(self, name) < 0)
-            goto error;
     }
+    if (dircheck(self, nameobj) < 0)
+        goto error;
 
     if (PyObject_SetAttrString((PyObject *)self, "name", nameobj) < 0)
         goto error;

-- 
Repository URL: http://hg.python.org/cpython

From python-checkins at python.org  Fri Jul  6 20:29:48 2012
From: python-checkins at python.org (ezio.melotti)
Date: Fri,  6 Jul 2012 20:29:48 +0200 (CEST)
Subject: [Python-checkins] r88980 -
	tracker/instances/python-dev/html/page.html
Message-ID: <3WTPcD2BvtzNT5@mail.python.org>

Author: ezio.melotti
Date: Fri Jul  6 20:29:47 2012
New Revision: 88980

Log:
#470: update links in the sidebar.

Modified:
   tracker/instances/python-dev/html/page.html

Modified: tracker/instances/python-dev/html/page.html
==============================================================================
--- tracker/instances/python-dev/html/page.html	(original)
+++ tracker/instances/python-dev/html/page.html	Fri Jul  6 20:29:47 2012
@@ -68,8 +68,7 @@
     
  • Documentation
  • Download
  • Community
  • -
  • PSF
  • -
  • Links
  • +
  • Foundation
  • Core Development
  • Issue Tracker
      From python-checkins at python.org Fri Jul 6 21:36:12 2012 From: python-checkins at python.org (georg.brandl) Date: Fri, 6 Jul 2012 21:36:12 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fix_leftover_q?= =?utf-8?q?uote=2E?= Message-ID: <3WTR4r6JrjzMwb@mail.python.org> http://hg.python.org/cpython/rev/b90968d584c3 changeset: 77957:b90968d584c3 branch: 2.7 user: Georg Brandl date: Fri Jul 06 21:36:48 2012 +0200 summary: Fix leftover quote. files: Doc/library/itertools.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -734,7 +734,7 @@ def grouper(n, iterable, fillvalue=None): "Collect data into fixed-length chunks or blocks" - # grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx" + # grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx args = [iter(iterable)] * n return izip_longest(fillvalue=fillvalue, *args) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 03:08:34 2012 From: python-checkins at python.org (matthias.klose) Date: Sat, 7 Jul 2012 03:08:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_-_Issue_=2315268=3A_Search?= =?utf-8?q?_curses=2Eh_in_/usr/include/ncursesw=2E?= Message-ID: <3WTZSL3F8fzNSS@mail.python.org> http://hg.python.org/cpython/rev/707761d59a4a changeset: 77958:707761d59a4a parent: 77955:19bd61ed3b3b user: doko at ubuntu.com date: Sat Jul 07 03:06:42 2012 +0200 summary: - Issue #15268: Search curses.h in /usr/include/ncursesw. files: Misc/NEWS | 2 ++ configure | 7 +++++++ configure.ac | 7 +++++++ 3 files changed, 16 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -72,6 +72,8 @@ - Issue #15235: Allow Berkley DB versions up to 5.3 to build the dbm module. +- Issue #15268: Search curses.h in /usr/include/ncursesw. + What's New in Python 3.3.0 Beta 1? ================================== diff --git a/configure b/configure --- a/configure +++ b/configure @@ -6852,6 +6852,8 @@ fi +ac_save_cppflags="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS -I/usr/include/ncursesw" for ac_header in asm/types.h conio.h curses.h direct.h dlfcn.h errno.h \ fcntl.h grp.h \ ieeefp.h io.h langinfo.h libintl.h ncurses.h process.h pthread.h \ @@ -6877,6 +6879,7 @@ done +CPPFLAGS=$ac_save_cppflags ac_header_dirent=no for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` @@ -14350,6 +14353,8 @@ fi +ac_save_cppflags="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS -I/usr/include/ncursesw" # On HP/UX 11.0, mvwdelch is a block with a return statement { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mvwdelch is an expression" >&5 $as_echo_n "checking whether mvwdelch is an expression... " >&6; } @@ -14503,6 +14508,8 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# last curses configure check +CPPFLAGS=$ac_save_cppflags { $as_echo "$as_me:${as_lineno-$LINENO}: checking for device files" >&5 $as_echo "$as_me: checking for device files" >&6;} diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -1485,6 +1485,8 @@ # checks for header files AC_HEADER_STDC +ac_save_cppflags="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS -I/usr/include/ncursesw" AC_CHECK_HEADERS(asm/types.h conio.h curses.h direct.h dlfcn.h errno.h \ fcntl.h grp.h \ ieeefp.h io.h langinfo.h libintl.h ncurses.h process.h pthread.h \ @@ -1498,6 +1500,7 @@ sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \ libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \ bluetooth/bluetooth.h linux/tipc.h spawn.h util.h) +CPPFLAGS=$ac_save_cppflags AC_HEADER_DIRENT AC_HEADER_MAJOR @@ -4205,6 +4208,8 @@ [Define if you have struct stat.st_mtimensec]) fi +ac_save_cppflags="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS -I/usr/include/ncursesw" # On HP/UX 11.0, mvwdelch is a block with a return statement AC_MSG_CHECKING(whether mvwdelch is an expression) AC_CACHE_VAL(ac_cv_mvwdelch_is_expression, @@ -4259,6 +4264,8 @@ AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no)] ) +# last curses configure check +CPPFLAGS=$ac_save_cppflags AC_MSG_NOTICE([checking for device files]) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 03:16:33 2012 From: python-checkins at python.org (ned.deily) Date: Sat, 7 Jul 2012 03:16:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devguide=3A_Issue_=2315259=3A_Remove_?= =?utf-8?q?reference_to_dailybuild=2Epy=2E?= Message-ID: <3WTZdY6JrtzNTS@mail.python.org> http://hg.python.org/devguide/rev/d1958a94d0ff changeset: 528:d1958a94d0ff user: Ned Deily date: Fri Jul 06 18:16:22 2012 -0700 summary: Issue #15259: Remove reference to dailybuild.py. (Original patch by Chris Jerdonek) files: docquality.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docquality.rst b/docquality.rst --- a/docquality.rst +++ b/docquality.rst @@ -14,9 +14,9 @@ documentation (which allows you to see how your changes will look along with validating that your new markup is correct). -The current in-development version of the documentation is available at -http://docs.python.org/dev/. It is re-generated from source once a day from the -``Doc/tools/dailybuild.py`` script as found in Python's source tree. +The current in-development version of the documentation can be viewed at +http://docs.python.org/dev/. This version is regenerated from source +once a day. If you would like a technical documentation style guide, the `Apple Publications Style Guide -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sat Jul 7 03:39:53 2012 From: python-checkins at python.org (ned.deily) Date: Sat, 7 Jul 2012 03:39:53 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devguide=3A_Issue_=2315260=3A_Expand_?= =?utf-8?q?information_on_Misc/NEWS_entries=2E?= Message-ID: <3WTb8T4QNKzNPx@mail.python.org> http://hg.python.org/devguide/rev/bbe197bf57a1 changeset: 529:bbe197bf57a1 user: Ned Deily date: Fri Jul 06 18:24:45 2012 -0700 summary: Issue #15260: Expand information on Misc/NEWS entries. (Patch by Chris Jerdonek) files: committing.rst | 50 ++++++++++++++++++++++++------------- 1 files changed, 32 insertions(+), 18 deletions(-) diff --git a/committing.rst b/committing.rst --- a/committing.rst +++ b/committing.rst @@ -43,8 +43,38 @@ making a complete patch. -Commit Messages and NEWS Entries --------------------------------- +NEWS Entries +------------ + +Almost all changes made to the code base deserve an entry in ``Misc/NEWS``. +The ``What's New in Python`` document is the place for more subjective +judgments of the "importance" of changes. There are two notable exceptions +to this general principle, and they both relate to changes that *already* +have a NEWS entry, and have not yet been included in any formal release +(including alpha and beta releases). These exceptions are: + +* If a change is reverted prior to release, then the corresponding entry + is simply removed. Otherwise, a new entry must be added noting that the + change has been reverted (e.g. when a feature is released in an alpha and + then cut prior to the first beta) + +* If a change is a fix (or other adjustment) to an earlier unreleased change + and the original NEWS entry remains valid, then no additional entry is + needed. + +New NEWS entries are customarily added at or near the top of their +respective sections, so that entries within a section appear in approximate +order from newest to oldest. However, this is customary and not a +requirement. + +A nice trick to make Mercurial?s automatic file merge work more smoothly +is to put a new entry after the first or first two entries rather than +at the very top. This way if you commit, pull new changesets and merge, +the merge will succeed automatically. + + +Commit Messages +--------------- Every commit has a commit message to document why a change was made and to communicate that reason to other core developers. Python core developers have @@ -67,22 +97,6 @@ understands the justification for the change). Also, if a non-core developer contributed to the resolution, it is good practice to credit them. -Almost all changes made to the code base deserve an entry in ``Misc/NEWS``. -The ``What's New in Python`` document is the place for more subjective -judgments of the "importance" of changes. There are two notable exceptions -to this general principle, and they both relate to changes that *already* -have a NEWS entry, and have not yet been included in any formal release -(including alpha and beta releases). These exceptions are: - -* If a change is reverted prior to release, then the corresponding entry - is simply removed. Otherwise, a new entry must be added noting that the - change has been reverted (e.g. when a feature is released in an alpha and - then cut prior to the first beta) - -* If a change is a fix (or other adjustment) to an earlier unreleased change - and the original NEWS entry remains valid, then no additional entry is - needed. - Mercurial hooks ''''''''''''''' -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sat Jul 7 05:35:26 2012 From: python-checkins at python.org (nick.coghlan) Date: Sat, 7 Jul 2012 05:35:26 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_14814=3A_=25s_implie?= =?utf-8?q?s_coercion_with_str=28=29_-_remove_a_lot_of_redundant_str=28=29?= Message-ID: <3WTdjp4KLyzNXt@mail.python.org> http://hg.python.org/cpython/rev/d9c98730e2e8 changeset: 77959:d9c98730e2e8 user: Nick Coghlan date: Sat Jul 07 13:34:50 2012 +1000 summary: Issue 14814: %s implies coercion with str() - remove a lot of redundant str() calls from the ipaddress implementation files: Lib/ipaddress.py | 67 +++++++++++++++++------------------ 1 files changed, 33 insertions(+), 34 deletions(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -242,7 +242,7 @@ raise TypeError('first and last must be IP addresses, not networks') if first.version != last.version: raise TypeError("%s and %s are not of the same version" % ( - str(first), str(last))) + first, last)) if first > last: raise ValueError('last IP address must be greater than first') @@ -266,7 +266,7 @@ if current <= last_int: break prefix = _get_prefix_length(first_int, current, ip_bits) - net = ip('%s/%d' % (str(first), prefix)) + net = ip('%s/%d' % (first, prefix)) yield net if current == ip._ALL_ONES: break @@ -348,12 +348,12 @@ if isinstance(ip, _BaseAddress): if ips and ips[-1]._version != ip._version: raise TypeError("%s and %s are not of the same version" % ( - str(ip), str(ips[-1]))) + ip, ips[-1])) ips.append(ip) elif ip._prefixlen == ip._max_prefixlen: if ips and ips[-1]._version != ip._version: raise TypeError("%s and %s are not of the same version" % ( - str(ip), str(ips[-1]))) + ip, ips[-1])) try: ips.append(ip.ip) except AttributeError: @@ -361,7 +361,7 @@ else: if nets and nets[-1]._version != ip._version: raise TypeError("%s and %s are not of the same version" % ( - str(ip), str(nets[-1]))) + ip, nets[-1])) nets.append(ip) # sort and dedup @@ -517,10 +517,10 @@ def __lt__(self, other): if self._version != other._version: raise TypeError('%s and %s are not of the same version' % ( - str(self), str(other))) + self, other)) if not isinstance(other, _BaseAddress): raise TypeError('%s and %s are not of the same type' % ( - str(self), str(other))) + self, other)) if self._ip != other._ip: return self._ip < other._ip return False @@ -528,10 +528,10 @@ def __gt__(self, other): if self._version != other._version: raise TypeError('%s and %s are not of the same version' % ( - str(self), str(other))) + self, other)) if not isinstance(other, _BaseAddress): raise TypeError('%s and %s are not of the same type' % ( - str(self), str(other))) + self, other)) if self._ip != other._ip: return self._ip > other._ip return False @@ -582,8 +582,7 @@ return '%s(%r)' % (self.__class__.__name__, str(self)) def __str__(self): - return '%s/%d' % (str(self.network_address), - self.prefixlen) + return '%s/%d' % (self.network_address, self.prefixlen) def hosts(self): """Generate Iterator over usable hosts in a network. @@ -621,10 +620,10 @@ def __lt__(self, other): if self._version != other._version: raise TypeError('%s and %s are not of the same version' % ( - str(self), str(other))) + self, other)) if not isinstance(other, _BaseNetwork): raise TypeError('%s and %s are not of the same type' % ( - str(self), str(other))) + self, other)) if self.network_address != other.network_address: return self.network_address < other.network_address if self.netmask != other.netmask: @@ -634,10 +633,10 @@ def __gt__(self, other): if self._version != other._version: raise TypeError('%s and %s are not of the same version' % ( - str(self), str(other))) + self, other)) if not isinstance(other, _BaseNetwork): raise TypeError('%s and %s are not of the same type' % ( - str(self), str(other))) + self, other)) if self.network_address != other.network_address: return self.network_address > other.network_address if self.netmask != other.netmask: @@ -659,7 +658,7 @@ def __eq__(self, other): if not isinstance(other, _BaseNetwork): raise TypeError('%s and %s are not of the same type' % ( - str(self), str(other))) + self, other)) return (self._version == other._version and self.network_address == other.network_address and int(self.netmask) == int(other.netmask)) @@ -712,15 +711,15 @@ @property def with_prefixlen(self): - return '%s/%d' % (str(self.network_address), self._prefixlen) + return '%s/%d' % (self.network_address, self._prefixlen) @property def with_netmask(self): - return '%s/%s' % (str(self.network_address), str(self.netmask)) + return '%s/%s' % (self.network_address, self.netmask) @property def with_hostmask(self): - return '%s/%s' % (str(self.network_address), str(self.hostmask)) + return '%s/%s' % (self.network_address, self.hostmask) @property def num_addresses(self): @@ -777,10 +776,10 @@ """ if not self._version == other._version: raise TypeError("%s and %s are not of the same version" % ( - str(self), str(other))) + self, other)) if not isinstance(other, _BaseNetwork): - raise TypeError("%s is not a network object" % str(other)) + raise TypeError("%s is not a network object" % other) if not (other.network_address >= self.network_address and other.broadcast_address <= self.broadcast_address): @@ -789,8 +788,8 @@ raise StopIteration # Make sure we're comparing the network of other. - other = other.__class__('%s/%s' % (str(other.network_address), - str(other.prefixlen))) + other = other.__class__('%s/%s' % (other.network_address, + other.prefixlen)) s1, s2 = self.subnets() while s1 != other and s2 != other: @@ -806,7 +805,7 @@ # If we got here, there's a bug somewhere. raise AssertionError('Error performing exclusion: ' 's1: %s s2: %s other: %s' % - (str(s1), str(s2), str(other))) + (s1, s2, other)) if s1 == other: yield s2 elif s2 == other: @@ -815,7 +814,7 @@ # If we got here, there's a bug somewhere. raise AssertionError('Error performing exclusion: ' 's1: %s s2: %s other: %s' % - (str(s1), str(s2), str(other))) + (s1, s2, other)) def compare_networks(self, other): """Compare two IP objects. @@ -852,7 +851,7 @@ # does this need to raise a ValueError? if self._version != other._version: raise TypeError('%s and %s are not of the same type' % ( - str(self), str(other))) + self, other)) # self._version == other._version below here: if self.network_address < other.network_address: return -1 @@ -919,11 +918,11 @@ if not self._is_valid_netmask(str(new_prefixlen)): raise ValueError( 'prefix length diff %d is invalid for netblock %s' % ( - new_prefixlen, str(self))) + new_prefixlen, self)) first = self.__class__('%s/%s' % - (str(self.network_address), - str(self._prefixlen + prefixlen_diff))) + (self.network_address, + self._prefixlen + prefixlen_diff)) yield first current = first @@ -932,8 +931,8 @@ if broadcast == self.broadcast_address: return new_addr = self._address_class(int(broadcast) + 1) - current = self.__class__('%s/%s' % (str(new_addr), - str(new_prefixlen))) + current = self.__class__('%s/%s' % (new_addr, + new_prefixlen)) yield current @@ -973,10 +972,10 @@ 'current prefixlen is %d, cannot have a prefixlen_diff of %d' % (self.prefixlen, prefixlen_diff)) # TODO (pmoody): optimize this. - t = self.__class__('%s/%d' % (str(self.network_address), + t = self.__class__('%s/%d' % (self.network_address, self.prefixlen - prefixlen_diff), strict=False) - return t.__class__('%s/%d' % (str(t.network_address), t.prefixlen)) + return t.__class__('%s/%d' % (t.network_address, t.prefixlen)) class _BaseV4: @@ -2032,7 +2031,7 @@ if strict: if (IPv6Address(int(self.network_address) & int(self.netmask)) != self.network_address): - raise ValueError('%s has host bits set' % str(self)) + raise ValueError('%s has host bits set' % self) self.network_address = IPv6Address(int(self.network_address) & int(self.netmask)) -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat Jul 7 06:00:17 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 07 Jul 2012 06:00:17 +0200 Subject: [Python-checkins] Daily reference leaks (707761d59a4a): sum=-1 Message-ID: results for 707761d59a4a on branch "default" -------------------------------------------- test_exceptions leaked [0, -1, 0] references, sum=-1 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog3TwLnX', '-x'] From python-checkins at python.org Sat Jul 7 11:31:40 2012 From: python-checkins at python.org (nick.coghlan) Date: Sat, 7 Jul 2012 11:31:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_14814=3A_Provide_mor?= =?utf-8?q?e_informative_error_messages_in_ipaddress=2C_and_ensure?= Message-ID: <3WTncr11BmzMs8@mail.python.org> http://hg.python.org/cpython/rev/16ff4889a858 changeset: 77960:16ff4889a858 user: Nick Coghlan date: Sat Jul 07 19:23:53 2012 +1000 summary: Issue 14814: Provide more informative error messages in ipaddress, and ensure that errors are caught as expected files: Lib/ipaddress.py | 141 ++++-- Lib/test/test_ipaddress.py | 553 ++++++++++++++++++------ Misc/NEWS | 4 + 3 files changed, 502 insertions(+), 196 deletions(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -17,7 +17,6 @@ IPV4LENGTH = 32 IPV6LENGTH = 128 - class AddressValueError(ValueError): """A Value Error related to the address.""" @@ -117,7 +116,7 @@ except (AddressValueError, NetmaskValueError): pass - raise ValueError('%r does not appear to be an IPv4 or IPv6 network' % + raise ValueError('%r does not appear to be an IPv4 or IPv6 interface' % address) @@ -157,6 +156,13 @@ raise ValueError("Address negative or too large for IPv6") +def _split_optional_netmask(address): + """Helper to split the netmask and raise AddressValueError if needed""" + addr = str(address).split('/') + if len(addr) > 2: + raise AddressValueError("Only one '/' permitted in %r" % address) + return addr + def _find_address_range(addresses): """Find a sequence of IPv#Address. @@ -481,7 +487,7 @@ def __init__(self, address): if (not isinstance(address, bytes) and '/' in str(address)): - raise AddressValueError(address) + raise AddressValueError("Unexpected '/' in %r" % address) def __index__(self): return self._ip @@ -1014,16 +1020,19 @@ AddressValueError: if ip_str isn't a valid IPv4 Address. """ + if not ip_str: + raise AddressValueError('Address cannot be empty') + octets = ip_str.split('.') if len(octets) != 4: - raise AddressValueError(ip_str) + raise AddressValueError("Expected 4 octets in %r" % ip_str) packed_ip = 0 for oc in octets: try: packed_ip = (packed_ip << 8) | self._parse_octet(oc) - except ValueError: - raise AddressValueError(ip_str) from None + except ValueError as exc: + raise AddressValueError("%s in %r" % (exc, ip_str)) from None return packed_ip def _parse_octet(self, octet_str): @@ -1039,15 +1048,21 @@ ValueError: if the octet isn't strictly a decimal from [0..255]. """ + if not octet_str: + raise ValueError("Empty octet not permitted") # Whitelist the characters, since int() allows a lot of bizarre stuff. - # Higher level wrappers convert these to more informative errors if not self._DECIMAL_DIGITS.issuperset(octet_str): - raise ValueError + raise ValueError("Only decimal digits permitted in %r" % octet_str) + # Convert to integer (we know digits are legal) octet_int = int(octet_str, 10) - # Disallow leading zeroes, because no clear standard exists on - # whether these should be interpreted as decimal or octal. - if octet_int > 255 or (octet_str[0] == '0' and len(octet_str) > 1): - raise ValueError + # Any octets that look like they *might* be written in octal, + # and which don't look exactly the same in both octal and + # decimal are rejected as ambiguous + if octet_int > 7 and octet_str[0] == '0': + raise ValueError("Ambiguous leading zero in %r not permitted" % + octet_str) + if octet_int > 255: + raise ValueError("Octet %d > 255 not permitted" % octet_int) return octet_int def _string_from_ip_int(self, ip_int): @@ -1080,7 +1095,13 @@ """ mask = netmask.split('.') if len(mask) == 4: - if [x for x in mask if int(x) not in self._valid_mask_octets]: + for x in mask: + try: + if int(x) in self._valid_mask_octets: + continue + except ValueError: + pass + # Found something that isn't an integer or isn't valid return False if [y for idx, y in enumerate(mask) if idx > 0 and y > mask[idx - 1]]: @@ -1251,7 +1272,8 @@ # Constructing from a packed address if isinstance(address, bytes): if len(address) != 4: - raise AddressValueError(address) + msg = "Packed address %r must be exactly 4 bytes" + raise AddressValueError(msg % address) self._ip = struct.unpack('!I', address)[0] return @@ -1275,9 +1297,7 @@ self._prefixlen = self._max_prefixlen return - addr = str(address).split('/') - if len(addr) > 2: - raise AddressValueError(address) + addr = _split_optional_netmask(address) IPv4Address.__init__(self, addr[0]) self.network = IPv4Network(address, strict=False) @@ -1382,7 +1402,8 @@ # Constructing from a packed address if isinstance(address, bytes): if len(address) != 4: - raise AddressValueError(address) + msg = "Packed address %r must be exactly 4 bytes" + raise AddressValueError(msg % address) self.network_address = IPv4Address( struct.unpack('!I', address)[0]) self._prefixlen = self._max_prefixlen @@ -1402,12 +1423,9 @@ # Assume input argument to be string or any object representation # which converts into a formatted IP prefix string. - addr = str(address).split('/') + addr = _split_optional_netmask(address) self.network_address = IPv4Address(self._ip_int_from_string(addr[0])) - if len(addr) > 2: - raise AddressValueError(address) - if len(addr) == 2: mask = addr[1].split('.') @@ -1420,14 +1438,15 @@ self.netmask = IPv4Address( self._ip_int_from_string(addr[1]) ^ self._ALL_ONES) else: - raise NetmaskValueError('%s is not a valid netmask' + raise NetmaskValueError('%r is not a valid netmask' % addr[1]) self._prefixlen = self._prefix_from_ip_int(int(self.netmask)) else: # We have a netmask in prefix length form. if not self._is_valid_netmask(addr[1]): - raise NetmaskValueError(addr[1]) + raise NetmaskValueError('%r is not a valid netmask' + % addr[1]) self._prefixlen = int(addr[1]) self.netmask = IPv4Address(self._ip_int_from_prefix( self._prefixlen)) @@ -1477,21 +1496,33 @@ AddressValueError: if ip_str isn't a valid IPv6 Address. """ + if not ip_str: + raise AddressValueError('Address cannot be empty') + parts = ip_str.split(':') # An IPv6 address needs at least 2 colons (3 parts). - if len(parts) < 3: - raise AddressValueError(ip_str) + _min_parts = 3 + if len(parts) < _min_parts: + msg = "At least %d parts expected in %r" % (_min_parts, ip_str) + raise AddressValueError(msg) # If the address has an IPv4-style suffix, convert it to hexadecimal. if '.' in parts[-1]: - ipv4_int = IPv4Address(parts.pop())._ip + try: + ipv4_int = IPv4Address(parts.pop())._ip + except AddressValueError as exc: + raise AddressValueError("%s in %r" % (exc, ip_str)) from None parts.append('%x' % ((ipv4_int >> 16) & 0xFFFF)) parts.append('%x' % (ipv4_int & 0xFFFF)) # An IPv6 address can't have more than 8 colons (9 parts). - if len(parts) > self._HEXTET_COUNT + 1: - raise AddressValueError(ip_str) + # The extra colon comes from using the "::" notation for a single + # leading or trailing zero part. + _max_parts = self._HEXTET_COUNT + 1 + if len(parts) > _max_parts: + msg = "At most %d colons permitted in %r" % (_max_parts-1, ip_str) + raise AddressValueError(msg) # Disregarding the endpoints, find '::' with nothing in between. # This indicates that a run of zeroes has been skipped. @@ -1501,7 +1532,8 @@ [None]) except ValueError: # Can't have more than one '::' - raise AddressValueError(ip_str) from None + msg = "At most one '::' permitted in %r" % ip_str + raise AddressValueError(msg) from None # parts_hi is the number of parts to copy from above/before the '::' # parts_lo is the number of parts to copy from below/after the '::' @@ -1512,20 +1544,30 @@ if not parts[0]: parts_hi -= 1 if parts_hi: - raise AddressValueError(ip_str) # ^: requires ^:: + msg = "Leading ':' only permitted as part of '::' in %r" + raise AddressValueError(msg % ip_str) # ^: requires ^:: if not parts[-1]: parts_lo -= 1 if parts_lo: - raise AddressValueError(ip_str) # :$ requires ::$ + msg = "Trailing ':' only permitted as part of '::' in %r" + raise AddressValueError(msg % ip_str) # :$ requires ::$ parts_skipped = self._HEXTET_COUNT - (parts_hi + parts_lo) if parts_skipped < 1: - raise AddressValueError(ip_str) + msg = "Expected at most %d other parts with '::' in %r" + raise AddressValueError(msg % (self._HEXTET_COUNT-1, ip_str)) else: # Otherwise, allocate the entire address to parts_hi. The # endpoints could still be empty, but _parse_hextet() will check # for that. if len(parts) != self._HEXTET_COUNT: - raise AddressValueError(ip_str) + msg = "Exactly %d parts expected without '::' in %r" + raise AddressValueError(msg % (self._HEXTET_COUNT, ip_str)) + if not parts[0]: + msg = "Leading ':' only permitted as part of '::' in %r" + raise AddressValueError(msg % ip_str) # ^: requires ^:: + if not parts[-1]: + msg = "Trailing ':' only permitted as part of '::' in %r" + raise AddressValueError(msg % ip_str) # :$ requires ::$ parts_hi = len(parts) parts_lo = 0 parts_skipped = 0 @@ -1541,8 +1583,8 @@ ip_int <<= 16 ip_int |= self._parse_hextet(parts[i]) return ip_int - except ValueError: - raise AddressValueError(ip_str) from None + except ValueError as exc: + raise AddressValueError("%s in %r" % (exc, ip_str)) from None def _parse_hextet(self, hextet_str): """Convert an IPv6 hextet string into an integer. @@ -1561,12 +1603,14 @@ # Whitelist the characters, since int() allows a lot of bizarre stuff. # Higher level wrappers convert these to more informative errors if not self._HEX_DIGITS.issuperset(hextet_str): - raise ValueError + raise ValueError("Only hex digits permitted in %r" % hextet_str) if len(hextet_str) > 4: - raise ValueError + msg = "At most 4 characters permitted in %r" + raise ValueError(msg % hextet_str) hextet_int = int(hextet_str, 16) if hextet_int > 0xFFFF: - raise ValueError + # This is unreachable due to the string length check above + raise ValueError("Part %d > 0xFFFF not permitted" % hextet_int) return hextet_int def _compress_hextets(self, hextets): @@ -1869,7 +1913,8 @@ # Constructing from a packed address if isinstance(address, bytes): if len(address) != 16: - raise AddressValueError(address) + msg = "Packed address %r must be exactly 16 bytes" + raise AddressValueError(msg % address) tmp = struct.unpack('!QQ', address) self._ip = (tmp[0] << 64) | tmp[1] return @@ -1877,9 +1922,6 @@ # Assume input argument to be string or any object representation # which converts into a formatted IP string. addr_str = str(address) - if not addr_str: - raise AddressValueError('') - self._ip = self._ip_int_from_string(addr_str) @property @@ -1897,7 +1939,7 @@ self._prefixlen = self._max_prefixlen return - addr = str(address).split('/') + addr = _split_optional_netmask(address) IPv6Address.__init__(self, addr[0]) self.network = IPv6Network(address, strict=False) self.netmask = self.network.netmask @@ -2003,7 +2045,8 @@ # Constructing from a packed address if isinstance(address, bytes): if len(address) != 16: - raise AddressValueError(address) + msg = "Packed address %r must be exactly 16 bytes" + raise AddressValueError(msg % address) tmp = struct.unpack('!QQ', address) self.network_address = IPv6Address((tmp[0] << 64) | tmp[1]) self._prefixlen = self._max_prefixlen @@ -2012,10 +2055,7 @@ # Assume input argument to be string or any object representation # which converts into a formatted IP prefix string. - addr = str(address).split('/') - - if len(addr) > 2: - raise AddressValueError(address) + addr = _split_optional_netmask(address) self.network_address = IPv6Address(self._ip_int_from_string(addr[0])) @@ -2023,7 +2063,8 @@ if self._is_valid_netmask(addr[1]): self._prefixlen = int(addr[1]) else: - raise NetmaskValueError(addr[1]) + raise NetmaskValueError('%r is not a valid netmask' + % addr[1]) else: self._prefixlen = self._max_prefixlen diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -5,8 +5,415 @@ import unittest +import re +import contextlib import ipaddress +class ErrorReporting(unittest.TestCase): + # One big change in ipaddress over the original ipaddr module is + # error reporting that tries to assume users *don't know the rules* + # for what constitutes an RFC compliant IP address + + # Note that if the constructors are refactored so that addresses with + # multiple problems get classified differently, that's OK - just + # move the affected examples to the newly appropriate test case. + + # The error reporting tests also cover a few corner cases that + # specifically *aren't* errors (such as leading zeroes in v6 + # address parts) that don't have an obvious home in the main test + # suite + + @contextlib.contextmanager + def assertCleanError(self, exc_type, details, *args): + """ + Ensure exception does not display a context by default + + Wraps unittest.TestCase.assertRaisesRegex + """ + if args: + details = details % args + cm = self.assertRaisesRegex(exc_type, details) + with cm as exc: + yield exc + # Ensure we produce clean tracebacks on failure + if exc.exception.__context__ is not None: + self.assertTrue(exc.exception.__suppress_context__) + + def assertAddressError(self, details, *args): + """Ensure a clean AddressValueError""" + return self.assertCleanError(ipaddress.AddressValueError, + details, *args) + + def assertNetmaskError(self, details, *args): + """Ensure a clean NetmaskValueError""" + return self.assertCleanError(ipaddress.NetmaskValueError, + details, *args) + +class AddressErrors_v4(ErrorReporting): + + def test_empty_address(self): + with self.assertAddressError("Address cannot be empty"): + ipaddress.IPv4Address("") + + def test_network_passed_as_address(self): + addr = "127.0.0.1/24" + with self.assertAddressError("Unexpected '/' in %r", addr): + ipaddress.IPv4Address(addr) + + def test_bad_address_split(self): + def assertBadSplit(addr): + with self.assertAddressError("Expected 4 octets in %r", addr): + ipaddress.IPv4Address(addr) + + assertBadSplit("127.0.1") + assertBadSplit("42.42.42.42.42") + assertBadSplit("42.42.42") + assertBadSplit("42.42") + assertBadSplit("42") + assertBadSplit("42..42.42.42") + assertBadSplit("42.42.42.42.") + assertBadSplit("42.42.42.42...") + assertBadSplit(".42.42.42.42") + assertBadSplit("...42.42.42.42") + assertBadSplit("016.016.016") + assertBadSplit("016.016") + assertBadSplit("016") + assertBadSplit("000") + assertBadSplit("0x0a.0x0a.0x0a") + assertBadSplit("0x0a.0x0a") + assertBadSplit("0x0a") + assertBadSplit(".") + assertBadSplit("bogus") + assertBadSplit("bogus.com") + assertBadSplit("1000") + assertBadSplit("1000000000000000") + assertBadSplit("192.168.0.1.com") + + def test_empty_octet(self): + def assertBadOctet(addr): + with self.assertAddressError("Empty octet not permitted in %r", + addr): + ipaddress.IPv4Address(addr) + + assertBadOctet("42..42.42") + assertBadOctet("...") + + def test_invalid_characters(self): + def assertBadOctet(addr, octet): + msg = "Only decimal digits permitted in %r in %r" % (octet, addr) + with self.assertAddressError(re.escape(msg)): + ipaddress.IPv4Address(addr) + + assertBadOctet("0x0a.0x0a.0x0a.0x0a", "0x0a") + assertBadOctet("42.42.42.-0", "-0") + assertBadOctet("42.42.42.+0", "+0") + assertBadOctet("42.42.42.-42", "-42") + assertBadOctet("+1.+2.+3.4", "+1") + assertBadOctet("1.2.3.4e0", "4e0") + assertBadOctet("1.2.3.4::", "4::") + assertBadOctet("1.a.2.3", "a") + + def test_leading_zeros(self): + def assertBadOctet(addr, octet): + msg = "Ambiguous leading zero in %r not permitted in %r" + with self.assertAddressError(msg, octet, addr): + ipaddress.IPv4Address(addr) + + assertBadOctet("016.016.016.016", "016") + assertBadOctet("001.000.008.016", "008") + self.assertEqual(ipaddress.IPv4Address("192.168.000.001"), + ipaddress.IPv4Address("192.168.0.1")) + + def test_octet_limit(self): + def assertBadOctet(addr, octet): + msg = "Octet %d > 255 not permitted in %r" + with self.assertAddressError(msg, octet, addr): + ipaddress.IPv4Address(addr) + + assertBadOctet("12345.67899.-54321.-98765", 12345) + assertBadOctet("257.0.0.0", 257) + + def test_bad_packed_length(self): + def assertBadLength(length): + addr = b'\x00' * length + msg = "Packed address %r must be exactly 4 bytes" % addr + with self.assertAddressError(re.escape(msg)): + ipaddress.IPv4Address(addr) + + assertBadLength(3) + assertBadLength(5) + + +class AddressErrors_v6(ErrorReporting): + + def test_empty_address(self): + with self.assertAddressError("Address cannot be empty"): + ipaddress.IPv6Address("") + + def test_network_passed_as_address(self): + addr = "::1/24" + with self.assertAddressError("Unexpected '/' in %r", addr): + ipaddress.IPv6Address(addr) + + def test_bad_address_split_v6_not_enough_parts(self): + def assertBadSplit(addr): + msg = "At least 3 parts expected in %r" + with self.assertAddressError(msg, addr): + ipaddress.IPv6Address(addr) + + assertBadSplit(":") + assertBadSplit(":1") + assertBadSplit("FEDC:9878") + + def test_bad_address_split_v6_too_many_colons(self): + def assertBadSplit(addr): + msg = "At most 8 colons permitted in %r" + with self.assertAddressError(msg, addr): + ipaddress.IPv6Address(addr) + + assertBadSplit("9:8:7:6:5:4:3::2:1") + assertBadSplit("10:9:8:7:6:5:4:3:2:1") + assertBadSplit("::8:7:6:5:4:3:2:1") + assertBadSplit("8:7:6:5:4:3:2:1::") + # A trailing IPv4 address is two parts + assertBadSplit("10:9:8:7:6:5:4:3:42.42.42.42") + + def test_bad_address_split_v6_too_many_parts(self): + def assertBadSplit(addr): + msg = "Exactly 8 parts expected without '::' in %r" + with self.assertAddressError(msg, addr): + ipaddress.IPv6Address(addr) + + assertBadSplit("3ffe:0:0:0:0:0:0:0:1") + assertBadSplit("9:8:7:6:5:4:3:2:1") + assertBadSplit("7:6:5:4:3:2:1") + # A trailing IPv4 address is two parts + assertBadSplit("9:8:7:6:5:4:3:42.42.42.42") + assertBadSplit("7:6:5:4:3:42.42.42.42") + + def test_bad_address_split_v6_too_many_parts_with_double_colon(self): + def assertBadSplit(addr): + msg = "Expected at most 7 other parts with '::' in %r" + with self.assertAddressError(msg, addr): + ipaddress.IPv6Address(addr) + + assertBadSplit("1:2:3:4::5:6:7:8") + + def test_bad_address_split_v6_repeated_double_colon(self): + def assertBadSplit(addr): + msg = "At most one '::' permitted in %r" + with self.assertAddressError(msg, addr): + ipaddress.IPv6Address(addr) + + assertBadSplit("3ffe::1::1") + assertBadSplit("1::2::3::4:5") + assertBadSplit("2001::db:::1") + assertBadSplit("3ffe::1::") + assertBadSplit("::3ffe::1") + assertBadSplit(":3ffe::1::1") + assertBadSplit("3ffe::1::1:") + assertBadSplit(":3ffe::1::1:") + assertBadSplit(":::") + assertBadSplit('2001:db8:::1') + + def test_bad_address_split_v6_leading_colon(self): + def assertBadSplit(addr): + msg = "Leading ':' only permitted as part of '::' in %r" + with self.assertAddressError(msg, addr): + ipaddress.IPv6Address(addr) + + assertBadSplit(":2001:db8::1") + assertBadSplit(":1:2:3:4:5:6:7") + assertBadSplit(":1:2:3:4:5:6:") + assertBadSplit(":6:5:4:3:2:1::") + + def test_bad_address_split_v6_trailing_colon(self): + def assertBadSplit(addr): + msg = "Trailing ':' only permitted as part of '::' in %r" + with self.assertAddressError(msg, addr): + ipaddress.IPv6Address(addr) + + assertBadSplit("2001:db8::1:") + assertBadSplit("1:2:3:4:5:6:7:") + assertBadSplit("::1.2.3.4:") + assertBadSplit("::7:6:5:4:3:2:") + + def test_bad_v4_part_in(self): + def assertBadAddressPart(addr, v4_error): + with self.assertAddressError("%s in %r", v4_error, addr): + ipaddress.IPv6Address(addr) + + assertBadAddressPart("3ffe::1.net", "Expected 4 octets in '1.net'") + assertBadAddressPart("3ffe::127.0.1", + "Expected 4 octets in '127.0.1'") + assertBadAddressPart("::1.2.3", + "Expected 4 octets in '1.2.3'") + assertBadAddressPart("::1.2.3.4.5", + "Expected 4 octets in '1.2.3.4.5'") + assertBadAddressPart("3ffe::1.1.1.net", + "Only decimal digits permitted in 'net' " + "in '1.1.1.net'") + + def test_invalid_characters(self): + def assertBadPart(addr, part): + msg = "Only hex digits permitted in %r in %r" % (part, addr) + with self.assertAddressError(re.escape(msg)): + ipaddress.IPv6Address(addr) + + assertBadPart("3ffe::goog", "goog") + assertBadPart("3ffe::-0", "-0") + assertBadPart("3ffe::+0", "+0") + assertBadPart("3ffe::-1", "-1") + assertBadPart("1.2.3.4::", "1.2.3.4") + assertBadPart('1234:axy::b', "axy") + + def test_part_length(self): + def assertBadPart(addr, part): + msg = "At most 4 characters permitted in %r in %r" + with self.assertAddressError(msg, part, addr): + ipaddress.IPv6Address(addr) + + assertBadPart("3ffe::10000", "10000") + assertBadPart("02001:db8::", "02001") + assertBadPart('2001:888888::1', "888888") + + def test_bad_packed_length(self): + def assertBadLength(length): + addr = b'\x00' * length + msg = "Packed address %r must be exactly 16 bytes" % addr + with self.assertAddressError(re.escape(msg)): + ipaddress.IPv6Address(addr) + + assertBadLength(15) + assertBadLength(17) + + +class NetmaskErrorsMixin_v4: + """Input validation on interfaces and networks is very similar""" + + @property + def factory(self): + raise NotImplementedError + + def test_split_netmask(self): + addr = "1.2.3.4/32/24" + with self.assertAddressError("Only one '/' permitted in %r" % addr): + self.factory(addr) + + def test_address_errors(self): + def assertBadAddress(addr, details): + with self.assertAddressError(details): + self.factory(addr) + + assertBadAddress("", "Address cannot be empty") + assertBadAddress("bogus", "Expected 4 octets") + assertBadAddress("google.com", "Expected 4 octets") + assertBadAddress("10/8", "Expected 4 octets") + assertBadAddress("::1.2.3.4", "Only decimal digits") + assertBadAddress("1.2.3.256", "256 > 255") + + def test_netmask_errors(self): + def assertBadNetmask(addr, netmask): + msg = "%r is not a valid netmask" + with self.assertNetmaskError(msg % netmask): + self.factory("%s/%s" % (addr, netmask)) + + assertBadNetmask("1.2.3.4", "") + assertBadNetmask("1.2.3.4", "33") + assertBadNetmask("1.2.3.4", "254.254.255.256") + assertBadNetmask("1.1.1.1", "240.255.0.0") + assertBadNetmask("1.1.1.1", "1.a.2.3") + assertBadNetmask("1.1.1.1", "pudding") + + def test_bad_packed_length(self): + def assertBadLength(length): + addr = b'\x00' * length + msg = "Packed address %r must be exactly 4 bytes" % addr + with self.assertAddressError(re.escape(msg)): + self.factory(addr) + + assertBadLength(3) + assertBadLength(5) + + +class InterfaceErrors_v4(ErrorReporting, NetmaskErrorsMixin_v4): + factory = ipaddress.IPv4Interface + +class NetworkErrors_v4(ErrorReporting, NetmaskErrorsMixin_v4): + factory = ipaddress.IPv4Network + + +class NetmaskErrorsMixin_v6: + """Input validation on interfaces and networks is very similar""" + + @property + def factory(self): + raise NotImplementedError + + def test_split_netmask(self): + addr = "cafe:cafe::/128/190" + with self.assertAddressError("Only one '/' permitted in %r" % addr): + self.factory(addr) + + def test_address_errors(self): + def assertBadAddress(addr, details): + with self.assertAddressError(details): + self.factory(addr) + + assertBadAddress("", "Address cannot be empty") + assertBadAddress("google.com", "At least 3 parts") + assertBadAddress("1.2.3.4", "At least 3 parts") + assertBadAddress("10/8", "At least 3 parts") + assertBadAddress("1234:axy::b", "Only hex digits") + + def test_netmask_errors(self): + def assertBadNetmask(addr, netmask): + msg = "%r is not a valid netmask" + with self.assertNetmaskError(msg % netmask): + self.factory("%s/%s" % (addr, netmask)) + + assertBadNetmask("::1", "") + assertBadNetmask("::1", "::1") + assertBadNetmask("::1", "1::") + assertBadNetmask("::1", "129") + assertBadNetmask("::1", "pudding") + + def test_bad_packed_length(self): + def assertBadLength(length): + addr = b'\x00' * length + msg = "Packed address %r must be exactly 16 bytes" % addr + with self.assertAddressError(re.escape(msg)): + self.factory(addr) + + assertBadLength(15) + assertBadLength(17) + + +class InterfaceErrors_v6(ErrorReporting, NetmaskErrorsMixin_v6): + factory = ipaddress.IPv6Interface + +class NetworkErrors_v6(ErrorReporting, NetmaskErrorsMixin_v6): + factory = ipaddress.IPv6Network + + +class FactoryFunctionErrors(ErrorReporting): + + def assertFactoryError(self, factory, kind): + """Ensure a clean ValueError with the expected message""" + addr = "camelot" + msg = '%r does not appear to be an IPv4 or IPv6 %s' + with self.assertCleanError(ValueError, msg, addr, kind): + factory(addr) + + def test_ip_address(self): + self.assertFactoryError(ipaddress.ip_address, "address") + + def test_ip_interface(self): + self.assertFactoryError(ipaddress.ip_interface, "interface") + + def test_ip_network(self): + self.assertFactoryError(ipaddress.ip_network, "network") + class IpaddrUnitTest(unittest.TestCase): @@ -46,104 +453,6 @@ self.assertRaises(ValueError, ipaddress.v6_int_to_packed, 2 ** ipaddress.IPV6LENGTH) - def testInvalidStringsInAddressFactory(self): - def AssertInvalidIP(ip_str): - with self.assertRaises(ValueError) as ex: - ipaddress.ip_address(ip_str) - self.assertIsNone(ex.exception.__context__) - - AssertInvalidIP("") - AssertInvalidIP("016.016.016.016") - AssertInvalidIP("016.016.016") - AssertInvalidIP("016.016") - AssertInvalidIP("016") - AssertInvalidIP("000.000.000.000") - AssertInvalidIP("000") - AssertInvalidIP("0x0a.0x0a.0x0a.0x0a") - AssertInvalidIP("0x0a.0x0a.0x0a") - AssertInvalidIP("0x0a.0x0a") - AssertInvalidIP("0x0a") - AssertInvalidIP("42.42.42.42.42") - AssertInvalidIP("42.42.42") - AssertInvalidIP("42.42") - AssertInvalidIP("42") - AssertInvalidIP("42..42.42") - AssertInvalidIP("42..42.42.42") - AssertInvalidIP("42.42.42.42.") - AssertInvalidIP("42.42.42.42...") - AssertInvalidIP(".42.42.42.42") - AssertInvalidIP("...42.42.42.42") - AssertInvalidIP("42.42.42.-0") - AssertInvalidIP("42.42.42.+0") - AssertInvalidIP(".") - AssertInvalidIP("...") - AssertInvalidIP("bogus") - AssertInvalidIP("bogus.com") - AssertInvalidIP("192.168.0.1.com") - AssertInvalidIP("12345.67899.-54321.-98765") - AssertInvalidIP("257.0.0.0") - AssertInvalidIP("42.42.42.-42") - AssertInvalidIP("3ffe::1.net") - AssertInvalidIP("3ffe::1::1") - AssertInvalidIP("1::2::3::4:5") - AssertInvalidIP("::7:6:5:4:3:2:") - AssertInvalidIP(":6:5:4:3:2:1::") - AssertInvalidIP("2001::db:::1") - AssertInvalidIP("FEDC:9878") - AssertInvalidIP("+1.+2.+3.4") - AssertInvalidIP("1.2.3.4e0") - AssertInvalidIP("::7:6:5:4:3:2:1:0") - AssertInvalidIP("7:6:5:4:3:2:1:0::") - AssertInvalidIP("9:8:7:6:5:4:3::2:1") - AssertInvalidIP("0:1:2:3::4:5:6:7") - AssertInvalidIP("3ffe:0:0:0:0:0:0:0:1") - AssertInvalidIP("3ffe::10000") - AssertInvalidIP("3ffe::goog") - AssertInvalidIP("3ffe::-0") - AssertInvalidIP("3ffe::+0") - AssertInvalidIP("3ffe::-1") - AssertInvalidIP(":") - AssertInvalidIP(":::") - AssertInvalidIP("::1.2.3") - AssertInvalidIP("::1.2.3.4.5") - AssertInvalidIP("::1.2.3.4:") - AssertInvalidIP("1.2.3.4::") - AssertInvalidIP("2001:db8::1:") - AssertInvalidIP(":2001:db8::1") - AssertInvalidIP(":1:2:3:4:5:6:7") - AssertInvalidIP("1:2:3:4:5:6:7:") - AssertInvalidIP(":1:2:3:4:5:6:") - AssertInvalidIP("1000") - AssertInvalidIP("1000000000000000") - AssertInvalidIP("02001:db8::") - self.assertRaises(ValueError, ipaddress.ip_interface, 'bogus') - - def testInvalidStringsInConstructors(self): - def AssertInvalidIP(ip_class, ip_str): - with self.assertRaises(ipaddress.AddressValueError) as ex: - ip_class(ip_str) - if ex.exception.__context__ is not None: - # Provide clean tracebacks by default - self.assertTrue(ex.exception.__suppress_context__) - - AssertInvalidIP(ipaddress.IPv4Address, '127.0.0.1/32') - AssertInvalidIP(ipaddress.IPv4Address(1)._ip_int_from_string, - '1.a.2.3') - AssertInvalidIP(ipaddress.IPv4Interface, '') - AssertInvalidIP(ipaddress.IPv4Interface, 'google.com') - AssertInvalidIP(ipaddress.IPv6Address, '1234:axy::b') - AssertInvalidIP(ipaddress.IPv6Address, '2001:db8:::1') - AssertInvalidIP(ipaddress.IPv6Address, '2001:888888::1') - AssertInvalidIP(ipaddress.IPv4Interface, '::1.2.3.4') - AssertInvalidIP(ipaddress.IPv6Interface, '') - AssertInvalidIP(ipaddress.IPv6Interface, 'google.com') - AssertInvalidIP(ipaddress.IPv6Interface, '1.2.3.4') - AssertInvalidIP(ipaddress.IPv6Interface, 'cafe:cafe::/128/190') - AssertInvalidIP(ipaddress.IPv6Interface, '1234:axy::b') - - def testInvalidHostmask(self): - self.assertFalse(ipaddress.IPv4Interface(1)._is_hostmask('1.a.2.3')) - def testInternals(self): first, last = ipaddress._find_address_range([ ipaddress.IPv4Address('10.10.10.10'), @@ -278,22 +587,6 @@ self.assertEqual(address('::'), address(b'\x00' * 16)) - def testIpFromPackedErrors(self): - def assertInvalidPackedAddress(f, length): - self.assertRaises(ValueError, f, b'\x00' * length) - assertInvalidPackedAddress(ipaddress.ip_address, 3) - assertInvalidPackedAddress(ipaddress.ip_address, 5) - assertInvalidPackedAddress(ipaddress.ip_address, 15) - assertInvalidPackedAddress(ipaddress.ip_address, 17) - assertInvalidPackedAddress(ipaddress.ip_interface, 3) - assertInvalidPackedAddress(ipaddress.ip_interface, 5) - assertInvalidPackedAddress(ipaddress.ip_interface, 15) - assertInvalidPackedAddress(ipaddress.ip_interface, 17) - assertInvalidPackedAddress(ipaddress.ip_network, 3) - assertInvalidPackedAddress(ipaddress.ip_network, 5) - assertInvalidPackedAddress(ipaddress.ip_network, 15) - assertInvalidPackedAddress(ipaddress.ip_network, 17) - def testGetIp(self): self.assertEqual(int(self.ipv4_interface.ip), 16909060) self.assertEqual(str(self.ipv4_interface.ip), '1.2.3.4') @@ -508,38 +801,6 @@ self.assertFalse(ipaddress.IPv4Network('1.1.0.0/16').__contains__( ipaddress.IPv4Network('1.0.0.0/15'))) - def testBadAddress(self): - self.assertRaises(ipaddress.AddressValueError, ipaddress.IPv4Interface, - 'poop') - self.assertRaises(ipaddress.AddressValueError, - ipaddress.IPv4Interface, '1.2.3.256') - - self.assertRaises(ipaddress.AddressValueError, ipaddress.IPv6Interface, - 'poopv6') - self.assertRaises(ipaddress.AddressValueError, - ipaddress.IPv4Interface, '1.2.3.4/32/24') - self.assertRaises(ipaddress.AddressValueError, - ipaddress.IPv4Network, '1.2.3.4/32/24') - self.assertRaises(ipaddress.AddressValueError, - ipaddress.IPv4Interface, '10/8') - self.assertRaises(ipaddress.AddressValueError, - ipaddress.IPv6Interface, '10/8') - - - def testBadNetMask(self): - self.assertRaises(ipaddress.NetmaskValueError, - ipaddress.IPv4Interface, '1.2.3.4/') - self.assertRaises(ipaddress.NetmaskValueError, - ipaddress.IPv4Interface, '1.2.3.4/33') - self.assertRaises(ipaddress.NetmaskValueError, - ipaddress.IPv4Interface, '1.2.3.4/254.254.255.256') - self.assertRaises(ipaddress.NetmaskValueError, - ipaddress.IPv4Interface, '1.1.1.1/240.255.0.0') - self.assertRaises(ipaddress.NetmaskValueError, - ipaddress.IPv6Interface, '::1/') - self.assertRaises(ipaddress.NetmaskValueError, - ipaddress.IPv6Interface, '::1/129') - def testNth(self): self.assertEqual(str(self.ipv4_network[5]), '1.2.3.5') self.assertRaises(IndexError, self.ipv4_network.__getitem__, 256) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -23,6 +23,10 @@ Library ------- +- Issue #14814: ipaddress now provides more informative error messages when + constructing instances directly (changes permitted during beta due to + provisional API status) + - Issue #15247: FileIO now raises an error when given a file descriptor pointing to a directory. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 12:27:15 2012 From: python-checkins at python.org (florent.xicluna) Date: Sat, 7 Jul 2012 12:27:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE0OTkw?= =?utf-8?q?=3A_tokenize=3A_correctly_fail_with_SyntaxError_on_invalid_enco?= =?utf-8?q?ding?= Message-ID: <3WTprz0wlKzN5P@mail.python.org> http://hg.python.org/cpython/rev/5020afc0b7c9 changeset: 77961:5020afc0b7c9 branch: 3.2 parent: 77954:9cf9527358a5 user: Florent Xicluna date: Sat Jul 07 12:13:35 2012 +0200 summary: Issue #14990: tokenize: correctly fail with SyntaxError on invalid encoding declaration. files: Lib/test/test_tokenize.py | 4 ++++ Lib/tokenize.py | 2 +- Misc/NEWS | 3 +++ 3 files changed, 8 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -674,6 +674,10 @@ f = 'tokenize_tests-utf8-coding-cookie-and-utf8-bom-sig.txt' self.assertTrue(self._testFile(f)) + def test_bad_coding_cookie(self): + self.assertRaises(SyntaxError, self._testFile, 'bad_coding.py') + self.assertRaises(SyntaxError, self._testFile, 'bad_coding2.py') + class Test_Tokenize(TestCase): diff --git a/Lib/tokenize.py b/Lib/tokenize.py --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -310,7 +310,7 @@ raise SyntaxError("unknown encoding: " + encoding) if bom_found: - if codec.name != 'utf-8': + if encoding != 'utf-8': # This behaviour mimics the Python interpreter raise SyntaxError('encoding problem: utf-8') encoding += '-sig' diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -87,6 +87,9 @@ Library ------- +- Issue #14990: Correctly fail with SyntaxError on invalid encoding + declaration. + - Issue #15247: FileIO now raises an error when given a file descriptor pointing to a directory. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 12:27:16 2012 From: python-checkins at python.org (florent.xicluna) Date: Sat, 7 Jul 2012 12:27:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Merge_branch?= Message-ID: <3WTps05HNSzNW4@mail.python.org> http://hg.python.org/cpython/rev/b4322ad1fec4 changeset: 77962:b4322ad1fec4 parent: 77960:16ff4889a858 parent: 77961:5020afc0b7c9 user: Florent Xicluna date: Sat Jul 07 12:26:56 2012 +0200 summary: Merge branch files: Lib/test/test_tokenize.py | 4 ++++ Lib/tokenize.py | 2 +- Misc/NEWS | 3 +++ 3 files changed, 8 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -745,6 +745,10 @@ f = 'tokenize_tests-utf8-coding-cookie-and-utf8-bom-sig.txt' self.assertTrue(self._testFile(f)) + def test_bad_coding_cookie(self): + self.assertRaises(SyntaxError, self._testFile, 'bad_coding.py') + self.assertRaises(SyntaxError, self._testFile, 'bad_coding2.py') + class Test_Tokenize(TestCase): diff --git a/Lib/tokenize.py b/Lib/tokenize.py --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -388,7 +388,7 @@ raise SyntaxError(msg) if bom_found: - if codec.name != 'utf-8': + if encoding != 'utf-8': # This behaviour mimics the Python interpreter if filename is None: msg = 'encoding problem: utf-8' diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -23,6 +23,9 @@ Library ------- +- Issue #14990: Correctly fail with SyntaxError on invalid encoding + declaration. + - Issue #14814: ipaddress now provides more informative error messages when constructing instances directly (changes permitted during beta due to provisional API status) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 13:16:58 2012 From: python-checkins at python.org (florent.xicluna) Date: Sat, 7 Jul 2012 13:16:58 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Minor_refactoring_in_xml?= =?utf-8?q?=2Eetree=2EElementTree_doctype_parser=2E?= Message-ID: <3WTqyL4gQMzNJF@mail.python.org> http://hg.python.org/cpython/rev/5c1efcd53b8b changeset: 77963:5c1efcd53b8b user: Florent Xicluna date: Sat Jul 07 13:16:44 2012 +0200 summary: Minor refactoring in xml.etree.ElementTree doctype parser. files: Lib/xml/etree/ElementTree.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -1597,13 +1597,13 @@ type = self._doctype[1] if type == "PUBLIC" and n == 4: name, type, pubid, system = self._doctype + if pubid: + pubid = pubid[1:-1] elif type == "SYSTEM" and n == 3: name, type, system = self._doctype pubid = None else: return - if pubid: - pubid = pubid[1:-1] if hasattr(self.target, "doctype"): self.target.doctype(name, pubid, system[1:-1]) elif self.doctype != self._XMLParser__doctype: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 13:17:00 2012 From: python-checkins at python.org (florent.xicluna) Date: Sat, 7 Jul 2012 13:17:00 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Minor_refactoring_in_impor?= =?utf-8?q?tlib=2E=5Fbootstrap=2C_and_fix_the_=27=5Fwrap=27_docstring=2E?= Message-ID: <3WTqyN404tzNb8@mail.python.org> http://hg.python.org/cpython/rev/37850f083af5 changeset: 77964:37850f083af5 user: Florent Xicluna date: Sat Jul 07 13:16:44 2012 +0200 summary: Minor refactoring in importlib._bootstrap, and fix the '_wrap' docstring. files: Lib/importlib/_bootstrap.py | 29 ++++++++++++------------ 1 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -140,7 +140,7 @@ def _wrap(new, old): - """Simple substitute for functools.wraps.""" + """Simple substitute for functools.update_wrapper.""" for replace in ['__module__', '__name__', '__qualname__', '__doc__']: if hasattr(old, replace): setattr(new, replace, getattr(old, replace)) @@ -345,7 +345,7 @@ """Set __package__ on the returned module.""" def set_package_wrapper(*args, **kwargs): module = fxn(*args, **kwargs) - if not hasattr(module, '__package__') or module.__package__ is None: + if getattr(module, '__package__', None) is None: module.__package__ = module.__name__ if not hasattr(module, '__path__'): module.__package__ = module.__package__.rpartition('.')[0] @@ -438,7 +438,7 @@ """Decorator to verify the named module is built-in.""" def _requires_builtin_wrapper(self, fullname): if fullname not in sys.builtin_module_names: - raise ImportError("{0} is not a built-in module".format(fullname), + raise ImportError("{} is not a built-in module".format(fullname), name=fullname) return fxn(self, fullname) _wrap(_requires_builtin_wrapper, fxn) @@ -449,7 +449,7 @@ """Decorator to verify the named module is frozen.""" def _requires_frozen_wrapper(self, fullname): if not _imp.is_frozen(fullname): - raise ImportError("{0} is not a frozen module".format(fullname), + raise ImportError("{} is not a frozen module".format(fullname), name=fullname) return fxn(self, fullname) _wrap(_requires_frozen_wrapper, fxn) @@ -511,7 +511,7 @@ @classmethod @_requires_builtin def is_package(cls, fullname): - """Return None as built-in modules are never packages.""" + """Return False as built-in modules are never packages.""" return False @@ -936,7 +936,7 @@ return len(self._recalculate()) def __repr__(self): - return "_NamespacePath({0!r})".format(self._path) + return "_NamespacePath({!r})".format(self._path) def __contains__(self, item): return item in self._recalculate() @@ -1198,7 +1198,7 @@ if len(bits) < level: raise ValueError('attempted relative import beyond top-level package') base = bits[0] - return '{0}.{1}'.format(base, name) if name else base + return '{}.{}'.format(base, name) if name else base def _find_module(name, path): @@ -1228,7 +1228,7 @@ if not isinstance(package, str): raise TypeError("__package__ not set to a string") elif package not in sys.modules: - msg = ("Parent module {0!r} not loaded, cannot perform relative " + msg = ("Parent module {!r} not loaded, cannot perform relative " "import") raise SystemError(msg.format(package)) if not name and level == 0: @@ -1267,7 +1267,7 @@ parent_module = sys.modules[parent] setattr(parent_module, name.rpartition('.')[2], module) # Set __package__ if the loader did not. - if not hasattr(module, '__package__') or module.__package__ is None: + if getattr(module, '__package__', None) is None: try: module.__package__ = module.__name__ if not hasattr(module, '__path__'): @@ -1336,11 +1336,12 @@ fromlist = list(fromlist) fromlist.remove('*') fromlist.extend(module.__all__) - for x in (y for y in fromlist if not hasattr(module, y)): - try: - import_('{0}.{1}'.format(module.__name__, x)) - except ImportError: - pass + for x in fromlist: + if not hasattr(module, x): + try: + import_('{}.{}'.format(module.__name__, x)) + except ImportError: + pass return module -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 13:43:42 2012 From: python-checkins at python.org (nick.coghlan) Date: Sat, 7 Jul 2012 13:43:42 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_14814=3A_Make_the_ip?= =?utf-8?q?address_code_easier_to_follow_by_using_newer_language?= Message-ID: <3WTrYB6XbvzNWq@mail.python.org> http://hg.python.org/cpython/rev/af4ae710daf3 changeset: 77965:af4ae710daf3 user: Nick Coghlan date: Sat Jul 07 21:43:30 2012 +1000 summary: Issue 14814: Make the ipaddress code easier to follow by using newer language features (patch by Serhiy Storchaka) files: Lib/ipaddress.py | 156 ++++++++++++++-------------------- 1 files changed, 66 insertions(+), 90 deletions(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -214,8 +214,10 @@ if number == 0: return bits for i in range(bits): - if (number >> i) % 2: + if (number >> i) & 1: return i + # All bits of interest were zero, even if there are more in the number + return bits def summarize_address_range(first, last): @@ -263,20 +265,13 @@ first_int = first._ip last_int = last._ip while first_int <= last_int: - nbits = _count_righthand_zero_bits(first_int, ip_bits) - current = None - while nbits >= 0: - addend = 2**nbits - 1 - current = first_int + addend - nbits -= 1 - if current <= last_int: - break - prefix = _get_prefix_length(first_int, current, ip_bits) - net = ip('%s/%d' % (first, prefix)) + nbits = min(_count_righthand_zero_bits(first_int, ip_bits), + (last_int - first_int + 1).bit_length() - 1) + net = ip('%s/%d' % (first, ip_bits - nbits)) yield net - if current == ip._ALL_ONES: + first_int += 1 << nbits + if first_int - 1 == ip._ALL_ONES: break - first_int = current + 1 first = first.__class__(first_int) @@ -304,26 +299,28 @@ passed. """ - ret_array = [] - optimized = False + while True: + last_addr = None + ret_array = [] + optimized = False - for cur_addr in addresses: - if not ret_array: - ret_array.append(cur_addr) - continue - if (cur_addr.network_address >= ret_array[-1].network_address and - cur_addr.broadcast_address <= ret_array[-1].broadcast_address): - optimized = True - elif cur_addr == list(ret_array[-1].supernet().subnets())[1]: - ret_array.append(ret_array.pop().supernet()) - optimized = True - else: - ret_array.append(cur_addr) + for cur_addr in addresses: + if not ret_array: + last_addr = cur_addr + ret_array.append(cur_addr) + elif (cur_addr.network_address >= last_addr.network_address and + cur_addr.broadcast_address <= last_addr.broadcast_address): + optimized = True + elif cur_addr == list(last_addr.supernet().subnets())[1]: + ret_array[-1] = last_addr = last_addr.supernet() + optimized = True + else: + last_addr = cur_addr + ret_array.append(cur_addr) - if optimized: - return _collapse_addresses_recursive(ret_array) - - return ret_array + addresses = ret_array + if not optimized: + return addresses def collapse_addresses(addresses): @@ -452,13 +449,7 @@ An integer, the prefix length. """ - while mask: - if ip_int & 1 == 1: - break - ip_int >>= 1 - mask -= 1 - - return mask + return mask - _count_righthand_zero_bits(ip_int, mask) def _ip_string_from_prefix(self, prefixlen=None): """Turn a prefix length into a dotted decimal string. @@ -597,18 +588,16 @@ or broadcast addresses. """ - cur = int(self.network_address) + 1 - bcast = int(self.broadcast_address) - 1 - while cur <= bcast: - cur += 1 - yield self._address_class(cur - 1) + network = int(self.network_address) + broadcast = int(self.broadcast_address) + for x in range(network + 1, broadcast): + yield self._address_class(x) def __iter__(self): - cur = int(self.network_address) - bcast = int(self.broadcast_address) - while cur <= bcast: - cur += 1 - yield self._address_class(cur - 1) + network = int(self.network_address) + broadcast = int(self.broadcast_address) + for x in range(network, broadcast + 1): + yield self._address_class(x) def __getitem__(self, n): network = int(self.network_address) @@ -998,7 +987,7 @@ _DECIMAL_DIGITS = frozenset('0123456789') # the valid octets for host and netmasks. only useful for IPv4. - _valid_mask_octets = set((255, 254, 252, 248, 240, 224, 192, 128, 0)) + _valid_mask_octets = frozenset((255, 254, 252, 248, 240, 224, 192, 128, 0)) def __init__(self, address): self._version = 4 @@ -1027,13 +1016,10 @@ if len(octets) != 4: raise AddressValueError("Expected 4 octets in %r" % ip_str) - packed_ip = 0 - for oc in octets: - try: - packed_ip = (packed_ip << 8) | self._parse_octet(oc) - except ValueError as exc: - raise AddressValueError("%s in %r" % (exc, ip_str)) from None - return packed_ip + try: + return int.from_bytes(map(self._parse_octet, octets), 'big') + except ValueError as exc: + raise AddressValueError("%s in %r" % (exc, ip_str)) from None def _parse_octet(self, octet_str): """Convert a decimal octet into an integer. @@ -1075,11 +1061,7 @@ The IP address as a string in dotted decimal notation. """ - octets = [] - for _ in range(4): - octets.insert(0, str(ip_int & 0xFF)) - ip_int >>= 8 - return '.'.join(octets) + return '.'.join(map(str, ip_int.to_bytes(4, 'big'))) def _is_valid_netmask(self, netmask): """Verify that the netmask is valid. @@ -1095,17 +1077,16 @@ """ mask = netmask.split('.') if len(mask) == 4: - for x in mask: - try: - if int(x) in self._valid_mask_octets: - continue - except ValueError: - pass + try: + for x in mask: + if int(x) not in self._valid_mask_octets: + return False + except ValueError: # Found something that isn't an integer or isn't valid return False - if [y for idx, y in enumerate(mask) if idx > 0 and - y > mask[idx - 1]]: - return False + for idx, y in enumerate(mask): + if idx > 0 and y > mask[idx - 1]: + return False return True try: netmask = int(netmask) @@ -1125,7 +1106,7 @@ """ bits = ip_str.split('.') try: - parts = [int(x) for x in bits if int(x) in self._valid_mask_octets] + parts = [x for x in map(int, bits) if x in self._valid_mask_octets] except ValueError: return False if len(parts) != len(bits): @@ -1526,14 +1507,14 @@ # Disregarding the endpoints, find '::' with nothing in between. # This indicates that a run of zeroes has been skipped. - try: - skip_index, = ( - [i for i in range(1, len(parts) - 1) if not parts[i]] or - [None]) - except ValueError: - # Can't have more than one '::' - msg = "At most one '::' permitted in %r" % ip_str - raise AddressValueError(msg) from None + skip_index = None + for i in range(1, len(parts) - 1): + if not parts[i]: + if skip_index is not None: + # Can't have more than one '::' + msg = "At most one '::' permitted in %r" % ip_str + raise AddressValueError(msg) + skip_index = i # parts_hi is the number of parts to copy from above/before the '::' # parts_lo is the number of parts to copy from below/after the '::' @@ -1680,9 +1661,7 @@ raise ValueError('IPv6 address is too large') hex_str = '%032x' % ip_int - hextets = [] - for x in range(0, 32, 4): - hextets.append('%x' % int(hex_str[x:x+4], 16)) + hextets = ['%x' % int(hex_str[x:x+4], 16) for x in range(0, 32, 4)] hextets = self._compress_hextets(hextets) return ':'.join(hextets) @@ -1705,11 +1684,8 @@ ip_str = str(self) ip_int = self._ip_int_from_string(ip_str) - parts = [] - for i in range(self._HEXTET_COUNT): - parts.append('%04x' % (ip_int & 0xFFFF)) - ip_int >>= 16 - parts.reverse() + hex_str = '%032x' % ip_int + parts = [hex_str[x:x+4] for x in range(0, 32, 4)] if isinstance(self, (_BaseNetwork, IPv6Interface)): return '%s/%d' % (':'.join(parts), self.prefixlen) return ':'.join(parts) @@ -1756,9 +1732,9 @@ IPv6Network('FE00::/9')] if isinstance(self, _BaseAddress): - return len([x for x in reserved_networks if self in x]) > 0 - return len([x for x in reserved_networks if self.network_address in x - and self.broadcast_address in x]) > 0 + return any(self in x for x in reserved_networks) + return any(self.network_address in x and self.broadcast_address in x + for x in reserved_networks) @property def is_link_local(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 14:09:00 2012 From: python-checkins at python.org (mark.dickinson) Date: Sat, 7 Jul 2012 14:09:00 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Use_correct_types_for_ASCI?= =?utf-8?q?I=5FCHAR=5FMASK_integer_constants=2E?= Message-ID: <3WTs6N4bZ6zNdK@mail.python.org> http://hg.python.org/cpython/rev/ab9e824116eb changeset: 77966:ab9e824116eb user: Mark Dickinson date: Sat Jul 07 14:08:48 2012 +0200 summary: Use correct types for ASCII_CHAR_MASK integer constants. files: Objects/stringlib/codecs.h | 4 ++-- Objects/stringlib/find_max_char.h | 4 ++-- Objects/unicodeobject.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Objects/stringlib/codecs.h b/Objects/stringlib/codecs.h --- a/Objects/stringlib/codecs.h +++ b/Objects/stringlib/codecs.h @@ -8,9 +8,9 @@ /* Mask to quickly check whether a C 'long' contains a non-ASCII, UTF8-encoded char. */ #if (SIZEOF_LONG == 8) -# define ASCII_CHAR_MASK 0x8080808080808080L +# define ASCII_CHAR_MASK 0x8080808080808080UL #elif (SIZEOF_LONG == 4) -# define ASCII_CHAR_MASK 0x80808080L +# define ASCII_CHAR_MASK 0x80808080UL #else # error C 'long' size should be either 4 or 8! #endif diff --git a/Objects/stringlib/find_max_char.h b/Objects/stringlib/find_max_char.h --- a/Objects/stringlib/find_max_char.h +++ b/Objects/stringlib/find_max_char.h @@ -8,9 +8,9 @@ /* Mask to quickly check whether a C 'long' contains a non-ASCII, UTF8-encoded char. */ #if (SIZEOF_LONG == 8) -# define UCS1_ASCII_CHAR_MASK 0x8080808080808080L +# define UCS1_ASCII_CHAR_MASK 0x8080808080808080UL #elif (SIZEOF_LONG == 4) -# define UCS1_ASCII_CHAR_MASK 0x80808080L +# define UCS1_ASCII_CHAR_MASK 0x80808080UL #else # error C 'long' size should be either 4 or 8! #endif diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -4639,9 +4639,9 @@ /* Mask to quickly check whether a C 'long' contains a non-ASCII, UTF8-encoded char. */ #if (SIZEOF_LONG == 8) -# define ASCII_CHAR_MASK 0x8080808080808080L +# define ASCII_CHAR_MASK 0x8080808080808080UL #elif (SIZEOF_LONG == 4) -# define ASCII_CHAR_MASK 0x80808080L +# define ASCII_CHAR_MASK 0x80808080UL #else # error C 'long' size should be either 4 or 8! #endif -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 14:15:34 2012 From: python-checkins at python.org (nick.coghlan) Date: Sat, 7 Jul 2012 14:15:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_14814=3A_Explain_how?= =?utf-8?q?_to_get_more_error_detail_in_the_ipaddress_tutorial=2C?= Message-ID: <3WTsFy6NDFzNcM@mail.python.org> http://hg.python.org/cpython/rev/d03dbc324b60 changeset: 77967:d03dbc324b60 user: Nick Coghlan date: Sat Jul 07 22:15:22 2012 +1000 summary: Issue 14814: Explain how to get more error detail in the ipaddress tutorial, and tweak the display for octet errors in IPv4 (noticed the formatting problem when adding to the docs) files: Doc/howto/ipaddress.rst | 48 ++++++++++++++++++++----- Lib/ipaddress.py | 5 +- Lib/test/test_ipaddress.py | 6 +- 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/Doc/howto/ipaddress.rst b/Doc/howto/ipaddress.rst --- a/Doc/howto/ipaddress.rst +++ b/Doc/howto/ipaddress.rst @@ -277,23 +277,49 @@ 3221225985 -Exceptions raised by :mod:`ipaddress` -===================================== +Getting more detail when instance creation fails +================================================ When creating address/network/interface objects using the version-agnostic -factory functions, any errors will be reported as :exc:`ValueError`. +factory functions, any errors will be reported as :exc:`ValueError` with +a generic error message that simply says the passed in value was not +recognised as an object of that type. The lack of a specific error is +because it's necessary to know whether the value is *supposed* to be IPv4 +or IPv6 in order to provide more detail on why it has been rejected. -For some use cases, it desirable to know whether it is the address or the -netmask which is incorrect. To support these use cases, the class -constructors actually raise the :exc:`ValueError` subclasses -:exc:`ipaddress.AddressValueError` and :exc:`ipaddress.NetmaskValueError` -to indicate exactly which part of the definition failed to parse correctly. +To support use cases where it is useful to have access to this additional +detail, the individual class constructors actually raise the +:exc:`ValueError` subclasses :exc:`ipaddress.AddressValueError` and +:exc:`ipaddress.NetmaskValueError` to indicate exactly which part of +the definition failed to parse correctly. -Both of the module specific exceptions have :exc:`ValueError` as their +The error messages are significantly more detailed when using the +class constructors directly. For example:: + + >>> ipaddress.ip_address("192.168.0.256") + Traceback (most recent call last): + ... + ValueError: '192.168.0.256' does not appear to be an IPv4 or IPv6 address + >>> ipaddress.IPv4Address("192.168.0.256") + Traceback (most recent call last): + ... + ipaddress.AddressValueError: Octet 256 (> 255) not permitted in '192.168.0.256' + + >>> ipaddress.ip_network("192.168.0.1/64") + Traceback (most recent call last): + ... + ValueError: '192.168.0.1/64' does not appear to be an IPv4 or IPv6 network + >>> ipaddress.IPv4Network("192.168.0.1/64") + Traceback (most recent call last): + ... + ipaddress.NetmaskValueError: '64' is not a valid netmask + +However, both of the module specific exceptions have :exc:`ValueError` as their parent class, so if you're not concerned with the particular type of error, you can still write code like the following:: try: - ipaddress.IPv4Address(address) + network = ipaddress.IPv4Network(address) except ValueError: - print('address/netmask is invalid:', address) + print('address/netmask is invalid for IPv4:', address) + diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1048,7 +1048,7 @@ raise ValueError("Ambiguous leading zero in %r not permitted" % octet_str) if octet_int > 255: - raise ValueError("Octet %d > 255 not permitted" % octet_int) + raise ValueError("Octet %d (> 255) not permitted" % octet_int) return octet_int def _string_from_ip_int(self, ip_int): @@ -1591,7 +1591,8 @@ hextet_int = int(hextet_str, 16) if hextet_int > 0xFFFF: # This is unreachable due to the string length check above - raise ValueError("Part %d > 0xFFFF not permitted" % hextet_int) + msg = "Part 0x%X (> 0xFFFF) not permitted" + raise ValueError(msg % hextet_int) return hextet_int def _compress_hextets(self, hextets): diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -126,8 +126,8 @@ def test_octet_limit(self): def assertBadOctet(addr, octet): - msg = "Octet %d > 255 not permitted in %r" - with self.assertAddressError(msg, octet, addr): + msg = "Octet %d (> 255) not permitted in %r" % (octet, addr) + with self.assertAddressError(re.escape(msg)): ipaddress.IPv4Address(addr) assertBadOctet("12345.67899.-54321.-98765", 12345) @@ -310,7 +310,7 @@ assertBadAddress("google.com", "Expected 4 octets") assertBadAddress("10/8", "Expected 4 octets") assertBadAddress("::1.2.3.4", "Only decimal digits") - assertBadAddress("1.2.3.256", "256 > 255") + assertBadAddress("1.2.3.256", re.escape("256 (> 255)")) def test_netmask_errors(self): def assertBadNetmask(addr, netmask): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 14:53:59 2012 From: python-checkins at python.org (nick.coghlan) Date: Sat, 7 Jul 2012 14:53:59 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_14814=3A_Further_cle?= =?utf-8?q?an_ups_to_the_ipaddress_tutorial?= Message-ID: <3WTt6H2ByFzN0G@mail.python.org> http://hg.python.org/cpython/rev/86d3b4067f74 changeset: 77968:86d3b4067f74 user: Nick Coghlan date: Sat Jul 07 22:53:46 2012 +1000 summary: Issue 14814: Further clean ups to the ipaddress tutorial files: Doc/howto/ipaddress.rst | 37 ++++++++++++++++++---------- 1 files changed, 24 insertions(+), 13 deletions(-) diff --git a/Doc/howto/ipaddress.rst b/Doc/howto/ipaddress.rst --- a/Doc/howto/ipaddress.rst +++ b/Doc/howto/ipaddress.rst @@ -9,11 +9,11 @@ .. topic:: Overview - This document aims to provide a gentle introduction to :mod:`ipaddress` - module. It is aimed primarily at users that aren't already familiar with - IP networking terminology, but may also be useful to network engineers - wanting an overview of how the ipaddress module represents IP network - addressing concepts. + This document aims to provide a gentle introduction to the + :mod:`ipaddress` module. It is aimed primarily at users that aren't + already familiar with IP networking terminology, but may also be useful + to network engineers wanting an overview of how :mod:`ipaddress` + represents IP network addressing concepts. Creating Address/Network/Interface objects @@ -45,8 +45,9 @@ Addresses, often referred to as "host addresses" are the most basic unit when working with IP addressing. The simplest way to create addresses is -to use the :func:`ipaddress.ip_address` factory function, which automatically determines -whether to create an IPv4 or IPv6 address based on the passed in value:: +to use the :func:`ipaddress.ip_address` factory function, which automatically +determines whether to create an IPv4 or IPv6 address based on the passed in +value:: >>> ipaddress.ip_address('192.0.2.1') IPv4Address('192.0.2.1') @@ -121,8 +122,9 @@ >>> ipaddress.ip_network(42540766411282592856903984951653826560) IPv6Network('2001:db8::/128') -Creation of a particular kind of network can be forced by calling the -class constructor directly instead of using the factory function. +As with addresses, creation of a particular kind of network can be forced +by calling the class constructor directly instead of using the factory +function. Host Interfaces @@ -130,7 +132,7 @@ As mentioned just above, if you need to describe an address on a particular network, neither the address nor the network classes are sufficient. -Notation like ``192.0.2.1/24`` is commonly used network engineers and the +Notation like ``192.0.2.1/24`` is commonly used by network engineers and the people who write tools for firewalls and routers as shorthand for "the host ``192.0.2.1`` on the network ``192.0.2.0/24``", Accordingly, :mod:`ipaddress` provides a set of hybrid classes that associate an address with a particular @@ -213,10 +215,19 @@ Exploding or compressing the address:: + >>> addr6.exploded + '2001:0db8:0000:0000:0000:0000:0000:0000' + >>> addr6.compressed + '2001:db8::' >>> net6.exploded - '2001:0000:0000:0000:0000:0000:0000:0000/96' - >>> addr6.exploded - '2001:0000:0000:0000:0000:0000:0000:0001' + '2001:0db8:0000:0000:0000:0000:0000:0000/96' + >>> net6.compressed + '2001:db8::/96' + +While IPv4 doesn't support explosion or compression, the associated objects +still provide the relevant properties so that version neutral code can +easily ensure the most concise or most verbose form is used for IPv6 +addresses while still correctly handling IPv4 addresses. Networks as lists of Addresses -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 14:57:15 2012 From: python-checkins at python.org (jesus.cea) Date: Sat, 7 Jul 2012 14:57:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Cope_with_OSs_lying_-_=231?= =?utf-8?q?0142=3A_Support_for_SEEK=5FHOLE/SEEK=5FDATA?= Message-ID: <3WTtB30zBRzNKn@mail.python.org> http://hg.python.org/cpython/rev/d69f95e57792 changeset: 77969:d69f95e57792 user: Jesus Cea date: Sat Jul 07 14:56:04 2012 +0200 summary: Cope with OSs lying - #10142: Support for SEEK_HOLE/SEEK_DATA files: Lib/test/test_posix.py | 20 ++++++++++++-------- 1 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -1017,9 +1017,6 @@ @unittest.skipUnless(hasattr(os, 'SEEK_HOLE'), "test needs an OS that reports file holes") - @unittest.skipIf(sys.platform in ('freebsd7', 'freebsd8', 'freebsd9'), - "Skip test because known kernel bug - " \ - "http://lists.freebsd.org/pipermail/freebsd-amd64/2012-January/014332.html") def test_fs_holes(self): # Even if the filesystem doesn't report holes, # if the OS supports it the SEEK_* constants @@ -1032,11 +1029,18 @@ fp.flush() size = fp.tell() fno = fp.fileno() - for i in range(size): - self.assertEqual(i, os.lseek(fno, i, os.SEEK_DATA)) - self.assertLessEqual(size, os.lseek(fno, i, os.SEEK_HOLE)) - self.assertRaises(OSError, os.lseek, fno, size, os.SEEK_DATA) - self.assertRaises(OSError, os.lseek, fno, size, os.SEEK_HOLE) + try : + for i in range(size): + self.assertEqual(i, os.lseek(fno, i, os.SEEK_DATA)) + self.assertLessEqual(size, os.lseek(fno, i, os.SEEK_HOLE)) + self.assertRaises(OSError, os.lseek, fno, size, os.SEEK_DATA) + self.assertRaises(OSError, os.lseek, fno, size, os.SEEK_HOLE) + except OSError : + # Some OSs claim to support SEEK_HOLE/SEEK_DATA + # but it is not true. + # For instance: + # http://lists.freebsd.org/pipermail/freebsd-amd64/2012-January/014332.html + raise unittest.SkipTest("OSError raised!") class PosixGroupsTester(unittest.TestCase): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 15:08:42 2012 From: python-checkins at python.org (nick.coghlan) Date: Sat, 7 Jul 2012 15:08:42 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_14814=3A_Correctly_r?= =?utf-8?q?eturn_NotImplemented_from_ipaddress=2E=5FBaseNetwork=2E=5F=5Feq?= =?utf-8?b?X18=?= Message-ID: <3WTtRG6h3vzN4C@mail.python.org> http://hg.python.org/cpython/rev/2e9cba1d1554 changeset: 77970:2e9cba1d1554 user: Nick Coghlan date: Sat Jul 07 23:05:59 2012 +1000 summary: Issue 14814: Correctly return NotImplemented from ipaddress._BaseNetwork.__eq__ files: Lib/ipaddress.py | 12 ++++++------ Lib/test/test_ipaddress.py | 17 ++++++++++++++++- Misc/NEWS | 3 +++ 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -651,12 +651,12 @@ return not lt def __eq__(self, other): - if not isinstance(other, _BaseNetwork): - raise TypeError('%s and %s are not of the same type' % ( - self, other)) - return (self._version == other._version and - self.network_address == other.network_address and - int(self.netmask) == int(other.netmask)) + try: + return (self._version == other._version and + self.network_address == other.network_address and + int(self.netmask) == int(other.netmask)) + except AttributeError: + return NotImplemented def __ne__(self, other): eq = self.__eq__(other) diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -462,7 +462,6 @@ self.assertEqual(128, ipaddress._count_righthand_zero_bits(0, 128)) self.assertEqual("IPv4Network('1.2.3.0/24')", repr(self.ipv4_network)) self.assertEqual('0x1020318', hex(self.ipv4_network)) - self.assertRaises(TypeError, self.ipv4_network.__eq__, object()) def testMissingAddressVersion(self): class Broken(ipaddress._BaseAddress): @@ -496,6 +495,22 @@ self.assertEqual(str(self.ipv6_network.hostmask), '::ffff:ffff:ffff:ffff') + def testEqualityChecks(self): + # __eq__ should never raise TypeError directly + other = object() + def assertEqualityNotImplemented(instance): + self.assertEqual(instance.__eq__(other), NotImplemented) + self.assertEqual(instance.__ne__(other), NotImplemented) + self.assertFalse(instance == other) + self.assertTrue(instance != other) + + assertEqualityNotImplemented(self.ipv4_address) + assertEqualityNotImplemented(self.ipv4_network) + assertEqualityNotImplemented(self.ipv4_interface) + assertEqualityNotImplemented(self.ipv6_address) + assertEqualityNotImplemented(self.ipv6_network) + assertEqualityNotImplemented(self.ipv6_interface) + def testBadVersionComparison(self): # These should always raise TypeError v4addr = ipaddress.ip_address('1.1.1.1') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -23,6 +23,9 @@ Library ------- +- Issue #14814: ipaddress network objects correctly return NotImplemented + when compared to arbitrary objects instead of raising TypeError + - Issue #14990: Correctly fail with SyntaxError on invalid encoding declaration. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 16:45:46 2012 From: python-checkins at python.org (nick.coghlan) Date: Sat, 7 Jul 2012 16:45:46 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_14814=3A_Ensure_orde?= =?utf-8?q?ring_semantics_across_all_3_entity_types_in_ipaddress?= Message-ID: <3WTwbG43M9zNWF@mail.python.org> http://hg.python.org/cpython/rev/9b359b6c9a39 changeset: 77971:9b359b6c9a39 user: Nick Coghlan date: Sun Jul 08 00:45:33 2012 +1000 summary: Issue 14814: Ensure ordering semantics across all 3 entity types in ipaddress are consistent and well-defined files: Lib/ipaddress.py | 136 ++++++++++---------- Lib/test/test_ipaddress.py | 158 +++++++++++++++--------- Misc/NEWS | 3 + 3 files changed, 169 insertions(+), 128 deletions(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -12,7 +12,7 @@ import struct - +import functools IPV4LENGTH = 32 IPV6LENGTH = 128 @@ -405,7 +405,38 @@ return NotImplemented -class _IPAddressBase: +class _TotalOrderingMixin: + # Helper that derives the other comparison operations from + # __lt__ and __eq__ + def __eq__(self, other): + raise NotImplementedError + def __ne__(self, other): + equal = self.__eq__(other) + if equal is NotImplemented: + return NotImplemented + return not equal + def __lt__(self, other): + raise NotImplementedError + def __le__(self, other): + less = self.__lt__(other) + if less is NotImplemented or not less: + return self.__eq__(other) + return less + def __gt__(self, other): + less = self.__lt__(other) + if less is NotImplemented: + return NotImplemented + equal = self.__eq__(other) + if equal is NotImplemented: + return NotImplemented + return not (less or equal) + def __ge__(self, other): + less = self.__lt__(other) + if less is NotImplemented: + return NotImplemented + return not less + +class _IPAddressBase(_TotalOrderingMixin): """The mother class.""" @@ -465,7 +496,6 @@ prefixlen = self._prefixlen return self._string_from_ip_int(self._ip_int_from_prefix(prefixlen)) - class _BaseAddress(_IPAddressBase): """A generic IP object. @@ -493,24 +523,6 @@ except AttributeError: return NotImplemented - def __ne__(self, other): - eq = self.__eq__(other) - if eq is NotImplemented: - return NotImplemented - return not eq - - def __le__(self, other): - gt = self.__gt__(other) - if gt is NotImplemented: - return NotImplemented - return not gt - - def __ge__(self, other): - lt = self.__lt__(other) - if lt is NotImplemented: - return NotImplemented - return not lt - def __lt__(self, other): if self._version != other._version: raise TypeError('%s and %s are not of the same version' % ( @@ -522,17 +534,6 @@ return self._ip < other._ip return False - def __gt__(self, other): - if self._version != other._version: - raise TypeError('%s and %s are not of the same version' % ( - self, other)) - if not isinstance(other, _BaseAddress): - raise TypeError('%s and %s are not of the same type' % ( - self, other)) - if self._ip != other._ip: - return self._ip > other._ip - return False - # Shorthand for Integer addition and subtraction. This is not # meant to ever support addition/subtraction of addresses. def __add__(self, other): @@ -625,31 +626,6 @@ return self.netmask < other.netmask return False - def __gt__(self, other): - if self._version != other._version: - raise TypeError('%s and %s are not of the same version' % ( - self, other)) - if not isinstance(other, _BaseNetwork): - raise TypeError('%s and %s are not of the same type' % ( - self, other)) - if self.network_address != other.network_address: - return self.network_address > other.network_address - if self.netmask != other.netmask: - return self.netmask > other.netmask - return False - - def __le__(self, other): - gt = self.__gt__(other) - if gt is NotImplemented: - return NotImplemented - return not gt - - def __ge__(self, other): - lt = self.__lt__(other) - if lt is NotImplemented: - return NotImplemented - return not lt - def __eq__(self, other): try: return (self._version == other._version and @@ -658,12 +634,6 @@ except AttributeError: return NotImplemented - def __ne__(self, other): - eq = self.__eq__(other) - if eq is NotImplemented: - return NotImplemented - return not eq - def __hash__(self): return hash(int(self.network_address) ^ int(self.netmask)) @@ -1292,11 +1262,27 @@ self.network.prefixlen) def __eq__(self, other): + address_equal = IPv4Address.__eq__(self, other) + if not address_equal or address_equal is NotImplemented: + return address_equal try: - return (IPv4Address.__eq__(self, other) and - self.network == other.network) + return self.network == other.network except AttributeError: + # An interface with an associated network is NOT the + # same as an unassociated address. That's why the hash + # takes the extra info into account. + return False + + def __lt__(self, other): + address_less = IPv4Address.__lt__(self, other) + if address_less is NotImplemented: return NotImplemented + try: + return self.network < other.network + except AttributeError: + # We *do* allow addresses and interfaces to be sorted. The + # unassociated address is considered less than all interfaces. + return False def __hash__(self): return self._ip ^ self._prefixlen ^ int(self.network.network_address) @@ -1928,11 +1914,27 @@ self.network.prefixlen) def __eq__(self, other): + address_equal = IPv6Address.__eq__(self, other) + if not address_equal or address_equal is NotImplemented: + return address_equal try: - return (IPv6Address.__eq__(self, other) and - self.network == other.network) + return self.network == other.network except AttributeError: + # An interface with an associated network is NOT the + # same as an unassociated address. That's why the hash + # takes the extra info into account. + return False + + def __lt__(self, other): + address_less = IPv6Address.__lt__(self, other) + if address_less is NotImplemented: return NotImplemented + try: + return self.network < other.network + except AttributeError: + # We *do* allow addresses and interfaces to be sorted. The + # unassociated address is considered less than all interfaces. + return False def __hash__(self): return self._ip ^ self._prefixlen ^ int(self.network.network_address) diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -415,6 +415,93 @@ self.assertFactoryError(ipaddress.ip_network, "network") +class ComparisonTests(unittest.TestCase): + + v4addr = ipaddress.IPv4Address(1) + v4net = ipaddress.IPv4Network(1) + v4intf = ipaddress.IPv4Interface(1) + v6addr = ipaddress.IPv6Address(1) + v6net = ipaddress.IPv6Network(1) + v6intf = ipaddress.IPv6Interface(1) + + v4_addresses = [v4addr, v4intf] + v4_objects = v4_addresses + [v4net] + v6_addresses = [v6addr, v6intf] + v6_objects = v6_addresses + [v6net] + objects = v4_objects + v6_objects + + def test_foreign_type_equality(self): + # __eq__ should never raise TypeError directly + other = object() + for obj in self.objects: + self.assertNotEqual(obj, other) + self.assertFalse(obj == other) + self.assertEqual(obj.__eq__(other), NotImplemented) + self.assertEqual(obj.__ne__(other), NotImplemented) + + def test_mixed_type_equality(self): + # Ensure none of the internal objects accidentally + # expose the right set of attributes to become "equal" + for lhs in self.objects: + for rhs in self.objects: + if lhs is rhs: + continue + self.assertNotEqual(lhs, rhs) + + def test_containment(self): + for obj in self.v4_addresses: + self.assertIn(obj, self.v4net) + for obj in self.v6_addresses: + self.assertIn(obj, self.v6net) + for obj in self.v4_objects + [self.v6net]: + self.assertNotIn(obj, self.v6net) + for obj in self.v6_objects + [self.v4net]: + self.assertNotIn(obj, self.v4net) + + def test_mixed_type_ordering(self): + for lhs in self.objects: + for rhs in self.objects: + if isinstance(lhs, type(rhs)) or isinstance(rhs, type(lhs)): + continue + self.assertRaises(TypeError, lambda: lhs < rhs) + self.assertRaises(TypeError, lambda: lhs > rhs) + self.assertRaises(TypeError, lambda: lhs <= rhs) + self.assertRaises(TypeError, lambda: lhs >= rhs) + + def test_mixed_type_key(self): + # with get_mixed_type_key, you can sort addresses and network. + v4_ordered = [self.v4addr, self.v4net, self.v4intf] + v6_ordered = [self.v6addr, self.v6net, self.v6intf] + self.assertEqual(v4_ordered, + sorted(self.v4_objects, + key=ipaddress.get_mixed_type_key)) + self.assertEqual(v6_ordered, + sorted(self.v6_objects, + key=ipaddress.get_mixed_type_key)) + self.assertEqual(v4_ordered + v6_ordered, + sorted(self.objects, + key=ipaddress.get_mixed_type_key)) + self.assertEqual(NotImplemented, ipaddress.get_mixed_type_key(object)) + + def test_incompatible_versions(self): + # These should always raise TypeError + v4addr = ipaddress.ip_address('1.1.1.1') + v4net = ipaddress.ip_network('1.1.1.1') + v6addr = ipaddress.ip_address('::1') + v6net = ipaddress.ip_address('::1') + + self.assertRaises(TypeError, v4addr.__lt__, v6addr) + self.assertRaises(TypeError, v4addr.__gt__, v6addr) + self.assertRaises(TypeError, v4net.__lt__, v6net) + self.assertRaises(TypeError, v4net.__gt__, v6net) + + self.assertRaises(TypeError, v6addr.__lt__, v4addr) + self.assertRaises(TypeError, v6addr.__gt__, v4addr) + self.assertRaises(TypeError, v6net.__lt__, v4net) + self.assertRaises(TypeError, v6net.__gt__, v4net) + + + class IpaddrUnitTest(unittest.TestCase): def setUp(self): @@ -495,67 +582,6 @@ self.assertEqual(str(self.ipv6_network.hostmask), '::ffff:ffff:ffff:ffff') - def testEqualityChecks(self): - # __eq__ should never raise TypeError directly - other = object() - def assertEqualityNotImplemented(instance): - self.assertEqual(instance.__eq__(other), NotImplemented) - self.assertEqual(instance.__ne__(other), NotImplemented) - self.assertFalse(instance == other) - self.assertTrue(instance != other) - - assertEqualityNotImplemented(self.ipv4_address) - assertEqualityNotImplemented(self.ipv4_network) - assertEqualityNotImplemented(self.ipv4_interface) - assertEqualityNotImplemented(self.ipv6_address) - assertEqualityNotImplemented(self.ipv6_network) - assertEqualityNotImplemented(self.ipv6_interface) - - def testBadVersionComparison(self): - # These should always raise TypeError - v4addr = ipaddress.ip_address('1.1.1.1') - v4net = ipaddress.ip_network('1.1.1.1') - v6addr = ipaddress.ip_address('::1') - v6net = ipaddress.ip_address('::1') - - self.assertRaises(TypeError, v4addr.__lt__, v6addr) - self.assertRaises(TypeError, v4addr.__gt__, v6addr) - self.assertRaises(TypeError, v4net.__lt__, v6net) - self.assertRaises(TypeError, v4net.__gt__, v6net) - - self.assertRaises(TypeError, v6addr.__lt__, v4addr) - self.assertRaises(TypeError, v6addr.__gt__, v4addr) - self.assertRaises(TypeError, v6net.__lt__, v4net) - self.assertRaises(TypeError, v6net.__gt__, v4net) - - def testMixedTypeComparison(self): - v4addr = ipaddress.ip_address('1.1.1.1') - v4net = ipaddress.ip_network('1.1.1.1/32') - v6addr = ipaddress.ip_address('::1') - v6net = ipaddress.ip_network('::1/128') - - self.assertFalse(v4net.__contains__(v6net)) - self.assertFalse(v6net.__contains__(v4net)) - - self.assertRaises(TypeError, lambda: v4addr < v4net) - self.assertRaises(TypeError, lambda: v4addr > v4net) - self.assertRaises(TypeError, lambda: v4net < v4addr) - self.assertRaises(TypeError, lambda: v4net > v4addr) - - self.assertRaises(TypeError, lambda: v6addr < v6net) - self.assertRaises(TypeError, lambda: v6addr > v6net) - self.assertRaises(TypeError, lambda: v6net < v6addr) - self.assertRaises(TypeError, lambda: v6net > v6addr) - - # with get_mixed_type_key, you can sort addresses and network. - self.assertEqual([v4addr, v4net], - sorted([v4net, v4addr], - key=ipaddress.get_mixed_type_key)) - self.assertEqual([v6addr, v6net], - sorted([v6net, v6addr], - key=ipaddress.get_mixed_type_key)) - self.assertEqual(NotImplemented, ipaddress.get_mixed_type_key(object)) - def testIpFromInt(self): self.assertEqual(self.ipv4_interface._ip, ipaddress.IPv4Interface(16909060)._ip) @@ -1049,6 +1075,16 @@ self.assertTrue(ipaddress.ip_address('::1') <= ipaddress.ip_address('::2')) + def testInterfaceComparison(self): + self.assertTrue(ipaddress.ip_interface('1.1.1.1') <= + ipaddress.ip_interface('1.1.1.1')) + self.assertTrue(ipaddress.ip_interface('1.1.1.1') <= + ipaddress.ip_interface('1.1.1.2')) + self.assertTrue(ipaddress.ip_interface('::1') <= + ipaddress.ip_interface('::1')) + self.assertTrue(ipaddress.ip_interface('::1') <= + ipaddress.ip_interface('::2')) + def testNetworkComparison(self): # ip1 and ip2 have the same network address ip1 = ipaddress.IPv4Network('1.1.1.0/24') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -23,6 +23,9 @@ Library ------- +- Issue #14814: implement more consistent ordering and sorting behaviour + for ipaddress objects + - Issue #14814: ipaddress network objects correctly return NotImplemented when compared to arbitrary objects instead of raising TypeError -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 17:04:33 2012 From: python-checkins at python.org (florent.xicluna) Date: Sat, 7 Jul 2012 17:04:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2313248=3A_argparse?= =?utf-8?q?=3A_Remove_obsolete_argument_=22version=22_of_ArgumentParser=2E?= Message-ID: <3WTx0x2w0rzMQf@mail.python.org> http://hg.python.org/cpython/rev/5393382c1b1d changeset: 77972:5393382c1b1d user: Florent Xicluna date: Sat Jul 07 17:02:22 2012 +0200 summary: Issue #13248: argparse: Remove obsolete argument "version" of ArgumentParser. files: Lib/argparse.py | 37 +------------ Lib/test/test_argparse.py | 79 ++++++++++++-------------- Misc/NEWS | 2 + 3 files changed, 39 insertions(+), 79 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1579,7 +1579,6 @@ usage=None, description=None, epilog=None, - version=None, parents=[], formatter_class=HelpFormatter, prefix_chars='-', @@ -1588,14 +1587,6 @@ conflict_handler='error', add_help=True): - if version is not None: - import warnings - warnings.warn( - """The "version" argument to ArgumentParser is deprecated. """ - """Please use """ - """"add_argument(..., action='version', version="N", ...)" """ - """instead""", DeprecationWarning) - superinit = super(ArgumentParser, self).__init__ superinit(description=description, prefix_chars=prefix_chars, @@ -1609,7 +1600,6 @@ self.prog = prog self.usage = usage self.epilog = epilog - self.version = version self.formatter_class = formatter_class self.fromfile_prefix_chars = fromfile_prefix_chars self.add_help = add_help @@ -1624,7 +1614,7 @@ return string self.register('type', None, identity) - # add help and version arguments if necessary + # add help argument if necessary # (using explicit default to override global argument_default) default_prefix = '-' if '-' in prefix_chars else prefix_chars[0] if self.add_help: @@ -1632,12 +1622,6 @@ default_prefix+'h', default_prefix*2+'help', action='help', default=SUPPRESS, help=_('show this help message and exit')) - if self.version: - self.add_argument( - default_prefix+'v', default_prefix*2+'version', - action='version', default=SUPPRESS, - version=self.version, - help=_("show program's version number and exit")) # add parent arguments and defaults for parent in parents: @@ -1657,7 +1641,6 @@ 'prog', 'usage', 'description', - 'version', 'formatter_class', 'conflict_handler', 'add_help', @@ -2320,16 +2303,6 @@ # determine help from format above return formatter.format_help() - def format_version(self): - import warnings - warnings.warn( - 'The format_version method is deprecated -- the "version" ' - 'argument to ArgumentParser is no longer supported.', - DeprecationWarning) - formatter = self._get_formatter() - formatter.add_text(self.version) - return formatter.format_help() - def _get_formatter(self): return self.formatter_class(prog=self.prog) @@ -2346,14 +2319,6 @@ file = _sys.stdout self._print_message(self.format_help(), file) - def print_version(self, file=None): - import warnings - warnings.warn( - 'The print_version method is deprecated -- the "version" ' - 'argument to ArgumentParser is no longer supported.', - DeprecationWarning) - self._print_message(self.format_version(), file) - def _print_message(self, message, file=None): if message: if file is None: diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -1323,20 +1323,21 @@ class TestParserDefault42(ParserTestCase): """Test actions with a parser-level default of 42""" - parser_signature = Sig(argument_default=42, version='1.0') + parser_signature = Sig(argument_default=42) argument_signatures = [ + Sig('--version', action='version', version='1.0'), Sig('foo', nargs='?'), Sig('bar', nargs='*'), Sig('--baz', action='store_true'), ] failures = ['-x'] successes = [ - ('', NS(foo=42, bar=42, baz=42)), - ('a', NS(foo='a', bar=42, baz=42)), - ('a b', NS(foo='a', bar=['b'], baz=42)), - ('--baz', NS(foo=42, bar=42, baz=True)), - ('a --baz', NS(foo='a', bar=42, baz=True)), - ('--baz a b', NS(foo='a', bar=['b'], baz=True)), + ('', NS(foo=42, bar=42, baz=42, version=42)), + ('a', NS(foo='a', bar=42, baz=42, version=42)), + ('a b', NS(foo='a', bar=['b'], baz=42, version=42)), + ('--baz', NS(foo=42, bar=42, baz=True, version=42)), + ('a --baz', NS(foo='a', bar=42, baz=True, version=42)), + ('--baz a b', NS(foo='a', bar=['b'], baz=True, version=42)), ] @@ -2896,10 +2897,9 @@ parser_text = sfile.getvalue() self._test(tester, parser_text) - # add tests for {format,print}_{usage,help,version} + # add tests for {format,print}_{usage,help} for func_suffix, std_name in [('usage', 'stdout'), - ('help', 'stdout'), - ('version', 'stderr')]: + ('help', 'stdout')]: AddTests(cls, func_suffix, std_name) bases = TestCase, @@ -2910,8 +2910,9 @@ """Make sure that argument help aligns when options are longer""" parser_signature = Sig(prog='PROG', description='DESCRIPTION', - epilog='EPILOG', version='0.1') + epilog='EPILOG') argument_signatures = [ + Sig('-v', '--version', action='version', version='0.1'), Sig('-x', action='store_true', help='X HELP'), Sig('--y', help='Y HELP'), Sig('foo', help='FOO HELP'), @@ -2946,8 +2947,9 @@ """Make sure that argument help aligns when options are longer""" parser_signature = Sig(prog='PROG', description='DESCRIPTION', - epilog='EPILOG', version='0.1') + epilog='EPILOG') argument_signatures = [ + Sig('-v', '--version', action='version', version='0.1'), Sig('-x', action='store_true', help='X HELP'), Sig('--y', help='Y HELP'), Sig('foo', help='FOO HELP'), @@ -3114,9 +3116,9 @@ class TestHelpWrappingLongNames(HelpTestCase): """Make sure that text after long names starts on the next line""" - parser_signature = Sig(usage='USAGE', description= 'D D' * 30, - version='V V'*30) + parser_signature = Sig(usage='USAGE', description= 'D D' * 30) argument_signatures = [ + Sig('-v', '--version', action='version', version='V V' * 30), Sig('-x', metavar='X' * 25, help='XH XH' * 20), Sig('y', metavar='y' * 25, help='YH YH' * 20), ] @@ -3719,8 +3721,9 @@ class TestHelpVersionOptional(HelpTestCase): """Test that the --version argument can be suppressed help messages""" - parser_signature = Sig(prog='PROG', version='1.0') + parser_signature = Sig(prog='PROG') argument_signatures = [ + Sig('-v', '--version', action='version', version='1.0'), Sig('--foo', help='foo help'), Sig('spam', help='spam help'), ] @@ -3953,8 +3956,8 @@ class TestHelpSubparsersOrdering(HelpTestCase): """Test ordering of subcommands in help matches the code""" parser_signature = Sig(prog='PROG', - description='display some subcommands', - version='0.1') + description='display some subcommands') + argument_signatures = [Sig('-v', '--version', action='version', version='0.1')] subparsers_signatures = [Sig(name=name) for name in ('a', 'b', 'c', 'd', 'e')] @@ -3982,8 +3985,8 @@ class TestHelpSubparsersWithHelpOrdering(HelpTestCase): """Test ordering of subcommands in help matches the code""" parser_signature = Sig(prog='PROG', - description='display some subcommands', - version='0.1') + description='display some subcommands') + argument_signatures = [Sig('-v', '--version', action='version', version='0.1')] subcommand_data = (('a', 'a subcommand help'), ('b', 'b subcommand help'), @@ -4280,32 +4283,28 @@ parser.format_help(), self._get_error(parser.parse_args, args_str.split()).stdout) - def assertPrintVersionExit(self, parser, args_str): - self.assertEqual( - parser.format_version(), - self._get_error(parser.parse_args, args_str.split()).stderr) - def assertArgumentParserError(self, parser, *args): self.assertRaises(ArgumentParserError, parser.parse_args, args) def test_version(self): - parser = ErrorRaisingArgumentParser(version='1.0') + parser = ErrorRaisingArgumentParser() + parser.add_argument('-v', '--version', action='version', version='1.0') self.assertPrintHelpExit(parser, '-h') self.assertPrintHelpExit(parser, '--help') - self.assertPrintVersionExit(parser, '-v') - self.assertPrintVersionExit(parser, '--version') + self.assertRaises(AttributeError, getattr, parser, 'format_version') def test_version_format(self): - parser = ErrorRaisingArgumentParser(prog='PPP', version='%(prog)s 3.5') + parser = ErrorRaisingArgumentParser(prog='PPP') + parser.add_argument('-v', '--version', action='version', version='%(prog)s 3.5') msg = self._get_error(parser.parse_args, ['-v']).stderr self.assertEqual('PPP 3.5\n', msg) def test_version_no_help(self): - parser = ErrorRaisingArgumentParser(add_help=False, version='1.0') + parser = ErrorRaisingArgumentParser(add_help=False) + parser.add_argument('-v', '--version', action='version', version='1.0') self.assertArgumentParserError(parser, '-h') self.assertArgumentParserError(parser, '--help') - self.assertPrintVersionExit(parser, '-v') - self.assertPrintVersionExit(parser, '--version') + self.assertRaises(AttributeError, getattr, parser, 'format_version') def test_version_action(self): parser = ErrorRaisingArgumentParser(prog='XXX') @@ -4325,12 +4324,13 @@ parser.add_argument('-x', action='help') parser.add_argument('-y', action='version') self.assertPrintHelpExit(parser, '-x') - self.assertPrintVersionExit(parser, '-y') self.assertArgumentParserError(parser, '-v') self.assertArgumentParserError(parser, '--version') + self.assertRaises(AttributeError, getattr, parser, 'format_version') def test_help_version_extra_arguments(self): - parser = ErrorRaisingArgumentParser(version='1.0') + parser = ErrorRaisingArgumentParser() + parser.add_argument('--version', action='version', version='1.0') parser.add_argument('-x', action='store_true') parser.add_argument('y') @@ -4342,8 +4342,7 @@ format = '%s %%s %s' % (prefix, suffix) self.assertPrintHelpExit(parser, format % '-h') self.assertPrintHelpExit(parser, format % '--help') - self.assertPrintVersionExit(parser, format % '-v') - self.assertPrintVersionExit(parser, format % '--version') + self.assertRaises(AttributeError, getattr, parser, 'format_version') # ====================== @@ -4398,7 +4397,7 @@ parser = argparse.ArgumentParser(prog='PROG') string = ( "ArgumentParser(prog='PROG', usage=None, description=None, " - "version=None, formatter_class=%r, conflict_handler='error', " + "formatter_class=%r, conflict_handler='error', " "add_help=True)" % argparse.HelpFormatter) self.assertStringEqual(parser, string) @@ -4760,13 +4759,7 @@ self.assertEqual(sorted(items), sorted(argparse.__all__)) def test_main(): - # silence warnings about version argument - these are expected - with support.check_warnings( - ('The "version" argument to ArgumentParser is deprecated.', - DeprecationWarning), - ('The (format|print)_version method is deprecated', - DeprecationWarning)): - support.run_unittest(__name__) + support.run_unittest(__name__) # Remove global references to avoid looking like we have refleaks. RFile.seen = {} WFile.seen = set() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -23,6 +23,8 @@ Library ------- +- Issue #13248: Remove obsolete argument "version" of argparse.ArgumentParser. + - Issue #14814: implement more consistent ordering and sorting behaviour for ipaddress objects -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 17:04:35 2012 From: python-checkins at python.org (florent.xicluna) Date: Sat, 7 Jul 2012 17:04:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2313248=3A_io=3A_Re?= =?utf-8?q?move_obsolete_argument_=22max=5Fbuffer=5Fsize=22_of_BufferedWri?= =?utf-8?q?ter?= Message-ID: <3WTx0z3VxFzNXR@mail.python.org> http://hg.python.org/cpython/rev/700f989afbad changeset: 77973:700f989afbad user: Florent Xicluna date: Sat Jul 07 17:03:22 2012 +0200 summary: Issue #13248: io: Remove obsolete argument "max_buffer_size" of BufferedWriter and BufferedRWPair. files: Doc/library/io.rst | 7 ---- Lib/_pyio.py | 22 ++------------ Lib/test/test_io.py | 10 ++---- Misc/NEWS | 3 ++ Modules/_io/bufferedio.c | 42 ++++++--------------------- 5 files changed, 21 insertions(+), 63 deletions(-) diff --git a/Doc/library/io.rst b/Doc/library/io.rst --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -604,8 +604,6 @@ *raw* stream. If the *buffer_size* is not given, it defaults to :data:`DEFAULT_BUFFER_SIZE`. - A third argument, *max_buffer_size*, is supported, but unused and deprecated. - :class:`BufferedWriter` provides or overrides these methods in addition to those from :class:`BufferedIOBase` and :class:`IOBase`: @@ -631,8 +629,6 @@ in the first argument. If the *buffer_size* is omitted it defaults to :data:`DEFAULT_BUFFER_SIZE`. - A third argument, *max_buffer_size*, is supported, but unused and deprecated. - :class:`BufferedRandom` is capable of anything :class:`BufferedReader` or :class:`BufferedWriter` can do. @@ -647,9 +643,6 @@ writeable respectively. If the *buffer_size* is omitted it defaults to :data:`DEFAULT_BUFFER_SIZE`. - A fourth argument, *max_buffer_size*, is supported, but unused and - deprecated. - :class:`BufferedRWPair` implements all of :class:`BufferedIOBase`\'s methods except for :meth:`~BufferedIOBase.detach`, which raises :exc:`UnsupportedOperation`. diff --git a/Lib/_pyio.py b/Lib/_pyio.py --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -5,7 +5,6 @@ import os import abc import codecs -import warnings import errno # Import _thread instead of threading to reduce startup cost try: @@ -1065,19 +1064,13 @@ DEFAULT_BUFFER_SIZE. """ - _warning_stack_offset = 2 - - def __init__(self, raw, - buffer_size=DEFAULT_BUFFER_SIZE, max_buffer_size=None): + def __init__(self, raw, buffer_size=DEFAULT_BUFFER_SIZE): if not raw.writable(): raise IOError('"raw" argument must be writable.') _BufferedIOMixin.__init__(self, raw) if buffer_size <= 0: raise ValueError("invalid buffer size") - if max_buffer_size is not None: - warnings.warn("max_buffer_size is deprecated", DeprecationWarning, - self._warning_stack_offset) self.buffer_size = buffer_size self._write_buf = bytearray() self._write_lock = Lock() @@ -1167,15 +1160,11 @@ # XXX The usefulness of this (compared to having two separate IO # objects) is questionable. - def __init__(self, reader, writer, - buffer_size=DEFAULT_BUFFER_SIZE, max_buffer_size=None): + def __init__(self, reader, writer, buffer_size=DEFAULT_BUFFER_SIZE): """Constructor. The arguments are two RawIO instances. """ - if max_buffer_size is not None: - warnings.warn("max_buffer_size is deprecated", DeprecationWarning, 2) - if not reader.readable(): raise IOError('"reader" argument must be readable.') @@ -1232,13 +1221,10 @@ defaults to DEFAULT_BUFFER_SIZE. """ - _warning_stack_offset = 3 - - def __init__(self, raw, - buffer_size=DEFAULT_BUFFER_SIZE, max_buffer_size=None): + def __init__(self, raw, buffer_size=DEFAULT_BUFFER_SIZE): raw._checkSeekable() BufferedReader.__init__(self, raw, buffer_size) - BufferedWriter.__init__(self, raw, buffer_size, max_buffer_size) + BufferedWriter.__init__(self, raw, buffer_size) def seek(self, pos, whence=0): if whence not in valid_seek_flags: diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -1255,9 +1255,8 @@ self.assertRaises(IOError, bufio.tell) self.assertRaises(IOError, bufio.write, b"abcdef") - def test_max_buffer_size_deprecation(self): - with support.check_warnings(("max_buffer_size is deprecated", - DeprecationWarning)): + def test_max_buffer_size_removal(self): + with self.assertRaises(TypeError): self.tp(self.MockRawIO(), 8, 12) @@ -1313,9 +1312,8 @@ pair = self.tp(self.MockRawIO(), self.MockRawIO()) self.assertRaises(self.UnsupportedOperation, pair.detach) - def test_constructor_max_buffer_size_deprecation(self): - with support.check_warnings(("max_buffer_size is deprecated", - DeprecationWarning)): + def test_constructor_max_buffer_size_removal(self): + with self.assertRaises(TypeError): self.tp(self.MockRawIO(), self.MockRawIO(), 8, 12) def test_constructor_with_not_readable(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -23,6 +23,9 @@ Library ------- +- Issue #13248: Remove obsolete argument "max_buffer_size" of BufferedWriter + and BufferedRWPair, from the io module. + - Issue #13248: Remove obsolete argument "version" of argparse.ArgumentParser. - Issue #14814: implement more consistent ordering and sorting behaviour diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -1759,15 +1759,6 @@ -static int -complain_about_max_buffer_size(void) -{ - if (PyErr_WarnEx(PyExc_DeprecationWarning, - "max_buffer_size is deprecated", 1) < 0) - return 0; - return 1; -} - /* * class BufferedWriter */ @@ -1776,7 +1767,7 @@ "\n" "The constructor creates a BufferedWriter for the given writeable raw\n" "stream. If the buffer_size is not given, it defaults to\n" - "DEFAULT_BUFFER_SIZE. max_buffer_size isn't used anymore.\n" + "DEFAULT_BUFFER_SIZE.\n" ); static void @@ -1789,23 +1780,18 @@ static int bufferedwriter_init(buffered *self, PyObject *args, PyObject *kwds) { - /* TODO: properly deprecate max_buffer_size */ - char *kwlist[] = {"raw", "buffer_size", "max_buffer_size", NULL}; + char *kwlist[] = {"raw", "buffer_size", NULL}; Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; - Py_ssize_t max_buffer_size = -234; PyObject *raw; self->ok = 0; self->detached = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|nn:BufferedReader", kwlist, - &raw, &buffer_size, &max_buffer_size)) { + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|n:BufferedReader", kwlist, + &raw, &buffer_size)) { return -1; } - if (max_buffer_size != -234 && !complain_about_max_buffer_size()) - return -1; - if (_PyIOBase_check_writable(raw, Py_True) == NULL) return -1; @@ -2186,16 +2172,12 @@ { PyObject *reader, *writer; Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; - Py_ssize_t max_buffer_size = -234; - if (!PyArg_ParseTuple(args, "OO|nn:BufferedRWPair", &reader, &writer, - &buffer_size, &max_buffer_size)) { + if (!PyArg_ParseTuple(args, "OO|n:BufferedRWPair", &reader, &writer, + &buffer_size)) { return -1; } - if (max_buffer_size != -234 && !complain_about_max_buffer_size()) - return -1; - if (_PyIOBase_check_readable(reader, Py_True) == NULL) return -1; if (_PyIOBase_check_writable(writer, Py_True) == NULL) @@ -2420,28 +2402,24 @@ "\n" "The constructor creates a reader and writer for a seekable stream,\n" "raw, given in the first argument. If the buffer_size is omitted it\n" - "defaults to DEFAULT_BUFFER_SIZE. max_buffer_size isn't used anymore.\n" + "defaults to DEFAULT_BUFFER_SIZE.\n" ); static int bufferedrandom_init(buffered *self, PyObject *args, PyObject *kwds) { - char *kwlist[] = {"raw", "buffer_size", "max_buffer_size", NULL}; + char *kwlist[] = {"raw", "buffer_size", NULL}; Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; - Py_ssize_t max_buffer_size = -234; PyObject *raw; self->ok = 0; self->detached = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|nn:BufferedReader", kwlist, - &raw, &buffer_size, &max_buffer_size)) { + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|n:BufferedReader", kwlist, + &raw, &buffer_size)) { return -1; } - if (max_buffer_size != -234 && !complain_about_max_buffer_size()) - return -1; - if (_PyIOBase_check_seekable(raw, Py_True) == NULL) return -1; if (_PyIOBase_check_readable(raw, Py_True) == NULL) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 17:04:36 2012 From: python-checkins at python.org (florent.xicluna) Date: Sat, 7 Jul 2012 17:04:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Add_tests_to_marshall_doub?= =?utf-8?q?le_with_xmlrpc=2Eclient=2E?= Message-ID: <3WTx106QDszNWK@mail.python.org> http://hg.python.org/cpython/rev/c257c5eea42f changeset: 77974:c257c5eea42f user: Florent Xicluna date: Sat Jul 07 17:03:25 2012 +0200 summary: Add tests to marshall double with xmlrpc.client. files: Lib/test/test_xmlrpc.py | 16 ++++++++++++++++ 1 files changed, 16 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py --- a/Lib/test/test_xmlrpc.py +++ b/Lib/test/test_xmlrpc.py @@ -154,6 +154,22 @@ self.assertRaises(OverflowError, m.dump_int, xmlrpclib.MININT-1, dummy_write) + def test_dump_double(self): + xmlrpclib.dumps((float(2 ** 34),)) + xmlrpclib.dumps((float(xmlrpclib.MAXINT), + float(xmlrpclib.MININT))) + xmlrpclib.dumps((float(xmlrpclib.MAXINT + 42), + float(xmlrpclib.MININT - 42))) + + def dummy_write(s): + pass + + m = xmlrpclib.Marshaller() + m.dump_double(xmlrpclib.MAXINT, dummy_write) + m.dump_double(xmlrpclib.MININT, dummy_write) + m.dump_double(xmlrpclib.MAXINT + 42, dummy_write) + m.dump_double(xmlrpclib.MININT - 42, dummy_write) + def test_dump_none(self): value = alist + [None] arg1 = (alist + [None],) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 17:04:38 2012 From: python-checkins at python.org (florent.xicluna) Date: Sat, 7 Jul 2012 17:04:38 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_trace=3A_remove_unused_imp?= =?utf-8?q?orts=2E?= Message-ID: <3WTx12251HzNXR@mail.python.org> http://hg.python.org/cpython/rev/f1604371240a changeset: 77975:f1604371240a user: Florent Xicluna date: Sat Jul 07 17:03:52 2012 +0200 summary: trace: remove unused imports. files: Lib/trace.py | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diff --git a/Lib/trace.py b/Lib/trace.py --- a/Lib/trace.py +++ b/Lib/trace.py @@ -48,19 +48,16 @@ r.write_results(show_missing=True, coverdir="/tmp") """ __all__ = ['Trace', 'CoverageResults'] -import io import linecache import os import re import sys -import time import token import tokenize import inspect import gc import dis import pickle -from warnings import warn as _warn try: from time import monotonic as _time except ImportError: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 17:04:39 2012 From: python-checkins at python.org (florent.xicluna) Date: Sat, 7 Jul 2012 17:04:39 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Some_cleanup_in_the_Tools_?= =?utf-8?q?directory=2E?= Message-ID: <3WTx136BrWzNXt@mail.python.org> http://hg.python.org/cpython/rev/5b71f5891c54 changeset: 77976:5b71f5891c54 user: Florent Xicluna date: Sat Jul 07 17:03:54 2012 +0200 summary: Some cleanup in the Tools directory. files: Tools/ccbench/ccbench.py | 1 - Tools/demo/life.py | 89 +++++++++++-------- Tools/demo/ss1.py | 1 - Tools/i18n/pygettext.py | 1 - Tools/iobench/iobench.py | 2 - Tools/parser/unparse.py | 1 - Tools/pybench/pybench.py | 6 +- Tools/unicode/makeunicodedata.py | 1 - 8 files changed, 53 insertions(+), 49 deletions(-) diff --git a/Tools/ccbench/ccbench.py b/Tools/ccbench/ccbench.py --- a/Tools/ccbench/ccbench.py +++ b/Tools/ccbench/ccbench.py @@ -10,7 +10,6 @@ import time import os import sys -import functools import itertools import threading import subprocess diff --git a/Tools/demo/life.py b/Tools/demo/life.py --- a/Tools/demo/life.py +++ b/Tools/demo/life.py @@ -46,38 +46,38 @@ self.state = {} self.scr = scr Y, X = self.scr.getmaxyx() - self.X, self.Y = X-2, Y-2-1 + self.X, self.Y = X - 2, Y - 2 - 1 self.char = char self.scr.clear() # Draw a border around the board - border_line = '+'+(self.X*'-')+'+' + border_line = '+' + (self.X * '-') + '+' self.scr.addstr(0, 0, border_line) - self.scr.addstr(self.Y+1, 0, border_line) + self.scr.addstr(self.Y + 1, 0, border_line) for y in range(0, self.Y): - self.scr.addstr(1+y, 0, '|') - self.scr.addstr(1+y, self.X+1, '|') + self.scr.addstr(1 + y, 0, '|') + self.scr.addstr(1 + y, self.X + 1, '|') self.scr.refresh() def set(self, y, x): """Set a cell to the live state""" - if x<0 or self.X<=x or y<0 or self.Y<=y: - raise ValueError("Coordinates out of range %i,%i"% (y, x)) - self.state[x,y] = 1 + if x < 0 or self.X <= x or y < 0 or self.Y <= y: + raise ValueError("Coordinates out of range %i,%i" % (y, x)) + self.state[x, y] = 1 def toggle(self, y, x): """Toggle a cell's state between live and dead""" if x < 0 or self.X <= x or y < 0 or self.Y <= y: - raise ValueError("Coordinates out of range %i,%i"% (y, x)) + raise ValueError("Coordinates out of range %i,%i" % (y, x)) if (x, y) in self.state: del self.state[x, y] - self.scr.addch(y+1, x+1, ' ') + self.scr.addch(y + 1, x + 1, ' ') else: self.state[x, y] = 1 if curses.has_colors(): # Let's pick a random color! self.scr.attrset(curses.color_pair(random.randrange(1, 7))) - self.scr.addch(y+1, x+1, self.char) + self.scr.addch(y + 1, x + 1, self.char) self.scr.attrset(0) self.scr.refresh() @@ -88,43 +88,46 @@ def display(self, update_board=True): """Display the whole board, optionally computing one generation""" - M,N = self.X, self.Y + M, N = self.X, self.Y if not update_board: for i in range(0, M): for j in range(0, N): - if (i,j) in self.state: - self.scr.addch(j+1, i+1, self.char) + if (i, j) in self.state: + self.scr.addch(j + 1, i + 1, self.char) else: - self.scr.addch(j+1, i+1, ' ') + self.scr.addch(j + 1, i + 1, ' ') self.scr.refresh() return d = {} self.boring = 1 for i in range(0, M): - L = range( max(0, i-1), min(M, i+2) ) + L = range(max(0, i - 1), min(M, i + 2)) for j in range(0, N): s = 0 - live = (i,j) in self.state - for k in range( max(0, j-1), min(N, j+2) ): + live = (i, j) in self.state + for k in range(max(0, j - 1), min(N, j + 2)): for l in L: - if (l,k) in self.state: + if (l, k) in self.state: s += 1 s -= live if s == 3: # Birth - d[i,j] = 1 + d[i, j] = 1 if curses.has_colors(): # Let's pick a random color! self.scr.attrset(curses.color_pair( random.randrange(1, 7))) - self.scr.addch(j+1, i+1, self.char) + self.scr.addch(j + 1, i + 1, self.char) self.scr.attrset(0) - if not live: self.boring = 0 - elif s == 2 and live: d[i,j] = 1 # Survival + if not live: + self.boring = 0 + elif s == 2 and live: + # Survival + d[i, j] = 1 elif live: # Death - self.scr.addch(j+1, i+1, ' ') + self.scr.addch(j + 1, i + 1, ' ') self.boring = 0 self.state = d self.scr.refresh() @@ -135,16 +138,17 @@ for i in range(0, self.X): for j in range(0, self.Y): if random.random() > 0.5: - self.set(j,i) + self.set(j, i) def erase_menu(stdscr, menu_y): "Clear the space where the menu resides" stdscr.move(menu_y, 0) stdscr.clrtoeol() - stdscr.move(menu_y+1, 0) + stdscr.move(menu_y + 1, 0) stdscr.clrtoeol() + def display_menu(stdscr, menu_y): "Display the menu of possible keystroke commands" erase_menu(stdscr, menu_y) @@ -154,15 +158,16 @@ stdscr.attrset(curses.color_pair(1)) stdscr.addstr(menu_y, 4, 'Use the cursor keys to move, and space or Enter to toggle a cell.') - stdscr.addstr(menu_y+1, 4, + stdscr.addstr(menu_y + 1, 4, 'E)rase the board, R)andom fill, S)tep once or C)ontinuously, Q)uit') stdscr.attrset(0) + def keyloop(stdscr): # Clear the screen and display the menu of keys stdscr.clear() stdscr_y, stdscr_x = stdscr.getmaxyx() - menu_y = (stdscr_y-3)-1 + menu_y = (stdscr_y - 3) - 1 display_menu(stdscr, menu_y) # If color, then initialize the color pairs @@ -179,16 +184,16 @@ curses.mousemask(curses.BUTTON1_CLICKED) # Allocate a subwindow for the Life board and create the board object - subwin = stdscr.subwin(stdscr_y-3, stdscr_x, 0, 0) + subwin = stdscr.subwin(stdscr_y - 3, stdscr_x, 0, 0) board = LifeBoard(subwin, char=ord('*')) board.display(update_board=False) # xpos, ypos are the cursor's position - xpos, ypos = board.X//2, board.Y//2 + xpos, ypos = board.X // 2, board.Y // 2 # Main loop: while True: - stdscr.move(1+ypos, 1+xpos) # Move the cursor + stdscr.move(1 + ypos, 1 + xpos) # Move the cursor c = stdscr.getch() # Get a keystroke if 0 < c < 256: c = chr(c) @@ -224,15 +229,21 @@ board.display(update_board=False) elif c in 'Ss': board.display() - else: pass # Ignore incorrect keys - elif c == curses.KEY_UP and ypos > 0: ypos -= 1 - elif c == curses.KEY_DOWN and ypos < board.Y-1: ypos += 1 - elif c == curses.KEY_LEFT and xpos > 0: xpos -= 1 - elif c == curses.KEY_RIGHT and xpos < board.X-1: xpos += 1 + else: + # Ignore incorrect keys + pass + elif c == curses.KEY_UP and ypos > 0: + ypos -= 1 + elif c == curses.KEY_DOWN and ypos + 1 < board.Y: + ypos += 1 + elif c == curses.KEY_LEFT and xpos > 0: + xpos -= 1 + elif c == curses.KEY_RIGHT and xpos + 1 < board.X: + xpos += 1 elif c == curses.KEY_MOUSE: mouse_id, mouse_x, mouse_y, mouse_z, button_state = curses.getmouse() - if (mouse_x > 0 and mouse_x < board.X+1 and - mouse_y > 0 and mouse_y < board.Y+1): + if (mouse_x > 0 and mouse_x < board.X + 1 and + mouse_y > 0 and mouse_y < board.Y + 1): xpos = mouse_x - 1 ypos = mouse_y - 1 board.toggle(ypos, xpos) @@ -245,7 +256,7 @@ def main(stdscr): - keyloop(stdscr) # Enter the main loop + keyloop(stdscr) # Enter the main loop if __name__ == '__main__': curses.wrapper(main) diff --git a/Tools/demo/ss1.py b/Tools/demo/ss1.py --- a/Tools/demo/ss1.py +++ b/Tools/demo/ss1.py @@ -812,7 +812,6 @@ def test_basic(): "Basic non-gui self-test." - import os a = Sheet() for x in range(1, 11): for y in range(1, 11): diff --git a/Tools/i18n/pygettext.py b/Tools/i18n/pygettext.py --- a/Tools/i18n/pygettext.py +++ b/Tools/i18n/pygettext.py @@ -163,7 +163,6 @@ import getopt import token import tokenize -import operator __version__ = '1.5' diff --git a/Tools/iobench/iobench.py b/Tools/iobench/iobench.py --- a/Tools/iobench/iobench.py +++ b/Tools/iobench/iobench.py @@ -1,8 +1,6 @@ # -*- coding: utf-8 -*- # This file should be kept compatible with both Python 2.6 and Python >= 3.0. -import functools -import hashlib import itertools import os import platform diff --git a/Tools/parser/unparse.py b/Tools/parser/unparse.py --- a/Tools/parser/unparse.py +++ b/Tools/parser/unparse.py @@ -1,6 +1,5 @@ "Usage: unparse.py " import sys -import math import ast import tokenize import io diff --git a/Tools/pybench/pybench.py b/Tools/pybench/pybench.py --- a/Tools/pybench/pybench.py +++ b/Tools/pybench/pybench.py @@ -35,7 +35,9 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE ! """ -import sys, time, operator, platform +import sys +import time +import platform from CommandLine import * try: @@ -963,8 +965,6 @@ pickle.dump(bench,f) f.close() except IOError as reason: - print('* Error opening/writing reportfile') - except IOError as reason: print('* Error opening/writing reportfile %s: %s' % ( reportfile, reason)) diff --git a/Tools/unicode/makeunicodedata.py b/Tools/unicode/makeunicodedata.py --- a/Tools/unicode/makeunicodedata.py +++ b/Tools/unicode/makeunicodedata.py @@ -32,7 +32,6 @@ import zipfile from textwrap import dedent -from operator import itemgetter SCRIPT = sys.argv[0] VERSION = "3.2" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 17:35:06 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 7 Jul 2012 17:35:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Add_a_blurb_about_PEP_412?= Message-ID: <3WTxhB5hVBzNDc@mail.python.org> http://hg.python.org/cpython/rev/b51a85ed3e63 changeset: 77977:b51a85ed3e63 user: Antoine Pitrou date: Sat Jul 07 17:33:42 2012 +0200 summary: Add a blurb about PEP 412 files: Doc/whatsnew/3.3.rst | 12 ++++++++++++ 1 files changed, 12 insertions(+), 0 deletions(-) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -477,6 +477,18 @@ '' +PEP 412: Key-Sharing Dictionary +=============================== + +:pep:`412` - Key-Sharing Dictionary + PEP written and implemented by Mark Shannon. + +Dictionaries used for the storage of objects' attributes are now able to +share part of their internal storage between each other (namely, the part +which stores the keys and their respective hashes). This reduces the memory +consumption of programs creating many instances of non-builtin types. + + Using importlib as the Implementation of Import =============================================== :issue:`2377` - Replace __import__ w/ importlib.__import__ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 18:44:01 2012 From: python-checkins at python.org (ross.lagerwall) Date: Sat, 7 Jul 2012 18:44:01 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_=2315277=3A_Fix_a_resource?= =?utf-8?q?_leak_in_support=2Epy_when_IPv6_is_disabled=2E?= Message-ID: <3WTzCj3vy4zMxB@mail.python.org> http://hg.python.org/cpython/rev/c9299edf1f67 changeset: 77978:c9299edf1f67 parent: 77970:2e9cba1d1554 user: Ross Lagerwall date: Sat Jul 07 18:40:32 2012 +0200 summary: #15277: Fix a resource leak in support.py when IPv6 is disabled. The leak occurred by setting: echo 1 > /proc/sys/net/ipv6/conf/all/disable_ipv6 before running test_support. Patch by Brian Brazil. files: Lib/test/support.py | 8 +++++--- Misc/NEWS | 6 ++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -493,14 +493,16 @@ def _is_ipv6_enabled(): """Check whether IPv6 is enabled on this host.""" if socket.has_ipv6: + sock = None try: sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) sock.bind(('::1', 0)) + return True except (socket.error, socket.gaierror): pass - else: - sock.close() - return True + finally: + if sock: + sock.close() return False IPV6_ENABLED = _is_ipv6_enabled() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -74,6 +74,12 @@ * C frames that are garbage-collecting * C frames that are due to the invocation of a PyCFunction +Tests +----- + +- Issue #15277: Fix a resource leak in support.py when IPv6 is disabled. + Patch by Brian Brazil. + Build ----- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 18:44:03 2012 From: python-checkins at python.org (ross.lagerwall) Date: Sat, 7 Jul 2012 18:44:03 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_remote=2E?= Message-ID: <3WTzCl2CbmzNXW@mail.python.org> http://hg.python.org/cpython/rev/00cd92d0b7d4 changeset: 77979:00cd92d0b7d4 parent: 77977:b51a85ed3e63 parent: 77978:c9299edf1f67 user: Ross Lagerwall date: Sat Jul 07 18:42:57 2012 +0200 summary: Merge with remote. files: Lib/test/support.py | 8 +++++--- Misc/NEWS | 6 ++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -493,14 +493,16 @@ def _is_ipv6_enabled(): """Check whether IPv6 is enabled on this host.""" if socket.has_ipv6: + sock = None try: sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) sock.bind(('::1', 0)) + return True except (socket.error, socket.gaierror): pass - else: - sock.close() - return True + finally: + if sock: + sock.close() return False IPV6_ENABLED = _is_ipv6_enabled() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -82,6 +82,12 @@ * C frames that are garbage-collecting * C frames that are due to the invocation of a PyCFunction +Tests +----- + +- Issue #15277: Fix a resource leak in support.py when IPv6 is disabled. + Patch by Brian Brazil. + Build ----- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 18:59:17 2012 From: python-checkins at python.org (lukasz.langa) Date: Sat, 7 Jul 2012 18:59:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fixes_=2314590=3A_ConfigPa?= =?utf-8?q?rser_doesn=27t_strip_inline_comment_when_delimiter_occurs?= Message-ID: <3WTzYK5F08zN37@mail.python.org> http://hg.python.org/cpython/rev/5257bb466d18 changeset: 77980:5257bb466d18 parent: 77977:b51a85ed3e63 user: ?ukasz Langa date: Sat Jul 07 18:54:08 2012 +0200 summary: Fixes #14590: ConfigParser doesn't strip inline comment when delimiter occurs earlier without preceding space. files: Lib/configparser.py | 20 ++++++++--- Lib/test/test_configparser.py | 37 +++++++++++++++++++++++ 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/Lib/configparser.py b/Lib/configparser.py --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -993,18 +993,26 @@ indent_level = 0 e = None # None, or an exception for lineno, line in enumerate(fp, start=1): - comment_start = None + comment_start = sys.maxsize # strip inline comments - for prefix in self._inline_comment_prefixes: - index = line.find(prefix) - if index == 0 or (index > 0 and line[index-1].isspace()): - comment_start = index - break + inline_prefixes = {p: -1 for p in self._inline_comment_prefixes} + while comment_start == sys.maxsize and inline_prefixes: + next_prefixes = {} + for prefix, index in inline_prefixes.items(): + index = line.find(prefix, index+1) + if index == -1: + continue + next_prefixes[prefix] = index + if index == 0 or (index > 0 and line[index-1].isspace()): + comment_start = min(comment_start, index) + inline_prefixes = next_prefixes # strip full line comments for prefix in self._comment_prefixes: if line.strip().startswith(prefix): comment_start = 0 break + if comment_start == sys.maxsize: + comment_start = None value = line[:comment_start].strip() if not value: if self._empty_lines_in_values: diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -1618,6 +1618,42 @@ self.assertEqual(repr(e1), repr(e2)) +class InlineCommentStrippingTestCase(unittest.TestCase): + """Tests for issue #14590: ConfigParser doesn't strip inline comment when + delimiter occurs earlier without preceding space..""" + + def test_stripping(self): + cfg = configparser.ConfigParser(inline_comment_prefixes=(';', '#', + '//')) + cfg.read_string(""" + [section] + k1 = v1;still v1 + k2 = v2 ;a comment + k3 = v3 ; also a comment + k4 = v4;still v4 ;a comment + k5 = v5;still v5 ; also a comment + k6 = v6;still v6; and still v6 ;a comment + k7 = v7;still v7; and still v7 ; also a comment + + [multiprefix] + k1 = v1;still v1 #a comment ; yeah, pretty much + k2 = v2 // this already is a comment ; continued + k3 = v3;#//still v3# and still v3 ; a comment + """) + s = cfg['section'] + self.assertEqual(s['k1'], 'v1;still v1') + self.assertEqual(s['k2'], 'v2') + self.assertEqual(s['k3'], 'v3') + self.assertEqual(s['k4'], 'v4;still v4') + self.assertEqual(s['k5'], 'v5;still v5') + self.assertEqual(s['k6'], 'v6;still v6; and still v6') + self.assertEqual(s['k7'], 'v7;still v7; and still v7') + s = cfg['multiprefix'] + self.assertEqual(s['k1'], 'v1;still v1') + self.assertEqual(s['k2'], 'v2') + self.assertEqual(s['k3'], 'v3;#//still v3# and still v3') + + def test_main(): support.run_unittest( ConfigParserTestCase, @@ -1640,4 +1676,5 @@ ReadFileTestCase, CoverageOneHundredTestCase, ExceptionPicklingTestCase, + InlineCommentStrippingTestCase, ) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 18:59:19 2012 From: python-checkins at python.org (lukasz.langa) Date: Sat, 7 Jul 2012 18:59:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge_remote?= Message-ID: <3WTzYM3bqJzNWK@mail.python.org> http://hg.python.org/cpython/rev/8f9e391c1e6c changeset: 77981:8f9e391c1e6c parent: 77979:00cd92d0b7d4 parent: 77980:5257bb466d18 user: ?ukasz Langa date: Sat Jul 07 18:58:44 2012 +0200 summary: Merge remote files: Lib/configparser.py | 20 ++++++++--- Lib/test/test_configparser.py | 37 +++++++++++++++++++++++ 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/Lib/configparser.py b/Lib/configparser.py --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -993,18 +993,26 @@ indent_level = 0 e = None # None, or an exception for lineno, line in enumerate(fp, start=1): - comment_start = None + comment_start = sys.maxsize # strip inline comments - for prefix in self._inline_comment_prefixes: - index = line.find(prefix) - if index == 0 or (index > 0 and line[index-1].isspace()): - comment_start = index - break + inline_prefixes = {p: -1 for p in self._inline_comment_prefixes} + while comment_start == sys.maxsize and inline_prefixes: + next_prefixes = {} + for prefix, index in inline_prefixes.items(): + index = line.find(prefix, index+1) + if index == -1: + continue + next_prefixes[prefix] = index + if index == 0 or (index > 0 and line[index-1].isspace()): + comment_start = min(comment_start, index) + inline_prefixes = next_prefixes # strip full line comments for prefix in self._comment_prefixes: if line.strip().startswith(prefix): comment_start = 0 break + if comment_start == sys.maxsize: + comment_start = None value = line[:comment_start].strip() if not value: if self._empty_lines_in_values: diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -1618,6 +1618,42 @@ self.assertEqual(repr(e1), repr(e2)) +class InlineCommentStrippingTestCase(unittest.TestCase): + """Tests for issue #14590: ConfigParser doesn't strip inline comment when + delimiter occurs earlier without preceding space..""" + + def test_stripping(self): + cfg = configparser.ConfigParser(inline_comment_prefixes=(';', '#', + '//')) + cfg.read_string(""" + [section] + k1 = v1;still v1 + k2 = v2 ;a comment + k3 = v3 ; also a comment + k4 = v4;still v4 ;a comment + k5 = v5;still v5 ; also a comment + k6 = v6;still v6; and still v6 ;a comment + k7 = v7;still v7; and still v7 ; also a comment + + [multiprefix] + k1 = v1;still v1 #a comment ; yeah, pretty much + k2 = v2 // this already is a comment ; continued + k3 = v3;#//still v3# and still v3 ; a comment + """) + s = cfg['section'] + self.assertEqual(s['k1'], 'v1;still v1') + self.assertEqual(s['k2'], 'v2') + self.assertEqual(s['k3'], 'v3') + self.assertEqual(s['k4'], 'v4;still v4') + self.assertEqual(s['k5'], 'v5;still v5') + self.assertEqual(s['k6'], 'v6;still v6; and still v6') + self.assertEqual(s['k7'], 'v7;still v7; and still v7') + s = cfg['multiprefix'] + self.assertEqual(s['k1'], 'v1;still v1') + self.assertEqual(s['k2'], 'v2') + self.assertEqual(s['k3'], 'v3;#//still v3# and still v3') + + def test_main(): support.run_unittest( ConfigParserTestCase, @@ -1640,4 +1676,5 @@ ReadFileTestCase, CoverageOneHundredTestCase, ExceptionPicklingTestCase, + InlineCommentStrippingTestCase, ) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 19:51:07 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 7 Jul 2012 19:51:07 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Check-in_compiled_importli?= =?utf-8?q?b_changes_=28you_must_run_=22make=22_after_modifying_the?= Message-ID: <3WV0j74kQ2zN0G@mail.python.org> http://hg.python.org/cpython/rev/4e32c450f438 changeset: 77982:4e32c450f438 user: Antoine Pitrou date: Sat Jul 07 19:49:44 2012 +0200 summary: Check-in compiled importlib changes (you must run "make" after modifying the importlib sources). files: Python/importlib.h | 6888 +++++++++++++++---------------- 1 files changed, 3437 insertions(+), 3451 deletions(-) diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 7 20:31:33 2012 From: python-checkins at python.org (eric.araujo) Date: Sat, 7 Jul 2012 20:31:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Backed_out_changeset_4dc72bbf?= =?utf-8?q?9ed2_=28need_more_discussion_+_delegate=29?= Message-ID: <3WV1bn2JlNzNCy@mail.python.org> http://hg.python.org/peps/rev/136ef3de98d5 changeset: 4484:136ef3de98d5 user: ?ric Araujo date: Sat Jul 07 14:31:27 2012 -0400 summary: Backed out changeset 4dc72bbf9ed2 (need more discussion + delegate) files: pep-0345.txt | 36 +----------------------------------- 1 files changed, 1 insertions(+), 35 deletions(-) diff --git a/pep-0345.txt b/pep-0345.txt --- a/pep-0345.txt +++ b/pep-0345.txt @@ -26,7 +26,7 @@ Version 1.2 of the metadata format adds a number of optional fields designed to make third-party packaging of Python Software easier. These fields are "Requires-Python", "Requires-External", "Requires-Dist", -"Provides-Dist", "Provides-Extra", and "Obsoletes-Dist". This version also changes the +"Provides-Dist", and "Obsoletes-Dist". This version also changes the "Platform" field. Three new fields were also added: "Maintainer", "Maintainer-email" and "Project-URL". @@ -395,36 +395,6 @@ The label is a free text limited to 32 signs. -Provides-Extra (multiple use) -::::::::::::::::::::::::::::: - -A string containing the name of an optional feature. Must be a valid Python -identifier. May be used to make a dependency conditional on whether the -optional feature has been requested. - -Example:: - - Provides-Extra: pdf - Requires-Dist: reportlab; extra == 'pdf' - -A second distribution requires an optional dependency by placing it -inside square brackets, and can request multiple features by separating -them with a comma (,). The requirements are evaluated for each requested -feature and added to the set of requirements for the distribution. - -Example:: - - Requires-Dist: beaglevote[pdf] - Requires-Dist: libexample[test, doc] - -Two feature names `test` and `doc` are reserved to mark dependencies that -are needed for running automated tests and generating documentation, -respectively. - -It is legal to specify `Provides-Extra:` without referencing it in any -`Requires-Dist:`. - - Version Specifiers ================== @@ -463,8 +433,6 @@ - ``Requires-Dist: zope.interface (3.1)``: any version that starts with 3.1, excluding post or pre-releases. -- ``Requires-Dist: zope.interface (==3.1)``: equivalent to ``Requires-Dist: - zope.interface (3.1)``. - ``Requires-Dist: zope.interface (3.1.0)``: any version that starts with 3.1.0, excluding post or pre-releases. Since that particular project doesn't use more than 3 digits, it also means "only the 3.1.0 release". @@ -517,7 +485,6 @@ - platform.machine = platform.machine() - platform.python_implementation = platform.python_implementation() - a free string, like ``'2.4'``, or ``'win32'`` -- extra = (name of requested feature) Notice that ``in`` is restricted to strings, meaning that it is not possible to use other sequences like tuples or lists on the right side. @@ -551,7 +518,6 @@ - Requires-External - Requires-Dist - Provides-Dist - - Provides-Extra - Obsoletes-Dist - Project-URL -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat Jul 7 23:29:08 2012 From: python-checkins at python.org (senthil.kumaran) Date: Sat, 7 Jul 2012 23:29:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_5931_-_Python_runtime_?= =?utf-8?q?hardcoded_in_wsgiref=2Esimple=5Fserver_-_Now_it_specifies?= Message-ID: <3WV5Xh3VfXzNcF@mail.python.org> http://hg.python.org/cpython/rev/34e705fa4da4 changeset: 77983:34e705fa4da4 user: Senthil Kumaran date: Sat Jul 07 14:29:58 2012 -0700 summary: Fix 5931 - Python runtime hardcoded in wsgiref.simple_server - Now it specifies an implementation specific term. files: Doc/library/wsgiref.rst | 5 +++++ Lib/test/test_wsgiref.py | 10 ++++++++-- Lib/wsgiref/simple_server.py | 3 ++- Misc/NEWS | 3 +++ 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/Doc/library/wsgiref.rst b/Doc/library/wsgiref.rst --- a/Doc/library/wsgiref.rst +++ b/Doc/library/wsgiref.rst @@ -609,6 +609,11 @@ as :class:`BaseCGIHandler` and :class:`CGIHandler`) that are not HTTP origin servers. + .. versionchanged:: 3.3 + + The term "Python" is replaced with implementation specific term like + "CPython", "Jython" etc. + .. method:: BaseHandler.get_scheme() diff --git a/Lib/test/test_wsgiref.py b/Lib/test/test_wsgiref.py --- a/Lib/test/test_wsgiref.py +++ b/Lib/test/test_wsgiref.py @@ -9,6 +9,8 @@ from wsgiref.simple_server import make_server from io import StringIO, BytesIO, BufferedReader from socketserver import BaseServer +from platform import python_implementation + import os import re import sys @@ -129,9 +131,11 @@ class IntegrationTests(TestCase): def check_hello(self, out, has_length=True): + pyver = (python_implementation() + "/" + + sys.version.split()[0]) self.assertEqual(out, ("HTTP/1.0 200 OK\r\n" - "Server: WSGIServer/0.2 Python/"+sys.version.split()[0]+"\r\n" + "Server: WSGIServer/0.2 " + pyver +"\r\n" "Content-Type: text/plain\r\n" "Date: Mon, 05 Jun 2006 18:49:54 GMT\r\n" + (has_length and "Content-Length: 13\r\n" or "") + @@ -185,9 +189,11 @@ out, err = run_amock(validator(app)) self.assertTrue(err.endswith('"GET / HTTP/1.0" 200 4\n')) ver = sys.version.split()[0].encode('ascii') + py = python_implementation().encode('ascii') + pyver = py + b"/" + ver self.assertEqual( b"HTTP/1.0 200 OK\r\n" - b"Server: WSGIServer/0.2 Python/" + ver + b"\r\n" + b"Server: WSGIServer/0.2 "+ pyver + b"\r\n" b"Content-Type: text/plain; charset=utf-8\r\n" b"Date: Wed, 24 Dec 2008 13:29:32 GMT\r\n" b"\r\n" diff --git a/Lib/wsgiref/simple_server.py b/Lib/wsgiref/simple_server.py --- a/Lib/wsgiref/simple_server.py +++ b/Lib/wsgiref/simple_server.py @@ -14,13 +14,14 @@ import sys import urllib.parse from wsgiref.handlers import SimpleHandler +from platform import python_implementation __version__ = "0.2" __all__ = ['WSGIServer', 'WSGIRequestHandler', 'demo_app', 'make_server'] server_version = "WSGIServer/" + __version__ -sys_version = "Python/" + sys.version.split()[0] +sys_version = python_implementation() + "/" + sys.version.split()[0] software_version = server_version + ' ' + sys_version diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -23,6 +23,9 @@ Library ------- +- Issue #5931: wsgiref environ variable SERVER_SOFTWARE will specify an + implementation specific term like Cpython, Jython instead of generic "Python" + - Issue #13248: Remove obsolete argument "max_buffer_size" of BufferedWriter and BufferedRWPair, from the io module. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 02:15:04 2012 From: python-checkins at python.org (senthil.kumaran) Date: Sun, 8 Jul 2012 02:15:04 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_Fix_issue14826?= =?utf-8?q?_-_make_urllib=2Erequest=2ERequest_quoted_url_consistent_with?= Message-ID: <3WV9D85ygYzNdL@mail.python.org> http://hg.python.org/cpython/rev/01c8d800efd2 changeset: 77984:01c8d800efd2 branch: 3.2 parent: 77961:5020afc0b7c9 user: Senthil Kumaran date: Sat Jul 07 17:11:44 2012 -0700 summary: Fix issue14826 - make urllib.request.Request quoted url consistent with URLOpener open method. Patch contributed by Stephen Thorne. files: Lib/test/test_urllib.py | 5 +++++ Lib/urllib/request.py | 3 ++- Misc/NEWS | 5 +++++ 3 files changed, 12 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -1246,6 +1246,11 @@ # ftp.close() + def test_quote_url(self): + Request = urllib.request.Request + request = Request("http://www.python.org/foo bar") + self.assertEqual(request.full_url, "http://www.python.org/foo%20bar") + def test_main(): support.run_unittest( diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -180,7 +180,8 @@ def __init__(self, url, data=None, headers={}, origin_req_host=None, unverifiable=False): # unwrap('') --> 'type://host/path' - self.full_url = unwrap(url) + self.full_url = unwrap(to_bytes(url)) + self.full_url = quote(self.full_url, safe="%/:=&?~#+!$,;'@()*[]|") self.full_url, self.fragment = splittag(self.full_url) self.data = data self.headers = {} diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -87,6 +87,11 @@ Library ------- +- Issue #14826: Quote urls in urllib.request.Request identically to how they + are quoted by urllib.request.URLopener. Allows urls to spaces in them to work + transparently with urllib.request.urlopen(...). Patch contributed by Stephen + Thorne. + - Issue #14990: Correctly fail with SyntaxError on invalid encoding declaration. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 02:15:06 2012 From: python-checkins at python.org (senthil.kumaran) Date: Sun, 8 Jul 2012 02:15:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Fix_issue14826_-_make_urllib=2Erequest=2ERequest_quoted_?= =?utf-8?q?url_consistent_with?= Message-ID: <3WV9DB2phYzNdL@mail.python.org> http://hg.python.org/cpython/rev/e6bb919b2623 changeset: 77985:e6bb919b2623 parent: 77983:34e705fa4da4 parent: 77984:01c8d800efd2 user: Senthil Kumaran date: Sat Jul 07 17:15:52 2012 -0700 summary: Fix issue14826 - make urllib.request.Request quoted url consistent with URLOpener open method. Patch contributed by Stephen Thorne. files: Lib/test/test_urllib.py | 5 +++++ Lib/urllib/request.py | 3 ++- Misc/NEWS | 5 +++++ 3 files changed, 12 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -1272,6 +1272,11 @@ request.method = 'HEAD' self.assertEqual(request.get_method(), 'HEAD') + def test_quote_url(self): + Request = urllib.request.Request + request = Request("http://www.python.org/foo bar") + self.assertEqual(request.full_url, "http://www.python.org/foo%20bar") + def test_main(): support.run_unittest( diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -263,7 +263,8 @@ origin_req_host=None, unverifiable=False, method=None): # unwrap('') --> 'type://host/path' - self.full_url = unwrap(url) + self.full_url = unwrap(to_bytes(url)) + self.full_url = quote(self.full_url, safe="%/:=&?~#+!$,;'@()*[]|") self.full_url, self.fragment = splittag(self.full_url) self.data = data self.headers = {} diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -23,6 +23,11 @@ Library ------- +- Issue #14826: Quote urls in urllib.request.Request identically to how they + are quoted by urllib.request.URLopener. Allows urls to spaces in them to work + transparently with urllib.request.urlopen(...). Patch contributed by Stephen + Thorne. + - Issue #5931: wsgiref environ variable SERVER_SOFTWARE will specify an implementation specific term like Cpython, Jython instead of generic "Python" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 02:37:14 2012 From: python-checkins at python.org (senthil.kumaran) Date: Sun, 8 Jul 2012 02:37:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fix_issue14826?= =?utf-8?q?_-_make_urllib=2Erequest=2ERequest_quoted_url_consistent_with?= Message-ID: <3WV9jk4g6rzNfP@mail.python.org> http://hg.python.org/cpython/rev/d931a3b64fd6 changeset: 77986:d931a3b64fd6 branch: 2.7 parent: 77957:b90968d584c3 user: Senthil Kumaran date: Sat Jul 07 17:37:53 2012 -0700 summary: Fix issue14826 - make urllib.request.Request quoted url consistent with URLOpener open method. Patch contributed by Stephen Thorne. files: Lib/test/test_urllib2.py | 6 ++++++ Lib/urllib2.py | 5 +++-- Misc/NEWS | 5 +++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -1325,6 +1325,12 @@ req = Request("") self.assertEqual("www.python.org", req.get_host()) + def test_quoted_full_url(self): + Request = urllib2.Request + request = Request('http://www.python.org/foo bar') + self.assertEqual(request.get_full_url(), + 'http://www.python.org/foo%20bar') + def test_url_fragment(self): req = Request("http://www.python.org/?qs=query#fragment=true") self.assertEqual("/?qs=query", req.get_selector()) diff --git a/Lib/urllib2.py b/Lib/urllib2.py --- a/Lib/urllib2.py +++ b/Lib/urllib2.py @@ -110,7 +110,7 @@ from StringIO import StringIO from urllib import (unwrap, unquote, splittype, splithost, quote, - addinfourl, splitport, splittag, + addinfourl, splitport, splittag, toBytes, splitattr, ftpwrapper, splituser, splitpasswd, splitvalue) # support for FileHandler, proxies via environment variables @@ -196,7 +196,8 @@ def __init__(self, url, data=None, headers={}, origin_req_host=None, unverifiable=False): # unwrap('') --> 'type://host/path' - self.__original = unwrap(url) + self.__original = unwrap(toBytes(url)) + self.__original = quote(self.__original, safe="%/:=&?~#+!$,;'@()*[]|") self.__original, self.__fragment = splittag(self.__original) self.type = None # self.__r_type is what's left after doing the splittype diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -84,6 +84,11 @@ Library ------- +- Issue #14826: Quote urls in urllib2.Request identically to how they + are quoted by urllib.URLopener. Allows urls to spaces in them to work + transparently with urllib.request.urlopen(...). Patch contributed by Stephen + Thorne. + - Issue #15247: FileIO now raises an error when given a file descriptor pointing to a directory. -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sun Jul 8 06:00:07 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 08 Jul 2012 06:00:07 +0200 Subject: [Python-checkins] Daily reference leaks (e6bb919b2623): sum=1 Message-ID: results for e6bb919b2623 on branch "default" -------------------------------------------- test_exceptions leaked [0, 0, -1] references, sum=-1 test_dbm leaked [0, 0, 2] references, sum=2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogqgeyEd', '-x'] From python-checkins at python.org Sun Jul 8 09:36:35 2012 From: python-checkins at python.org (nick.coghlan) Date: Sun, 8 Jul 2012 09:36:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_14814=3A_Further_err?= =?utf-8?q?or_case_testing_coverage_and_cleanups?= Message-ID: <3WVM1b6dflzNgK@mail.python.org> http://hg.python.org/cpython/rev/18c1d4d60bdf changeset: 77987:18c1d4d60bdf parent: 77985:e6bb919b2623 user: Nick Coghlan date: Sun Jul 08 17:11:04 2012 +1000 summary: Issue 14814: Further error case testing coverage and cleanups files: Lib/ipaddress.py | 51 ++++---- Lib/test/test_ipaddress.py | 140 +++++++++++------------- 2 files changed, 93 insertions(+), 98 deletions(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -163,6 +163,7 @@ raise AddressValueError("Only one '/' permitted in %r" % address) return addr + def _find_address_range(addresses): """Find a sequence of IPv#Address. @@ -408,6 +409,8 @@ class _TotalOrderingMixin: # Helper that derives the other comparison operations from # __lt__ and __eq__ + # We avoid functools.total_ordering because it doesn't handle + # NotImplemented correctly yet (http://bugs.python.org/issue10042) def __eq__(self, other): raise NotImplementedError def __ne__(self, other): @@ -455,6 +458,22 @@ msg = '%200s has no version specified' % (type(self),) raise NotImplementedError(msg) + def _check_int_address(self, address): + if address < 0: + msg = "%d (< 0) is not permitted as an IPv%d address" + raise AddressValueError(msg % (address, self._version)) + if address > self._ALL_ONES: + msg = "%d (>= 2**%d) is not permitted as an IPv%d address" + raise AddressValueError(msg % (address, self._max_prefixlen, + self._version)) + + def _check_packed_address(self, address, expected_len): + address_len = len(address) + if address_len != expected_len: + msg = "%r (len %d != %d) is not permitted as an IPv%d address" + raise AddressValueError(msg % (address, address_len, + expected_len, self._version)) + def _ip_int_from_prefix(self, prefixlen=None): """Turn the prefix length netmask into a int for comparison. @@ -1215,16 +1234,13 @@ # Efficient constructor from integer. if isinstance(address, int): + self._check_int_address(address) self._ip = address - if address < 0 or address > self._ALL_ONES: - raise AddressValueError(address) return # Constructing from a packed address if isinstance(address, bytes): - if len(address) != 4: - msg = "Packed address %r must be exactly 4 bytes" - raise AddressValueError(msg % address) + self._check_packed_address(address, 4) self._ip = struct.unpack('!I', address)[0] return @@ -1368,11 +1384,7 @@ # Constructing from a packed address if isinstance(address, bytes): - if len(address) != 4: - msg = "Packed address %r must be exactly 4 bytes" - raise AddressValueError(msg % address) - self.network_address = IPv4Address( - struct.unpack('!I', address)[0]) + self.network_address = IPv4Address(address) self._prefixlen = self._max_prefixlen self.netmask = IPv4Address(self._ALL_ONES) #fixme: address/network test here @@ -1380,11 +1392,9 @@ # Efficient constructor from integer. if isinstance(address, int): + self.network_address = IPv4Address(address) self._prefixlen = self._max_prefixlen self.netmask = IPv4Address(self._ALL_ONES) - if address < 0 or address > self._ALL_ONES: - raise AddressValueError(address) - self.network_address = IPv4Address(address) #fixme: address/network test here. return @@ -1868,16 +1878,13 @@ # Efficient constructor from integer. if isinstance(address, int): + self._check_int_address(address) self._ip = address - if address < 0 or address > self._ALL_ONES: - raise AddressValueError(address) return # Constructing from a packed address if isinstance(address, bytes): - if len(address) != 16: - msg = "Packed address %r must be exactly 16 bytes" - raise AddressValueError(msg % address) + self._check_packed_address(address, 16) tmp = struct.unpack('!QQ', address) self._ip = (tmp[0] << 64) | tmp[1] return @@ -2014,8 +2021,6 @@ # Efficient constructor from integer. if isinstance(address, int): - if address < 0 or address > self._ALL_ONES: - raise AddressValueError(address) self.network_address = IPv6Address(address) self._prefixlen = self._max_prefixlen self.netmask = IPv6Address(self._ALL_ONES) @@ -2023,11 +2028,7 @@ # Constructing from a packed address if isinstance(address, bytes): - if len(address) != 16: - msg = "Packed address %r must be exactly 16 bytes" - raise AddressValueError(msg % address) - tmp = struct.unpack('!QQ', address) - self.network_address = IPv6Address((tmp[0] << 64) | tmp[1]) + self.network_address = IPv6Address(address) self._prefixlen = self._max_prefixlen self.netmask = IPv6Address(self._ALL_ONES) return diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -23,6 +23,10 @@ # address parts) that don't have an obvious home in the main test # suite + @property + def factory(self): + raise NotImplementedError + @contextlib.contextmanager def assertCleanError(self, exc_type, details, *args): """ @@ -49,11 +53,64 @@ return self.assertCleanError(ipaddress.NetmaskValueError, details, *args) -class AddressErrors_v4(ErrorReporting): +class CommonErrorsMixin: def test_empty_address(self): with self.assertAddressError("Address cannot be empty"): - ipaddress.IPv4Address("") + self.factory("") + + def test_floats_rejected(self): + with self.assertAddressError(re.escape(repr("1.0"))): + self.factory(1.0) + +class CommonErrorsMixin_v4(CommonErrorsMixin): + + def test_negative_ints_rejected(self): + msg = "-1 (< 0) is not permitted as an IPv4 address" + with self.assertAddressError(re.escape(msg)): + self.factory(-1) + + def test_large_ints_rejected(self): + msg = "%d (>= 2**32) is not permitted as an IPv4 address" + with self.assertAddressError(re.escape(msg % 2**32)): + self.factory(2**32) + + def test_bad_packed_length(self): + def assertBadLength(length): + addr = b'\x00' * length + msg = "%r (len %d != 4) is not permitted as an IPv4 address" + with self.assertAddressError(re.escape(msg % (addr, length))): + self.factory(addr) + + assertBadLength(3) + assertBadLength(5) + +class CommonErrorsMixin_v6(CommonErrorsMixin): + + def test_negative_ints_rejected(self): + msg = "-1 (< 0) is not permitted as an IPv6 address" + with self.assertAddressError(re.escape(msg)): + self.factory(-1) + + def test_large_ints_rejected(self): + msg = "%d (>= 2**128) is not permitted as an IPv6 address" + with self.assertAddressError(re.escape(msg % 2**128)): + self.factory(2**128) + + def test_bad_packed_length(self): + def assertBadLength(length): + addr = b'\x00' * length + msg = "%r (len %d != 16) is not permitted as an IPv6 address" + with self.assertAddressError(re.escape(msg % (addr, length))): + self.factory(addr) + self.factory(addr) + + assertBadLength(15) + assertBadLength(17) + + +class AddressErrors_v4(ErrorReporting, CommonErrorsMixin_v4): + factory = ipaddress.IPv4Address def test_network_passed_as_address(self): addr = "127.0.0.1/24" @@ -133,22 +190,9 @@ assertBadOctet("12345.67899.-54321.-98765", 12345) assertBadOctet("257.0.0.0", 257) - def test_bad_packed_length(self): - def assertBadLength(length): - addr = b'\x00' * length - msg = "Packed address %r must be exactly 4 bytes" % addr - with self.assertAddressError(re.escape(msg)): - ipaddress.IPv4Address(addr) - assertBadLength(3) - assertBadLength(5) - - -class AddressErrors_v6(ErrorReporting): - - def test_empty_address(self): - with self.assertAddressError("Address cannot be empty"): - ipaddress.IPv6Address("") +class AddressErrors_v6(ErrorReporting, CommonErrorsMixin_v6): + factory = ipaddress.IPv6Address def test_network_passed_as_address(self): addr = "::1/24" @@ -277,24 +321,10 @@ assertBadPart("02001:db8::", "02001") assertBadPart('2001:888888::1', "888888") - def test_bad_packed_length(self): - def assertBadLength(length): - addr = b'\x00' * length - msg = "Packed address %r must be exactly 16 bytes" % addr - with self.assertAddressError(re.escape(msg)): - ipaddress.IPv6Address(addr) - assertBadLength(15) - assertBadLength(17) - - -class NetmaskErrorsMixin_v4: +class NetmaskErrorsMixin_v4(CommonErrorsMixin_v4): """Input validation on interfaces and networks is very similar""" - @property - def factory(self): - raise NotImplementedError - def test_split_netmask(self): addr = "1.2.3.4/32/24" with self.assertAddressError("Only one '/' permitted in %r" % addr): @@ -305,7 +335,8 @@ with self.assertAddressError(details): self.factory(addr) - assertBadAddress("", "Address cannot be empty") + assertBadAddress("/", "Address cannot be empty") + assertBadAddress("/8", "Address cannot be empty") assertBadAddress("bogus", "Expected 4 octets") assertBadAddress("google.com", "Expected 4 octets") assertBadAddress("10/8", "Expected 4 octets") @@ -325,17 +356,6 @@ assertBadNetmask("1.1.1.1", "1.a.2.3") assertBadNetmask("1.1.1.1", "pudding") - def test_bad_packed_length(self): - def assertBadLength(length): - addr = b'\x00' * length - msg = "Packed address %r must be exactly 4 bytes" % addr - with self.assertAddressError(re.escape(msg)): - self.factory(addr) - - assertBadLength(3) - assertBadLength(5) - - class InterfaceErrors_v4(ErrorReporting, NetmaskErrorsMixin_v4): factory = ipaddress.IPv4Interface @@ -343,13 +363,9 @@ factory = ipaddress.IPv4Network -class NetmaskErrorsMixin_v6: +class NetmaskErrorsMixin_v6(CommonErrorsMixin_v6): """Input validation on interfaces and networks is very similar""" - @property - def factory(self): - raise NotImplementedError - def test_split_netmask(self): addr = "cafe:cafe::/128/190" with self.assertAddressError("Only one '/' permitted in %r" % addr): @@ -360,7 +376,8 @@ with self.assertAddressError(details): self.factory(addr) - assertBadAddress("", "Address cannot be empty") + assertBadAddress("/", "Address cannot be empty") + assertBadAddress("/8", "Address cannot be empty") assertBadAddress("google.com", "At least 3 parts") assertBadAddress("1.2.3.4", "At least 3 parts") assertBadAddress("10/8", "At least 3 parts") @@ -378,17 +395,6 @@ assertBadNetmask("::1", "129") assertBadNetmask("::1", "pudding") - def test_bad_packed_length(self): - def assertBadLength(length): - addr = b'\x00' * length - msg = "Packed address %r must be exactly 16 bytes" % addr - with self.assertAddressError(re.escape(msg)): - self.factory(addr) - - assertBadLength(15) - assertBadLength(17) - - class InterfaceErrors_v6(ErrorReporting, NetmaskErrorsMixin_v6): factory = ipaddress.IPv6Interface @@ -585,10 +591,6 @@ def testIpFromInt(self): self.assertEqual(self.ipv4_interface._ip, ipaddress.IPv4Interface(16909060)._ip) - self.assertRaises(ipaddress.AddressValueError, - ipaddress.IPv4Interface, 2**32) - self.assertRaises(ipaddress.AddressValueError, - ipaddress.IPv4Interface, -1) ipv4 = ipaddress.ip_network('1.2.3.4') ipv6 = ipaddress.ip_network('2001:658:22a:cafe:200:0:0:1') @@ -598,14 +600,6 @@ v6_int = 42540616829182469433547762482097946625 self.assertEqual(self.ipv6_interface._ip, ipaddress.IPv6Interface(v6_int)._ip) - self.assertRaises(ipaddress.AddressValueError, - ipaddress.IPv6Interface, 2**128) - self.assertRaises(ipaddress.AddressValueError, - ipaddress.IPv6Interface, -1) - self.assertRaises(ipaddress.AddressValueError, - ipaddress.IPv6Network, 2**128) - self.assertRaises(ipaddress.AddressValueError, - ipaddress.IPv6Network, -1) self.assertEqual(ipaddress.ip_network(self.ipv4_address._ip).version, 4) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 10:01:47 2012 From: python-checkins at python.org (ross.lagerwall) Date: Sun, 8 Jul 2012 10:01:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_=2315284=3A_Skip_=7Bsend?= =?utf-8?q?=2Crecv=7Dmsg_tests_with_disabled_IPv6?= Message-ID: <3WVMZg0FCtzNj8@mail.python.org> http://hg.python.org/cpython/rev/b71dc2e9e00d changeset: 77988:b71dc2e9e00d user: Ross Lagerwall date: Sun Jul 08 09:53:57 2012 +0200 summary: #15284: Skip {send,recv}msg tests with disabled IPv6 Patch by Brian Brazil. files: Lib/test/test_socket.py | 10 +++++----- Misc/NEWS | 3 +++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -3202,28 +3202,28 @@ pass @requireAttrs(socket.socket, "sendmsg") - at unittest.skipUnless(socket.has_ipv6, "Python not built with IPv6 support") + at unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.') @requireSocket("AF_INET6", "SOCK_DGRAM") @unittest.skipUnless(thread, 'Threading required for this test.') class SendmsgUDP6Test(SendmsgConnectionlessTests, SendrecvmsgUDP6TestBase): pass @requireAttrs(socket.socket, "recvmsg") - at unittest.skipUnless(socket.has_ipv6, "Python not built with IPv6 support") + at unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.') @requireSocket("AF_INET6", "SOCK_DGRAM") @unittest.skipUnless(thread, 'Threading required for this test.') class RecvmsgUDP6Test(RecvmsgTests, SendrecvmsgUDP6TestBase): pass @requireAttrs(socket.socket, "recvmsg_into") - at unittest.skipUnless(socket.has_ipv6, "Python not built with IPv6 support") + at unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.') @requireSocket("AF_INET6", "SOCK_DGRAM") @unittest.skipUnless(thread, 'Threading required for this test.') class RecvmsgIntoUDP6Test(RecvmsgIntoTests, SendrecvmsgUDP6TestBase): pass @requireAttrs(socket.socket, "recvmsg") - at unittest.skipUnless(socket.has_ipv6, "Python not built with IPv6 support") + at unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.') @requireAttrs(socket, "IPPROTO_IPV6") @requireSocket("AF_INET6", "SOCK_DGRAM") @unittest.skipUnless(thread, 'Threading required for this test.') @@ -3232,7 +3232,7 @@ pass @requireAttrs(socket.socket, "recvmsg_into") - at unittest.skipUnless(socket.has_ipv6, "Python not built with IPv6 support") + at unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.') @requireAttrs(socket, "IPPROTO_IPV6") @requireSocket("AF_INET6", "SOCK_DGRAM") @unittest.skipUnless(thread, 'Threading required for this test.') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -93,6 +93,9 @@ Tests ----- +- Issue #15284: Skip {send,recv}msg tests in test_socket when IPv6 is not + enabled. Patch by Brian Brazil. + - Issue #15277: Fix a resource leak in support.py when IPv6 is disabled. Patch by Brian Brazil. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 10:32:35 2012 From: python-checkins at python.org (senthil.kumaran) Date: Sun, 8 Jul 2012 10:32:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fix_the_buildb?= =?utf-8?q?ot_failure_-_msg164973?= Message-ID: <3WVNGC3DbxzNmR@mail.python.org> http://hg.python.org/cpython/rev/7fe270af83ca changeset: 77989:7fe270af83ca branch: 2.7 parent: 77986:d931a3b64fd6 user: Senthil Kumaran date: Sun Jul 08 01:14:53 2012 -0700 summary: Fix the buildbot failure - msg164973 files: Lib/urllib2.py | 2 +- Misc/NEWS | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Lib/urllib2.py b/Lib/urllib2.py --- a/Lib/urllib2.py +++ b/Lib/urllib2.py @@ -196,7 +196,7 @@ def __init__(self, url, data=None, headers={}, origin_req_host=None, unverifiable=False): # unwrap('') --> 'type://host/path' - self.__original = unwrap(toBytes(url)) + self.__original = unwrap(url) self.__original = quote(self.__original, safe="%/:=&?~#+!$,;'@()*[]|") self.__original, self.__fragment = splittag(self.__original) self.type = None diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -84,10 +84,9 @@ Library ------- -- Issue #14826: Quote urls in urllib2.Request identically to how they - are quoted by urllib.URLopener. Allows urls to spaces in them to work - transparently with urllib.request.urlopen(...). Patch contributed by Stephen - Thorne. +- Issue #14826: Quote urls in urllib2.Request similar to how they are quoted by + urllib.URLopener. Allows urls to spaces in them to work transparently with + urllib.request.urlopen(...). Patch contributed by Stephen Thorne. - Issue #15247: FileIO now raises an error when given a file descriptor pointing to a directory. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 10:32:37 2012 From: python-checkins at python.org (senthil.kumaran) Date: Sun, 8 Jul 2012 10:32:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_markup_for_versionchan?= =?utf-8?q?ged_sphinx_directive=2E?= Message-ID: <3WVNGF0JDczNmk@mail.python.org> http://hg.python.org/cpython/rev/3a47aa5b3285 changeset: 77990:3a47aa5b3285 parent: 77987:18c1d4d60bdf user: Senthil Kumaran date: Sun Jul 08 01:32:57 2012 -0700 summary: Fix markup for versionchanged sphinx directive. files: Doc/library/wsgiref.rst | 6 ++---- 1 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Doc/library/wsgiref.rst b/Doc/library/wsgiref.rst --- a/Doc/library/wsgiref.rst +++ b/Doc/library/wsgiref.rst @@ -610,10 +610,8 @@ servers. .. versionchanged:: 3.3 - - The term "Python" is replaced with implementation specific term like - "CPython", "Jython" etc. - + The term "Python" is replaced with implementation specific term like + "CPython", "Jython" etc. .. method:: BaseHandler.get_scheme() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 10:32:38 2012 From: python-checkins at python.org (senthil.kumaran) Date: Sun, 8 Jul 2012 10:32:38 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_merge_heads?= Message-ID: <3WVNGG3fhKzNnP@mail.python.org> http://hg.python.org/cpython/rev/163b6d6036ed changeset: 77991:163b6d6036ed parent: 77990:3a47aa5b3285 parent: 77988:b71dc2e9e00d user: Senthil Kumaran date: Sun Jul 08 01:33:19 2012 -0700 summary: merge heads files: Lib/test/test_socket.py | 10 +++++----- Misc/NEWS | 3 +++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -3202,28 +3202,28 @@ pass @requireAttrs(socket.socket, "sendmsg") - at unittest.skipUnless(socket.has_ipv6, "Python not built with IPv6 support") + at unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.') @requireSocket("AF_INET6", "SOCK_DGRAM") @unittest.skipUnless(thread, 'Threading required for this test.') class SendmsgUDP6Test(SendmsgConnectionlessTests, SendrecvmsgUDP6TestBase): pass @requireAttrs(socket.socket, "recvmsg") - at unittest.skipUnless(socket.has_ipv6, "Python not built with IPv6 support") + at unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.') @requireSocket("AF_INET6", "SOCK_DGRAM") @unittest.skipUnless(thread, 'Threading required for this test.') class RecvmsgUDP6Test(RecvmsgTests, SendrecvmsgUDP6TestBase): pass @requireAttrs(socket.socket, "recvmsg_into") - at unittest.skipUnless(socket.has_ipv6, "Python not built with IPv6 support") + at unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.') @requireSocket("AF_INET6", "SOCK_DGRAM") @unittest.skipUnless(thread, 'Threading required for this test.') class RecvmsgIntoUDP6Test(RecvmsgIntoTests, SendrecvmsgUDP6TestBase): pass @requireAttrs(socket.socket, "recvmsg") - at unittest.skipUnless(socket.has_ipv6, "Python not built with IPv6 support") + at unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.') @requireAttrs(socket, "IPPROTO_IPV6") @requireSocket("AF_INET6", "SOCK_DGRAM") @unittest.skipUnless(thread, 'Threading required for this test.') @@ -3232,7 +3232,7 @@ pass @requireAttrs(socket.socket, "recvmsg_into") - at unittest.skipUnless(socket.has_ipv6, "Python not built with IPv6 support") + at unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.') @requireAttrs(socket, "IPPROTO_IPV6") @requireSocket("AF_INET6", "SOCK_DGRAM") @unittest.skipUnless(thread, 'Threading required for this test.') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -93,6 +93,9 @@ Tests ----- +- Issue #15284: Skip {send,recv}msg tests in test_socket when IPv6 is not + enabled. Patch by Brian Brazil. + - Issue #15277: Fix a resource leak in support.py when IPv6 is disabled. Patch by Brian Brazil. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 11:22:20 2012 From: python-checkins at python.org (senthil.kumaran) Date: Sun, 8 Jul 2012 11:22:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_issue_14826_-_?= =?utf-8?q?Address_the_buildbot_failure_=28_explanation_msg164973=29?= Message-ID: <3WVPMc1nHPzNTS@mail.python.org> http://hg.python.org/cpython/rev/ee1828dc3bf6 changeset: 77992:ee1828dc3bf6 branch: 3.2 parent: 77984:01c8d800efd2 user: Senthil Kumaran date: Sun Jul 08 02:08:48 2012 -0700 summary: issue 14826 - Address the buildbot failure ( explanation msg164973) files: Lib/urllib/request.py | 2 +- Misc/NEWS | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -180,7 +180,7 @@ def __init__(self, url, data=None, headers={}, origin_req_host=None, unverifiable=False): # unwrap('') --> 'type://host/path' - self.full_url = unwrap(to_bytes(url)) + self.full_url = unwrap(url) self.full_url = quote(self.full_url, safe="%/:=&?~#+!$,;'@()*[]|") self.full_url, self.fragment = splittag(self.full_url) self.data = data diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -87,8 +87,8 @@ Library ------- -- Issue #14826: Quote urls in urllib.request.Request identically to how they - are quoted by urllib.request.URLopener. Allows urls to spaces in them to work +- Issue #14826: Quote urls in urllib.request.Request similar to how they are + quoted by urllib.request.URLopener. Allows urls to spaces in them to work transparently with urllib.request.urlopen(...). Patch contributed by Stephen Thorne. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 11:22:22 2012 From: python-checkins at python.org (senthil.kumaran) Date: Sun, 8 Jul 2012 11:22:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_issue_14826_-_Address_the_buildbot_failure_quote_of_url_?= =?utf-8?q?is_the_required_change?= Message-ID: <3WVPMf0FVWzNZ6@mail.python.org> http://hg.python.org/cpython/rev/dc30111a5d7e changeset: 77993:dc30111a5d7e parent: 77991:163b6d6036ed parent: 77992:ee1828dc3bf6 user: Senthil Kumaran date: Sun Jul 08 02:16:08 2012 -0700 summary: issue 14826 - Address the buildbot failure quote of url is the required change ( explanation msg164973) files: Lib/urllib/request.py | 2 +- Misc/NEWS | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -263,7 +263,7 @@ origin_req_host=None, unverifiable=False, method=None): # unwrap('') --> 'type://host/path' - self.full_url = unwrap(to_bytes(url)) + self.full_url = unwrap(url) self.full_url = quote(self.full_url, safe="%/:=&?~#+!$,;'@()*[]|") self.full_url, self.fragment = splittag(self.full_url) self.data = data diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -23,7 +23,7 @@ Library ------- -- Issue #14826: Quote urls in urllib.request.Request identically to how they +- Issue #14826: Quote urls in urllib.request.Request similar to how they are quoted by urllib.request.URLopener. Allows urls to spaces in them to work transparently with urllib.request.urlopen(...). Patch contributed by Stephen Thorne. @@ -173,7 +173,7 @@ - Issue #15176: Clarified behavior, documentation, and implementation of os.listdir(). - + - Issue #15061: Re-implemented hmac.compare_digest() in C to prevent further timing analysis and to support all buffer protocol aware objects as well as ASCII only str instances safely. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 11:22:23 2012 From: python-checkins at python.org (senthil.kumaran) Date: Sun, 8 Jul 2012 11:22:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_revert_the_cha?= =?utf-8?q?nges_done_in_d931a3b64fd6__-_buildbot_failure=2E?= Message-ID: <3WVPMg3HDRzNdV@mail.python.org> http://hg.python.org/cpython/rev/224b27a8d9be changeset: 77994:224b27a8d9be branch: 2.7 parent: 77986:d931a3b64fd6 user: Senthil Kumaran date: Sun Jul 08 02:20:27 2012 -0700 summary: revert the changes done in d931a3b64fd6 - buildbot failure. The fix for issue14826 might need to address toBytes and test_url_encoding in test_cookielib.py before it is brought back in. files: Lib/test/test_urllib2.py | 6 ------ Lib/urllib2.py | 3 +-- Misc/NEWS | 5 ----- 3 files changed, 1 insertions(+), 13 deletions(-) diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -1325,12 +1325,6 @@ req = Request("") self.assertEqual("www.python.org", req.get_host()) - def test_quoted_full_url(self): - Request = urllib2.Request - request = Request('http://www.python.org/foo bar') - self.assertEqual(request.get_full_url(), - 'http://www.python.org/foo%20bar') - def test_url_fragment(self): req = Request("http://www.python.org/?qs=query#fragment=true") self.assertEqual("/?qs=query", req.get_selector()) diff --git a/Lib/urllib2.py b/Lib/urllib2.py --- a/Lib/urllib2.py +++ b/Lib/urllib2.py @@ -196,8 +196,7 @@ def __init__(self, url, data=None, headers={}, origin_req_host=None, unverifiable=False): # unwrap('') --> 'type://host/path' - self.__original = unwrap(toBytes(url)) - self.__original = quote(self.__original, safe="%/:=&?~#+!$,;'@()*[]|") + self.__original = unwrap(url) self.__original, self.__fragment = splittag(self.__original) self.type = None # self.__r_type is what's left after doing the splittype diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -84,11 +84,6 @@ Library ------- -- Issue #14826: Quote urls in urllib2.Request identically to how they - are quoted by urllib.URLopener. Allows urls to spaces in them to work - transparently with urllib.request.urlopen(...). Patch contributed by Stephen - Thorne. - - Issue #15247: FileIO now raises an error when given a file descriptor pointing to a directory. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 11:22:24 2012 From: python-checkins at python.org (senthil.kumaran) Date: Sun, 8 Jul 2012 11:22:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMi43IC0+IDIuNyk6?= =?utf-8?q?_merge_heads=2E?= Message-ID: <3WVPMh6C5czNkm@mail.python.org> http://hg.python.org/cpython/rev/45cd2d816f4d changeset: 77995:45cd2d816f4d branch: 2.7 parent: 77994:224b27a8d9be parent: 77989:7fe270af83ca user: Senthil Kumaran date: Sun Jul 08 02:22:44 2012 -0700 summary: merge heads. files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 12:02:54 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 8 Jul 2012 12:02:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315110=3A_Fix_the_?= =?utf-8?q?tracebacks_generated_by_=22import_xxx=22_to_not_show_the?= Message-ID: <3WVQGQ4CX9zNsx@mail.python.org> http://hg.python.org/cpython/rev/8c877ad00bc4 changeset: 77996:8c877ad00bc4 parent: 77993:dc30111a5d7e user: Antoine Pitrou date: Sun Jul 08 12:01:27 2012 +0200 summary: Issue #15110: Fix the tracebacks generated by "import xxx" to not show the importlib stack frames. files: Lib/importlib/_bootstrap.py | 25 +- Lib/test/test_import.py | 93 + Misc/NEWS | 3 + Python/import.c | 66 + Python/importlib.h | 5051 +++++++++++----------- 5 files changed, 2748 insertions(+), 2490 deletions(-) diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -541,7 +541,7 @@ """Load a frozen module.""" is_reload = fullname in sys.modules try: - m = _imp.init_frozen(fullname) + m = cls._exec_module(fullname) # Let our own module_repr() method produce a suitable repr. del m.__file__ return m @@ -568,6 +568,13 @@ """Return if the frozen module is a package.""" return _imp.is_frozen_package(fullname) + @classmethod + def _exec_module(cls, fullname): + """Helper for load_module, allowing to isolate easily (when + looking at a traceback) whether an error comes from executing + an imported module's code.""" + return _imp.init_frozen(fullname) + class _LoaderBasics: @@ -644,9 +651,15 @@ else: module.__package__ = module.__package__.rpartition('.')[0] module.__loader__ = self - exec(code_object, module.__dict__) + self._exec_module(code_object, module.__dict__) return module + def _exec_module(self, code_object, module_dict): + """Helper for _load_module, allowing to isolate easily (when + looking at a traceback) whether an error comes from executing + an imported module's code.""" + exec(code_object, module_dict) + class SourceLoader(_LoaderBasics): @@ -869,7 +882,7 @@ """Load an extension module.""" is_reload = fullname in sys.modules try: - module = _imp.load_dynamic(fullname, self.path) + module = self._exec_module(fullname, self.path) _verbose_message('extension module loaded from {!r}', self.path) return module except: @@ -889,6 +902,12 @@ """Return None as extension modules have no source code.""" return None + def _exec_module(self, fullname, path): + """Helper for load_module, allowing to isolate easily (when + looking at a traceback) whether an error comes from executing + an imported module's code.""" + return _imp.load_dynamic(fullname, path) + class _NamespacePath: """Represents a namespace package's path. It uses the module name diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -768,6 +768,98 @@ self.assertTrue(mod.__file__.endswith('_bootstrap.py'), mod.__file__) +class ImportTracebackTests(unittest.TestCase): + + def setUp(self): + os.mkdir(TESTFN) + self.old_path = sys.path[:] + sys.path.insert(0, TESTFN) + + def tearDown(self): + sys.path[:] = self.old_path + rmtree(TESTFN) + + def create_module(self, mod, contents): + with open(os.path.join(TESTFN, mod + ".py"), "w") as f: + f.write(contents) + self.addCleanup(unload, mod) + importlib.invalidate_caches() + + def assert_traceback(self, tb, files): + deduped_files = [] + while tb: + code = tb.tb_frame.f_code + fn = code.co_filename + if not deduped_files or fn != deduped_files[-1]: + deduped_files.append(fn) + tb = tb.tb_next + self.assertEqual(len(deduped_files), len(files), deduped_files) + for fn, pat in zip(deduped_files, files): + self.assertRegex(fn, pat) + + def test_nonexistent_module(self): + try: + # assertRaises() clears __traceback__ + import nonexistent_xyzzy + except ImportError as e: + tb = e.__traceback__ + else: + self.fail("ImportError should have been raised") + self.assert_traceback(tb, [__file__]) + + def test_nonexistent_module_nested(self): + self.create_module("foo", "import nonexistent_xyzzy") + try: + import foo + except ImportError as e: + tb = e.__traceback__ + else: + self.fail("ImportError should have been raised") + self.assert_traceback(tb, [__file__, 'foo.py']) + + def test_exec_failure(self): + self.create_module("foo", "1/0") + try: + import foo + except ZeroDivisionError as e: + tb = e.__traceback__ + else: + self.fail("ZeroDivisionError should have been raised") + self.assert_traceback(tb, [__file__, 'foo.py']) + + def test_exec_failure_nested(self): + self.create_module("foo", "import bar") + self.create_module("bar", "1/0") + try: + import foo + except ZeroDivisionError as e: + tb = e.__traceback__ + else: + self.fail("ZeroDivisionError should have been raised") + self.assert_traceback(tb, [__file__, 'foo.py', 'bar.py']) + + @cpython_only + def test_import_bug(self): + # We simulate a bug in importlib and check that it's not stripped + # away from the traceback. + self.create_module("foo", "") + importlib = sys.modules['_frozen_importlib'] + old_load_module = importlib.SourceLoader.load_module + try: + def load_module(*args): + 1/0 + importlib.SourceLoader.load_module = load_module + try: + import foo + except ZeroDivisionError as e: + tb = e.__traceback__ + else: + self.fail("ZeroDivisionError should have been raised") + self.assert_traceback(tb, [__file__, 'tb_next; + PyFrameObject *frame = traceback->tb_frame; + PyCodeObject *code = frame->f_code; + int now_in_importlib; + + assert(PyTraceBack_Check(tb)); + now_in_importlib = (PyUnicode_CompareWithASCIIString( + code->co_filename, + importlib_filename) == 0); + if (now_in_importlib && !in_importlib) { + /* This is the link to this chunk of importlib tracebacks */ + outer_link = prev_link; + } + in_importlib = now_in_importlib; + + if (in_importlib && + (always_trim || + PyUnicode_CompareWithASCIIString(code->co_name, + exec_funcname) == 0)) { + PyObject *tmp = *outer_link; + *outer_link = next; + Py_XINCREF(next); + Py_DECREF(tmp); + prev_link = outer_link; + } + else { + prev_link = (PyObject **) &traceback->tb_next; + } + tb = next; + } +done: + PyErr_Restore(exception, value, base_tb); +} + + PyObject * PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals, PyObject *locals, PyObject *given_fromlist, @@ -1693,6 +1757,8 @@ Py_XDECREF(package); Py_XDECREF(globals); Py_XDECREF(fromlist); + if (final_mod == NULL) + remove_importlib_frames(); return final_mod; } diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 12:08:59 2012 From: python-checkins at python.org (florent.xicluna) Date: Sun, 8 Jul 2012 12:08:59 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2311022_and_=231528?= =?utf-8?q?7=3A_correctly_remove_the_TESTFN_file_in_test=5Fbuiltin=2E?= Message-ID: <3WVQPR4QZhzNZ9@mail.python.org> http://hg.python.org/cpython/rev/6651c932d014 changeset: 77997:6651c932d014 user: Florent Xicluna date: Sun Jul 08 12:08:45 2012 +0200 summary: Issue #11022 and #15287: correctly remove the TESTFN file in test_builtin. files: Lib/test/test_builtin.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -960,7 +960,7 @@ self.assertEqual(fp.read(1000), 'YYY'*100) finally: fp.close() - unlink(TESTFN) + unlink(TESTFN) def test_open_default_encoding(self): old_environ = dict(os.environ) @@ -979,6 +979,7 @@ self.assertEqual(fp.encoding, current_locale_encoding) finally: fp.close() + unlink(TESTFN) finally: os.environ.clear() os.environ.update(old_environ) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 12:45:25 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 8 Jul 2012 12:45:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315291=3A_Fix_a_me?= =?utf-8?q?mory_leak_where_AST_nodes_where_not_properly_deallocated=2E?= Message-ID: <3WVRCT1PqWzNhK@mail.python.org> http://hg.python.org/cpython/rev/048d8d9aecf1 changeset: 77998:048d8d9aecf1 parent: 77996:8c877ad00bc4 user: Antoine Pitrou date: Sun Jul 08 12:43:32 2012 +0200 summary: Issue #15291: Fix a memory leak where AST nodes where not properly deallocated. files: Misc/NEWS | 3 +++ Parser/asdl_c.py | 1 + Python/Python-ast.c | 1 + 3 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #15291: Fix a memory leak where AST nodes where not properly + deallocated. + - Issue #15110: Fix the tracebacks generated by "import xxx" to not show the importlib stack frames. diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -612,6 +612,7 @@ ast_dealloc(AST_object *self) { Py_CLEAR(self->dict); + Py_TYPE(self)->tp_free(self); } static int diff --git a/Python/Python-ast.c b/Python/Python-ast.c --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -464,6 +464,7 @@ ast_dealloc(AST_object *self) { Py_CLEAR(self->dict); + Py_TYPE(self)->tp_free(self); } static int -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 12:45:26 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 8 Jul 2012 12:45:26 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge?= Message-ID: <3WVRCV60fszNpg@mail.python.org> http://hg.python.org/cpython/rev/1a04f0b043be changeset: 77999:1a04f0b043be parent: 77998:048d8d9aecf1 parent: 77997:6651c932d014 user: Antoine Pitrou date: Sun Jul 08 12:43:59 2012 +0200 summary: Merge files: Lib/test/test_builtin.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -960,7 +960,7 @@ self.assertEqual(fp.read(1000), 'YYY'*100) finally: fp.close() - unlink(TESTFN) + unlink(TESTFN) def test_open_default_encoding(self): old_environ = dict(os.environ) @@ -979,6 +979,7 @@ self.assertEqual(fp.encoding, current_locale_encoding) finally: fp.close() + unlink(TESTFN) finally: os.environ.clear() os.environ.update(old_environ) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 13:18:26 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 8 Jul 2012 13:18:26 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_test_failure_under_Win?= =?utf-8?q?dows?= Message-ID: <3WVRxZ0NzDzNcW@mail.python.org> http://hg.python.org/cpython/rev/740c2d5ecd04 changeset: 78000:740c2d5ecd04 user: Antoine Pitrou date: Sun Jul 08 13:16:15 2012 +0200 summary: Fix test failure under Windows files: Lib/test/test_import.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -795,7 +795,7 @@ tb = tb.tb_next self.assertEqual(len(deduped_files), len(files), deduped_files) for fn, pat in zip(deduped_files, files): - self.assertRegex(fn, pat) + self.assertIn(pat, fn) def test_nonexistent_module(self): try: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 13:38:24 2012 From: python-checkins at python.org (nick.coghlan) Date: Sun, 8 Jul 2012 13:38:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_14814=3A_Remove_dead?= =?utf-8?q?_function_=28noticed_by_Serhiy_Storchaka=29?= Message-ID: <3WVSNc35nvzNcR@mail.python.org> http://hg.python.org/cpython/rev/45265ecaa3e4 changeset: 78001:45265ecaa3e4 user: Nick Coghlan date: Sun Jul 08 21:38:12 2012 +1000 summary: Issue 14814: Remove dead function (noticed by Serhiy Storchaka) files: Lib/ipaddress.py | 18 ------------------ Lib/test/test_ipaddress.py | 1 - 2 files changed, 0 insertions(+), 19 deletions(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -183,24 +183,6 @@ return (first, last) -def _get_prefix_length(number1, number2, bits): - """Get the number of leading bits that are same for two numbers. - - Args: - number1: an integer. - number2: another integer. - bits: the maximum number of bits to compare. - - Returns: - The number of leading bits that are the same for two numbers. - - """ - for i in range(bits): - if number1 >> i == number2 >> i: - return bits - i - return 0 - - def _count_righthand_zero_bits(number, bits): """Count the number of zero bits on the right hand side. diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -551,7 +551,6 @@ ipaddress.IPv4Address('10.10.10.10'), ipaddress.IPv4Address('10.10.10.12')]) self.assertEqual(first, last) - self.assertEqual(0, ipaddress._get_prefix_length(2**32, 0, 32)) self.assertEqual(128, ipaddress._count_righthand_zero_bits(0, 128)) self.assertEqual("IPv4Network('1.2.3.0/24')", repr(self.ipv4_network)) self.assertEqual('0x1020318', hex(self.ipv4_network)) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 14:01:42 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 8 Jul 2012 14:01:42 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_test=5Finspect_messing?= =?utf-8?q?_up_with_linecache=2Ecache=2E?= Message-ID: <3WVSvV23X3zNWF@mail.python.org> http://hg.python.org/cpython/rev/76e7ae9eb569 changeset: 78002:76e7ae9eb569 parent: 78000:740c2d5ecd04 user: Antoine Pitrou date: Sun Jul 08 13:48:46 2012 +0200 summary: Fix test_inspect messing up with linecache.cache. files: Lib/test/test_inspect.py | 12 +++++++++--- 1 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -285,7 +285,10 @@ co = compile("None", fn, "exec") self.assertEqual(inspect.getsourcefile(co), None) linecache.cache[co.co_filename] = (1, None, "None", co.co_filename) - self.assertEqual(normcase(inspect.getsourcefile(co)), fn) + try: + self.assertEqual(normcase(inspect.getsourcefile(co)), fn) + finally: + del linecache.cache[co.co_filename] def test_getfile(self): self.assertEqual(inspect.getfile(mod.StupidGit), mod.__file__) @@ -407,8 +410,11 @@ self.assertRaises(IOError, inspect.findsource, co) self.assertRaises(IOError, inspect.getsource, co) linecache.cache[co.co_filename] = (1, None, lines, co.co_filename) - self.assertEqual(inspect.findsource(co), (lines,0)) - self.assertEqual(inspect.getsource(co), lines[0]) + try: + self.assertEqual(inspect.findsource(co), (lines,0)) + self.assertEqual(inspect.getsource(co), lines[0]) + finally: + del linecache.cache[co.co_filename] class TestNoEOL(GetSourceBase): def __init__(self, *args, **kwargs): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 14:01:43 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 8 Jul 2012 14:01:43 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge?= Message-ID: <3WVSvW63hwzNWF@mail.python.org> http://hg.python.org/cpython/rev/9afdd8c25bf2 changeset: 78003:9afdd8c25bf2 parent: 78001:45265ecaa3e4 parent: 78002:76e7ae9eb569 user: Antoine Pitrou date: Sun Jul 08 14:00:06 2012 +0200 summary: Merge files: Lib/test/test_inspect.py | 12 +++++++++--- 1 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -285,7 +285,10 @@ co = compile("None", fn, "exec") self.assertEqual(inspect.getsourcefile(co), None) linecache.cache[co.co_filename] = (1, None, "None", co.co_filename) - self.assertEqual(normcase(inspect.getsourcefile(co)), fn) + try: + self.assertEqual(normcase(inspect.getsourcefile(co)), fn) + finally: + del linecache.cache[co.co_filename] def test_getfile(self): self.assertEqual(inspect.getfile(mod.StupidGit), mod.__file__) @@ -407,8 +410,11 @@ self.assertRaises(IOError, inspect.findsource, co) self.assertRaises(IOError, inspect.getsource, co) linecache.cache[co.co_filename] = (1, None, lines, co.co_filename) - self.assertEqual(inspect.findsource(co), (lines,0)) - self.assertEqual(inspect.getsource(co), lines[0]) + try: + self.assertEqual(inspect.findsource(co), (lines,0)) + self.assertEqual(inspect.getsource(co), lines[0]) + finally: + del linecache.cache[co.co_filename] class TestNoEOL(GetSourceBase): def __init__(self, *args, **kwargs): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 15:14:16 2012 From: python-checkins at python.org (nick.coghlan) Date: Sun, 8 Jul 2012 15:14:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_14814=3A_The_new_sys?= =?utf-8?q?tematic_tests_aren=27t_just_about_error_reporting_any?= Message-ID: <3WVVWD22TgzNt6@mail.python.org> http://hg.python.org/cpython/rev/7aa75ea4116d changeset: 78004:7aa75ea4116d user: Nick Coghlan date: Sun Jul 08 23:06:45 2012 +1000 summary: Issue 14814: The new systematic tests aren't just about error reporting any more - change names accordingly. Added and tweaked some example to ensure they were covering the intended code paths files: Lib/ipaddress.py | 23 +++-- Lib/test/test_ipaddress.py | 98 +++++++++++++++++++------ 2 files changed, 85 insertions(+), 36 deletions(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1009,15 +1009,21 @@ raise ValueError("Empty octet not permitted") # Whitelist the characters, since int() allows a lot of bizarre stuff. if not self._DECIMAL_DIGITS.issuperset(octet_str): - raise ValueError("Only decimal digits permitted in %r" % octet_str) + msg = "Only decimal digits permitted in %r" + raise ValueError(msg % octet_str) + # We do the length check second, since the invalid character error + # is likely to be more informative for the user + if len(octet_str) > 3: + msg = "At most 3 characters permitted in %r" + raise ValueError(msg % octet_str) # Convert to integer (we know digits are legal) octet_int = int(octet_str, 10) # Any octets that look like they *might* be written in octal, # and which don't look exactly the same in both octal and # decimal are rejected as ambiguous if octet_int > 7 and octet_str[0] == '0': - raise ValueError("Ambiguous leading zero in %r not permitted" % - octet_str) + msg = "Ambiguous (octal/decimal) value in %r not permitted" + raise ValueError(msg % octet_str) if octet_int > 255: raise ValueError("Octet %d (> 255) not permitted" % octet_int) return octet_int @@ -1560,18 +1566,15 @@ """ # Whitelist the characters, since int() allows a lot of bizarre stuff. - # Higher level wrappers convert these to more informative errors if not self._HEX_DIGITS.issuperset(hextet_str): raise ValueError("Only hex digits permitted in %r" % hextet_str) + # We do the length check second, since the invalid character error + # is likely to be more informative for the user if len(hextet_str) > 4: msg = "At most 4 characters permitted in %r" raise ValueError(msg % hextet_str) - hextet_int = int(hextet_str, 16) - if hextet_int > 0xFFFF: - # This is unreachable due to the string length check above - msg = "Part 0x%X (> 0xFFFF) not permitted" - raise ValueError(msg % hextet_int) - return hextet_int + # Length check means we can skip checking the integer value + return int(hextet_str, 16) def _compress_hextets(self, hextets): """Compresses a list of hextets. diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -9,19 +9,24 @@ import contextlib import ipaddress -class ErrorReporting(unittest.TestCase): +class BaseTestCase(unittest.TestCase): # One big change in ipaddress over the original ipaddr module is # error reporting that tries to assume users *don't know the rules* # for what constitutes an RFC compliant IP address + # Ensuring these errors are emitted correctly in all relevant cases + # meant moving to a more systematic test structure that allows the + # test structure to map more directly to the module structure + # Note that if the constructors are refactored so that addresses with # multiple problems get classified differently, that's OK - just # move the affected examples to the newly appropriate test case. - # The error reporting tests also cover a few corner cases that - # specifically *aren't* errors (such as leading zeroes in v6 - # address parts) that don't have an obvious home in the main test - # suite + # There is some duplication between the original relatively ad hoc + # test suite and the new systematic tests. While some redundancy in + # testing is considered preferable to accidentally deleting a valid + # test, the original test suite will likely be reduced over time as + # redundant tests are identified. @property def factory(self): @@ -53,7 +58,11 @@ return self.assertCleanError(ipaddress.NetmaskValueError, details, *args) -class CommonErrorsMixin: + def assertInstancesEqual(self, lhs, rhs): + """Check constructor arguments produce equivalent instances""" + self.assertEqual(self.factory(lhs), self.factory(rhs)) + +class CommonTestMixin: def test_empty_address(self): with self.assertAddressError("Address cannot be empty"): @@ -63,7 +72,19 @@ with self.assertAddressError(re.escape(repr("1.0"))): self.factory(1.0) -class CommonErrorsMixin_v4(CommonErrorsMixin): +class CommonTestMixin_v4(CommonTestMixin): + + def test_leading_zeros(self): + self.assertInstancesEqual("000.000.000.000", "0.0.0.0") + self.assertInstancesEqual("192.168.000.001", "192.168.0.1") + + def test_int(self): + self.assertInstancesEqual(0, "0.0.0.0") + self.assertInstancesEqual(3232235521, "192.168.0.1") + + def test_packed(self): + self.assertInstancesEqual(bytes.fromhex("00000000"), "0.0.0.0") + self.assertInstancesEqual(bytes.fromhex("c0a80001"), "192.168.0.1") def test_negative_ints_rejected(self): msg = "-1 (< 0) is not permitted as an IPv4 address" @@ -77,7 +98,7 @@ def test_bad_packed_length(self): def assertBadLength(length): - addr = b'\x00' * length + addr = bytes(length) msg = "%r (len %d != 4) is not permitted as an IPv4 address" with self.assertAddressError(re.escape(msg % (addr, length))): self.factory(addr) @@ -85,7 +106,23 @@ assertBadLength(3) assertBadLength(5) -class CommonErrorsMixin_v6(CommonErrorsMixin): +class CommonTestMixin_v6(CommonTestMixin): + + def test_leading_zeros(self): + self.assertInstancesEqual("0000::0000", "::") + self.assertInstancesEqual("000::c0a8:0001", "::c0a8:1") + + def test_int(self): + self.assertInstancesEqual(0, "::") + self.assertInstancesEqual(3232235521, "::c0a8:1") + + def test_packed(self): + addr = bytes(12) + bytes.fromhex("00000000") + self.assertInstancesEqual(addr, "::") + addr = bytes(12) + bytes.fromhex("c0a80001") + self.assertInstancesEqual(addr, "::c0a8:1") + addr = bytes.fromhex("c0a80001") + bytes(12) + self.assertInstancesEqual(addr, "c0a8:1::") def test_negative_ints_rejected(self): msg = "-1 (< 0) is not permitted as an IPv6 address" @@ -99,7 +136,7 @@ def test_bad_packed_length(self): def assertBadLength(length): - addr = b'\x00' * length + addr = bytes(length) msg = "%r (len %d != 16) is not permitted as an IPv6 address" with self.assertAddressError(re.escape(msg % (addr, length))): self.factory(addr) @@ -109,7 +146,7 @@ assertBadLength(17) -class AddressErrors_v4(ErrorReporting, CommonErrorsMixin_v4): +class AddressTestCase_v4(BaseTestCase, CommonTestMixin_v4): factory = ipaddress.IPv4Address def test_network_passed_as_address(self): @@ -162,6 +199,7 @@ ipaddress.IPv4Address(addr) assertBadOctet("0x0a.0x0a.0x0a.0x0a", "0x0a") + assertBadOctet("0xa.0x0a.0x0a.0x0a", "0xa") assertBadOctet("42.42.42.-0", "-0") assertBadOctet("42.42.42.+0", "+0") assertBadOctet("42.42.42.-42", "-42") @@ -170,16 +208,23 @@ assertBadOctet("1.2.3.4::", "4::") assertBadOctet("1.a.2.3", "a") - def test_leading_zeros(self): + def test_octal_decimal_ambiguity(self): def assertBadOctet(addr, octet): - msg = "Ambiguous leading zero in %r not permitted in %r" - with self.assertAddressError(msg, octet, addr): + msg = "Ambiguous (octal/decimal) value in %r not permitted in %r" + with self.assertAddressError(re.escape(msg % (octet, addr))): ipaddress.IPv4Address(addr) assertBadOctet("016.016.016.016", "016") assertBadOctet("001.000.008.016", "008") - self.assertEqual(ipaddress.IPv4Address("192.168.000.001"), - ipaddress.IPv4Address("192.168.0.1")) + + def test_octet_length(self): + def assertBadOctet(addr, octet): + msg = "At most 3 characters permitted in %r in %r" + with self.assertAddressError(re.escape(msg % (octet, addr))): + ipaddress.IPv4Address(addr) + + assertBadOctet("0000.000.000.000", "0000") + assertBadOctet("12345.67899.-54321.-98765", "12345") def test_octet_limit(self): def assertBadOctet(addr, octet): @@ -187,11 +232,11 @@ with self.assertAddressError(re.escape(msg)): ipaddress.IPv4Address(addr) - assertBadOctet("12345.67899.-54321.-98765", 12345) assertBadOctet("257.0.0.0", 257) + assertBadOctet("192.168.0.999", 999) -class AddressErrors_v6(ErrorReporting, CommonErrorsMixin_v6): +class AddressTestCase_v6(BaseTestCase, CommonTestMixin_v6): factory = ipaddress.IPv6Address def test_network_passed_as_address(self): @@ -317,12 +362,13 @@ with self.assertAddressError(msg, part, addr): ipaddress.IPv6Address(addr) + assertBadPart("::00000", "00000") assertBadPart("3ffe::10000", "10000") assertBadPart("02001:db8::", "02001") assertBadPart('2001:888888::1', "888888") -class NetmaskErrorsMixin_v4(CommonErrorsMixin_v4): +class NetmaskTestMixin_v4(CommonTestMixin_v4): """Input validation on interfaces and networks is very similar""" def test_split_netmask(self): @@ -352,18 +398,18 @@ assertBadNetmask("1.2.3.4", "") assertBadNetmask("1.2.3.4", "33") assertBadNetmask("1.2.3.4", "254.254.255.256") + assertBadNetmask("1.1.1.1", "254.xyz.2.3") assertBadNetmask("1.1.1.1", "240.255.0.0") - assertBadNetmask("1.1.1.1", "1.a.2.3") assertBadNetmask("1.1.1.1", "pudding") -class InterfaceErrors_v4(ErrorReporting, NetmaskErrorsMixin_v4): +class InterfaceTestCase_v4(BaseTestCase, NetmaskTestMixin_v4): factory = ipaddress.IPv4Interface -class NetworkErrors_v4(ErrorReporting, NetmaskErrorsMixin_v4): +class NetworkTestCase_v4(BaseTestCase, NetmaskTestMixin_v4): factory = ipaddress.IPv4Network -class NetmaskErrorsMixin_v6(CommonErrorsMixin_v6): +class NetmaskTestMixin_v6(CommonTestMixin_v6): """Input validation on interfaces and networks is very similar""" def test_split_netmask(self): @@ -395,14 +441,14 @@ assertBadNetmask("::1", "129") assertBadNetmask("::1", "pudding") -class InterfaceErrors_v6(ErrorReporting, NetmaskErrorsMixin_v6): +class InterfaceTestCase_v6(BaseTestCase, NetmaskTestMixin_v6): factory = ipaddress.IPv6Interface -class NetworkErrors_v6(ErrorReporting, NetmaskErrorsMixin_v6): +class NetworkTestCase_v6(BaseTestCase, NetmaskTestMixin_v6): factory = ipaddress.IPv6Network -class FactoryFunctionErrors(ErrorReporting): +class FactoryFunctionErrors(BaseTestCase): def assertFactoryError(self, factory, kind): """Ensure a clean ValueError with the expected message""" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 18:51:06 2012 From: python-checkins at python.org (vinay.sajip) Date: Sun, 8 Jul 2012 18:51:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Closes_=2315281=2C_=231528?= =?utf-8?q?3=3A_Don=27t_make_venv_scripts_executable=2C_but_copy_source_mo?= =?utf-8?q?de?= Message-ID: <3WVbKQ2SGGzNmv@mail.python.org> http://hg.python.org/cpython/rev/9c345b4bd97e changeset: 78005:9c345b4bd97e user: Vinay Sajip date: Sun Jul 08 17:50:42 2012 +0100 summary: Closes #15281, #15283: Don't make venv scripts executable, but copy source mode instead, and provide better help for pyvenv. files: Lib/venv/__init__.py | 13 ++++++++++--- 1 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -316,7 +316,7 @@ data = self.replace_variables(data, context) with open(dstfile, mode) as f: f.write(data) - os.chmod(dstfile, 0o755) + shutil.copymode(srcfile, dstfile) def create(env_dir, system_site_packages=False, clear=False, symlinks=False): @@ -354,7 +354,12 @@ description='Creates virtual Python ' 'environments in one or ' 'more target ' - 'directories.') + 'directories.', + epilog='Once an environment has been ' + 'created, you may wish to ' + 'activate it, e.g. by ' + 'sourcing an activate script ' + 'in its bin directory.') parser.add_argument('dirs', metavar='ENV_DIR', nargs='+', help='A directory to create the environment in.') parser.add_argument('--system-site-packages', default=False, @@ -368,7 +373,9 @@ use_symlinks = True parser.add_argument('--symlinks', default=use_symlinks, action='store_true', dest='symlinks', - help="Attempt to symlink rather than copy.") + help='Try to use symlinks rather than copies, ' + 'when symlinks are not the default for ' + 'the platform.') parser.add_argument('--clear', default=False, action='store_true', dest='clear', help='Delete the environment ' 'directory if it already ' -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 20:03:54 2012 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 8 Jul 2012 20:03:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_add_gc_support_to_the_AST_?= =?utf-8?q?base_type_=28closes_=2315293=29?= Message-ID: <3WVcxQ2LzFzNtf@mail.python.org> http://hg.python.org/cpython/rev/85cccc38d01c changeset: 78006:85cccc38d01c user: Benjamin Peterson date: Sun Jul 08 11:03:46 2012 -0700 summary: add gc support to the AST base type (closes #15293) files: Parser/asdl_c.py | 21 +++++++++++++++++---- Python/Python-ast.c | 21 +++++++++++++++++---- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -616,6 +616,19 @@ } static int +ast_traverse(AST_object *self, visitproc visit, void *arg) +{ + Py_VISIT(self->dict); + return 0; +} + +static void +ast_clear(AST_object *self) +{ + Py_CLEAR(self->dict); +} + +static int ast_type_init(PyObject *self, PyObject *args, PyObject *kw) { _Py_IDENTIFIER(_fields); @@ -718,10 +731,10 @@ PyObject_GenericGetAttr, /* tp_getattro */ PyObject_GenericSetAttr, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ + (traverseproc)ast_traverse, /* tp_traverse */ + (inquiry)ast_clear, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ @@ -737,7 +750,7 @@ (initproc)ast_type_init, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ PyType_GenericNew, /* tp_new */ - PyObject_Del, /* tp_free */ + PyObject_GC_Del, /* tp_free */ }; diff --git a/Python/Python-ast.c b/Python/Python-ast.c --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -468,6 +468,19 @@ } static int +ast_traverse(AST_object *self, visitproc visit, void *arg) +{ + Py_VISIT(self->dict); + return 0; +} + +static void +ast_clear(AST_object *self) +{ + Py_CLEAR(self->dict); +} + +static int ast_type_init(PyObject *self, PyObject *args, PyObject *kw) { _Py_IDENTIFIER(_fields); @@ -570,10 +583,10 @@ PyObject_GenericGetAttr, /* tp_getattro */ PyObject_GenericSetAttr, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ + (traverseproc)ast_traverse, /* tp_traverse */ + (inquiry)ast_clear, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ @@ -589,7 +602,7 @@ (initproc)ast_type_init, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ PyType_GenericNew, /* tp_new */ - PyObject_Del, /* tp_free */ + PyObject_GC_Del, /* tp_free */ }; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 20:06:09 2012 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 8 Jul 2012 20:06:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_add_news_note_for_85cccc38?= =?utf-8?q?d01c?= Message-ID: <3WVd011838zNsM@mail.python.org> http://hg.python.org/cpython/rev/ea0337239f2e changeset: 78007:ea0337239f2e user: Benjamin Peterson date: Sun Jul 08 11:06:04 2012 -0700 summary: add news note for 85cccc38d01c files: Misc/NEWS | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #15293: Add GC support to the AST base node type. + - Issue #15291: Fix a memory leak where AST nodes where not properly deallocated. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 20:13:41 2012 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 8 Jul 2012 20:13:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_test_AST_base_type_garbage?= =?utf-8?q?_collection?= Message-ID: <3WVd8j29ddzNtH@mail.python.org> http://hg.python.org/cpython/rev/5c2e30c484cf changeset: 78008:5c2e30c484cf user: Benjamin Peterson date: Sun Jul 08 11:13:36 2012 -0700 summary: test AST base type garbage collection files: Lib/test/test_ast.py | 15 ++++++++++++++- 1 files changed, 14 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -1,8 +1,10 @@ import os import sys import unittest +import ast +import weakref + from test import support -import ast def to_tuple(t): if t is None or isinstance(t, (str, int, complex)): @@ -207,6 +209,17 @@ # "_ast.AST constructor takes 0 positional arguments" ast.AST(2) + def test_AST_garbage_collection(self): + class X: + pass + a = ast.AST() + a.x = X() + a.x.a = a + ref = weakref.ref(a.x) + del a + support.gc_collect() + self.assertIsNone(ref()) + def test_snippets(self): for input, output, kind in ((exec_tests, exec_results, "exec"), (single_tests, single_results, "single"), -- Repository URL: http://hg.python.org/cpython From tjreedy at udel.edu Sun Jul 8 19:22:43 2012 From: tjreedy at udel.edu (Terry Reedy) Date: Sun, 08 Jul 2012 13:22:43 -0400 Subject: [Python-checkins] cpython: Issue 14814: The new systematic tests aren't just about error reporting any In-Reply-To: <3WVVWD22TgzNt6@mail.python.org> References: <3WVVWD22TgzNt6@mail.python.org> Message-ID: <4FF9C1E3.2000501@udel.edu> On 7/8/2012 9:14 AM, nick.coghlan wrote: > if not self._DECIMAL_DIGITS.issuperset(octet_str): > - raise ValueError("Only decimal digits permitted in %r" % octet_str) > + msg = "Only decimal digits permitted in %r" > + raise ValueError(msg % octet_str) > + # We do the length check second, since the invalid character error > + # is likely to be more informative for the user > + if len(octet_str) > 3: > + msg = "At most 3 characters permitted in %r" > + raise ValueError(msg % octet_str) If you want to report both errors, when present: msg = '' if not self._DECIMAL_DIGITS.issuperset(octet_str): msg = "Only decimal digits permitted in %r" % octet_str if len(octet_str) > 3: msg = msg + ("; " if msg else '') + "At most 3 characters permitted in %r" % octet_str if msg: raise ValueError(msg) 8 lines either way ;-) > if not self._HEX_DIGITS.issuperset(hextet_str): > raise ValueError("Only hex digits permitted in %r" % hextet_str) > + # We do the length check second, since the invalid character error > + # is likely to be more informative for the user > if len(hextet_str) > 4: > msg = "At most 4 characters permitted in %r" > raise ValueError(msg % hextet_str) Same thing for hextet string msg = '' if not self._HEX_DIGITS.issuperset(hextet_str): msg = "Only hex digits permitted in %r" % hextet_str if len(hextet_str) > 4: msg = msg + ("; " if msg else '') + "At most 4 characters permitted in %r" % hextet_str if msg: raise ValueError(msg) (These *could* be factored into one private function with 5 params, but probably not worth it for just 2 calls.) I guess these would require another change to the tests ;-). > +class BaseTestCase(unittest.TestCase): > # One big change in ipaddress over the original ipaddr module is > # error reporting that tries to assume users *don't know the rules* > # for what constitutes an RFC compliant IP address Good assumption. There *will* be people who learn by trial and error. --- Terry Jan Reedy From python-checkins at python.org Sun Jul 8 20:59:31 2012 From: python-checkins at python.org (amaury.forgeotdarc) Date: Sun, 8 Jul 2012 20:59:31 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315110=3A_Also_hid?= =?utf-8?q?e_importlib_frames_when_importing_a_builtin_module_fails=2E?= Message-ID: <3WVf9b1srMzNlN@mail.python.org> http://hg.python.org/cpython/rev/37e68da59047 changeset: 78009:37e68da59047 user: Amaury Forgeot d'Arc date: Sun Jul 08 20:52:38 2012 +0200 summary: Issue #15110: Also hide importlib frames when importing a builtin module fails. files: Lib/importlib/_bootstrap.py | 6 +- Python/importlib.h | 5485 +++++++++++----------- 2 files changed, 2755 insertions(+), 2736 deletions(-) diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -490,13 +490,17 @@ """Load a built-in module.""" is_reload = fullname in sys.modules try: - return _imp.init_builtin(fullname) + return cls._exec_module(fullname) except: if not is_reload and fullname in sys.modules: del sys.modules[fullname] raise @classmethod + def _exec_module(cls, fullname): + return _imp.init_builtin(fullname) + + @classmethod @_requires_builtin def get_code(cls, fullname): """Return None as built-in modules do not have code objects.""" diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 21:03:12 2012 From: python-checkins at python.org (amaury.forgeotdarc) Date: Sun, 8 Jul 2012 21:03:12 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315110=3A_Copy_sam?= =?utf-8?q?e_docstring_as_other_=27=5Fexec=5Fmodule=27_methods=2E?= Message-ID: <3WVfFr5nYYzNlN@mail.python.org> http://hg.python.org/cpython/rev/5d43154d68a8 changeset: 78010:5d43154d68a8 user: Amaury Forgeot d'Arc date: Sun Jul 08 21:03:01 2012 +0200 summary: Issue #15110: Copy same docstring as other '_exec_module' methods. files: Lib/importlib/_bootstrap.py | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -498,6 +498,9 @@ @classmethod def _exec_module(cls, fullname): + """Helper for load_module, allowing to isolate easily (when + looking at a traceback) whether an error comes from executing + an imported module's code.""" return _imp.init_builtin(fullname) @classmethod -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 23:53:50 2012 From: python-checkins at python.org (terry.reedy) Date: Sun, 8 Jul 2012 23:53:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzEzNTU3?= =?utf-8?q?=3A_Clarify_effect_of_giving_two_different_namespaces_to_exec_o?= =?utf-8?q?r?= Message-ID: <3WVk2k4S2szNM5@mail.python.org> http://hg.python.org/cpython/rev/ab22ffa6fb2e changeset: 78011:ab22ffa6fb2e branch: 2.7 parent: 77995:45cd2d816f4d user: Terry Jan Reedy date: Sun Jul 08 17:35:26 2012 -0400 summary: Issue #13557: Clarify effect of giving two different namespaces to exec or execfile(). files: Doc/library/functions.rst | 5 ++++- Doc/reference/simple_stmts.rst | 3 +++ Misc/NEWS | 4 +++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -430,7 +430,10 @@ The arguments are a file name and two optional dictionaries. The file is parsed and evaluated as a sequence of Python statements (similarly to a module) using the *globals* and *locals* dictionaries as global and local namespace. If - provided, *locals* can be any mapping object. + provided, *locals* can be any mapping object. Remember that at module level, + globals and locals are the same dictionary. If two separate objects are + passed as *globals* and *locals*, the code will be executed as if it were + embedded in a class definition. .. versionchanged:: 2.4 formerly *locals* was required to be a dictionary. diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -993,6 +993,9 @@ it should be a dictionary, which will be used for both the global and the local variables. If two expressions are given, they are used for the global and local variables, respectively. If provided, *locals* can be any mapping object. +Remember that at module level, globals and locals are the same dictionary. If +two separate objects are given as *globals* and *locals*, the code will be +executed as if it were embedded in a class definition. .. versionchanged:: 2.4 Formerly, *locals* was required to be a dictionary. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -284,7 +284,9 @@ - Issue #14437: Fix building the _io module under Cygwin. Documentation -------------- + +- Issue #13557: Clarify effect of giving two different namespaces to exec or + execfile(). - Issue #14034: added the argparse tutorial. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 23:53:53 2012 From: python-checkins at python.org (terry.reedy) Date: Sun, 8 Jul 2012 23:53:53 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzEzNTU3?= =?utf-8?q?=3A_Clarify_effect_of_giving_two_different_namespaces_to_exec_o?= =?utf-8?q?r?= Message-ID: <3WVk2n1b6szNT6@mail.python.org> http://hg.python.org/cpython/rev/ea670d71a36d changeset: 78012:ea670d71a36d branch: 3.2 parent: 77992:ee1828dc3bf6 user: Terry Jan Reedy date: Sun Jul 08 17:36:14 2012 -0400 summary: Issue #13557: Clarify effect of giving two different namespaces to exec or execfile(). files: Doc/library/functions.rst | 5 ++++- Misc/NEWS | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -417,7 +417,10 @@ current scope. If only *globals* is provided, it must be a dictionary, which will be used for both the global and the local variables. If *globals* and *locals* are given, they are used for the global and local variables, - respectively. If provided, *locals* can be any mapping object. + respectively. If provided, *locals* can be any mapping object. Remember + that at module level, globals and locals are the same dictionary. If exec + gets two separate objects as *globals* and *locals*, the code will be + executed as if it were embedded in a class definition. If the *globals* dictionary does not contain a value for the key ``__builtins__``, a reference to the dictionary of the built-in module diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -380,14 +380,14 @@ Documentation ------------- +- Issue #13557: Clarify effect of giving two different namespaces to exec or + execfile(). + - Issue #8799: Fix and improve the threading.Condition documentation. - Issue #14943: Correct a default argument value for winreg.OpenKey and correctly list the argument names in the function's explanation. -Documentation -------------- - - Issue #14034: added the argparse tutorial. Tools/Demos -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 8 23:53:54 2012 From: python-checkins at python.org (terry.reedy) Date: Sun, 8 Jul 2012 23:53:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Merge_3=2E2_closes_issue_13557?= Message-ID: <3WVk2p4SJ1zNX3@mail.python.org> http://hg.python.org/cpython/rev/b47ae7a9e685 changeset: 78013:b47ae7a9e685 parent: 78010:5d43154d68a8 parent: 78012:ea670d71a36d user: Terry Jan Reedy date: Sun Jul 08 17:52:58 2012 -0400 summary: Merge 3.2 closes issue 13557 files: Doc/library/functions.rst | 5 ++++- Misc/NEWS | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -413,7 +413,10 @@ current scope. If only *globals* is provided, it must be a dictionary, which will be used for both the global and the local variables. If *globals* and *locals* are given, they are used for the global and local variables, - respectively. If provided, *locals* can be any mapping object. + respectively. If provided, *locals* can be any mapping object. Remember + that at module level, globals and locals are the same dictionary. If exec + gets two separate objects as *globals* and *locals*, the code will be + executed as if it were embedded in a class definition. If the *globals* dictionary does not contain a value for the key ``__builtins__``, a reference to the dictionary of the built-in module diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -98,6 +98,12 @@ * C frames that are garbage-collecting * C frames that are due to the invocation of a PyCFunction +Documentation +------------- + +- Issue #13557: Clarify effect of giving two different namespaces to exec or + execfile(). + Tests ----- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 00:43:03 2012 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 9 Jul 2012 00:43:03 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Minor_algorithmic_tweaks?= =?utf-8?q?=2C_better_factoring=2C_improved_docstrings_and_variable?= Message-ID: <3WVl7W37qWzNR7@mail.python.org> http://hg.python.org/cpython/rev/77ca62751877 changeset: 78014:77ca62751877 user: Raymond Hettinger date: Sun Jul 08 15:42:54 2012 -0700 summary: Minor algorithmic tweaks, better factoring, improved docstrings and variable names files: Tools/scripts/highlight.py | 117 +++++++++++++----------- 1 files changed, 62 insertions(+), 55 deletions(-) diff --git a/Tools/scripts/highlight.py b/Tools/scripts/highlight.py --- a/Tools/scripts/highlight.py +++ b/Tools/scripts/highlight.py @@ -1,24 +1,9 @@ #!/usr/bin/env python3 -'''Add syntax highlighting to Python source code +'''Add syntax highlighting to Python source code''' -Example command-line calls: +__all__ = ['analyze_python', 'ansi_highlight', 'default_ansi', + 'html_highlight', 'build_html_page', 'default_css', 'default_html'] - # Show syntax highlighted code in the terminal window - $ ./highlight.py myfile.py - - # Colorize myfile.py and display in a browser - $ ./highlight.py -b myfile.py - - # Create an HTML section that can be embedded in an existing webpage - ./highlight.py -s myfile.py - - # Create a complete HTML file - $ ./highlight.py -c myfile.py > myfile.html - -''' - -__all__ = ['colorize_html', 'build_page', 'default_css', 'default_html', - 'colorize_ansi', 'default_ansi'] __author__ = 'Raymond Hettinger' import keyword, tokenize, cgi, functools @@ -31,13 +16,16 @@ 'Join content from a range of lines between start and end' (srow, scol), (erow, ecol) = start, end if srow == erow: - rows = [lines[srow-1][scol:ecol]] - else: - rows = [lines[srow-1][scol:]] + lines[srow: erow-1] + [lines[erow-1][:ecol]] + return lines[srow-1][scol:ecol], end + rows = [lines[srow-1][scol:]] + lines[srow: erow-1] + [lines[erow-1][:ecol]] return ''.join(rows), end -def isolate_tokens(source): - 'Generate chunks of source and identify chunks to be highlighted' +def analyze_python(source): + '''Generate and classify chunks of Python for syntax highlighting. + Yields tuples in the form: (leadin_text, category, categorized_text). + The final tuple has empty strings for the category and categorized text. + + ''' lines = source.splitlines(True) lines.append('') readline = functools.partial(next, iter(lines), '') @@ -65,36 +53,37 @@ kind = 'keyword' elif is_builtin(tok_str) and prev_tok_str != '.': kind = 'builtin' - line_upto_token, written = combine_range(lines, written, (srow, scol)) - line_thru_token, written = combine_range(lines, written, (erow, ecol)) - yield kind, line_upto_token, line_thru_token + if kind: + line_upto_token, written = combine_range(lines, written, (srow, scol)) + line_thru_token, written = combine_range(lines, written, (erow, ecol)) + yield line_upto_token, kind, line_thru_token + line_upto_token, written = combine_range(lines, written, (erow, ecol)) + yield line_upto_token, '', '' default_ansi = { - 'comment': '\033[0;31m', - 'string': '\033[0;32m', - 'docstring': '\033[0;32m', - 'keyword': '\033[0;33m', - 'builtin': '\033[0;35m', - 'definition': '\033[0;33m', - 'defname': '\033[0;34m', - 'operator': '\033[0;33m', + 'comment': ('\033[0;31m', '\033[0m'), + 'string': ('\033[0;32m', '\033[0m'), + 'docstring': ('\033[0;32m', '\033[0m'), + 'keyword': ('\033[0;33m', '\033[0m'), + 'builtin': ('\033[0;35m', '\033[0m'), + 'definition': ('\033[0;33m', '\033[0m'), + 'defname': ('\033[0;34m', '\033[0m'), + 'operator': ('\033[0;33m', '\033[0m'), } -def colorize_ansi(source, colors=default_ansi): - 'Add syntax highlighting to Python source code using ANSI escape sequences' +def ansi_highlight(classified_text, colors=default_ansi): + 'Add syntax highlighting to source code using ANSI escape sequences' # http://en.wikipedia.org/wiki/ANSI_escape_code result = [] - for kind, line_upto_token, line_thru_token in isolate_tokens(source): - if kind: - result += [line_upto_token, colors[kind], line_thru_token, '\033[0m'] - else: - result += [line_upto_token, line_thru_token] + for line_upto_token, kind, line_thru_token in classified_text: + opener, closer = colors.get(kind, ('', '')) + result += [line_upto_token, opener, line_thru_token, closer] return ''.join(result) -def colorize_html(source): - 'Convert Python source code to an HTML fragment with colorized markup' - result = ['
      \n']
      -    for kind, line_upto_token, line_thru_token in isolate_tokens(source):
      +def html_highlight(classified_text,opener='
      \n', closer='
      \n'): + 'Convert classified text to an HTML fragment' + result = [opener] + for line_upto_token, kind, line_thru_token in classified_text: if kind: result += [cgi.escape(line_upto_token), '' % kind, @@ -103,7 +92,7 @@ else: result += [cgi.escape(line_upto_token), cgi.escape(line_thru_token)] - result += ['
      \n'] + result += [closer] return ''.join(result) default_css = { @@ -134,21 +123,38 @@ ''' -def build_page(source, title='python', css=default_css, html=default_html): - 'Create a complete HTML page with colorized Python source code' +def build_html_page(classified_text, title='python', + css=default_css, html=default_html): + 'Create a complete HTML page with colorized source code' css_str = '\n'.join(['%s %s' % item for item in css.items()]) - result = colorize_html(source) + result = html_highlight(classified_text) title = cgi.escape(title) return html.format(title=title, css=css_str, body=result) if __name__ == '__main__': - import sys, argparse, webbrowser, os + import sys, argparse, webbrowser, os, textwrap parser = argparse.ArgumentParser( - description = 'Add syntax highlighting to Python source') + description = 'Add syntax highlighting to Python source code', + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog = textwrap.dedent(''' + examples: + + # Show syntax highlighted code in the terminal window + $ ./highlight.py myfile.py + + # Colorize myfile.py and display in a browser + $ ./highlight.py -b myfile.py + + # Create an HTML section to embed in an existing webpage + ./highlight.py -s myfile.py + + # Create a complete HTML file + $ ./highlight.py -c myfile.py > myfile.html + ''')) parser.add_argument('sourcefile', metavar = 'SOURCEFILE', - help = 'File containing Python sourcecode') + help = 'file containing Python sourcecode') parser.add_argument('-b', '--browser', action = 'store_true', help = 'launch a browser to show results') parser.add_argument('-c', '--complete', action = 'store_true', @@ -164,13 +170,14 @@ sourcefile = args.sourcefile with open(sourcefile) as f: source = f.read() + classified_text = analyze_python(source) if args.complete or args.browser: - encoded = build_page(source, title=sourcefile) + encoded = build_html_page(classified_text, title=sourcefile) elif args.section: - encoded = colorize_html(source) + encoded = html_highlight(classified_text) else: - encoded = colorize_ansi(source) + encoded = ansi_highlight(classified_text) if args.browser: htmlfile = os.path.splitext(os.path.basename(sourcefile))[0] + '.html' -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 01:02:02 2012 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 9 Jul 2012 01:02:02 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_15265=3A_document_th?= =?utf-8?q?e_exception_raised_for_invalid_sample_sizes=2E?= Message-ID: <3WVlYQ41nmzNLp@mail.python.org> http://hg.python.org/cpython/rev/72174d8af3ba changeset: 78015:72174d8af3ba user: Raymond Hettinger date: Sun Jul 08 16:01:53 2012 -0700 summary: Issue 15265: document the exception raised for invalid sample sizes. files: Doc/library/random.rst | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Doc/library/random.rst b/Doc/library/random.rst --- a/Doc/library/random.rst +++ b/Doc/library/random.rst @@ -150,6 +150,9 @@ argument. This is especially fast and space efficient for sampling from a large population: ``sample(range(10000000), 60)``. + If the sample size is larger than the population size, a :exc:``ValueError`` + is raised. + The following functions generate specific real-valued distributions. Function parameters are named after the corresponding variables in the distribution's equation, as used in common mathematical practice; most of these equations can -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 01:04:10 2012 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 9 Jul 2012 01:04:10 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Make_it_easier_to_search_f?= =?utf-8?q?or_the_grouper=28=29_recipe=2E?= Message-ID: <3WVlbt6CHdzNMD@mail.python.org> http://hg.python.org/cpython/rev/a809c6ffa332 changeset: 78016:a809c6ffa332 user: Raymond Hettinger date: Sun Jul 08 16:04:03 2012 -0700 summary: Make it easier to search for the grouper() recipe. files: Doc/library/itertools.rst | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -705,7 +705,8 @@ return zip(a, b) def grouper(n, iterable, fillvalue=None): - "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx" + "Collect data into fixed-length chunks or blocks" + # grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx" args = [iter(iterable)] * n return zip_longest(*args, fillvalue=fillvalue) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 02:59:11 2012 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 9 Jul 2012 02:59:11 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_revert_the_cha?= =?utf-8?q?nges_done_for_issue14826_-_quoting_witin_Request_is_not_desirab?= =?utf-8?b?bGUu?= Message-ID: <3WVp8b5zKZzNBf@mail.python.org> http://hg.python.org/cpython/rev/ebd37273e0fe changeset: 78017:ebd37273e0fe branch: 3.2 parent: 78012:ea670d71a36d user: Senthil Kumaran date: Sun Jul 08 17:47:25 2012 -0700 summary: revert the changes done for issue14826 - quoting witin Request is not desirable. files: Lib/test/test_urllib.py | 5 ----- Lib/urllib/request.py | 1 - Misc/NEWS | 5 ----- 3 files changed, 0 insertions(+), 11 deletions(-) diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -1246,11 +1246,6 @@ # ftp.close() - def test_quote_url(self): - Request = urllib.request.Request - request = Request("http://www.python.org/foo bar") - self.assertEqual(request.full_url, "http://www.python.org/foo%20bar") - def test_main(): support.run_unittest( diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -181,7 +181,6 @@ origin_req_host=None, unverifiable=False): # unwrap('') --> 'type://host/path' self.full_url = unwrap(url) - self.full_url = quote(self.full_url, safe="%/:=&?~#+!$,;'@()*[]|") self.full_url, self.fragment = splittag(self.full_url) self.data = data self.headers = {} diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -87,11 +87,6 @@ Library ------- -- Issue #14826: Quote urls in urllib.request.Request similar to how they are - quoted by urllib.request.URLopener. Allows urls to spaces in them to work - transparently with urllib.request.urlopen(...). Patch contributed by Stephen - Thorne. - - Issue #14990: Correctly fail with SyntaxError on invalid encoding declaration. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 03:00:09 2012 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 9 Jul 2012 03:00:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_revert_the_changes_done_for_issue14826_-_quoting_witin_R?= =?utf-8?q?equest_is_not_desirable=2E?= Message-ID: <3WVp9j2dj2zNVr@mail.python.org> http://hg.python.org/cpython/rev/a4bdb637d818 changeset: 78018:a4bdb637d818 parent: 78016:a809c6ffa332 parent: 78017:ebd37273e0fe user: Senthil Kumaran date: Sun Jul 08 18:00:47 2012 -0700 summary: revert the changes done for issue14826 - quoting witin Request is not desirable. files: Lib/test/test_urllib.py | 5 ----- Lib/urllib/request.py | 1 - Misc/NEWS | 5 ----- 3 files changed, 0 insertions(+), 11 deletions(-) diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -1272,11 +1272,6 @@ request.method = 'HEAD' self.assertEqual(request.get_method(), 'HEAD') - def test_quote_url(self): - Request = urllib.request.Request - request = Request("http://www.python.org/foo bar") - self.assertEqual(request.full_url, "http://www.python.org/foo%20bar") - def test_main(): support.run_unittest( diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -264,7 +264,6 @@ method=None): # unwrap('') --> 'type://host/path' self.full_url = unwrap(url) - self.full_url = quote(self.full_url, safe="%/:=&?~#+!$,;'@()*[]|") self.full_url, self.fragment = splittag(self.full_url) self.data = data self.headers = {} diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -31,11 +31,6 @@ Library ------- -- Issue #14826: Quote urls in urllib.request.Request similar to how they - are quoted by urllib.request.URLopener. Allows urls to spaces in them to work - transparently with urllib.request.urlopen(...). Patch contributed by Stephen - Thorne. - - Issue #5931: wsgiref environ variable SERVER_SOFTWARE will specify an implementation specific term like Cpython, Jython instead of generic "Python" -- Repository URL: http://hg.python.org/cpython From ncoghlan at gmail.com Mon Jul 9 04:13:24 2012 From: ncoghlan at gmail.com (Nick Coghlan) Date: Mon, 9 Jul 2012 12:13:24 +1000 Subject: [Python-checkins] cpython: Issue 14814: The new systematic tests aren't just about error reporting any In-Reply-To: <4FF9C1E3.2000501@udel.edu> References: <3WVVWD22TgzNt6@mail.python.org> <4FF9C1E3.2000501@udel.edu> Message-ID: On Mon, Jul 9, 2012 at 3:22 AM, Terry Reedy wrote: > On 7/8/2012 9:14 AM, nick.coghlan wrote: > If you want to report both errors, when present: I don't really - when there are multiple things wrong with the address, ipaddress just reports the first one it notices (e.g. IPv4Address("google.com") will complain about the lack of "." separators rather than the fact that "google" and "com" are not valid octets). This was just a case where I started to reorder the checks to do the faster one first, and then realised it was more user friendly to check the other way around (since the success case will always include both checks, it only makes a difference to the speed of rejection of some invalid cases). Most of the other validation checks have a more obvious suitable order (for example, there's no reason to start checking individual parts if we can't even split the parts up appropriately). >> +class BaseTestCase(unittest.TestCase): >> # One big change in ipaddress over the original ipaddr module is >> # error reporting that tries to assume users *don't know the rules* >> # for what constitutes an RFC compliant IP address > > > Good assumption. There *will* be people who learn by trial and error. *cough* It's conceivable I started down this path due to using the REPL for exploration while making an initial attempt at writing method and data attribute docs over the weekend. I'm firmly in the category of IPv4 network programming engineers with next to no IPv6 experience :) Cheers, Nick. -- Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia From solipsis at pitrou.net Mon Jul 9 05:59:17 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 09 Jul 2012 05:59:17 +0200 Subject: [Python-checkins] Daily reference leaks (a4bdb637d818): sum=0 Message-ID: results for a4bdb637d818 on branch "default" -------------------------------------------- test_imp leaked [-1, 1, 0] references, sum=0 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogIFjGlH', '-x'] From python-checkins at python.org Mon Jul 9 06:15:58 2012 From: python-checkins at python.org (terry.reedy) Date: Mon, 9 Jul 2012 06:15:58 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgMTI1MTA6?= =?utf-8?q?_Delete_actual_first_param_name_for_all_methods=3B_revise_tests?= =?utf-8?q?=2E?= Message-ID: <3WVtWf6ZQvzNQV@mail.python.org> http://hg.python.org/cpython/rev/eea379307efa changeset: 78019:eea379307efa branch: 3.2 parent: 78017:ebd37273e0fe user: Terry Jan Reedy date: Mon Jul 09 00:13:21 2012 -0400 summary: Issue 12510: Delete actual first param name for all methods; revise tests. files: Lib/idlelib/CallTips.py | 34 +++++++++++++++++----------- 1 files changed, 20 insertions(+), 14 deletions(-) diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py --- a/Lib/idlelib/CallTips.py +++ b/Lib/idlelib/CallTips.py @@ -117,7 +117,7 @@ return None # The following are used in both get_argspec and tests -_self_pat = re.compile('self\,?\s*') +_first_param = re.compile('(?<=\()\w*\,?\s*') _default_callable_argspec = "No docstring, see docs." def get_argspec(ob): @@ -141,7 +141,7 @@ argspec = inspect.formatargspec(*inspect.getfullargspec(fob)) if (isinstance(ob, (type, types.MethodType)) or isinstance(ob.__call__, types.MethodType)): - argspec = _self_pat.sub("", argspec) + argspec = _first_param.sub("", argspec) if isinstance(ob.__call__, types.MethodType): doc = ob.__call__.__doc__ @@ -169,8 +169,7 @@ def t2(a, b=None): "(a, b=None)" def t3(a, *args): "(a, *args)" def t4(*args): "(*args)" - def t5(a, *args): "(a, *args)" - def t6(a, b=None, *args, **kw): "(a, b=None, *args, **kw)" + def t5(a, b=None, *args, **kw): "(a, b=None, *args, **kw)" class TC(object): "(ai=None, *b)" @@ -179,13 +178,13 @@ def t2(self, ai, b=None): "(self, ai, b=None)" def t3(self, ai, *args): "(self, ai, *args)" def t4(self, *args): "(self, *args)" - def t5(self, ai, *args): "(self, ai, *args)" - def t6(self, ai, b=None, *args, **kw): "(self, ai, b=None, *args, **kw)" + def t5(self, ai, b=None, *args, **kw): "(self, ai, b=None, *args, **kw)" + def t6(no, self): "(no, self)" @classmethod def cm(cls, a): "(cls, a)" @staticmethod def sm(b): "(b)" - def __call__(self, ci): "(ci)" + def __call__(self, ci): "(self, ci)" tc = TC() @@ -228,19 +227,26 @@ test('SB()', _default_callable_argspec) def test_funcs(): - for func in (t1, t2, t3, t4, t5, t6, TC,): + for func in (t1, t2, t3, t4, t5, TC,): fdoc = func.__doc__ test(func.__name__, fdoc + "\n" + fdoc) - for func in (TC.t1, TC.t2, TC.t3, TC.t4, TC.t5, TC.t6, TC.cm, TC.sm): + for func in (TC.t1, TC.t2, TC.t3, TC.t4, TC.t5, TC.t6, TC.sm, + TC.__call__): fdoc = func.__doc__ test('TC.'+func.__name__, fdoc + "\n" + fdoc) + fdoc = TC.cm.__func__.__doc__ + test('TC.cm.__func__', fdoc + "\n" + fdoc) def test_methods(): - for func in (tc.t1, tc.t2, tc.t3, tc.t4, tc.t5, tc.t6): - fdoc = func.__doc__ - test('tc.'+func.__name__, _self_pat.sub("", fdoc) + "\n" + fdoc) - fdoc = tc.__call__.__doc__ - test('tc', fdoc + "\n" + fdoc) + # test that first parameter is correctly removed from argspec + # using _first_param re to calculate expected masks re errors + for meth, mdoc in ((tc.t1, "()"), (tc.t4, "(*args)"), (tc.t6, "(self)"), + (TC.cm, "(a)"),): + test('tc.'+meth.__name__, mdoc + "\n" + meth.__doc__) + test('tc', "(ci)" + "\n" + tc.__call__.__doc__) + # directly test that re works to delete unicode parameter name + uni = "(A\u0391\u0410\u05d0\u0627\u0905\u1e00\u3042, a)" # various As + assert _first_param.sub('', uni) == '(a)' def test_non_callables(): # expression evaluates, but not to a callable -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 06:16:00 2012 From: python-checkins at python.org (terry.reedy) Date: Mon, 9 Jul 2012 06:16:00 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E2_Issue_12510?= Message-ID: <3WVtWh4Yz4zNQV@mail.python.org> http://hg.python.org/cpython/rev/464c6a50b0ce changeset: 78020:464c6a50b0ce parent: 78018:a4bdb637d818 parent: 78019:eea379307efa user: Terry Jan Reedy date: Mon Jul 09 00:15:14 2012 -0400 summary: Merge with 3.2 Issue 12510 files: Lib/idlelib/CallTips.py | 34 +++++++++++++++++----------- 1 files changed, 20 insertions(+), 14 deletions(-) diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py --- a/Lib/idlelib/CallTips.py +++ b/Lib/idlelib/CallTips.py @@ -117,7 +117,7 @@ return None # The following are used in both get_argspec and tests -_self_pat = re.compile('self\,?\s*') +_first_param = re.compile('(?<=\()\w*\,?\s*') _default_callable_argspec = "No docstring, see docs." def get_argspec(ob): @@ -141,7 +141,7 @@ argspec = inspect.formatargspec(*inspect.getfullargspec(fob)) if (isinstance(ob, (type, types.MethodType)) or isinstance(ob.__call__, types.MethodType)): - argspec = _self_pat.sub("", argspec) + argspec = _first_param.sub("", argspec) if isinstance(ob.__call__, types.MethodType): doc = ob.__call__.__doc__ @@ -169,8 +169,7 @@ def t2(a, b=None): "(a, b=None)" def t3(a, *args): "(a, *args)" def t4(*args): "(*args)" - def t5(a, *args): "(a, *args)" - def t6(a, b=None, *args, **kw): "(a, b=None, *args, **kw)" + def t5(a, b=None, *args, **kw): "(a, b=None, *args, **kw)" class TC(object): "(ai=None, *b)" @@ -179,13 +178,13 @@ def t2(self, ai, b=None): "(self, ai, b=None)" def t3(self, ai, *args): "(self, ai, *args)" def t4(self, *args): "(self, *args)" - def t5(self, ai, *args): "(self, ai, *args)" - def t6(self, ai, b=None, *args, **kw): "(self, ai, b=None, *args, **kw)" + def t5(self, ai, b=None, *args, **kw): "(self, ai, b=None, *args, **kw)" + def t6(no, self): "(no, self)" @classmethod def cm(cls, a): "(cls, a)" @staticmethod def sm(b): "(b)" - def __call__(self, ci): "(ci)" + def __call__(self, ci): "(self, ci)" tc = TC() @@ -228,19 +227,26 @@ test('SB()', _default_callable_argspec) def test_funcs(): - for func in (t1, t2, t3, t4, t5, t6, TC,): + for func in (t1, t2, t3, t4, t5, TC,): fdoc = func.__doc__ test(func.__name__, fdoc + "\n" + fdoc) - for func in (TC.t1, TC.t2, TC.t3, TC.t4, TC.t5, TC.t6, TC.cm, TC.sm): + for func in (TC.t1, TC.t2, TC.t3, TC.t4, TC.t5, TC.t6, TC.sm, + TC.__call__): fdoc = func.__doc__ test('TC.'+func.__name__, fdoc + "\n" + fdoc) + fdoc = TC.cm.__func__.__doc__ + test('TC.cm.__func__', fdoc + "\n" + fdoc) def test_methods(): - for func in (tc.t1, tc.t2, tc.t3, tc.t4, tc.t5, tc.t6): - fdoc = func.__doc__ - test('tc.'+func.__name__, _self_pat.sub("", fdoc) + "\n" + fdoc) - fdoc = tc.__call__.__doc__ - test('tc', fdoc + "\n" + fdoc) + # test that first parameter is correctly removed from argspec + # using _first_param re to calculate expected masks re errors + for meth, mdoc in ((tc.t1, "()"), (tc.t4, "(*args)"), (tc.t6, "(self)"), + (TC.cm, "(a)"),): + test('tc.'+meth.__name__, mdoc + "\n" + meth.__doc__) + test('tc', "(ci)" + "\n" + tc.__call__.__doc__) + # directly test that re works to delete unicode parameter name + uni = "(A\u0391\u0410\u05d0\u0627\u0905\u1e00\u3042, a)" # various As + assert _first_param.sub('', uni) == '(a)' def test_non_callables(): # expression evaluates, but not to a callable -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 10:17:31 2012 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 9 Jul 2012 10:17:31 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Add_verbose_option_for_dia?= =?utf-8?q?gnostics?= Message-ID: <3WVztM0KmszM3h@mail.python.org> http://hg.python.org/cpython/rev/9ded92b7f27c changeset: 78021:9ded92b7f27c user: Raymond Hettinger date: Mon Jul 09 01:17:22 2012 -0700 summary: Add verbose option for diagnostics files: Tools/scripts/highlight.py | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-) diff --git a/Tools/scripts/highlight.py b/Tools/scripts/highlight.py --- a/Tools/scripts/highlight.py +++ b/Tools/scripts/highlight.py @@ -10,7 +10,7 @@ def is_builtin(s): 'Return True if s is the name of a builtin' - return s in vars(__builtins__) + return hasattr(__builtins__, s) def combine_range(lines, start, end): 'Join content from a range of lines between start and end' @@ -161,6 +161,8 @@ help = 'build a complete html webpage') parser.add_argument('-s', '--section', action = 'store_true', help = 'show an HTML section rather than a complete webpage') + parser.add_argument('-v', '--verbose', action = 'store_true', + help = 'display categorized text to stderr') args = parser.parse_args() if args.section and (args.browser or args.complete): @@ -172,6 +174,12 @@ source = f.read() classified_text = analyze_python(source) + if args.verbose: + classified_text = list(classified_text) + for line_upto_token, kind, line_thru_token in classified_text: + sys.stderr.write('%15s: %r\n' % ('leadin', line_upto_token)) + sys.stderr.write('%15s: %r\n\n' % (kind, line_thru_token)) + if args.complete or args.browser: encoded = build_html_page(classified_text, title=sourcefile) elif args.section: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 10:25:58 2012 From: python-checkins at python.org (vinay.sajip) Date: Mon, 9 Jul 2012 10:25:58 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315283=3A_Updated_?= =?utf-8?q?pyvenv_documentation_to_expand_on_activation=2E?= Message-ID: <3WW0466grWzMhd@mail.python.org> http://hg.python.org/cpython/rev/baf5ed391a7f changeset: 78022:baf5ed391a7f parent: 78020:464c6a50b0ce user: Vinay Sajip date: Mon Jul 09 09:24:59 2012 +0100 summary: Issue #15283: Updated pyvenv documentation to expand on activation. files: Doc/library/venv.rst | 60 +++++++++++++++++++++++++++++- Doc/using/scripts.rst | 33 ++++++++++++++++- 2 files changed, 88 insertions(+), 5 deletions(-) diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -50,7 +50,7 @@ The command, if run with ``-h``, will show the available options:: - usage: pyvenv [-h] [--system-site-packages] [--symlink] [--clear] + usage: pyvenv [-h] [--system-site-packages] [--symlinks] [--clear] [--upgrade] ENV_DIR [ENV_DIR ...] Creates virtual Python environments in one or more target directories. @@ -62,7 +62,8 @@ -h, --help show this help message and exit --system-site-packages Give access to the global site-packages dir to the virtual environment. - --symlink Attempt to symlink rather than copy. + --symlinks Try to use symlinks rather than copies, when symlinks + are not the default for the platform. --clear Delete the environment directory if it already exists. If not specified and the directory exists, an error is raised. @@ -79,6 +80,56 @@ Multiple paths can be given to ``pyvenv``, in which case an identical virtualenv will be created, according to the given options, at each provided path. +Once a venv has been created, it can be "activated" using a script in the +venv's binary directory. The invocation of the script is platform-specific: on +a Posix platform, you would typically do:: + + $ source /bin/activate + +whereas on Windows, you might do:: + + c:\> /Scripts/activate + +if you are using the ``cmd.exe`` shell, or perhaps:: + + PS C:\> /Scripts/Activate.ps1 + +if you use PowerShell. + +You don't specifically *need* to activate an environment; activation just +prepends the venv's binary directory to your path, so that "python" invokes the +venv's Python interpreter and you can run installed scripts without having to +use their full path. However, all scripts installed in a venv should be +runnable without activating it, and run with the venv's Python automatically. + +You can deactivate a venv by typing "deactivate" in your shell. The exact +mechanism is platform-specific: for example, the Bash activation script defines +a "deactivate" function, whereas on Windows there are separate scripts called +``deactivate.bat`` and ``Deactivate.ps1`` which are installed when the venv is +created. + +.. note:: A virtual environment (also called a ``venv``) is a Python + environment such that the Python interpreter, libraries and scripts + installed into it are isolated from those installed in other virtual + environments, and (by default) any libraries installed in a "system" Python, + i.e. one which is installed as part of your operating system. + + A venv is a directory tree which contains Python executable files and + other files which indicate that it is a venv. + + Common installation tools such as ``distribute`` and ``pip`` work as + expected with venvs - i.e. when a venv is active, they install Python + packages into the venv without needing to be told to do so explicitly. + + When a venv is active (i.e. the venv's Python interpreter is running), the + attributes :attr:`sys.prefix` and :attr:`sys.exec_prefix` point to the base + directory of the venv, whereas :attr:`sys.base_prefix` and + :attr:`sys.base_exec_prefix` point to the non-venv Python installation + which was used to create the venv. If a venv is not active, then + :attr:`sys.prefix` is the same as :attr:`sys.base_prefix` and + :attr:`sys.exec_prefix` is the same as :attr:`sys.base_exec_prefix` (they + all point to a non-venv Python installation). + API --- @@ -105,7 +156,10 @@ e.g. ``pythonw.exe``), rather than copying. Defaults to ``True`` on Linux and Unix systems, but ``False`` on Windows and Mac OS X. - .. XXX it also takes "upgrade"! + * ``upgrade`` -- a Boolean value which, if True, will upgrade an existing + environment with the running Python - for use when that Python has been + upgraded in-place (defaults to ``False``). + Creators of third-party virtual environment tools will be free to use the diff --git a/Doc/using/scripts.rst b/Doc/using/scripts.rst --- a/Doc/using/scripts.rst +++ b/Doc/using/scripts.rst @@ -33,7 +33,7 @@ The command, if run with ``-h``, will show the available options:: - usage: pyvenv [-h] [--system-site-packages] [--symlink] [--clear] + usage: pyvenv [-h] [--system-site-packages] [--symlinks] [--clear] [--upgrade] ENV_DIR [ENV_DIR ...] Creates virtual Python environments in one or more target directories. @@ -45,7 +45,8 @@ -h, --help show this help message and exit --system-site-packages Give access to the global site-packages dir to the virtual environment. - --symlink Attempt to symlink rather than copy. + --symlinks Try to use symlinks rather than copies, when symlinks + are not the default for the platform. --clear Delete the environment directory if it already exists. If not specified and the directory exists, an error is raised. @@ -63,6 +64,34 @@ virtualenv will be created, according to the given options, at each provided path. +Once a venv has been created, it can be "activated" using a script in the +venv's binary directory. The invocation of the script is platform-specific: on +a Posix platform, you would typically do:: + + $ source /bin/activate + +whereas on Windows, you might do:: + + c:\> /Scripts/activate + +if you are using the ``cmd.exe`` shell, or perhaps:: + + PS C:\> /Scripts/Activate.ps1 + +if you use PowerShell. + +You don't specifically *need* to activate an environment; activation just +prepends the venv's binary directory to your path, so that "python" invokes the +venv's Python interpreter and you can run installed scripts without having to +use their full path. However, all scripts installed in a venv should be +runnable without activating it, and run with the venv's Python automatically. + +You can deactivate a venv by typing "deactivate" in your shell. The exact +mechanism is platform-specific: for example, the Bash activation script defines +a "deactivate" function, whereas on Windows there are separate scripts called +``deactivate.bat`` and ``Deactivate.ps1`` which are installed when the venv is +created. + .. note:: A virtual environment (also called a ``venv``) is a Python environment such that the Python interpreter, libraries and scripts installed into it are isolated from those installed in other virtual -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 10:26:00 2012 From: python-checkins at python.org (vinay.sajip) Date: Mon, 9 Jul 2012 10:26:00 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merged_upstream_changes=2E?= Message-ID: <3WW0484qV0zNlN@mail.python.org> http://hg.python.org/cpython/rev/867adc562169 changeset: 78023:867adc562169 parent: 78022:baf5ed391a7f parent: 78021:9ded92b7f27c user: Vinay Sajip date: Mon Jul 09 09:25:46 2012 +0100 summary: Merged upstream changes. files: Tools/scripts/highlight.py | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-) diff --git a/Tools/scripts/highlight.py b/Tools/scripts/highlight.py --- a/Tools/scripts/highlight.py +++ b/Tools/scripts/highlight.py @@ -10,7 +10,7 @@ def is_builtin(s): 'Return True if s is the name of a builtin' - return s in vars(__builtins__) + return hasattr(__builtins__, s) def combine_range(lines, start, end): 'Join content from a range of lines between start and end' @@ -161,6 +161,8 @@ help = 'build a complete html webpage') parser.add_argument('-s', '--section', action = 'store_true', help = 'show an HTML section rather than a complete webpage') + parser.add_argument('-v', '--verbose', action = 'store_true', + help = 'display categorized text to stderr') args = parser.parse_args() if args.section and (args.browser or args.complete): @@ -172,6 +174,12 @@ source = f.read() classified_text = analyze_python(source) + if args.verbose: + classified_text = list(classified_text) + for line_upto_token, kind, line_thru_token in classified_text: + sys.stderr.write('%15s: %r\n' % ('leadin', line_upto_token)) + sys.stderr.write('%15s: %r\n\n' % (kind, line_thru_token)) + if args.complete or args.browser: encoded = build_html_page(classified_text, title=sourcefile) elif args.section: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 11:37:16 2012 From: python-checkins at python.org (vinay.sajip) Date: Mon, 9 Jul 2012 11:37:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Added_cross-references_to_?= =?utf-8?q?venv_definition=2E?= Message-ID: <3WW1fN5xhwzNpd@mail.python.org> http://hg.python.org/cpython/rev/9e3523f93254 changeset: 78024:9e3523f93254 user: Vinay Sajip date: Mon Jul 09 10:37:01 2012 +0100 summary: Added cross-references to venv definition. files: Doc/library/sys.rst | 25 ++++++++++++++----------- Doc/library/venv.rst | 4 +++- Doc/using/scripts.rst | 28 +++------------------------- 3 files changed, 20 insertions(+), 37 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -32,10 +32,11 @@ .. data:: base_exec_prefix Set during Python startup, before ``site.py`` is run, to the same value as - :data:`exec_prefix`. If not running in a virtual environment, the values - will stay the same; if ``site.py`` finds that a virtual environment is in - use, the values of :data:`prefix` and :data:`exec_prefix` will be changed to - point to the virtual environment, whereas :data:`base_prefix` and + :data:`exec_prefix`. If not running in a + :ref:`virtual environment `, the values will stay the same; if + ``site.py`` finds that a virtual environment is in use, the values of + :data:`prefix` and :data:`exec_prefix` will be changed to point to the + virtual environment, whereas :data:`base_prefix` and :data:`base_exec_prefix` will remain pointing to the base Python installation (the one which the virtual environment was created from). @@ -45,7 +46,7 @@ .. data:: base_prefix Set during Python startup, before ``site.py`` is run, to the same value as - :data:`prefix`. If not running in a virtual environment, the values + :data:`prefix`. If not running in a :ref:`virtual environment `, the values will stay the same; if ``site.py`` finds that a virtual environment is in use, the values of :data:`prefix` and :data:`exec_prefix` will be changed to point to the virtual environment, whereas :data:`base_prefix` and @@ -241,9 +242,10 @@ installed in :file:`{exec_prefix}/lib/python{X.Y}/lib-dynload`, where *X.Y* is the version number of Python, for example ``3.2``. - .. note:: If a virtual environment is in effect, this value will be changed - in ``site.py`` to point to the virtual environment. The value for the - Python installation will still be available, via :data:`base_exec_prefix`. + .. note:: If a :ref:`virtual environment ` is in effect, this + value will be changed in ``site.py`` to point to the virtual environment. + The value for the Python installation will still be available, via + :data:`base_exec_prefix`. .. data:: executable @@ -865,9 +867,10 @@ stored in :file:`{prefix}/include/python{X.Y}`, where *X.Y* is the version number of Python, for example ``3.2``. - .. note:: If a virtual environment is in effect, this value will be changed - in ``site.py`` to point to the virtual environment. The value for the - Python installation will still be available, via :data:`base_prefix`. + .. note:: If a :ref:`virtual environment ` is in effect, this + value will be changed in ``site.py`` to point to the virtual + environment. The value for the Python installation will still be + available, via :data:`base_prefix`. .. data:: ps1 diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -88,7 +88,7 @@ whereas on Windows, you might do:: - c:\> /Scripts/activate + C:\> /Scripts/activate if you are using the ``cmd.exe`` shell, or perhaps:: @@ -108,6 +108,8 @@ ``deactivate.bat`` and ``Deactivate.ps1`` which are installed when the venv is created. +.. _venv-def: + .. note:: A virtual environment (also called a ``venv``) is a Python environment such that the Python interpreter, libraries and scripts installed into it are isolated from those installed in other virtual diff --git a/Doc/using/scripts.rst b/Doc/using/scripts.rst --- a/Doc/using/scripts.rst +++ b/Doc/using/scripts.rst @@ -6,8 +6,8 @@ pyvenv - Creating virtual environments -------------------------------------- -Creation of virtual environments is done by executing the ``pyvenv`` -script:: +Creation of :ref:`virtual environments ` is done by executing the +``pyvenv`` script:: pyvenv /path/to/new/virtual/environment @@ -72,7 +72,7 @@ whereas on Windows, you might do:: - c:\> /Scripts/activate + C:\> /Scripts/activate if you are using the ``cmd.exe`` shell, or perhaps:: @@ -92,25 +92,3 @@ ``deactivate.bat`` and ``Deactivate.ps1`` which are installed when the venv is created. -.. note:: A virtual environment (also called a ``venv``) is a Python - environment such that the Python interpreter, libraries and scripts - installed into it are isolated from those installed in other virtual - environments, and (by default) any libraries installed in a "system" Python, - i.e. one which is installed as part of your operating system. - - A venv is a directory tree which contains Python executable files and - other files which indicate that it is a venv. - - Common installation tools such as ``distribute`` and ``pip`` work as - expected with venvs - i.e. when a venv is active, they install Python - packages into the venv without needing to be told to do so explicitly. - - When a venv is active (i.e. the venv's Python interpreter is running), the - attributes :attr:`sys.prefix` and :attr:`sys.exec_prefix` point to the base - directory of the venv, whereas :attr:`sys.base_prefix` and - :attr:`sys.base_exec_prefix` point to the non-venv Python installation - which was used to create the venv. If a venv is not active, then - :attr:`sys.prefix` is the same as :attr:`sys.base_prefix` and - :attr:`sys.exec_prefix` is the same as :attr:`sys.base_exec_prefix` (they - all point to a non-venv Python installation). - -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 19:24:43 2012 From: python-checkins at python.org (brett.cannon) Date: Mon, 9 Jul 2012 19:24:43 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315256=3A_Re-use_t?= =?utf-8?q?he_ImportError_exception_message_as_defined_by?= Message-ID: <3WWD1l5Nh3zNdW@mail.python.org> http://hg.python.org/cpython/rev/75831951a6b5 changeset: 78025:75831951a6b5 user: Brett Cannon date: Mon Jul 09 13:24:34 2012 -0400 summary: Issue #15256: Re-use the ImportError exception message as defined by importlib._bootstrap in imp to fix a grammatical mistake. Thanks to Marc Abramowitz for the patch. files: Lib/imp.py | 2 +- Misc/NEWS | 2 ++ 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/imp.py b/Lib/imp.py --- a/Lib/imp.py +++ b/Lib/imp.py @@ -230,7 +230,7 @@ continue break # Break out of outer loop when breaking out of inner loop. else: - raise ImportError('No module name {!r}'.format(name), name=name) + raise ImportError(_bootstrap._ERR_MSG.format(name), name=name) encoding = None if mode == 'U': diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -31,6 +31,8 @@ Library ------- +- Issue #15256: Grammatical mistake in exception raised by imp.find_module(). + - Issue #5931: wsgiref environ variable SERVER_SOFTWARE will specify an implementation specific term like Cpython, Jython instead of generic "Python" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 19:58:17 2012 From: python-checkins at python.org (brett.cannon) Date: Mon, 9 Jul 2012 19:58:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315056=3A_imp=2Eca?= =?utf-8?q?che=5Ffrom=5Fsource=28=29_and_source=5Ffrom=5Fcache=28=29_raise?= Message-ID: <3WWDmT3rPZzNv4@mail.python.org> http://hg.python.org/cpython/rev/e86330669bb5 changeset: 78026:e86330669bb5 user: Brett Cannon date: Mon Jul 09 13:58:07 2012 -0400 summary: Issue #15056: imp.cache_from_source() and source_from_cache() raise NotimplementedError when sys.implementation.cache_tag is None. Thanks to Pranav Ravichandran for taking an initial stab at the patch. files: Doc/library/imp.rst | 21 +- Lib/imp.py | 5 +- Lib/importlib/_bootstrap.py | 21 +- Lib/test/test_imp.py | 18 + Misc/NEWS | 3 + Python/importlib.h | 7621 +++++++++++----------- 6 files changed, 3881 insertions(+), 3808 deletions(-) diff --git a/Doc/library/imp.rst b/Doc/library/imp.rst --- a/Doc/library/imp.rst +++ b/Doc/library/imp.rst @@ -180,14 +180,19 @@ source *path*. For example, if *path* is ``/foo/bar/baz.py`` the return value would be ``/foo/bar/__pycache__/baz.cpython-32.pyc`` for Python 3.2. The ``cpython-32`` string comes from the current magic tag (see - :func:`get_tag`). The returned path will end in ``.pyc`` when - ``__debug__`` is True or ``.pyo`` for an optimized Python + :func:`get_tag`; if :attr:`sys.implementation.cache_tag` is not defined then + :exc:`NotImplementedError` will be raised). The returned path will end in + ``.pyc`` when ``__debug__`` is True or ``.pyo`` for an optimized Python (i.e. ``__debug__`` is False). By passing in True or False for *debug_override* you can override the system's value for ``__debug__`` for extension selection. *path* need not exist. + .. versionchanged:: 3.3 + If :attr:`sys.implementation.cache_tag` is ``None``, then + :exc:`NotImplementedError` is raised. + .. function:: source_from_cache(path) @@ -195,7 +200,13 @@ file path. For example, if *path* is ``/foo/bar/__pycache__/baz.cpython-32.pyc`` the returned path would be ``/foo/bar/baz.py``. *path* need not exist, however if it does not conform - to :pep:`3147` format, a ``ValueError`` is raised. + to :pep:`3147` format, a ``ValueError`` is raised. If + :attr:`sys.implementation.cache_tag` is not defined, + :exc:`NotImplementedError` is raised. + + .. versionchanged:: 3.3 + Raise :exc:`NotImplementedError` when + :attr:`sys.implementation.cache_tag` is not defined. .. function:: get_tag() @@ -203,6 +214,10 @@ Return the :pep:`3147` magic tag string matching this version of Python's magic number, as returned by :func:`get_magic`. + .. note:: + You may use :attr:`sys.implementation.cache_tag` directly starting + in Python 3.3. + The following functions help interact with the import system's internal locking mechanism. Locking semantics of imports are an implementation diff --git a/Lib/imp.py b/Lib/imp.py --- a/Lib/imp.py +++ b/Lib/imp.py @@ -58,9 +58,12 @@ The .pyc/.pyo file does not need to exist; this simply returns the path to the .py file calculated to correspond to the .pyc/.pyo file. If path does - not conform to PEP 3147 format, ValueError will be raised. + not conform to PEP 3147 format, ValueError will be raised. If + sys.implementation.cache_tag is None then NotImplementedError is raised. """ + if sys.implementation.cache_tag is None: + raise NotImplementedError('sys.implementation.cache_tag is None') head, pycache_filename = os.path.split(path) head, pycache = os.path.split(head) if pycache != _bootstrap._PYCACHE: diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -321,6 +321,8 @@ If debug_override is not None, then it must be a boolean and is taken as the value of __debug__ instead. + If sys.implementation.cache_tag is None then NotImplementedError is raised. + """ debug = __debug__ if debug_override is None else debug_override if debug: @@ -329,7 +331,10 @@ suffixes = OPTIMIZED_BYTECODE_SUFFIXES head, tail = _path_split(path) base_filename, sep, _ = tail.partition('.') - filename = ''.join([base_filename, sep, _TAG, suffixes[0]]) + tag = sys.implementation.cache_tag + if tag is None: + raise NotImplementedError('sys.implementation.cache_tag is None') + filename = ''.join([base_filename, sep, tag, suffixes[0]]) return _path_join(head, _PYCACHE, filename) @@ -649,7 +654,10 @@ code_object = self.get_code(name) module.__file__ = self.get_filename(name) if not sourceless: - module.__cached__ = cache_from_source(module.__file__) + try: + module.__cached__ = cache_from_source(module.__file__) + except NotImplementedError: + module.__cached__ = module.__file__ else: module.__cached__ = module.__file__ module.__package__ = name @@ -718,9 +726,12 @@ """ source_path = self.get_filename(fullname) - bytecode_path = cache_from_source(source_path) source_mtime = None - if bytecode_path is not None: + try: + bytecode_path = cache_from_source(source_path) + except NotImplementedError: + bytecode_path = None + else: try: st = self.path_stats(source_path) except NotImplementedError: @@ -1417,7 +1428,6 @@ _MAGIC_NUMBER = None # Set in _setup() -_TAG = None # Set in _setup() def _setup(sys_module, _imp_module): @@ -1479,7 +1489,6 @@ # Constants setattr(self_module, '_relax_case', _make_relax_case()) setattr(self_module, '_MAGIC_NUMBER', _imp_module.get_magic()) - setattr(self_module, '_TAG', sys.implementation.cache_tag) if builtin_os == 'nt': SOURCE_SUFFIXES.append('.pyw') diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py --- a/Lib/test/test_imp.py +++ b/Lib/test/test_imp.py @@ -231,6 +231,8 @@ tag = imp.get_tag() + @unittest.skipUnless(sys.implementation.cache_tag is not None, + 'requires sys.implementation.cache_tag not be None') def test_cache_from_source(self): # Given the path to a .py file, return the path to its PEP 3147 # defined .pyc file (i.e. under __pycache__). @@ -239,6 +241,12 @@ 'qux.{}.pyc'.format(self.tag)) self.assertEqual(imp.cache_from_source(path, True), expect) + def test_cache_from_source_no_cache_tag(self): + # Non cache tag means NotImplementedError. + with support.swap_attr(sys.implementation, 'cache_tag', None): + with self.assertRaises(NotImplementedError): + imp.cache_from_source('whatever.py') + def test_cache_from_source_no_dot(self): # Directory with a dot, filename without dot. path = os.path.join('foo.bar', 'file') @@ -283,6 +291,9 @@ imp.cache_from_source('\\foo\\bar\\baz/qux.py', True), '\\foo\\bar\\baz\\__pycache__\\qux.{}.pyc'.format(self.tag)) + @unittest.skipUnless(sys.implementation.cache_tag is not None, + 'requires sys.implementation.cache_tag to not be ' + 'None') def test_source_from_cache(self): # Given the path to a PEP 3147 defined .pyc file, return the path to # its source. This tests the good path. @@ -291,6 +302,13 @@ expect = os.path.join('foo', 'bar', 'baz', 'qux.py') self.assertEqual(imp.source_from_cache(path), expect) + def test_source_from_cache_no_cache_tag(self): + # If sys.implementation.cache_tag is None, raise NotImplementedError. + path = os.path.join('blah', '__pycache__', 'whatever.pyc') + with support.swap_attr(sys.implementation, 'cache_tag', None): + with self.assertRaises(NotImplementedError): + imp.source_from_cache(path) + def test_source_from_cache_bad_path(self): # When the path to a pyc file is not in PEP 3147 format, a ValueError # is raised. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -31,6 +31,9 @@ Library ------- +- Issue #15056: imp.cache_from_source() and source_from_cache() raise + NotImplementedError when sys.implementation.cache_tag is set to None. + - Issue #15256: Grammatical mistake in exception raised by imp.find_module(). - Issue #5931: wsgiref environ variable SERVER_SOFTWARE will specify an diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 20:10:31 2012 From: python-checkins at python.org (brett.cannon) Date: Mon, 9 Jul 2012 20:10:31 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315288=3A_Clarify_?= =?utf-8?q?that_pkgutil=2Ewalk=5Fpackages=28=29_and_friends_will_no?= Message-ID: <3WWF2b4bBZzNxg@mail.python.org> http://hg.python.org/cpython/rev/96f7926ea444 changeset: 78027:96f7926ea444 user: Brett Cannon date: Mon Jul 09 14:10:23 2012 -0400 summary: Issue #15288: Clarify that pkgutil.walk_packages() and friends will no longer work as expected in Python 3.3 as importlib's loaders do not implement the non-standard iter_modules() method. Also link to the term "loader" in the requisite notes to help make it clearer what has happened. files: Doc/library/pkgutil.rst | 17 +++++++++++++---- Misc/NEWS | 5 +++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Doc/library/pkgutil.rst b/Doc/library/pkgutil.rst --- a/Doc/library/pkgutil.rst +++ b/Doc/library/pkgutil.rst @@ -139,8 +139,13 @@ *prefix* is a string to output on the front of every module name on output. .. note:: - Only works for importers which define a ``iter_modules()`` method, which - is non-standard but implemented by classes defined in this module. + Only works wtih a :term:`loader` which defines a ``iter_modules()`` + method, which is non-standard but implemented by classes defined in this + module. + + .. versionchanged:: 3.3 + As of Python 3.3, the import system provides loaders by default, but they + do not include the ``iter_modules()`` method required by this function. .. function:: walk_packages(path=None, prefix='', onerror=None) @@ -171,8 +176,12 @@ walk_packages(ctypes.__path__, ctypes.__name__ + '.') .. note:: - Only works for importers which define a ``iter_modules()`` method, which - is non-standard but implemented by classes defined in this module. + Only works for a :term:`loader` which define a ``iter_modules()`` method, + which is non-standard but implemented by classes defined in this module. + + .. versionchanged:: 3.3 + As of Python 3.3, the import system provides loaders by default, but they + do not include the ``iter_modules()`` method required by this function. .. function:: get_data(package, resource) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -101,6 +101,11 @@ Documentation ------------- +- Issue #15288: Link to the term "loader" in notes in pkgutil about how things + won't work as expected in Python 3.3 and mark the requisite functions as + "changed" since they will no longer work with modules directly imported by + import itself. + - Issue #13557: Clarify effect of giving two different namespaces to exec or execfile(). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 20:15:39 2012 From: python-checkins at python.org (brett.cannon) Date: Mon, 9 Jul 2012 20:15:39 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Add_a_note_about_pkgutil_a?= =?utf-8?q?nd_how_some_things_do_not_work_in_the_face_of_PEP_302?= Message-ID: <3WWF8W0XCHzNyb@mail.python.org> http://hg.python.org/cpython/rev/43f2ada6ee87 changeset: 78028:43f2ada6ee87 user: Brett Cannon date: Mon Jul 09 14:15:32 2012 -0400 summary: Add a note about pkgutil and how some things do not work in the face of PEP 302 permeating throughout import. files: Doc/whatsnew/3.3.rst | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -1721,7 +1721,7 @@ * Because ``None`` is now inserted into :attr:`sys.path_importer_cache`, if you are clearing out entries in the dictionary of paths that do not have a finder, you will need to remove keys paired with values of ``None`` **and** - :class:`imp.NullImporter` to be backwards-compatible. This will need to extra + :class:`imp.NullImporter` to be backwards-compatible. This will lead to extra overhead on older versions of Python that re-insert ``None`` into :attr:`sys.path_importer_cache` where it repesents the use of implicit finders, but semantically it should not change anything. @@ -1731,6 +1731,12 @@ both the modification time and size of the source file the bytecode file was compiled from. +* :func:`pkgutil.iter_modules` and :func:`pkgutil.walk_packages` no longer work + with modules imported using the default import system. Both functions have + always relied on a non-standard method (``iter_modules()``) to be defined on + loaders to work and the import system now always provides a loader for + modules but does not implement the non-standard method. + Porting C code -------------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 20:22:20 2012 From: python-checkins at python.org (brett.cannon) Date: Mon, 9 Jul 2012 20:22:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315242=3A_Have_PyI?= =?utf-8?q?mport=5FGetMagicTag=28=29_return_a_const_char_*?= Message-ID: <3WWFJD5yXTzP2q@mail.python.org> http://hg.python.org/cpython/rev/ee01fd98b5b0 changeset: 78029:ee01fd98b5b0 user: Brett Cannon date: Mon Jul 09 14:22:12 2012 -0400 summary: Issue #15242: Have PyImport_GetMagicTag() return a const char * defined in sysmodule.c instead of straight out of a Unicode object. Thanks to Amaury Forgeot d'Arc for noticing the bug and Eric Snow for writing the patch. files: Doc/c-api/import.rst | 3 ++- Python/import.c | 18 ++++-------------- Python/sysmodule.c | 32 ++++++++++++++++++-------------- 3 files changed, 24 insertions(+), 29 deletions(-) diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -178,7 +178,8 @@ .. c:function:: const char * PyImport_GetMagicTag() Return the magic tag string for :pep:`3147` format Python bytecode file - names. + names. Keep in mind that the value at ``sys.implementation.cache_tag`` is + authoritative and should be used instead of this function. .. versionadded:: 3.2 diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -116,7 +116,7 @@ */ #define MAGIC (3230 | ((long)'\r'<<16) | ((long)'\n'<<24)) #define CACHEDIR "__pycache__" -/* Current magic word and string tag as globals. */ +/* Current magic word as global. */ static long pyc_magic = MAGIC; /* See _PyImport_FixupExtensionObject() below */ @@ -520,22 +520,12 @@ } +extern const char * _PySys_ImplCacheTag; + const char * PyImport_GetMagicTag(void) { - PyObject *impl, *tag; - const char *raw_tag; - - /* We could also pull it from imp or importlib. */ - impl = PySys_GetObject("implementation"); - if (impl == NULL) - return NULL; - tag = PyObject_GetAttrString(impl, "cache_tag"); - if (tag == NULL) - return NULL; - raw_tag = PyUnicode_DATA(tag); - Py_DECREF(tag); - return raw_tag; + return _PySys_ImplCacheTag; } diff --git a/Python/sysmodule.c b/Python/sysmodule.c --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1478,6 +1478,22 @@ return version_info; } +/* sys.implementation values */ +#define NAME "cpython" +const char *_PySys_ImplName = NAME; +#define QUOTE(arg) #arg +#define STRIFY(name) QUOTE(name) +#define MAJOR STRIFY(PY_MAJOR_VERSION) +#define MINOR STRIFY(PY_MINOR_VERSION) +#define TAG NAME "-" MAJOR MINOR; +const char *_PySys_ImplCacheTag = TAG; +#undef NAME +#undef QUOTE +#undef STRIFY +#undef MAJOR +#undef MINOR +#undef TAG + static PyObject * make_impl_info(PyObject *version_info) { @@ -1490,13 +1506,7 @@ /* populate the dict */ -#define NAME "cpython" -#define QUOTE(arg) #arg -#define STRIFY(name) QUOTE(name) -#define MAJOR STRIFY(PY_MAJOR_VERSION) -#define MINOR STRIFY(PY_MINOR_VERSION) -#define TAG NAME "-" MAJOR MINOR - value = PyUnicode_FromString(NAME); + value = PyUnicode_FromString(_PySys_ImplName); if (value == NULL) goto error; res = PyDict_SetItemString(impl_info, "name", value); @@ -1504,19 +1514,13 @@ if (res < 0) goto error; - value = PyUnicode_FromString(TAG); + value = PyUnicode_FromString(_PySys_ImplCacheTag); if (value == NULL) goto error; res = PyDict_SetItemString(impl_info, "cache_tag", value); Py_DECREF(value); if (res < 0) goto error; -#undef NAME -#undef QUOTE -#undef STRIFY -#undef MAJOR -#undef MINOR -#undef TAG res = PyDict_SetItemString(impl_info, "version", version_info); if (res < 0) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 20:40:45 2012 From: python-checkins at python.org (brett.cannon) Date: Mon, 9 Jul 2012 20:40:45 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Use_the_proper_term=2E?= Message-ID: <3WWFjT4MK4zNys@mail.python.org> http://hg.python.org/cpython/rev/db2393edd0c5 changeset: 78030:db2393edd0c5 user: Brett Cannon date: Mon Jul 09 14:40:38 2012 -0400 summary: Use the proper term. files: Doc/library/pkgutil.rst | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/library/pkgutil.rst b/Doc/library/pkgutil.rst --- a/Doc/library/pkgutil.rst +++ b/Doc/library/pkgutil.rst @@ -139,12 +139,12 @@ *prefix* is a string to output on the front of every module name on output. .. note:: - Only works wtih a :term:`loader` which defines a ``iter_modules()`` + Only works with a :term:`finder` which defines a ``iter_modules()`` method, which is non-standard but implemented by classes defined in this module. .. versionchanged:: 3.3 - As of Python 3.3, the import system provides loaders by default, but they + As of Python 3.3, the import system provides finders by default, but they do not include the ``iter_modules()`` method required by this function. @@ -176,11 +176,11 @@ walk_packages(ctypes.__path__, ctypes.__name__ + '.') .. note:: - Only works for a :term:`loader` which define a ``iter_modules()`` method, + Only works for a :term:`finder` which define a ``iter_modules()`` method, which is non-standard but implemented by classes defined in this module. .. versionchanged:: 3.3 - As of Python 3.3, the import system provides loaders by default, but they + As of Python 3.3, the import system provides finders by default, but they do not include the ``iter_modules()`` method required by this function. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 20:53:18 2012 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 9 Jul 2012 20:53:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzEzNTMy?= =?utf-8?q?=3A_Check_that_arguments_to_sys=2Estdout=2Ewrite_are_strings=2E?= Message-ID: <3WWFzy2kjKzNtF@mail.python.org> http://hg.python.org/cpython/rev/422242dbce30 changeset: 78031:422242dbce30 branch: 3.2 parent: 78019:eea379307efa user: Martin v. L?wis date: Mon Jul 09 20:46:11 2012 +0200 summary: Issue #13532: Check that arguments to sys.stdout.write are strings. files: Lib/idlelib/NEWS.txt | 2 ++ Lib/idlelib/PyShell.py | 2 ++ Lib/idlelib/run.py | 24 +++++++++++++++++++++--- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,6 +1,8 @@ What's New in IDLE 3.2.4? ========================= +- Issue #13532: Check that arguments to sys.stdout.write are strings. + - Issue # 12510: Attempt to get certain tool tips no longer crashes IDLE. Erroneous tool tips have been corrected. Default added for callables. diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -1242,6 +1242,8 @@ self.encoding = encoding def write(self, s): + if not isinstance(s, str): + raise TypeError('must be str, not ' + type(s).__name__) self.shell.write(s, self.tags) def writelines(self, lines): diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -1,4 +1,5 @@ import sys +import io import linecache import time import socket @@ -244,6 +245,23 @@ quitting = True thread.interrupt_main() +class _RPCFile(io.TextIOBase): + """Wrapper class for the RPC proxy to typecheck arguments + that may not support pickling.""" + + def __init__(self, rpc): + super.__setattr__(self, 'rpc', rpc) + + def __getattr__(self, name): + return getattr(self.rpc, name) + + def __setattr__(self, name, value): + return setattr(self.rpc, name, value) + + def write(self, s): + if not isinstance(s, str): + raise TypeError('must be str, not ' + type(s).__name__) + return self.rpc.write(s) class MyHandler(rpc.RPCHandler): @@ -251,9 +269,9 @@ """Override base method""" executive = Executive(self) self.register("exec", executive) - sys.stdin = self.console = self.get_remote_proxy("stdin") - sys.stdout = self.get_remote_proxy("stdout") - sys.stderr = self.get_remote_proxy("stderr") + sys.stdin = self.console = _RPCFile(self.get_remote_proxy("stdin")) + sys.stdout = _RPCFile(self.get_remote_proxy("stdout")) + sys.stderr = _RPCFile(self.get_remote_proxy("stderr")) # page help() text to shell. import pydoc # import must be done here to capture i/o binding pydoc.pager = pydoc.plainpager -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 20:53:20 2012 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 9 Jul 2012 20:53:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4y?= Message-ID: <3WWG001StbzNys@mail.python.org> http://hg.python.org/cpython/rev/4915cd0cb7af changeset: 78032:4915cd0cb7af parent: 78029:ee01fd98b5b0 parent: 78031:422242dbce30 user: Martin v. L?wis date: Mon Jul 09 20:48:56 2012 +0200 summary: merge 3.2 files: Lib/idlelib/NEWS.txt | 2 ++ Lib/idlelib/PyShell.py | 2 ++ Lib/idlelib/run.py | 24 +++++++++++++++++++++--- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,6 +1,8 @@ What's New in IDLE 3.3.0? ========================= +- Issue #13532: Check that arguments to sys.stdout.write are strings. + - Issue # 12510: Attempt to get certain tool tips no longer crashes IDLE. Erroneous tool tips have been corrected. Default added for callables. diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -1258,6 +1258,8 @@ self.encoding = encoding def write(self, s): + if not isinstance(s, str): + raise TypeError('must be str, not ' + type(s).__name__) self.shell.write(s, self.tags) def writelines(self, lines): diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -1,4 +1,5 @@ import sys +import io import linecache import time import socket @@ -257,6 +258,23 @@ quitting = True thread.interrupt_main() +class _RPCFile(io.TextIOBase): + """Wrapper class for the RPC proxy to typecheck arguments + that may not support pickling.""" + + def __init__(self, rpc): + super.__setattr__(self, 'rpc', rpc) + + def __getattr__(self, name): + return getattr(self.rpc, name) + + def __setattr__(self, name, value): + return setattr(self.rpc, name, value) + + def write(self, s): + if not isinstance(s, str): + raise TypeError('must be str, not ' + type(s).__name__) + return self.rpc.write(s) class MyHandler(rpc.RPCHandler): @@ -264,9 +282,9 @@ """Override base method""" executive = Executive(self) self.register("exec", executive) - sys.stdin = self.console = self.get_remote_proxy("stdin") - sys.stdout = self.get_remote_proxy("stdout") - sys.stderr = self.get_remote_proxy("stderr") + sys.stdin = self.console = _RPCFile(self.get_remote_proxy("stdin")) + sys.stdout = _RPCFile(self.get_remote_proxy("stdout")) + sys.stderr = _RPCFile(self.get_remote_proxy("stderr")) sys.displayhook = rpc.displayhook # page help() text to shell. import pydoc # import must be done here to capture i/o binding -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 20:53:21 2012 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 9 Jul 2012 20:53:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_merge_heads?= Message-ID: <3WWG015lLFzNys@mail.python.org> http://hg.python.org/cpython/rev/3a6b6434ac33 changeset: 78033:3a6b6434ac33 parent: 78030:db2393edd0c5 parent: 78032:4915cd0cb7af user: Martin v. L?wis date: Mon Jul 09 20:51:45 2012 +0200 summary: merge heads files: Lib/idlelib/NEWS.txt | 2 ++ Lib/idlelib/PyShell.py | 2 ++ Lib/idlelib/run.py | 24 +++++++++++++++++++++--- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,6 +1,8 @@ What's New in IDLE 3.3.0? ========================= +- Issue #13532: Check that arguments to sys.stdout.write are strings. + - Issue # 12510: Attempt to get certain tool tips no longer crashes IDLE. Erroneous tool tips have been corrected. Default added for callables. diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -1258,6 +1258,8 @@ self.encoding = encoding def write(self, s): + if not isinstance(s, str): + raise TypeError('must be str, not ' + type(s).__name__) self.shell.write(s, self.tags) def writelines(self, lines): diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -1,4 +1,5 @@ import sys +import io import linecache import time import socket @@ -257,6 +258,23 @@ quitting = True thread.interrupt_main() +class _RPCFile(io.TextIOBase): + """Wrapper class for the RPC proxy to typecheck arguments + that may not support pickling.""" + + def __init__(self, rpc): + super.__setattr__(self, 'rpc', rpc) + + def __getattr__(self, name): + return getattr(self.rpc, name) + + def __setattr__(self, name, value): + return setattr(self.rpc, name, value) + + def write(self, s): + if not isinstance(s, str): + raise TypeError('must be str, not ' + type(s).__name__) + return self.rpc.write(s) class MyHandler(rpc.RPCHandler): @@ -264,9 +282,9 @@ """Override base method""" executive = Executive(self) self.register("exec", executive) - sys.stdin = self.console = self.get_remote_proxy("stdin") - sys.stdout = self.get_remote_proxy("stdout") - sys.stderr = self.get_remote_proxy("stderr") + sys.stdin = self.console = _RPCFile(self.get_remote_proxy("stdin")) + sys.stdout = _RPCFile(self.get_remote_proxy("stdout")) + sys.stderr = _RPCFile(self.get_remote_proxy("stderr")) sys.displayhook = rpc.displayhook # page help() text to shell. import pydoc # import must be done here to capture i/o binding -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 20:53:23 2012 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 9 Jul 2012 20:53:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_normalize_whit?= =?utf-8?q?espace?= Message-ID: <3WWG032Yx8zNys@mail.python.org> http://hg.python.org/cpython/rev/c4652486f1b4 changeset: 78034:c4652486f1b4 branch: 3.2 parent: 78031:422242dbce30 user: Martin v. L?wis date: Mon Jul 09 20:52:40 2012 +0200 summary: normalize whitespace files: Lib/idlelib/run.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -246,7 +246,7 @@ thread.interrupt_main() class _RPCFile(io.TextIOBase): - """Wrapper class for the RPC proxy to typecheck arguments + """Wrapper class for the RPC proxy to typecheck arguments that may not support pickling.""" def __init__(self, rpc): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 20:53:24 2012 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 9 Jul 2012 20:53:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4y?= Message-ID: <3WWG046mbjzNys@mail.python.org> http://hg.python.org/cpython/rev/0c4a4070813a changeset: 78035:0c4a4070813a parent: 78033:3a6b6434ac33 parent: 78034:c4652486f1b4 user: Martin v. L?wis date: Mon Jul 09 20:53:03 2012 +0200 summary: merge 3.2 files: Lib/idlelib/run.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -259,7 +259,7 @@ thread.interrupt_main() class _RPCFile(io.TextIOBase): - """Wrapper class for the RPC proxy to typecheck arguments + """Wrapper class for the RPC proxy to typecheck arguments that may not support pickling.""" def __init__(self, rpc): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 21:02:01 2012 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 9 Jul 2012 21:02:01 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogLSBJc3N1ZSAjMTM1?= =?utf-8?q?32=3A_Check_that_arguments_to_sys=2Estdout=2Ewrite_are_strings?= =?utf-8?q?=2E?= Message-ID: <3WWGB14NpTzNtv@mail.python.org> http://hg.python.org/cpython/rev/58189e37331c changeset: 78036:58189e37331c branch: 2.7 parent: 78011:ab22ffa6fb2e user: Martin v. L?wis date: Mon Jul 09 21:01:49 2012 +0200 summary: - Issue #13532: Check that arguments to sys.stdout.write are strings. files: Lib/idlelib/NEWS.txt | 2 ++ Lib/idlelib/PyShell.py | 2 ++ Lib/idlelib/run.py | 24 +++++++++++++++++++++--- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,6 +1,8 @@ What's New in IDLE 2.7.4? ========================= +- Issue #13532: Check that arguments to sys.stdout.write are strings. + - Issue # 12510: Attempt to get certain tool tips no longer crashes IDLE. - Issue10365: File open dialog now works instead of crashing even when diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -1265,6 +1265,8 @@ self.encoding = encoding def write(self, s): + if not isinstance(s, str): + raise TypeError('must be str, not ' + type(s).__name__) self.shell.write(s, self.tags) def writelines(self, lines): diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -1,4 +1,5 @@ import sys +import io import linecache import time import socket @@ -248,6 +249,23 @@ quitting = True thread.interrupt_main() +class _RPCFile(io.TextIOBase): + """Wrapper class for the RPC proxy to typecheck arguments + that may not support pickling.""" + + def __init__(self, rpc): + super.__setattr__(self, 'rpc', rpc) + + def __getattr__(self, name): + return getattr(self.rpc, name) + + def __setattr__(self, name, value): + return setattr(self.rpc, name, value) + + def write(self, s): + if not isinstance(s, str): + raise TypeError('must be str, not ' + type(s).__name__) + return self.rpc.write(s) class MyHandler(rpc.RPCHandler): @@ -255,9 +273,9 @@ """Override base method""" executive = Executive(self) self.register("exec", executive) - sys.stdin = self.console = self.get_remote_proxy("stdin") - sys.stdout = self.get_remote_proxy("stdout") - sys.stderr = self.get_remote_proxy("stderr") + sys.stdin = self.console = _RPCFile(self.get_remote_proxy("stdin")) + sys.stdout = _RPCFile(self.get_remote_proxy("stdout")) + sys.stderr = _RPCFile(self.get_remote_proxy("stderr")) from idlelib import IOBinding sys.stdin.encoding = sys.stdout.encoding = \ sys.stderr.encoding = IOBinding.encoding -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 21:08:03 2012 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 9 Jul 2012 21:08:03 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Widen_test_to_?= =?utf-8?q?support_unicode=2E?= Message-ID: <3WWGJz3VcKzP09@mail.python.org> http://hg.python.org/cpython/rev/2993f566c82e changeset: 78037:2993f566c82e branch: 2.7 user: Martin v. L?wis date: Mon Jul 09 21:07:41 2012 +0200 summary: Widen test to support unicode. files: Lib/idlelib/PyShell.py | 2 +- Lib/idlelib/run.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -1265,7 +1265,7 @@ self.encoding = encoding def write(self, s): - if not isinstance(s, str): + if not isinstance(s, basestring): raise TypeError('must be str, not ' + type(s).__name__) self.shell.write(s, self.tags) diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -263,7 +263,7 @@ return setattr(self.rpc, name, value) def write(self, s): - if not isinstance(s, str): + if not isinstance(s, basestring): raise TypeError('must be str, not ' + type(s).__name__) return self.rpc.write(s) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 21:27:37 2012 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 9 Jul 2012 21:27:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315294=3A_Fix_a_re?= =?utf-8?q?gression_in_pkgutil=2Eextend=5Fpath=28=29=27s_handling_of_neste?= =?utf-8?q?d?= Message-ID: <3WWGlY6fNJzP1c@mail.python.org> http://hg.python.org/cpython/rev/a7b8c3323db9 changeset: 78038:a7b8c3323db9 parent: 78035:0c4a4070813a user: Antoine Pitrou date: Mon Jul 09 21:23:58 2012 +0200 summary: Issue #15294: Fix a regression in pkgutil.extend_path()'s handling of nested namespace packages. files: Lib/pkgutil.py | 16 +++++++- Lib/test/test_pkgutil.py | 46 ++++++++++++++++++++++++++- Misc/NEWS | 3 + 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/Lib/pkgutil.py b/Lib/pkgutil.py --- a/Lib/pkgutil.py +++ b/Lib/pkgutil.py @@ -513,12 +513,22 @@ # frozen package. Return the path unchanged in that case. return path - pname = os.path.join(*name.split('.')) # Reconstitute as relative path sname_pkg = name + ".pkg" path = path[:] # Start with a copy of the existing path - for dir in sys.path: + parent_package, _, final_name = name.rpartition('.') + if parent_package: + try: + search_path = sys.modules[parent_package].__path__ + except (KeyError, AttributeError): + # We can't do anything: find_loader() returns None when + # passed a dotted name. + return path + else: + search_path = sys.path + + for dir in search_path: if not isinstance(dir, str): continue @@ -526,7 +536,7 @@ if finder is not None: # Is this finder PEP 420 compliant? if hasattr(finder, 'find_loader'): - loader, portions = finder.find_loader(name) + loader, portions = finder.find_loader(final_name) else: # No, no need to call it loader = None diff --git a/Lib/test/test_pkgutil.py b/Lib/test/test_pkgutil.py --- a/Lib/test/test_pkgutil.py +++ b/Lib/test/test_pkgutil.py @@ -1,4 +1,4 @@ -from test.support import run_unittest +from test.support import run_unittest, unload import unittest import sys import imp @@ -214,8 +214,50 @@ # XXX: test .pkg files +class NestedNamespacePackageTest(unittest.TestCase): + + def setUp(self): + self.basedir = tempfile.mkdtemp() + self.old_path = sys.path[:] + + def tearDown(self): + sys.path[:] = self.old_path + shutil.rmtree(self.basedir) + + def create_module(self, name, contents): + base, final = name.rsplit('.', 1) + base_path = os.path.join(self.basedir, base.replace('.', os.path.sep)) + os.makedirs(base_path, exist_ok=True) + with open(os.path.join(base_path, final + ".py"), 'w') as f: + f.write(contents) + + def test_nested(self): + pkgutil_boilerplate = ( + 'import pkgutil; ' + '__path__ = pkgutil.extend_path(__path__, __name__)') + self.create_module('a.pkg.__init__', pkgutil_boilerplate) + self.create_module('b.pkg.__init__', pkgutil_boilerplate) + self.create_module('a.pkg.subpkg.__init__', pkgutil_boilerplate) + self.create_module('b.pkg.subpkg.__init__', pkgutil_boilerplate) + self.create_module('a.pkg.subpkg.c', 'c = 1') + self.create_module('b.pkg.subpkg.d', 'd = 2') + sys.path.insert(0, os.path.join(self.basedir, 'a')) + sys.path.insert(0, os.path.join(self.basedir, 'b')) + import pkg + self.addCleanup(unload, 'pkg') + self.assertEqual(len(pkg.__path__), 2) + import pkg.subpkg + self.addCleanup(unload, 'pkg.subpkg') + self.assertEqual(len(pkg.subpkg.__path__), 2) + from pkg.subpkg.c import c + from pkg.subpkg.d import d + self.assertEqual(c, 1) + self.assertEqual(d, 2) + + def test_main(): - run_unittest(PkgutilTests, PkgutilPEP302Tests, ExtendPathTests) + run_unittest(PkgutilTests, PkgutilPEP302Tests, ExtendPathTests, + NestedNamespacePackageTest) # this is necessary if test is run repeated (like when finding leaks) import zipimport zipimport._zip_directory_cache.clear() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -31,6 +31,9 @@ Library ------- +- Issue #15294: Fix a regression in pkgutil.extend_path()'s handling of + nested namespace packages. + - Issue #15056: imp.cache_from_source() and source_from_cache() raise NotImplementedError when sys.implementation.cache_tag is set to None. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 21:27:39 2012 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 9 Jul 2012 21:27:39 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_Backport_test_?= =?utf-8?q?for_nested_namespace_packages=2E?= Message-ID: <3WWGlb3KfMzNWx@mail.python.org> http://hg.python.org/cpython/rev/f86df559319d changeset: 78039:f86df559319d branch: 3.2 parent: 78034:c4652486f1b4 user: Antoine Pitrou date: Mon Jul 09 21:23:58 2012 +0200 summary: Backport test for nested namespace packages. files: Lib/test/test_pkgutil.py | 46 ++++++++++++++++++++++++++- 1 files changed, 44 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_pkgutil.py b/Lib/test/test_pkgutil.py --- a/Lib/test/test_pkgutil.py +++ b/Lib/test/test_pkgutil.py @@ -1,4 +1,4 @@ -from test.support import run_unittest +from test.support import run_unittest, unload import unittest import sys import imp @@ -186,8 +186,50 @@ # XXX: test .pkg files +class NestedNamespacePackageTest(unittest.TestCase): + + def setUp(self): + self.basedir = tempfile.mkdtemp() + self.old_path = sys.path[:] + + def tearDown(self): + sys.path[:] = self.old_path + shutil.rmtree(self.basedir) + + def create_module(self, name, contents): + base, final = name.rsplit('.', 1) + base_path = os.path.join(self.basedir, base.replace('.', os.path.sep)) + os.makedirs(base_path, exist_ok=True) + with open(os.path.join(base_path, final + ".py"), 'w') as f: + f.write(contents) + + def test_nested(self): + pkgutil_boilerplate = ( + 'import pkgutil; ' + '__path__ = pkgutil.extend_path(__path__, __name__)') + self.create_module('a.pkg.__init__', pkgutil_boilerplate) + self.create_module('b.pkg.__init__', pkgutil_boilerplate) + self.create_module('a.pkg.subpkg.__init__', pkgutil_boilerplate) + self.create_module('b.pkg.subpkg.__init__', pkgutil_boilerplate) + self.create_module('a.pkg.subpkg.c', 'c = 1') + self.create_module('b.pkg.subpkg.d', 'd = 2') + sys.path.insert(0, os.path.join(self.basedir, 'a')) + sys.path.insert(0, os.path.join(self.basedir, 'b')) + import pkg + self.addCleanup(unload, 'pkg') + self.assertEqual(len(pkg.__path__), 2) + import pkg.subpkg + self.addCleanup(unload, 'pkg.subpkg') + self.assertEqual(len(pkg.subpkg.__path__), 2) + from pkg.subpkg.c import c + from pkg.subpkg.d import d + self.assertEqual(c, 1) + self.assertEqual(d, 2) + + def test_main(): - run_unittest(PkgutilTests, PkgutilPEP302Tests, ExtendPathTests) + run_unittest(PkgutilTests, PkgutilPEP302Tests, ExtendPathTests, + NestedNamespacePackageTest) # this is necessary if test is run repeated (like when finding leaks) import zipimport zipimport._zip_directory_cache.clear() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 21:27:40 2012 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 9 Jul 2012 21:27:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Null_merge?= Message-ID: <3WWGlc74bPzP3X@mail.python.org> http://hg.python.org/cpython/rev/606f5cc41d35 changeset: 78040:606f5cc41d35 parent: 78038:a7b8c3323db9 parent: 78039:f86df559319d user: Antoine Pitrou date: Mon Jul 09 21:26:05 2012 +0200 summary: Null merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 21:44:03 2012 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 9 Jul 2012 21:44:03 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_markup?= Message-ID: <3WWH6W6n3czP0G@mail.python.org> http://hg.python.org/cpython/rev/b89d961487e9 changeset: 78041:b89d961487e9 user: Raymond Hettinger date: Mon Jul 09 12:43:57 2012 -0700 summary: Fix markup files: Doc/library/random.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/random.rst b/Doc/library/random.rst --- a/Doc/library/random.rst +++ b/Doc/library/random.rst @@ -150,7 +150,7 @@ argument. This is especially fast and space efficient for sampling from a large population: ``sample(range(10000000), 60)``. - If the sample size is larger than the population size, a :exc:``ValueError`` + If the sample size is larger than the population size, a :exc:`ValueError` is raised. The following functions generate specific real-valued distributions. Function -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 22:09:39 2012 From: python-checkins at python.org (brett.cannon) Date: Mon, 9 Jul 2012 22:09:39 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315167_=28as_part_?= =?utf-8?q?of_=2313959=29=3A_imp=2Eget=5Fmagic=28=29_is_no_implemented_in?= Message-ID: <3WWHh316pPzP39@mail.python.org> http://hg.python.org/cpython/rev/efb5e6ab10f4 changeset: 78042:efb5e6ab10f4 parent: 78040:606f5cc41d35 user: Brett Cannon date: Mon Jul 09 16:09:00 2012 -0400 summary: Issue #15167 (as part of #13959): imp.get_magic() is no implemented in Lib/imp.py. files: Doc/c-api/import.rst | 5 +- Doc/whatsnew/3.3.rst | 3 + Lib/imp.py | 9 +- Lib/importlib/_bootstrap.py | 97 +- Python/import.c | 126 +- Python/importlib.h | 7640 +++++++++++----------- 6 files changed, 3941 insertions(+), 3939 deletions(-) diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -172,7 +172,10 @@ Return the magic number for Python bytecode files (a.k.a. :file:`.pyc` and :file:`.pyo` files). The magic number should be present in the first four bytes - of the bytecode file, in little-endian byte order. + of the bytecode file, in little-endian byte order. Returns -1 on error. + + .. versionchanged:: 3.3 + Return value of -1 upon failure. .. c:function:: const char * PyImport_GetMagicTag() diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -1761,6 +1761,9 @@ :c:func:`PyUnicode_FromFormat()`, your code will automatically take advantage of the new unicode representations. +* :c:func:`PyImport_GetMagicNumber` now returns -1 upon failure. + + Building C extensions --------------------- diff --git a/Lib/imp.py b/Lib/imp.py --- a/Lib/imp.py +++ b/Lib/imp.py @@ -10,12 +10,12 @@ load_dynamic, get_frozen_object, is_frozen_package, init_builtin, init_frozen, is_builtin, is_frozen, _fix_co_filename, extension_suffixes) -# Could move out of _imp, but not worth the code -from _imp import get_magic +# Directly exposed by this module from importlib._bootstrap import new_module from importlib._bootstrap import cache_from_source + from importlib import _bootstrap from importlib import machinery import os @@ -37,6 +37,11 @@ IMP_HOOK = 9 +def get_magic(): + """Return the magic number for .pyc or .pyo files.""" + return _bootstrap._MAGIC_BYTES + + def get_tag(): """Return the magic tag for .pyc or .pyo files.""" return sys.implementation.cache_tag diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -300,6 +300,96 @@ # Finder/loader utility code ################################################## +"""Magic word to reject .pyc files generated by other Python versions. +It should change for each incompatible change to the bytecode. + +The value of CR and LF is incorporated so if you ever read or write +a .pyc file in text mode the magic number will be wrong; also, the +Apple MPW compiler swaps their values, botching string constants. + +The magic numbers must be spaced apart at least 2 values, as the +-U interpeter flag will cause MAGIC+1 being used. They have been +odd numbers for some time now. + +There were a variety of old schemes for setting the magic number. +The current working scheme is to increment the previous value by +10. + +Starting with the adoption of PEP 3147 in Python 3.2, every bump in magic +number also includes a new "magic tag", i.e. a human readable string used +to represent the magic number in __pycache__ directories. When you change +the magic number, you must also set a new unique magic tag. Generally this +can be named after the Python major version of the magic number bump, but +it can really be anything, as long as it's different than anything else +that's come before. The tags are included in the following table, starting +with Python 3.2a0. + +Known values: + Python 1.5: 20121 + Python 1.5.1: 20121 + Python 1.5.2: 20121 + Python 1.6: 50428 + Python 2.0: 50823 + Python 2.0.1: 50823 + Python 2.1: 60202 + Python 2.1.1: 60202 + Python 2.1.2: 60202 + Python 2.2: 60717 + Python 2.3a0: 62011 + Python 2.3a0: 62021 + Python 2.3a0: 62011 (!) + Python 2.4a0: 62041 + Python 2.4a3: 62051 + Python 2.4b1: 62061 + Python 2.5a0: 62071 + Python 2.5a0: 62081 (ast-branch) + Python 2.5a0: 62091 (with) + Python 2.5a0: 62092 (changed WITH_CLEANUP opcode) + Python 2.5b3: 62101 (fix wrong code: for x, in ...) + Python 2.5b3: 62111 (fix wrong code: x += yield) + Python 2.5c1: 62121 (fix wrong lnotab with for loops and + storing constants that should have been removed) + Python 2.5c2: 62131 (fix wrong code: for x, in ... in listcomp/genexp) + Python 2.6a0: 62151 (peephole optimizations and STORE_MAP opcode) + Python 2.6a1: 62161 (WITH_CLEANUP optimization) + Python 3000: 3000 + 3010 (removed UNARY_CONVERT) + 3020 (added BUILD_SET) + 3030 (added keyword-only parameters) + 3040 (added signature annotations) + 3050 (print becomes a function) + 3060 (PEP 3115 metaclass syntax) + 3061 (string literals become unicode) + 3071 (PEP 3109 raise changes) + 3081 (PEP 3137 make __file__ and __name__ unicode) + 3091 (kill str8 interning) + 3101 (merge from 2.6a0, see 62151) + 3103 (__file__ points to source file) + Python 3.0a4: 3111 (WITH_CLEANUP optimization). + Python 3.0a5: 3131 (lexical exception stacking, including POP_EXCEPT) + Python 3.1a0: 3141 (optimize list, set and dict comprehensions: + change LIST_APPEND and SET_ADD, add MAP_ADD) + Python 3.1a0: 3151 (optimize conditional branches: + introduce POP_JUMP_IF_FALSE and POP_JUMP_IF_TRUE) + Python 3.2a0: 3160 (add SETUP_WITH) + tag: cpython-32 + Python 3.2a1: 3170 (add DUP_TOP_TWO, remove DUP_TOPX and ROT_FOUR) + tag: cpython-32 + Python 3.2a2 3180 (add DELETE_DEREF) + Python 3.3a0 3190 __class__ super closure changed + Python 3.3a0 3200 (__qualname__ added) + 3210 (added size modulo 2**32 to the pyc header) + Python 3.3a1 3220 (changed PEP 380 implementation) + Python 3.3a4 3230 (revert changes to implicit __class__ closure) + +MAGIC must change whenever the bytecode emitted by the compiler may no +longer be understood by older implementations of the eval loop (usually +due to the addition of new opcodes). + +""" +_RAW_MAGIC_NUMBER = 3230 | ord('\r') << 16 | ord('\n') << 24 +_MAGIC_BYTES = bytes(_RAW_MAGIC_NUMBER >> n & 0xff for n in range(0, 25, 8)) + _PYCACHE = '__pycache__' SOURCE_SUFFIXES = ['.py'] # _setup() adds .pyw as needed. @@ -611,7 +701,7 @@ magic = data[:4] raw_timestamp = data[4:8] raw_size = data[8:12] - if magic != _MAGIC_NUMBER: + if magic != _MAGIC_BYTES: msg = 'bad magic number in {!r}: {!r}'.format(fullname, magic) raise ImportError(msg, name=fullname, path=bytecode_path) elif len(raw_timestamp) != 4: @@ -768,7 +858,7 @@ _verbose_message('code object from {}', source_path) if (not sys.dont_write_bytecode and bytecode_path is not None and source_mtime is not None): - data = bytearray(_MAGIC_NUMBER) + data = bytearray(_MAGIC_BYTES) data.extend(_w_long(source_mtime)) data.extend(_w_long(len(source_bytes))) data.extend(marshal.dumps(code_object)) @@ -1427,8 +1517,6 @@ return _handle_fromlist(module, fromlist, _gcd_import) -_MAGIC_NUMBER = None # Set in _setup() - def _setup(sys_module, _imp_module): """Setup importlib by importing needed built-in modules and injecting them @@ -1488,7 +1576,6 @@ setattr(self_module, 'path_separators', set(path_separators)) # Constants setattr(self_module, '_relax_case', _make_relax_case()) - setattr(self_module, '_MAGIC_NUMBER', _imp_module.get_magic()) if builtin_os == 'nt': SOURCE_SUFFIXES.append('.pyw') diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -27,97 +27,7 @@ #endif -/* Magic word to reject .pyc files generated by other Python versions. - It should change for each incompatible change to the bytecode. - - The value of CR and LF is incorporated so if you ever read or write - a .pyc file in text mode the magic number will be wrong; also, the - Apple MPW compiler swaps their values, botching string constants. - - The magic numbers must be spaced apart at least 2 values, as the - -U interpeter flag will cause MAGIC+1 being used. They have been - odd numbers for some time now. - - There were a variety of old schemes for setting the magic number. - The current working scheme is to increment the previous value by - 10. - - Starting with the adoption of PEP 3147 in Python 3.2, every bump in magic - number also includes a new "magic tag", i.e. a human readable string used - to represent the magic number in __pycache__ directories. When you change - the magic number, you must also set a new unique magic tag. Generally this - can be named after the Python major version of the magic number bump, but - it can really be anything, as long as it's different than anything else - that's come before. The tags are included in the following table, starting - with Python 3.2a0. - - Known values: - Python 1.5: 20121 - Python 1.5.1: 20121 - Python 1.5.2: 20121 - Python 1.6: 50428 - Python 2.0: 50823 - Python 2.0.1: 50823 - Python 2.1: 60202 - Python 2.1.1: 60202 - Python 2.1.2: 60202 - Python 2.2: 60717 - Python 2.3a0: 62011 - Python 2.3a0: 62021 - Python 2.3a0: 62011 (!) - Python 2.4a0: 62041 - Python 2.4a3: 62051 - Python 2.4b1: 62061 - Python 2.5a0: 62071 - Python 2.5a0: 62081 (ast-branch) - Python 2.5a0: 62091 (with) - Python 2.5a0: 62092 (changed WITH_CLEANUP opcode) - Python 2.5b3: 62101 (fix wrong code: for x, in ...) - Python 2.5b3: 62111 (fix wrong code: x += yield) - Python 2.5c1: 62121 (fix wrong lnotab with for loops and - storing constants that should have been removed) - Python 2.5c2: 62131 (fix wrong code: for x, in ... in listcomp/genexp) - Python 2.6a0: 62151 (peephole optimizations and STORE_MAP opcode) - Python 2.6a1: 62161 (WITH_CLEANUP optimization) - Python 3000: 3000 - 3010 (removed UNARY_CONVERT) - 3020 (added BUILD_SET) - 3030 (added keyword-only parameters) - 3040 (added signature annotations) - 3050 (print becomes a function) - 3060 (PEP 3115 metaclass syntax) - 3061 (string literals become unicode) - 3071 (PEP 3109 raise changes) - 3081 (PEP 3137 make __file__ and __name__ unicode) - 3091 (kill str8 interning) - 3101 (merge from 2.6a0, see 62151) - 3103 (__file__ points to source file) - Python 3.0a4: 3111 (WITH_CLEANUP optimization). - Python 3.0a5: 3131 (lexical exception stacking, including POP_EXCEPT) - Python 3.1a0: 3141 (optimize list, set and dict comprehensions: - change LIST_APPEND and SET_ADD, add MAP_ADD) - Python 3.1a0: 3151 (optimize conditional branches: - introduce POP_JUMP_IF_FALSE and POP_JUMP_IF_TRUE) - Python 3.2a0: 3160 (add SETUP_WITH) - tag: cpython-32 - Python 3.2a1: 3170 (add DUP_TOP_TWO, remove DUP_TOPX and ROT_FOUR) - tag: cpython-32 - Python 3.2a2 3180 (add DELETE_DEREF) - Python 3.3a0 3190 __class__ super closure changed - Python 3.3a0 3200 (__qualname__ added) - 3210 (added size modulo 2**32 to the pyc header) - Python 3.3a1 3220 (changed PEP 380 implementation) - Python 3.3a4 3230 (revert changes to implicit __class__ closure) -*/ - -/* MAGIC must change whenever the bytecode emitted by the compiler may no - longer be understood by older implementations of the eval loop (usually - due to the addition of new opcodes) -*/ -#define MAGIC (3230 | ((long)'\r'<<16) | ((long)'\n'<<24)) #define CACHEDIR "__pycache__" -/* Current magic word as global. */ -static long pyc_magic = MAGIC; /* See _PyImport_FixupExtensionObject() below */ static PyObject *extensions = NULL; @@ -516,7 +426,12 @@ long PyImport_GetMagicNumber(void) { - return pyc_magic; + PyInterpreterState *interp = PyThreadState_Get()->interp; + PyObject *pyc_magic = PyObject_GetAttrString(interp->importlib, + "_RAW_MAGIC_NUMBER"); + if (pyc_magic == NULL) + return -1; + return PyLong_AsLong(pyc_magic); } @@ -1879,30 +1794,6 @@ return r; } - -/* Module 'imp' provides Python access to the primitives used for - importing modules. -*/ - -static PyObject * -imp_make_magic(long magic) -{ - char buf[4]; - - buf[0] = (char) ((magic >> 0) & 0xff); - buf[1] = (char) ((magic >> 8) & 0xff); - buf[2] = (char) ((magic >> 16) & 0xff); - buf[3] = (char) ((magic >> 24) & 0xff); - - return PyBytes_FromStringAndSize(buf, 4); -} - -static PyObject * -imp_get_magic(PyObject *self, PyObject *noargs) -{ - return imp_make_magic(pyc_magic); -} - static PyObject * imp_extension_suffixes(PyObject *self, PyObject *noargs) { @@ -2049,10 +1940,6 @@ PyDoc_STRVAR(doc_imp, "(Extremely) low-level import machinery bits as used by importlib and imp."); -PyDoc_STRVAR(doc_get_magic, -"get_magic() -> string\n\ -Return the magic number for .pyc or .pyo files."); - PyDoc_STRVAR(doc_extension_suffixes, "extension_suffixes() -> list of strings\n\ Returns the list of file suffixes used to identify extension modules."); @@ -2075,7 +1962,6 @@ On platforms without threads, this function does nothing."); static PyMethodDef imp_methods[] = { - {"get_magic", imp_get_magic, METH_NOARGS, doc_get_magic}, {"extension_suffixes", imp_extension_suffixes, METH_NOARGS, doc_extension_suffixes}, {"lock_held", imp_lock_held, METH_NOARGS, doc_lock_held}, diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 22:09:40 2012 From: python-checkins at python.org (brett.cannon) Date: Mon, 9 Jul 2012 22:09:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge?= Message-ID: <3WWHh45R0BzP3H@mail.python.org> http://hg.python.org/cpython/rev/44956cb4d7ea changeset: 78043:44956cb4d7ea parent: 78042:efb5e6ab10f4 parent: 78041:b89d961487e9 user: Brett Cannon date: Mon Jul 09 16:09:21 2012 -0400 summary: Merge files: Doc/library/random.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/random.rst b/Doc/library/random.rst --- a/Doc/library/random.rst +++ b/Doc/library/random.rst @@ -150,7 +150,7 @@ argument. This is especially fast and space efficient for sampling from a large population: ``sample(range(10000000), 60)``. - If the sample size is larger than the population size, a :exc:``ValueError`` + If the sample size is larger than the population size, a :exc:`ValueError` is raised. The following functions generate specific real-valued distributions. Function -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 22:42:07 2012 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 9 Jul 2012 22:42:07 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?benchmarks=3A_Use_PeakPagefileUsage_f?= =?utf-8?q?or_memory_usage_tracking_under_Windows=2C_for_better?= Message-ID: <3WWJPW3cy8zP3l@mail.python.org> http://hg.python.org/benchmarks/rev/5f6b46d86b40 changeset: 157:5f6b46d86b40 user: Antoine Pitrou date: Mon Jul 09 22:40:39 2012 +0200 summary: Use PeakPagefileUsage for memory usage tracking under Windows, for better accuracy. files: perf.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/perf.py b/perf.py --- a/perf.py +++ b/perf.py @@ -246,10 +246,10 @@ process_handle: handle to the process to get the memory usage for Returns: - The size of the process's private data, in kilobytes + The peak size of the process's private data, in kilobytes """ pmi = win32process.GetProcessMemoryInfo(process_handle) - return pmi["PagefileUsage"] // 1024 + return pmi["PeakPagefileUsage"] // 1024 @contextlib.contextmanager -- Repository URL: http://hg.python.org/benchmarks From python-checkins at python.org Mon Jul 9 22:43:58 2012 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 9 Jul 2012 22:43:58 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_initialize_variable_for_co?= =?utf-8?q?mpiler_happiness?= Message-ID: <3WWJRf613RzP2t@mail.python.org> http://hg.python.org/cpython/rev/7ed3b4f830c0 changeset: 78044:7ed3b4f830c0 user: Benjamin Peterson date: Mon Jul 09 13:43:53 2012 -0700 summary: initialize variable for compiler happiness files: Python/import.c | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -1289,9 +1289,9 @@ const char *importlib_filename = ""; const char *exec_funcname = "_exec_module"; int always_trim = 0; - int in_importlib; + int in_importlib = 0; PyObject *exception, *value, *base_tb, *tb; - PyObject **prev_link, **outer_link; + PyObject **prev_link, **outer_link = NULL; /* Synopsis: if it's an ImportError, we trim all importlib chunks from the traceback. Otherwise, we trim only those chunks which @@ -1306,7 +1306,6 @@ prev_link = &base_tb; tb = base_tb; - in_importlib = 0; while (tb != NULL) { PyTracebackObject *traceback = (PyTracebackObject *)tb; PyObject *next = (PyObject *) traceback->tb_next; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 9 23:58:17 2012 From: python-checkins at python.org (terry.reedy) Date: Mon, 9 Jul 2012 23:58:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgMTM1MzI6?= =?utf-8?q?_Allow_bytearrays_to_be_written_also=2E?= Message-ID: <3WWL5P1PcSzPDZ@mail.python.org> http://hg.python.org/cpython/rev/4f891f44ec15 changeset: 78045:4f891f44ec15 branch: 2.7 parent: 78037:2993f566c82e user: Terry Jan Reedy date: Mon Jul 09 17:57:13 2012 -0400 summary: Issue 13532: Allow bytearrays to be written also. files: Lib/idlelib/PyShell.py | 4 ++-- Lib/idlelib/run.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -1265,8 +1265,8 @@ self.encoding = encoding def write(self, s): - if not isinstance(s, basestring): - raise TypeError('must be str, not ' + type(s).__name__) + if not isinstance(s, (basestring, bytearray)): + raise TypeError('must be string, not ' + type(s).__name__) self.shell.write(s, self.tags) def writelines(self, lines): diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -263,8 +263,8 @@ return setattr(self.rpc, name, value) def write(self, s): - if not isinstance(s, basestring): - raise TypeError('must be str, not ' + type(s).__name__) + if not isinstance(s, (basestring, bytearray)): + raise TypeError('must be string, not ' + type(s).__name__) return self.rpc.write(s) class MyHandler(rpc.RPCHandler): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 10 01:41:57 2012 From: python-checkins at python.org (victor.stinner) Date: Tue, 10 Jul 2012 01:41:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_418=3A_Replace_adjusted_w?= =?utf-8?q?ith_adjustable_in_time=2Eget=5Fclock=5Finfo=28=29?= Message-ID: <3WWNP15WHdzPBc@mail.python.org> http://hg.python.org/peps/rev/a071af7d8e4d changeset: 4485:a071af7d8e4d user: Victor Stinner date: Tue Jul 10 01:38:53 2012 +0200 summary: PEP 418: Replace adjusted with adjustable in time.get_clock_info() files: pep-0418.txt | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-) diff --git a/pep-0418.txt b/pep-0418.txt --- a/pep-0418.txt +++ b/pep-0418.txt @@ -86,8 +86,8 @@ * time.monotonic() and time.perf_counter() may or may not be adjusted. For example, ``CLOCK_MONOTONIC`` is slewed on Linux, whereas ``GetTickCount()`` is not adjusted on Windows. - ``time.get_clock_info('monotonic')['adjusted']`` can be used to check - if the monotonic clock is adjusted or not. + ``time.get_clock_info('monotonic')['adjustable']`` can be used to check + if the monotonic clock is adjustable or not. * No time.thread_time() function is proposed by this PEP because it is not needed by Python standard library nor a common asked feature. Such function would only be available on Windows and Linux. On @@ -120,8 +120,9 @@ function. Examples: ``"QueryPerformanceCounter()"``, ``"clock_gettime(CLOCK_REALTIME)"``. * ``monotonic`` (bool): True if the clock cannot go backward. - * ``adjusted`` (bool): True if the clock can be adjusted (e.g. by a - NTP daemon). + * ``adjustable`` (bool): ``True`` if the clock can be changed automatically + (e.g. by a NTP daemon) or manually by the system administrator, ``False`` + otherwise * ``resolution`` (float): resolution in seconds of the clock. -- Repository URL: http://hg.python.org/peps From solipsis at pitrou.net Tue Jul 10 05:59:43 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 10 Jul 2012 05:59:43 +0200 Subject: [Python-checkins] Daily reference leaks (7ed3b4f830c0): sum=144 Message-ID: results for 7ed3b4f830c0 on branch "default" -------------------------------------------- test_runpy leaked [2, 2, 2] references, sum=6 test_zipimport leaked [46, 46, 46] references, sum=138 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogcMG1T1', '-x'] From python-checkins at python.org Tue Jul 10 06:33:23 2012 From: python-checkins at python.org (ned.deily) Date: Tue, 10 Jul 2012 06:33:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devguide=3A_no-op_change_to_test_web_?= =?utf-8?q?update_hook?= Message-ID: <3WWVsH5hKkzP3T@mail.python.org> http://hg.python.org/devguide/rev/576937245d05 changeset: 530:576937245d05 user: Ned Deily date: Mon Jul 09 21:33:15 2012 -0700 summary: no-op change to test web update hook files: docquality.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docquality.rst b/docquality.rst --- a/docquality.rst +++ b/docquality.rst @@ -15,8 +15,8 @@ validating that your new markup is correct). The current in-development version of the documentation can be viewed at -http://docs.python.org/dev/. This version is regenerated from source -once a day. +http://docs.python.org/dev/. This version is regenerated from source once +a day. If you would like a technical documentation style guide, the `Apple Publications Style Guide -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Tue Jul 10 07:07:33 2012 From: python-checkins at python.org (martin.v.loewis) Date: Tue, 10 Jul 2012 07:07:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Don=27t_package_removed_py?= =?utf-8?q?setup3_anymore=2E?= Message-ID: <3WWWcj1gMlzNyZ@mail.python.org> http://hg.python.org/cpython/rev/791e4c5ba1a9 changeset: 78046:791e4c5ba1a9 parent: 78044:7ed3b4f830c0 user: Martin v. L?wis date: Tue Jul 10 07:04:33 2012 +0200 summary: Don't package removed pysetup3 anymore. files: Tools/msi/msi.py | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Tools/msi/msi.py b/Tools/msi/msi.py --- a/Tools/msi/msi.py +++ b/Tools/msi/msi.py @@ -1146,7 +1146,6 @@ if f == 'Scripts': lib.add_file("2to3.py", src="2to3") lib.add_file("pydoc3.py", src="pydoc3") - lib.add_file("pysetup3.py", src="pysetup3") lib.add_file("pyvenv.py", src="pyvenv") if have_tcl: lib.start_component("pydocgui.pyw", tcltk, keyfile="pydocgui.pyw") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 10 07:07:35 2012 From: python-checkins at python.org (martin.v.loewis) Date: Tue, 10 Jul 2012 07:07:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315315=3A_Support_?= =?utf-8?q?VS_2010_in_distutils_cygwincompiler=2E?= Message-ID: <3WWWcl2WkFzP4m@mail.python.org> http://hg.python.org/cpython/rev/eee92b9ac4ad changeset: 78047:eee92b9ac4ad user: Martin v. L?wis date: Tue Jul 10 07:07:06 2012 +0200 summary: Issue #15315: Support VS 2010 in distutils cygwincompiler. files: Lib/distutils/cygwinccompiler.py | 3 +++ Misc/NEWS | 2 ++ 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/distutils/cygwinccompiler.py b/Lib/distutils/cygwinccompiler.py --- a/Lib/distutils/cygwinccompiler.py +++ b/Lib/distutils/cygwinccompiler.py @@ -78,6 +78,9 @@ elif msc_ver == '1500': # VS2008 / MSVC 9.0 return ['msvcr90'] + elif msc_ver == '1600': + # VS2010 / MSVC 10.0 + return ['msvcr100'] else: raise ValueError("Unknown MS Compiler version %s " % msc_ver) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -31,6 +31,8 @@ Library ------- +- Issue #15315: Support VS 2010 in distutils cygwincompiler. + - Issue #15294: Fix a regression in pkgutil.extend_path()'s handling of nested namespace packages. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 10 07:21:59 2012 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 10 Jul 2012 07:21:59 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_fix_refleak?= Message-ID: <3WWWxM29skzP4C@mail.python.org> http://hg.python.org/cpython/rev/3fa1414ce505 changeset: 78048:3fa1414ce505 user: Benjamin Peterson date: Mon Jul 09 22:21:55 2012 -0700 summary: fix refleak files: Python/import.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -431,7 +431,9 @@ "_RAW_MAGIC_NUMBER"); if (pyc_magic == NULL) return -1; - return PyLong_AsLong(pyc_magic); + long res = PyLong_AsLong(pyc_magic); + Py_DECREF(pyc_magic); + return res; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 10 08:52:29 2012 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 10 Jul 2012 08:52:29 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Add_simple_LaTeX_markup?= Message-ID: <3WWYxn0NSqzNRY@mail.python.org> http://hg.python.org/cpython/rev/08bfd88027bb changeset: 78049:08bfd88027bb user: Raymond Hettinger date: Mon Jul 09 23:52:08 2012 -0700 summary: Add simple LaTeX markup files: Tools/scripts/highlight.py | 98 ++++++++++++++++++++++--- 1 files changed, 85 insertions(+), 13 deletions(-) diff --git a/Tools/scripts/highlight.py b/Tools/scripts/highlight.py --- a/Tools/scripts/highlight.py +++ b/Tools/scripts/highlight.py @@ -1,12 +1,11 @@ #!/usr/bin/env python3 '''Add syntax highlighting to Python source code''' -__all__ = ['analyze_python', 'ansi_highlight', 'default_ansi', - 'html_highlight', 'build_html_page', 'default_css', 'default_html'] - __author__ = 'Raymond Hettinger' -import keyword, tokenize, cgi, functools +import keyword, tokenize, cgi, re, functools + +#### Analyze Python Source ################################# def is_builtin(s): 'Return True if s is the name of a builtin' @@ -60,6 +59,20 @@ line_upto_token, written = combine_range(lines, written, (erow, ecol)) yield line_upto_token, '', '' +#### Raw Output ########################################### + +def raw_highlight(classified_text): + 'Straight text display of text classifications' + result = [] + for line_upto_token, kind, line_thru_token in classified_text: + if line_upto_token: + result.append(' plain: %r\n' % line_upto_token) + if line_thru_token: + result.append('%15s: %r\n' % (kind, line_thru_token)) + return ''.join(result) + +#### ANSI Output ########################################### + default_ansi = { 'comment': ('\033[0;31m', '\033[0m'), 'string': ('\033[0;32m', '\033[0m'), @@ -80,6 +93,8 @@ result += [line_upto_token, opener, line_thru_token, closer] return ''.join(result) +#### HTML Output ########################################### + def html_highlight(classified_text,opener='
      \n', closer='
      \n'): 'Convert classified text to an HTML fragment' result = [opener] @@ -131,6 +146,59 @@ title = cgi.escape(title) return html.format(title=title, css=css_str, body=result) +#### LaTeX Output ########################################## + +default_latex_colors = { + 'comment': 'red', + 'string': 'green', + 'docstring': 'green', + 'keyword': 'orange', + 'builtin': 'purple', + 'definition': 'orange', + 'defname': 'blue', + 'operator': 'brown', +} + +default_latex_document = r''' +\documentclass{article} +\usepackage{alltt} +\usepackage{color} +\usepackage[usenames,dvipsnames]{xcolor} +\usepackage[cm]{fullpage} +\begin{document} +\center{\LARGE{%(title)s}} +\begin{alltt} +%(body)s +\end{alltt} +\end{document} +''' + +def latex_escape(s): + 'Replace LaTeX special characters with their escaped equivalents' + # http://en.wikibooks.org/wiki/LaTeX/Basics#Special_Characters + xlat = { + '#': r'\#', '$': r'\$', '%': r'\%', '^': r'\textasciicircum{}', + '&': r'\&', '_': r'\_', '{': r'\{', '}': r'\}', '~': r'\~{}', + '\\': r'\textbackslash{}', + } + return re.sub(r'[\\#$%^&_{}~]', lambda mo: xlat[mo.group()], s) + +def latex_highlight(classified_text, title = 'python', + colors = default_latex_colors, + document = default_latex_document): + 'Create a complete LaTeX document with colorized source code' + result = [] + for line_upto_token, kind, line_thru_token in classified_text: + if kind: + result += [latex_escape(line_upto_token), + r'{\color{%s}' % colors[kind], + latex_escape(line_thru_token), + '}'] + else: + result += [latex_escape(line_upto_token), + latex_escape(line_thru_token)] + return default_latex_document % dict(title=title, body=''.join(result)) + if __name__ == '__main__': import sys, argparse, webbrowser, os, textwrap @@ -152,6 +220,10 @@ # Create a complete HTML file $ ./highlight.py -c myfile.py > myfile.html + + # Create a PDF using LaTeX + $ ./highlight.py -l myfile.py | pdflatex + ''')) parser.add_argument('sourcefile', metavar = 'SOURCEFILE', help = 'file containing Python sourcecode') @@ -159,10 +231,12 @@ help = 'launch a browser to show results') parser.add_argument('-c', '--complete', action = 'store_true', help = 'build a complete html webpage') + parser.add_argument('-l', '--latex', action = 'store_true', + help = 'build a LaTeX document') + parser.add_argument('-r', '--raw', action = 'store_true', + help = 'raw parse of categorized text') parser.add_argument('-s', '--section', action = 'store_true', help = 'show an HTML section rather than a complete webpage') - parser.add_argument('-v', '--verbose', action = 'store_true', - help = 'display categorized text to stderr') args = parser.parse_args() if args.section and (args.browser or args.complete): @@ -174,16 +248,14 @@ source = f.read() classified_text = analyze_python(source) - if args.verbose: - classified_text = list(classified_text) - for line_upto_token, kind, line_thru_token in classified_text: - sys.stderr.write('%15s: %r\n' % ('leadin', line_upto_token)) - sys.stderr.write('%15s: %r\n\n' % (kind, line_thru_token)) - - if args.complete or args.browser: + if args.raw: + encoded = raw_highlight(classified_text) + elif args.complete or args.browser: encoded = build_html_page(classified_text, title=sourcefile) elif args.section: encoded = html_highlight(classified_text) + elif args.latex: + encoded = latex_highlight(classified_text, title=sourcefile) else: encoded = ansi_highlight(classified_text) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 10 09:21:24 2012 From: python-checkins at python.org (vinay.sajip) Date: Tue, 10 Jul 2012 09:21:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Factored_out_common_venv_d?= =?utf-8?q?ocumentation_and_added_more_information_about?= Message-ID: <3WWZb83rPrzP8L@mail.python.org> http://hg.python.org/cpython/rev/42d1da32d74f changeset: 78050:42d1da32d74f user: Vinay Sajip date: Tue Jul 10 08:21:07 2012 +0100 summary: Factored out common venv documentation and added more information about Distribute/pip. files: Doc/library/venv.rst | 89 ++------------------------ Doc/using/scripts.rst | 86 +------------------------- Doc/using/venv-create.inc | 85 +++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 167 deletions(-) diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -25,88 +25,8 @@ Creating virtual environments ----------------------------- -Creation of virtual environments is simplest executing the ``pyvenv`` script:: +.. include:: /using/venv-create.inc - pyvenv /path/to/new/virtual/environment - -Running this command creates the target directory (creating any parent -directories that don't exist already) and places a ``pyvenv.cfg`` file in it -with a ``home`` key pointing to the Python installation the command was run -from. It also creates a ``bin`` (or ``Scripts`` on Windows) subdirectory -containing a copy of the ``python`` binary (or binaries, in the case of -Windows). It also creates an (initially empty) ``lib/pythonX.Y/site-packages`` -subdirectory (on Windows, this is ``Lib\site-packages``). - -.. highlight:: none - -On Windows, you may have to invoke the ``pyvenv`` script as follows, if you -don't have the relevant PATH and PATHEXT settings:: - - c:\Temp>c:\Python33\python c:\Python33\Tools\Scripts\pyvenv.py myenv - -or equivalently:: - - c:\Temp>c:\Python33\python -m venv myenv - -The command, if run with ``-h``, will show the available options:: - - usage: pyvenv [-h] [--system-site-packages] [--symlinks] [--clear] - [--upgrade] ENV_DIR [ENV_DIR ...] - - Creates virtual Python environments in one or more target directories. - - positional arguments: - ENV_DIR A directory to create the environment in. - - optional arguments: - -h, --help show this help message and exit - --system-site-packages Give access to the global site-packages dir to the - virtual environment. - --symlinks Try to use symlinks rather than copies, when symlinks - are not the default for the platform. - --clear Delete the environment directory if it already exists. - If not specified and the directory exists, an error is - raised. - --upgrade Upgrade the environment directory to use this version - of Python, assuming Python has been upgraded in-place. - -If the target directory already exists an error will be raised, unless the -``--clear`` or ``--upgrade`` option was provided. - -The created ``pyvenv.cfg`` file also includes the -``include-system-site-packages`` key, set to ``true`` if ``venv`` is run with -the ``--system-site-packages`` option, ``false`` otherwise. - -Multiple paths can be given to ``pyvenv``, in which case an identical virtualenv -will be created, according to the given options, at each provided path. - -Once a venv has been created, it can be "activated" using a script in the -venv's binary directory. The invocation of the script is platform-specific: on -a Posix platform, you would typically do:: - - $ source /bin/activate - -whereas on Windows, you might do:: - - C:\> /Scripts/activate - -if you are using the ``cmd.exe`` shell, or perhaps:: - - PS C:\> /Scripts/Activate.ps1 - -if you use PowerShell. - -You don't specifically *need* to activate an environment; activation just -prepends the venv's binary directory to your path, so that "python" invokes the -venv's Python interpreter and you can run installed scripts without having to -use their full path. However, all scripts installed in a venv should be -runnable without activating it, and run with the venv's Python automatically. - -You can deactivate a venv by typing "deactivate" in your shell. The exact -mechanism is platform-specific: for example, the Bash activation script defines -a "deactivate" function, whereas on Windows there are separate scripts called -``deactivate.bat`` and ``Deactivate.ps1`` which are installed when the venv is -created. .. _venv-def: @@ -119,9 +39,14 @@ A venv is a directory tree which contains Python executable files and other files which indicate that it is a venv. - Common installation tools such as ``distribute`` and ``pip`` work as + Common installation tools such as ``Distribute`` and ``pip`` work as expected with venvs - i.e. when a venv is active, they install Python packages into the venv without needing to be told to do so explicitly. + Of course, you need to install them into the venv first: this could be + done by running ``distribute_setup.py`` with the venv activated, + followed by running ``easy_install pip``. Alternatively, you could download + the source tarballs and run ``python setup.py install`` after unpacking, + with the venv activated. When a venv is active (i.e. the venv's Python interpreter is running), the attributes :attr:`sys.prefix` and :attr:`sys.exec_prefix` point to the base diff --git a/Doc/using/scripts.rst b/Doc/using/scripts.rst --- a/Doc/using/scripts.rst +++ b/Doc/using/scripts.rst @@ -6,89 +6,5 @@ pyvenv - Creating virtual environments -------------------------------------- -Creation of :ref:`virtual environments ` is done by executing the -``pyvenv`` script:: +.. include:: venv-create.inc - pyvenv /path/to/new/virtual/environment - -Running this command creates the target directory (creating any parent -directories that don't exist already) and places a ``pyvenv.cfg`` file -in it with a ``home`` key pointing to the Python installation the -command was run from. It also creates a ``bin`` (or ``Scripts`` on -Windows) subdirectory containing a copy of the ``python`` binary (or -binaries, in the case of Windows). -It also creates an (initially empty) ``lib/pythonX.Y/site-packages`` -subdirectory (on Windows, this is ``Lib\site-packages``). - -.. highlight:: none - -On Windows, you may have to invoke the ``pyvenv`` script as follows, if you -don't have the relevant PATH and PATHEXT settings:: - - c:\Temp>c:\Python33\python c:\Python33\Tools\Scripts\pyvenv.py myenv - -or equivalently:: - - c:\Temp>c:\Python33\python -m venv myenv - -The command, if run with ``-h``, will show the available options:: - - usage: pyvenv [-h] [--system-site-packages] [--symlinks] [--clear] - [--upgrade] ENV_DIR [ENV_DIR ...] - - Creates virtual Python environments in one or more target directories. - - positional arguments: - ENV_DIR A directory to create the environment in. - - optional arguments: - -h, --help show this help message and exit - --system-site-packages Give access to the global site-packages dir to the - virtual environment. - --symlinks Try to use symlinks rather than copies, when symlinks - are not the default for the platform. - --clear Delete the environment directory if it already exists. - If not specified and the directory exists, an error is - raised. - --upgrade Upgrade the environment directory to use this version - of Python, assuming Python has been upgraded in-place. - -If the target directory already exists an error will be raised, unless -the ``--clear`` or ``--upgrade`` option was provided. - -The created ``pyvenv.cfg`` file also includes the -``include-system-site-packages`` key, set to ``true`` if ``venv`` is -run with the ``--system-site-packages`` option, ``false`` otherwise. - -Multiple paths can be given to ``pyvenv``, in which case an identical -virtualenv will be created, according to the given options, at each -provided path. - -Once a venv has been created, it can be "activated" using a script in the -venv's binary directory. The invocation of the script is platform-specific: on -a Posix platform, you would typically do:: - - $ source /bin/activate - -whereas on Windows, you might do:: - - C:\> /Scripts/activate - -if you are using the ``cmd.exe`` shell, or perhaps:: - - PS C:\> /Scripts/Activate.ps1 - -if you use PowerShell. - -You don't specifically *need* to activate an environment; activation just -prepends the venv's binary directory to your path, so that "python" invokes the -venv's Python interpreter and you can run installed scripts without having to -use their full path. However, all scripts installed in a venv should be -runnable without activating it, and run with the venv's Python automatically. - -You can deactivate a venv by typing "deactivate" in your shell. The exact -mechanism is platform-specific: for example, the Bash activation script defines -a "deactivate" function, whereas on Windows there are separate scripts called -``deactivate.bat`` and ``Deactivate.ps1`` which are installed when the venv is -created. - diff --git a/Doc/using/venv-create.inc b/Doc/using/venv-create.inc new file mode 100644 --- /dev/null +++ b/Doc/using/venv-create.inc @@ -0,0 +1,85 @@ +Creation of :ref:`virtual environments ` is done by executing the +``pyvenv`` script:: + + pyvenv /path/to/new/virtual/environment + +Running this command creates the target directory (creating any parent +directories that don't exist already) and places a ``pyvenv.cfg`` file in it +with a ``home`` key pointing to the Python installation the command was run +from. It also creates a ``bin`` (or ``Scripts`` on Windows) subdirectory +containing a copy of the ``python`` binary (or binaries, in the case of +Windows). It also creates an (initially empty) ``lib/pythonX.Y/site-packages`` +subdirectory (on Windows, this is ``Lib\site-packages``). + +.. highlight:: none + +On Windows, you may have to invoke the ``pyvenv`` script as follows, if you +don't have the relevant PATH and PATHEXT settings:: + + c:\Temp>c:\Python33\python c:\Python33\Tools\Scripts\pyvenv.py myenv + +or equivalently:: + + c:\Temp>c:\Python33\python -m venv myenv + +The command, if run with ``-h``, will show the available options:: + + usage: pyvenv [-h] [--system-site-packages] [--symlinks] [--clear] + [--upgrade] ENV_DIR [ENV_DIR ...] + + Creates virtual Python environments in one or more target directories. + + positional arguments: + ENV_DIR A directory to create the environment in. + + optional arguments: + -h, --help show this help message and exit + --system-site-packages Give access to the global site-packages dir to the + virtual environment. + --symlinks Try to use symlinks rather than copies, when symlinks + are not the default for the platform. + --clear Delete the environment directory if it already exists. + If not specified and the directory exists, an error is + raised. + --upgrade Upgrade the environment directory to use this version + of Python, assuming Python has been upgraded in-place. + +If the target directory already exists an error will be raised, unless +the ``--clear`` or ``--upgrade`` option was provided. + +The created ``pyvenv.cfg`` file also includes the +``include-system-site-packages`` key, set to ``true`` if ``venv`` is +run with the ``--system-site-packages`` option, ``false`` otherwise. + +Multiple paths can be given to ``pyvenv``, in which case an identical +virtualenv will be created, according to the given options, at each +provided path. + +Once a venv has been created, it can be "activated" using a script in the +venv's binary directory. The invocation of the script is platform-specific: on +a Posix platform, you would typically do:: + + $ source /bin/activate + +whereas on Windows, you might do:: + + C:\> /Scripts/activate + +if you are using the ``cmd.exe`` shell, or perhaps:: + + PS C:\> /Scripts/Activate.ps1 + +if you use PowerShell. + +You don't specifically *need* to activate an environment; activation just +prepends the venv's binary directory to your path, so that "python" invokes the +venv's Python interpreter and you can run installed scripts without having to +use their full path. However, all scripts installed in a venv should be +runnable without activating it, and run with the venv's Python automatically. + +You can deactivate a venv by typing "deactivate" in your shell. The exact +mechanism is platform-specific: for example, the Bash activation script defines +a "deactivate" function, whereas on Windows there are separate scripts called +``deactivate.bat`` and ``Deactivate.ps1`` which are installed when the venv is +created. + -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 10 16:05:09 2012 From: python-checkins at python.org (brett.cannon) Date: Tue, 10 Jul 2012 16:05:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315111=3A_When_a_m?= =?utf-8?q?odule_was_imported_using_a_=27from_import=27?= Message-ID: <3WWlY16YM4zN98@mail.python.org> http://hg.python.org/cpython/rev/dc18a2a66d16 changeset: 78051:dc18a2a66d16 user: Brett Cannon date: Tue Jul 10 10:05:00 2012 -0400 summary: Issue #15111: When a module was imported using a 'from import' statement (e.g. ``from distutils import msvc9compiler``) that triggers an ImportError of its own (e.g. the non-existence of winreg), let that exception propagate instead of raising a generic ImportError for the module being requested (e.g. msvc9compiler). files: Lib/importlib/_bootstrap.py | 10 +- Lib/importlib/test/import_/test_fromlist.py | 17 +- Misc/NEWS | 4 + Python/importlib.h | 801 ++++----- 4 files changed, 410 insertions(+), 422 deletions(-) diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -1459,16 +1459,14 @@ # The hell that is fromlist ... # If a package was imported, try to import stuff from fromlist. if hasattr(module, '__path__'): - if '*' in fromlist and hasattr(module, '__all__'): + if '*' in fromlist: fromlist = list(fromlist) fromlist.remove('*') - fromlist.extend(module.__all__) + if hasattr(module, '__all__'): + fromlist.extend(module.__all__) for x in fromlist: if not hasattr(module, x): - try: - import_('{}.{}'.format(module.__name__, x)) - except ImportError: - pass + import_('{}.{}'.format(module.__name__, x)) return module diff --git a/Lib/importlib/test/import_/test_fromlist.py b/Lib/importlib/test/import_/test_fromlist.py --- a/Lib/importlib/test/import_/test_fromlist.py +++ b/Lib/importlib/test/import_/test_fromlist.py @@ -39,11 +39,9 @@ [object case]. This is even true if the object does not exist [bad object]. If a package is being imported, then what is listed in fromlist may be - treated as a module to be imported [module]. But once again, even if - something in fromlist does not exist as a module, no error is thrown - [no module]. And this extends to what is contained in __all__ when '*' is - imported [using *]. And '*' does not need to be the only name in the - fromlist [using * with others]. + treated as a module to be imported [module]. And this extends to what is + contained in __all__ when '*' is imported [using *]. And '*' does not need + to be the only name in the fromlist [using * with others]. """ @@ -71,15 +69,6 @@ self.assertTrue(hasattr(module, 'module')) self.assertEqual(module.module.__name__, 'pkg.module') - def test_no_module_from_package(self): - # [no module] - with util.mock_modules('pkg.__init__') as importer: - with util.import_state(meta_path=[importer], - path_hooks=[imp.NullImporter]): - module = import_util.import_('pkg', fromlist='non_existent') - self.assertEqual(module.__name__, 'pkg') - self.assertTrue(not hasattr(module, 'non_existent')) - def test_empty_string(self): with util.mock_modules('pkg.__init__', 'pkg.mod') as importer: with util.import_state(meta_path=[importer]): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #15111: When a module imported using 'from import' has an ImportError + inside itself, don't mask that fact behind a generic ImportError for the + module itself. + - Issue #15293: Add GC support to the AST base node type. - Issue #15291: Fix a memory leak where AST nodes where not properly diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 10 18:29:27 2012 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 10 Jul 2012 18:29:27 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_compilation_under_Wind?= =?utf-8?q?ows?= Message-ID: <3WWplW10jmzN1Y@mail.python.org> http://hg.python.org/cpython/rev/2ecdda96f970 changeset: 78052:2ecdda96f970 user: Antoine Pitrou date: Tue Jul 10 18:27:54 2012 +0200 summary: Fix compilation under Windows files: Python/import.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -426,12 +426,13 @@ long PyImport_GetMagicNumber(void) { + long res; PyInterpreterState *interp = PyThreadState_Get()->interp; PyObject *pyc_magic = PyObject_GetAttrString(interp->importlib, "_RAW_MAGIC_NUMBER"); if (pyc_magic == NULL) return -1; - long res = PyLong_AsLong(pyc_magic); + res = PyLong_AsLong(pyc_magic); Py_DECREF(pyc_magic); return res; } -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Wed Jul 11 06:00:22 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 11 Jul 2012 06:00:22 +0200 Subject: [Python-checkins] Daily reference leaks (2ecdda96f970): sum=0 Message-ID: results for 2ecdda96f970 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogTqWtrV', '-x'] From python-checkins at python.org Wed Jul 11 08:30:54 2012 From: python-checkins at python.org (martin.v.loewis) Date: Wed, 11 Jul 2012 08:30:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE1MzE5?= =?utf-8?q?=3A_Revert_wrapping_of_sys=2Estdin=2E_Patch_by_Serhiy_Storchaka?= =?utf-8?q?=2E?= Message-ID: <3WX9QQ234pzMlD@mail.python.org> http://hg.python.org/cpython/rev/b90482742ee0 changeset: 78053:b90482742ee0 branch: 3.2 parent: 78039:f86df559319d user: Martin v. L?wis date: Wed Jul 11 08:29:03 2012 +0200 summary: Issue #15319: Revert wrapping of sys.stdin. Patch by Serhiy Storchaka. files: Lib/idlelib/NEWS.txt | 2 +- Lib/idlelib/run.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,7 +1,7 @@ What's New in IDLE 3.2.4? ========================= -- Issue #13532: Check that arguments to sys.stdout.write are strings. +- Issue #13532, #15319: Check that arguments to sys.stdout.write are strings. - Issue # 12510: Attempt to get certain tool tips no longer crashes IDLE. Erroneous tool tips have been corrected. Default added for callables. diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -269,7 +269,7 @@ """Override base method""" executive = Executive(self) self.register("exec", executive) - sys.stdin = self.console = _RPCFile(self.get_remote_proxy("stdin")) + sys.stdin = self.console = self.get_remote_proxy("stdin") sys.stdout = _RPCFile(self.get_remote_proxy("stdout")) sys.stderr = _RPCFile(self.get_remote_proxy("stderr")) # page help() text to shell. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 11 08:30:56 2012 From: python-checkins at python.org (martin.v.loewis) Date: Wed, 11 Jul 2012 08:30:56 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4y?= Message-ID: <3WX9QS0CGwzNmb@mail.python.org> http://hg.python.org/cpython/rev/6d4fab44fce2 changeset: 78054:6d4fab44fce2 parent: 78052:2ecdda96f970 parent: 78053:b90482742ee0 user: Martin v. L?wis date: Wed Jul 11 08:29:55 2012 +0200 summary: merge 3.2 files: Lib/idlelib/NEWS.txt | 2 +- Lib/idlelib/run.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,7 +1,7 @@ What's New in IDLE 3.3.0? ========================= -- Issue #13532: Check that arguments to sys.stdout.write are strings. +- Issue #13532, #15319: Check that arguments to sys.stdout.write are strings. - Issue # 12510: Attempt to get certain tool tips no longer crashes IDLE. Erroneous tool tips have been corrected. Default added for callables. diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -282,7 +282,7 @@ """Override base method""" executive = Executive(self) self.register("exec", executive) - sys.stdin = self.console = _RPCFile(self.get_remote_proxy("stdin")) + sys.stdin = self.console = self.get_remote_proxy("stdin") sys.stdout = _RPCFile(self.get_remote_proxy("stdout")) sys.stderr = _RPCFile(self.get_remote_proxy("stderr")) sys.displayhook = rpc.displayhook -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 11 08:32:17 2012 From: python-checkins at python.org (martin.v.loewis) Date: Wed, 11 Jul 2012 08:32:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE1MzE5?= =?utf-8?q?=3A_Revert_wrapping_of_sys=2Estdin=2E_Patch_by_Serhiy_Storchaka?= =?utf-8?q?=2E?= Message-ID: <3WX9S10zvSzNSw@mail.python.org> http://hg.python.org/cpython/rev/42424c1f605c changeset: 78055:42424c1f605c branch: 2.7 parent: 78045:4f891f44ec15 user: Martin v. L?wis date: Wed Jul 11 08:32:05 2012 +0200 summary: Issue #15319: Revert wrapping of sys.stdin. Patch by Serhiy Storchaka. files: Lib/idlelib/NEWS.txt | 2 +- Lib/idlelib/run.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,7 +1,7 @@ What's New in IDLE 2.7.4? ========================= -- Issue #13532: Check that arguments to sys.stdout.write are strings. +- Issue #13532, #15319: Check that arguments to sys.stdout.write are strings. - Issue # 12510: Attempt to get certain tool tips no longer crashes IDLE. diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -273,7 +273,7 @@ """Override base method""" executive = Executive(self) self.register("exec", executive) - sys.stdin = self.console = _RPCFile(self.get_remote_proxy("stdin")) + sys.stdin = self.console = self.get_remote_proxy("stdin") sys.stdout = _RPCFile(self.get_remote_proxy("stdout")) sys.stderr = _RPCFile(self.get_remote_proxy("stderr")) from idlelib import IOBinding -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 11 08:49:35 2012 From: python-checkins at python.org (martin.v.loewis) Date: Wed, 11 Jul 2012 08:49:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogRG9uJ3QgdXNlIFRl?= =?utf-8?q?xtIOBase_implementations_in_=5FRPCFile=2E?= Message-ID: <3WX9qz4q06zMFN@mail.python.org> http://hg.python.org/cpython/rev/ff2a5f4bacd5 changeset: 78056:ff2a5f4bacd5 branch: 3.2 parent: 78053:b90482742ee0 user: Martin v. L?wis date: Wed Jul 11 08:48:34 2012 +0200 summary: Don't use TextIOBase implementations in _RPCFile. files: Lib/idlelib/run.py | 10 ++++++++-- 1 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -247,12 +247,18 @@ class _RPCFile(io.TextIOBase): """Wrapper class for the RPC proxy to typecheck arguments - that may not support pickling.""" + that may not support pickling. The base class is there only + to support type tests; all implementations come from the remote + object.""" def __init__(self, rpc): super.__setattr__(self, 'rpc', rpc) - def __getattr__(self, name): + def __getattribute__(self, name): + # When accessing the 'rpc' attribute, use ours + if name == 'rpc': + return io.TextIOBase.__getattribute__(self, name) + # Else only look into the remote object only return getattr(self.rpc, name) def __setattr__(self, name, value): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 11 08:49:37 2012 From: python-checkins at python.org (martin.v.loewis) Date: Wed, 11 Jul 2012 08:49:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4y?= Message-ID: <3WX9r12BjtzNbx@mail.python.org> http://hg.python.org/cpython/rev/76b7b74c42bb changeset: 78057:76b7b74c42bb parent: 78054:6d4fab44fce2 parent: 78056:ff2a5f4bacd5 user: Martin v. L?wis date: Wed Jul 11 08:49:24 2012 +0200 summary: merge 3.2 files: Lib/idlelib/run.py | 10 ++++++++-- 1 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -260,12 +260,18 @@ class _RPCFile(io.TextIOBase): """Wrapper class for the RPC proxy to typecheck arguments - that may not support pickling.""" + that may not support pickling. The base class is there only + to support type tests; all implementations come from the remote + object.""" def __init__(self, rpc): super.__setattr__(self, 'rpc', rpc) - def __getattr__(self, name): + def __getattribute__(self, name): + # When accessing the 'rpc' attribute, use ours + if name == 'rpc': + return io.TextIOBase.__getattribute__(self, name) + # Else only look into the remote object only return getattr(self.rpc, name) def __setattr__(self, name, value): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 11 08:50:09 2012 From: python-checkins at python.org (martin.v.loewis) Date: Wed, 11 Jul 2012 08:50:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogRG9uJ3QgdXNlIFRl?= =?utf-8?q?xtIOBase_implementations_in_=5FRPCFile=2E?= Message-ID: <3WX9rd3Z6qzMFN@mail.python.org> http://hg.python.org/cpython/rev/b659315883dd changeset: 78058:b659315883dd branch: 2.7 parent: 78055:42424c1f605c user: Martin v. L?wis date: Wed Jul 11 08:49:58 2012 +0200 summary: Don't use TextIOBase implementations in _RPCFile. files: Lib/idlelib/run.py | 10 ++++++++-- 1 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -251,12 +251,18 @@ class _RPCFile(io.TextIOBase): """Wrapper class for the RPC proxy to typecheck arguments - that may not support pickling.""" + that may not support pickling. The base class is there only + to support type tests; all implementations come from the remote + object.""" def __init__(self, rpc): super.__setattr__(self, 'rpc', rpc) - def __getattr__(self, name): + def __getattribute__(self, name): + # When accessing the 'rpc' attribute, use ours + if name == 'rpc': + return io.TextIOBase.__getattribute__(self, name) + # Else only look into the remote object only return getattr(self.rpc, name) def __setattr__(self, name, value): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 11 09:18:24 2012 From: python-checkins at python.org (martin.v.loewis) Date: Wed, 11 Jul 2012 09:18:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogVXNlIF9SUENGaWxl?= =?utf-8?q?=2Ewrite_properly=2E?= Message-ID: <3WXBTD6fkRzNLp@mail.python.org> http://hg.python.org/cpython/rev/302df09a6aa8 changeset: 78059:302df09a6aa8 branch: 3.2 parent: 78056:ff2a5f4bacd5 user: Martin v. L?wis date: Wed Jul 11 09:17:15 2012 +0200 summary: Use _RPCFile.write properly. files: Lib/idlelib/run.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -255,8 +255,8 @@ super.__setattr__(self, 'rpc', rpc) def __getattribute__(self, name): - # When accessing the 'rpc' attribute, use ours - if name == 'rpc': + # When accessing the 'rpc' attribute, or 'write', use ours + if name in ('rpc', 'write'): return io.TextIOBase.__getattribute__(self, name) # Else only look into the remote object only return getattr(self.rpc, name) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 11 09:18:26 2012 From: python-checkins at python.org (martin.v.loewis) Date: Wed, 11 Jul 2012 09:18:26 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4y?= Message-ID: <3WXBTG48R9zNkW@mail.python.org> http://hg.python.org/cpython/rev/300e2bbd413c changeset: 78060:300e2bbd413c parent: 78057:76b7b74c42bb parent: 78059:302df09a6aa8 user: Martin v. L?wis date: Wed Jul 11 09:17:54 2012 +0200 summary: merge 3.2 files: Lib/idlelib/run.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -268,8 +268,8 @@ super.__setattr__(self, 'rpc', rpc) def __getattribute__(self, name): - # When accessing the 'rpc' attribute, use ours - if name == 'rpc': + # When accessing the 'rpc' attribute, or 'write', use ours + if name in ('rpc', 'write'): return io.TextIOBase.__getattribute__(self, name) # Else only look into the remote object only return getattr(self.rpc, name) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 11 09:19:25 2012 From: python-checkins at python.org (martin.v.loewis) Date: Wed, 11 Jul 2012 09:19:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogVXNlIF9SUENGaWxl?= =?utf-8?q?=2Ewrite_properly=2E?= Message-ID: <3WXBVP2khDzNLp@mail.python.org> http://hg.python.org/cpython/rev/93df82c18781 changeset: 78061:93df82c18781 branch: 2.7 parent: 78058:b659315883dd user: Martin v. L?wis date: Wed Jul 11 09:19:16 2012 +0200 summary: Use _RPCFile.write properly. files: Lib/idlelib/run.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -259,8 +259,8 @@ super.__setattr__(self, 'rpc', rpc) def __getattribute__(self, name): - # When accessing the 'rpc' attribute, use ours - if name == 'rpc': + # When accessing the 'rpc' attribute, or 'write', use ours + if name in ('rpc', 'write'): return io.TextIOBase.__getattribute__(self, name) # Else only look into the remote object only return getattr(self.rpc, name) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 11 19:23:28 2012 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 11 Jul 2012 19:23:28 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE1MzAw?= =?utf-8?q?=3A_Ensure_the_temporary_test_working_directories_are_in_the_sa?= =?utf-8?q?me?= Message-ID: <3WXRvN4sFszNnH@mail.python.org> http://hg.python.org/cpython/rev/724a6e0e35f0 changeset: 78062:724a6e0e35f0 branch: 3.2 parent: 78059:302df09a6aa8 user: Antoine Pitrou date: Wed Jul 11 19:19:14 2012 +0200 summary: Issue #15300: Ensure the temporary test working directories are in the same parent folder when running tests in multiprocess mode from a Python build. Patch by Chris Jerdonek. files: Lib/test/regrtest.py | 6 +++++- Misc/ACKS | 1 + Misc/NEWS | 4 ++++ 3 files changed, 10 insertions(+), 1 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -572,10 +572,14 @@ output.put((None, None, None, None)) return # -E is needed by some tests, e.g. test_import + # Running the child from the same working directory ensures + # that TEMPDIR for the child is the same when + # sysconfig.is_python_build() is true. See issue 15300. popen = Popen(base_cmd + ['--slaveargs', json.dumps(args_tuple)], stdout=PIPE, stderr=PIPE, universal_newlines=True, - close_fds=(os.name != 'nt')) + close_fds=(os.name != 'nt'), + cwd=support.SAVEDCWD) stdout, stderr = popen.communicate() # Strip last refcount output line if it exists, since it # comes from the shutdown of the interpreter in the subcommand. diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -458,6 +458,7 @@ Drew Jenkins Flemming Kj?r Jensen MunSic Jeong +Chris Jerdonek Orjan Johansen Fredrik Johansson Gregory K. Johnson diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -341,6 +341,10 @@ Tests ----- +- Issue #15300: Ensure the temporary test working directories are in the same + parent folder when running tests in multiprocess mode from a Python build. + Patch by Chris Jerdonek. + - test_nntplib now tolerates being run from behind NNTP gateways that add "X-Antivirus" headers to articles -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 11 19:23:30 2012 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 11 Jul 2012 19:23:30 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2315300=3A_Ensure_the_temporary_test_working_dire?= =?utf-8?q?ctories_are_in_the_same?= Message-ID: <3WXRvQ37TCzNw0@mail.python.org> http://hg.python.org/cpython/rev/4752fafb579d changeset: 78063:4752fafb579d parent: 78060:300e2bbd413c parent: 78062:724a6e0e35f0 user: Antoine Pitrou date: Wed Jul 11 19:21:31 2012 +0200 summary: Issue #15300: Ensure the temporary test working directories are in the same parent folder when running tests in multiprocess mode from a Python build. Patch by Chris Jerdonek. files: Lib/test/regrtest.py | 6 +++++- Misc/ACKS | 1 + Misc/NEWS | 4 ++++ 3 files changed, 10 insertions(+), 1 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -634,10 +634,14 @@ output.put((None, None, None, None)) return # -E is needed by some tests, e.g. test_import + # Running the child from the same working directory ensures + # that TEMPDIR for the child is the same when + # sysconfig.is_python_build() is true. See issue 15300. popen = Popen(base_cmd + ['--slaveargs', json.dumps(args_tuple)], stdout=PIPE, stderr=PIPE, universal_newlines=True, - close_fds=(os.name != 'nt')) + close_fds=(os.name != 'nt'), + cwd=support.SAVEDCWD) stdout, stderr = popen.communicate() retcode = popen.wait() # Strip last refcount output line if it exists, since it diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -505,6 +505,7 @@ Drew Jenkins Flemming Kj?r Jensen MunSic Jeong +Chris Jerdonek Jim Jewett Orjan Johansen Fredrik Johansson diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -121,6 +121,10 @@ Tests ----- +- Issue #15300: Ensure the temporary test working directories are in the same + parent folder when running tests in multiprocess mode from a Python build. + Patch by Chris Jerdonek. + - Issue #15284: Skip {send,recv}msg tests in test_socket when IPv6 is not enabled. Patch by Brian Brazil. -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Thu Jul 12 06:00:10 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 12 Jul 2012 06:00:10 +0200 Subject: [Python-checkins] Daily reference leaks (4752fafb579d): sum=0 Message-ID: results for 4752fafb579d on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/refloghrkGo1', '-x'] From python-checkins at python.org Thu Jul 12 19:23:32 2012 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 12 Jul 2012 19:23:32 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Try_to_fix_or_diagnose_bui?= =?utf-8?q?ldbot_failures?= Message-ID: <3WY3s05Y3tzP0l@mail.python.org> http://hg.python.org/cpython/rev/85083e50c717 changeset: 78064:85083e50c717 user: Antoine Pitrou date: Thu Jul 12 19:21:43 2012 +0200 summary: Try to fix or diagnose buildbot failures files: Lib/test/test_import.py | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -194,6 +194,7 @@ # New in 2.4, we shouldn't be able to import that no matter how often # we try. sys.path.insert(0, os.curdir) + importlib.invalidate_caches() if TESTFN in sys.modules: del sys.modules[TESTFN] try: @@ -465,7 +466,11 @@ unc += path[2:] sys.path.append(unc) try: - mod = __import__("test_trailing_slash") + try: + mod = __import__("test_trailing_slash") + except ImportError as e: + self.fail("could not import 'test_trailing_slash' from %r: %r" + % (unc, e)) self.assertEqual(mod.testdata, 'test_trailing_slash') unload("test_trailing_slash") finally: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 12 19:51:45 2012 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 12 Jul 2012 19:51:45 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Small_improvements_to_test?= =?utf-8?b?X3VuY19wYXRo?= Message-ID: <3WY4TY3QG5zP4s@mail.python.org> http://hg.python.org/cpython/rev/be240afaa894 changeset: 78065:be240afaa894 user: Antoine Pitrou date: Thu Jul 12 19:48:49 2012 +0200 summary: Small improvements to test_unc_path files: Lib/test/test_import.py | 15 ++++++++------- 1 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -454,8 +454,8 @@ # Regression test for http://bugs.python.org/issue3677. @unittest.skipUnless(sys.platform == 'win32', 'Windows-specific') def test_UNC_path(self): - with open(os.path.join(self.path, 'test_trailing_slash.py'), 'w') as f: - f.write("testdata = 'test_trailing_slash'") + with open(os.path.join(self.path, 'test_unc_path.py'), 'w') as f: + f.write("testdata = 'test_unc_path'") importlib.invalidate_caches() # Create the UNC path, like \\myhost\c$\foo\bar. path = os.path.abspath(self.path) @@ -464,15 +464,16 @@ drive = path[0] unc = "\\\\%s\\%s$"%(hn, drive) unc += path[2:] - sys.path.append(unc) + sys.path.insert(0, unc) try: try: - mod = __import__("test_trailing_slash") + mod = __import__("test_unc_path") except ImportError as e: - self.fail("could not import 'test_trailing_slash' from %r: %r" + self.fail("could not import 'test_unc_path' from %r: %r" % (unc, e)) - self.assertEqual(mod.testdata, 'test_trailing_slash') - unload("test_trailing_slash") + self.assertEqual(mod.testdata, 'test_unc_path') + self.assertTrue(mod.__file__.startswith(unc), mod.__file__) + unload("test_unc_path") finally: sys.path.remove(unc) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 12 19:51:47 2012 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 12 Jul 2012 19:51:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_For_diagnosis=2C_try_to_li?= =?utf-8?q?st_the_directory_first?= Message-ID: <3WY4Tb0DPpzNw0@mail.python.org> http://hg.python.org/cpython/rev/387ce49230cf changeset: 78066:387ce49230cf user: Antoine Pitrou date: Thu Jul 12 19:50:03 2012 +0200 summary: For diagnosis, try to list the directory first files: Lib/test/test_import.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -466,6 +466,7 @@ unc += path[2:] sys.path.insert(0, unc) try: + os.listdir(unc) try: mod = __import__("test_unc_path") except ImportError as e: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 12 20:27:04 2012 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 12 Jul 2012 20:27:04 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_Show_the_prope?= =?utf-8?q?r_way_to_exit_a_cmd_shell?= Message-ID: <3WY5GJ2WR9zP2y@mail.python.org> http://hg.python.org/cpython/rev/f1a0823b7772 changeset: 78067:f1a0823b7772 branch: 3.2 parent: 78062:724a6e0e35f0 user: Raymond Hettinger date: Thu Jul 12 11:26:01 2012 -0700 summary: Show the proper way to exit a cmd shell files: Doc/library/cmd.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/cmd.rst b/Doc/library/cmd.rst --- a/Doc/library/cmd.rst +++ b/Doc/library/cmd.rst @@ -276,7 +276,7 @@ print('Thank you for using Turtle') self.close() bye() - sys.exit(0) + return True # ----- record and playback ----- def do_record(self, arg): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 12 20:27:06 2012 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 12 Jul 2012 20:27:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3WY5GL00RgzP2y@mail.python.org> http://hg.python.org/cpython/rev/38f822128c65 changeset: 78068:38f822128c65 parent: 78066:387ce49230cf parent: 78067:f1a0823b7772 user: Raymond Hettinger date: Thu Jul 12 11:26:56 2012 -0700 summary: merge files: Doc/library/cmd.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/cmd.rst b/Doc/library/cmd.rst --- a/Doc/library/cmd.rst +++ b/Doc/library/cmd.rst @@ -276,7 +276,7 @@ print('Thank you for using Turtle') self.close() bye() - sys.exit(0) + return True # ----- record and playback ----- def do_record(self, arg): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 12 20:33:56 2012 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 12 Jul 2012 20:33:56 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogQWRkIGNfc2l6ZV90?= =?utf-8?q?_and_c=5Fssize=5Ft_to_the_ctypes_summary_table=2E?= Message-ID: <3WY5QD15trzM4h@mail.python.org> http://hg.python.org/cpython/rev/a8aa77458e12 changeset: 78069:a8aa77458e12 branch: 3.2 parent: 78067:f1a0823b7772 user: Antoine Pitrou date: Thu Jul 12 20:31:50 2012 +0200 summary: Add c_size_t and c_ssize_t to the ctypes summary table. files: Doc/library/ctypes.rst | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -243,6 +243,11 @@ | :class:`c_ulonglong` | :c:type:`unsigned __int64` or | int | | | :c:type:`unsigned long long` | | +----------------------+------------------------------------------+----------------------------+ +| :class:`c_size_t` | :c:type:`size_t` | int | ++----------------------+------------------------------------------+----------------------------+ +| :class:`c_ssize_t` | :c:type:`ssize_t` or | int | +| | :c:type:`Py_ssize_t` | | ++----------------------+------------------------------------------+----------------------------+ | :class:`c_float` | :c:type:`float` | float | +----------------------+------------------------------------------+----------------------------+ | :class:`c_double` | :c:type:`double` | float | -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 12 20:33:57 2012 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 12 Jul 2012 20:33:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Add_c=5Fsize=5Ft_and_c=5Fssize=5Ft_to_the_ctypes_summary?= =?utf-8?q?_table=2E?= Message-ID: <3WY5QF62tXzP38@mail.python.org> http://hg.python.org/cpython/rev/c2f33ce165f1 changeset: 78070:c2f33ce165f1 parent: 78068:38f822128c65 parent: 78069:a8aa77458e12 user: Antoine Pitrou date: Thu Jul 12 20:32:11 2012 +0200 summary: Add c_size_t and c_ssize_t to the ctypes summary table. files: Doc/library/ctypes.rst | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -248,6 +248,11 @@ | :class:`c_ulonglong` | :c:type:`unsigned __int64` or | int | | | :c:type:`unsigned long long` | | +----------------------+------------------------------------------+----------------------------+ +| :class:`c_size_t` | :c:type:`size_t` | int | ++----------------------+------------------------------------------+----------------------------+ +| :class:`c_ssize_t` | :c:type:`ssize_t` or | int | +| | :c:type:`Py_ssize_t` | | ++----------------------+------------------------------------------+----------------------------+ | :class:`c_float` | :c:type:`float` | float | +----------------------+------------------------------------------+----------------------------+ | :class:`c_double` | :c:type:`double` | float | -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 12 21:18:55 2012 From: python-checkins at python.org (stefan.krah) Date: Thu, 12 Jul 2012 21:18:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=237652=3A_Clean_up_?= =?utf-8?q?=5Fmpd=5Fqinvroot=28=29_and_mark_it_LIBMPDEC=5FONLY=2E_Use_the?= Message-ID: <3WY6Q72WlPzP7W@mail.python.org> http://hg.python.org/cpython/rev/afdb0e1a9dac changeset: 78071:afdb0e1a9dac user: Stefan Krah date: Thu Jul 12 21:17:59 2012 +0200 summary: Issue #7652: Clean up _mpd_qinvroot() and mark it LIBMPDEC_ONLY. Use the algorithm from decimal.py for mpd_qsqrt(). files: Modules/_decimal/libmpdec/mpdecimal.c | 313 +++++++------ 1 files changed, 159 insertions(+), 154 deletions(-) diff --git a/Modules/_decimal/libmpdec/mpdecimal.c b/Modules/_decimal/libmpdec/mpdecimal.c --- a/Modules/_decimal/libmpdec/mpdecimal.c +++ b/Modules/_decimal/libmpdec/mpdecimal.c @@ -4298,7 +4298,7 @@ /* * Set 'result' to log(10). * Ulp error: abs(result - log(10)) < ulp(log(10)) - * Relative error : abs(result - log(10)) < 5 * 10**-prec * log(10) + * Relative error: abs(result - log(10)) < 5 * 10**-prec * log(10) * * NOTE: The relative error is not derived from the ulp error, but * calculated separately using the fact that 23/10 < log(10) < 24/10. @@ -7204,6 +7204,19 @@ mpd_setspecial(r, MPD_POS, MPD_NAN); } +/* LIBMPDEC_ONLY */ +/* + * Schedule the optimal precision increase for the Newton iteration. + * v := input operand + * z_0 := initial approximation + * initprec := natural number such that abs(sqrt(v) - z_0) < 10**-initprec + * maxprec := target precision + * + * For convenience the output klist contains the elements in reverse order: + * klist := [k_n-1, ..., k_0], where + * 1) k_0 <= initprec and + * 2) abs(sqrt(v) - result) < 10**(-2*k_n-1 + 2) <= 10**-maxprec. + */ static inline int invroot_schedule_prec(mpd_ssize_t klist[MPD_MAX_PREC_LOG2], mpd_ssize_t maxprec, mpd_ssize_t initprec) @@ -7224,29 +7237,27 @@ } /* - * Initial approximation for the inverse square root. - * + * Initial approximation for the inverse square root function. * Input: - * v := 7 or 8 decimal digits with an implicit exponent of 10**-6, - * representing a number 1 <= x < 100. - * + * v := rational number, with 1 <= v < 100 + * vhat := floor(v * 10**6) * Output: - * An approximation to 1/sqrt(v) + * z := approximation to 1/sqrt(v), such that abs(z - 1/sqrt(v)) < 10**-3. */ static inline void -_invroot_init_approx(mpd_t *z, mpd_uint_t v) +_invroot_init_approx(mpd_t *z, mpd_uint_t vhat) { mpd_uint_t lo = 1000; mpd_uint_t hi = 10000; mpd_uint_t a, sq; - assert(v >= lo*lo && v < (hi+1)*(hi+1)); + assert(lo*lo <= vhat && vhat < (hi+1)*(hi+1)); for(;;) { a = (lo + hi) / 2; sq = a * a; - if (v >= sq) { - if (v < sq + 2*a + 1) { + if (vhat >= sq) { + if (vhat < sq + 2*a + 1) { break; } lo = a + 1; @@ -7256,7 +7267,19 @@ } } - /* At this point a/1000 is an approximation to sqrt(v). */ + /* + * After the binary search we have: + * 1) a**2 <= floor(v * 10**6) < (a + 1)**2 + * This implies: + * 2) a**2 <= v * 10**6 < (a + 1)**2 + * 3) a <= sqrt(v) * 10**3 < a + 1 + * Since 10**3 <= a: + * 4) 0 <= 10**prec/a - 1/sqrt(v) < 10**-prec + * We have: + * 5) 10**3/a - 10**-3 < floor(10**9/a) * 10**-6 <= 10**3/a + * Merging 4) and 5): + * 6) abs(floor(10**9/a) * 10**-6 - 1/sqrt(v)) < 10**-3 + */ mpd_minalloc(z); mpd_clear_flags(z); z->data[0] = 1000000000UL / a; @@ -7265,6 +7288,10 @@ mpd_setdigits(z); } +/* + * Set 'result' to 1/sqrt(a). + * Relative error: abs(result - 1/sqrt(a)) < 10**-prec * 1/sqrt(a) + */ static void _mpd_qinvroot(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status) @@ -7282,7 +7309,7 @@ mpd_ssize_t ideal_exp, shift; mpd_ssize_t adj, tz; mpd_ssize_t maxprec, fracdigits; - mpd_uint_t x, dummy; + mpd_uint_t vhat, dummy; int i, n; @@ -7301,30 +7328,33 @@ fracdigits = v->digits - 1; v->exp = -fracdigits; n = (v->digits > 7) ? 7 : (int)v->digits; - _mpd_get_msdigits(&dummy, &x, v, n); + /* Let vhat := floor(v * 10**(2*initprec)) */ + _mpd_get_msdigits(&dummy, &vhat, v, n); if (n < 7) { - x *= mpd_pow10[7-n]; + vhat *= mpd_pow10[7-n]; } } else { fracdigits = v->digits - 2; v->exp = -fracdigits; n = (v->digits > 8) ? 8 : (int)v->digits; - _mpd_get_msdigits(&dummy, &x, v, n); + /* Let vhat := floor(v * 10**(2*initprec)) */ + _mpd_get_msdigits(&dummy, &vhat, v, n); if (n < 8) { - x *= mpd_pow10[8-n]; + vhat *= mpd_pow10[8-n]; } } adj = (a->exp-v->exp) / 2; /* initial approximation */ - _invroot_init_approx(z, x); + _invroot_init_approx(z, vhat); mpd_maxcontext(&maxcontext); mpd_maxcontext(&varcontext); varcontext.round = MPD_ROUND_TRUNC; - maxprec = ctx->prec + 2; - + maxprec = ctx->prec + 1; + + /* initprec == 3 */ i = invroot_schedule_prec(klist, maxprec, 3); for (; i >= 0; i--) { varcontext.prec = 2*klist[i]+2; @@ -7358,15 +7388,14 @@ mpd_del(&t); if (v != &vtmp) mpd_del(v); *status |= (workstatus&MPD_Errors); - varcontext = *ctx; - varcontext.round = MPD_ROUND_HALF_EVEN; - mpd_qfinalize(result, &varcontext, status); + *status |= (MPD_Rounded|MPD_Inexact); } void mpd_qinvroot(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status) { + mpd_context_t workctx; if (mpd_isspecial(a)) { if (mpd_qcheck_nan(result, a, ctx, status)) { @@ -7391,75 +7420,29 @@ return; } - _mpd_qinvroot(result, a, ctx, status); -} - -/* - * Ensure correct rounding. Algorithm after Hull & Abrham, "Properly Rounded - * Variable Precision Square Root", ACM Transactions on Mathematical Software, - * Vol. 11, No. 3. - */ -static void -_mpd_fix_sqrt(mpd_t *result, const mpd_t *a, mpd_t *tmp, - const mpd_context_t *ctx, uint32_t *status) -{ - mpd_context_t maxctx; - MPD_NEW_CONST(u,0,0,1,1,1,5); - - mpd_maxcontext(&maxctx); - u.exp = u.digits - ctx->prec + result->exp - 1; - - _mpd_qsub(tmp, result, &u, &maxctx, status); - if (*status&MPD_Errors) goto nanresult; - - _mpd_qmul(tmp, tmp, tmp, &maxctx, status); - if (*status&MPD_Errors) goto nanresult; - - if (_mpd_cmp(tmp, a) == 1) { - u.exp += 1; - u.data[0] = 1; - _mpd_qsub(result, result, &u, &maxctx, status); - } - else { - _mpd_qadd(tmp, result, &u, &maxctx, status); - if (*status&MPD_Errors) goto nanresult; - - _mpd_qmul(tmp, tmp, tmp, &maxctx, status); - if (*status&MPD_Errors) goto nanresult; - - if (_mpd_cmp(tmp, a) == -1) { - u.exp += 1; - u.data[0] = 1; - _mpd_qadd(result, result, &u, &maxctx, status); - } - } - - return; - -nanresult: - mpd_setspecial(result, MPD_POS, MPD_NAN); -} - + workctx = *ctx; + workctx.prec += 2; + workctx.round = MPD_ROUND_HALF_EVEN; + _mpd_qinvroot(result, a, &workctx, status); + mpd_qfinalize(result, ctx, status); +} +/* END LIBMPDEC_ONLY */ + +/* Algorithm from decimal.py */ void mpd_qsqrt(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status) { - uint32_t workstatus = 0; - mpd_context_t varcontext; - mpd_t *z = result; /* current approximation */ - MPD_NEW_STATIC(v,0,0,0,0); /* a, normalized to a number between 1 and 10 */ - MPD_NEW_STATIC(vtmp,0,0,0,0); - MPD_NEW_STATIC(tmp,0,0,0,0); - mpd_ssize_t ideal_exp, shift; - mpd_ssize_t target_prec, fracdigits; - mpd_ssize_t a_exp, a_digits; - mpd_ssize_t adj, tz; - mpd_uint_t dummy, t; + mpd_context_t maxcontext; + MPD_NEW_STATIC(c,0,0,0,0); + MPD_NEW_STATIC(q,0,0,0,0); + MPD_NEW_STATIC(r,0,0,0,0); + MPD_NEW_CONST(two,0,0,1,1,1,2); + mpd_ssize_t prec, ideal_exp; + mpd_ssize_t l, shift; int exact = 0; - varcontext = *ctx; - varcontext.round = MPD_ROUND_HALF_EVEN; ideal_exp = (a->exp - (a->exp & 1)) / 2; if (mpd_isspecial(a)) { @@ -7483,79 +7466,101 @@ return; } - if (!mpd_qcopy(&v, a, status)) { - mpd_seterror(result, MPD_Malloc_error, status); - goto finish; - } - - a_exp = a->exp; - a_digits = a->digits; - - /* normalize a to 1 <= v < 100 */ - if ((v.digits+v.exp) & 1) { - fracdigits = v.digits - 1; - v.exp = -fracdigits; - _mpd_get_msdigits(&dummy, &t, &v, 3); - t = t < 100 ? t*10 : t; - t = t < 100 ? t*10 : t; + mpd_maxcontext(&maxcontext); + prec = ctx->prec + 1; + + if (!mpd_qcopy(&c, a, status)) { + goto malloc_error; + } + c.exp = 0; + + if (a->exp & 1) { + if (!mpd_qshiftl(&c, &c, 1, status)) { + goto malloc_error; + } + l = (a->digits >> 1) + 1; } else { - fracdigits = v.digits - 2; - v.exp = -fracdigits; - _mpd_get_msdigits(&dummy, &t, &v, 4); - t = t < 1000 ? t*10 : t; - t = t < 1000 ? t*10 : t; - t = t < 1000 ? t*10 : t; - } - adj = (a_exp-v.exp) / 2; - - - /* use excess digits */ - target_prec = (a_digits > ctx->prec) ? a_digits : ctx->prec; - target_prec += 2; - varcontext.prec = target_prec + 3; - - /* invroot is much faster for large numbers */ - _mpd_qinvroot(&tmp, &v, &varcontext, &workstatus); - - varcontext.prec = target_prec; - _mpd_qdiv(NO_IDEAL_EXP, z, &one, &tmp, &varcontext, &workstatus); - - - tz = mpd_trail_zeros(result); - if ((result->digits-tz)*2-1 <= v.digits) { - _mpd_qmul(&tmp, result, result, &varcontext, &workstatus); - if (workstatus&MPD_Errors) { - mpd_seterror(result, workstatus&MPD_Errors, status); - goto finish; - } - exact = (_mpd_cmp(&tmp, &v) == 0); - } - *status |= (workstatus&MPD_Errors); - - if (!exact && !mpd_isspecial(result) && !mpd_iszero(result)) { - _mpd_fix_sqrt(result, &v, &tmp, &varcontext, status); - if (mpd_isspecial(result)) goto finish; - *status |= (MPD_Rounded|MPD_Inexact); - } - - result->exp += adj; + l = (a->digits + 1) >> 1; + } + + shift = prec - l; + if (shift >= 0) { + if (!mpd_qshiftl(&c, &c, 2*shift, status)) { + goto malloc_error; + } + exact = 1; + } + else { + exact = !mpd_qshiftr_inplace(&c, -2*shift); + } + + ideal_exp -= shift; + + /* find result = floor(sqrt(c)) using Newton's method */ + if (!mpd_qshiftl(result, &one, prec, status)) { + goto malloc_error; + } + + while (1) { + _mpd_qdivmod(&q, &r, &c, result, &maxcontext, &maxcontext.status); + if (mpd_isspecial(result) || mpd_isspecial(&q)) { + mpd_seterror(result, maxcontext.status&MPD_Errors, status); + goto out; + } + if (_mpd_cmp(result, &q) <= 0) { + break; + } + _mpd_qadd_exact(result, result, &q, &maxcontext, &maxcontext.status); + if (mpd_isspecial(result)) { + mpd_seterror(result, maxcontext.status&MPD_Errors, status); + goto out; + } + _mpd_qdivmod(result, &r, result, &two, &maxcontext, &maxcontext.status); + } + if (exact) { - shift = ideal_exp - result->exp; - shift = (tz > shift) ? shift : tz; - if (shift > 0) { + _mpd_qmul_exact(&r, result, result, &maxcontext, &maxcontext.status); + if (mpd_isspecial(&r)) { + mpd_seterror(result, maxcontext.status&MPD_Errors, status); + goto out; + } + exact = (_mpd_cmp(&r, &c) == 0); + } + + if (exact) { + if (shift >= 0) { mpd_qshiftr_inplace(result, shift); - result->exp += shift; - } - } - - -finish: - mpd_del(&v); - mpd_del(&vtmp); - mpd_del(&tmp); - varcontext.prec = ctx->prec; - mpd_qfinalize(result, &varcontext, status); + } + else { + if (!mpd_qshiftl(result, result, -shift, status)) { + goto malloc_error; + } + } + ideal_exp += shift; + } + else { + int lsd = mpd_lsd(result->data[0]); + if (lsd == 0 || lsd == 5) { + result->data[0] += 1; + } + } + + result->exp = ideal_exp; + + +out: + mpd_del(&c); + mpd_del(&q); + mpd_del(&r); + maxcontext = *ctx; + maxcontext.round = MPD_ROUND_HALF_EVEN; + mpd_qfinalize(result, &maxcontext, status); + return; + +malloc_error: + mpd_seterror(result, MPD_Malloc_error, status); + goto out; } -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri Jul 13 05:59:15 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 13 Jul 2012 05:59:15 +0200 Subject: [Python-checkins] Daily reference leaks (afdb0e1a9dac): sum=0 Message-ID: results for afdb0e1a9dac on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/refloglxhW5G', '-x'] From python-checkins at python.org Fri Jul 13 08:02:13 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 13 Jul 2012 08:02:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Remove_=3Anoindex=3A_for_t?= =?utf-8?q?hreading=2EThread_which_killed_all_reference_links_to_it?= Message-ID: <3WYNhP4qbHzP7m@mail.python.org> http://hg.python.org/cpython/rev/443016afe037 changeset: 78072:443016afe037 user: Eli Bendersky date: Fri Jul 13 09:01:57 2012 +0300 summary: Remove :noindex: for threading.Thread which killed all reference links to it files: Doc/library/threading.rst | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst --- a/Doc/library/threading.rst +++ b/Doc/library/threading.rst @@ -134,7 +134,6 @@ .. class:: Thread - :noindex: A class that represents a thread of control. This class can be safely subclassed in a limited fashion. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 13 08:45:48 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 13 Jul 2012 08:45:48 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Some_fixes_for_the_documen?= =?utf-8?q?tation_of_multiprocessing_=28per_issue_=2313686=29?= Message-ID: <3WYPfh44fgzP4C@mail.python.org> http://hg.python.org/cpython/rev/caea3c64442b changeset: 78073:caea3c64442b user: Eli Bendersky date: Fri Jul 13 09:45:31 2012 +0300 summary: Some fixes for the documentation of multiprocessing (per issue #13686) files: Doc/library/multiprocessing.rst | 58 +++++++++++--------- 1 files changed, 33 insertions(+), 25 deletions(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -305,14 +305,12 @@ should always be ``None``; it exists solely for compatibility with :class:`threading.Thread`. *target* is the callable object to be invoked by the :meth:`run()` method. It defaults to ``None``, meaning nothing is - called. *name* is the process name. By default, a unique name is constructed - of the form 'Process-N\ :sub:`1`:N\ :sub:`2`:...:N\ :sub:`k`' where N\ - :sub:`1`,N\ :sub:`2`,...,N\ :sub:`k` is a sequence of integers whose length - is determined by the *generation* of the process. *args* is the argument - tuple for the target invocation. *kwargs* is a dictionary of keyword - arguments for the target invocation. If provided, the keyword-only *daemon* argument - sets the process :attr:`daemon` flag to ``True`` or ``False``. If ``None`` - (the default), this flag will be inherited from the creating process. + called. *name* is the process name (see :attr:`name` for more details). + *args* is the argument tuple for the target invocation. *kwargs* is a + dictionary of keyword arguments for the target invocation. If provided, + the keyword-only *daemon* argument sets the process :attr:`daemon` flag + to ``True`` or ``False``. If ``None`` (the default), this flag will be + inherited from the creating process. By default, no arguments are passed to *target*. @@ -352,11 +350,14 @@ .. attribute:: name - The process's name. - - The name is a string used for identification purposes only. It has no - semantics. Multiple processes may be given the same name. The initial - name is set by the constructor. + The process's name. The name is a string used for identification purposes + only. It has no semantics. Multiple processes may be given the same + name. + + The initial name is set by the constructor. If no explicit name is + provided to the constructor, a name of the form + 'Process-N\ :sub:`1`:N\ :sub:`2`:...:N\ :sub:`k`' is constructed, where + each N\ :sub:`k` is the N-th child of its parent. .. method:: is_alive @@ -462,6 +463,9 @@ >>> p.exitcode == -signal.SIGTERM True +.. exception:: ProcessError + + The base class of all :mod:`multiprocessing` exceptions. .. exception:: BufferTooShort @@ -471,6 +475,13 @@ If ``e`` is an instance of :exc:`BufferTooShort` then ``e.args[0]`` will give the message as a byte string. +.. exception:: AuthenticationError + + Raised when there is an authentication error. + +.. exception:: TimeoutError + + Raised by methods with a timeout when the timeout expires. Pipes and Queues ~~~~~~~~~~~~~~~~ @@ -1838,15 +1849,15 @@ If the reply matches the digest of the message using *authkey* as the key then a welcome message is sent to the other end of the connection. Otherwise - :exc:`AuthenticationError` is raised. + :exc:`~multiprocessing.AuthenticationError` is raised. .. function:: answerChallenge(connection, authkey) Receive a message, calculate the digest of the message using *authkey* as the key, and then send the digest back. - If a welcome message is not received, then :exc:`AuthenticationError` is - raised. + If a welcome message is not received, then + :exc:`~multiprocessing.AuthenticationError` is raised. .. function:: Client(address[, family[, authenticate[, authkey]]]) @@ -1860,7 +1871,8 @@ If *authenticate* is ``True`` or *authkey* is a string then digest authentication is used. The key used for authentication will be either *authkey* or ``current_process().authkey)`` if *authkey* is ``None``. - If authentication fails then :exc:`AuthenticationError` is raised. See + If authentication fails then + :exc:`~multiprocessing.AuthenticationError` is raised. See :ref:`multiprocessing-auth-keys`. .. class:: Listener([address[, family[, backlog[, authenticate[, authkey]]]]]) @@ -1901,13 +1913,15 @@ ``current_process().authkey`` is used as the authentication key. If *authkey* is ``None`` and *authenticate* is ``False`` then no authentication is done. If authentication fails then - :exc:`AuthenticationError` is raised. See :ref:`multiprocessing-auth-keys`. + :exc:`~multiprocessing.AuthenticationError` is raised. + See :ref:`multiprocessing-auth-keys`. .. method:: accept() Accept a connection on the bound socket or named pipe of the listener object and return a :class:`Connection` object. If authentication is - attempted and fails, then :exc:`AuthenticationError` is raised. + attempted and fails, then + :exc:`~multiprocessing.AuthenticationError` is raised. .. method:: close() @@ -1965,12 +1979,6 @@ .. versionadded:: 3.3 -The module defines two exceptions: - -.. exception:: AuthenticationError - - Exception raised when there is an authentication error. - **Examples** -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 13 08:52:56 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 13 Jul 2012 08:52:56 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315296=3A_Fix_mini?= =?utf-8?q?dom=2Etoxml/toprettyxml_for_non-unicode_encodings=2E__Patch?= Message-ID: <3WYPpw3tXhzP5w@mail.python.org> http://hg.python.org/cpython/rev/7b97cea795d8 changeset: 78074:7b97cea795d8 user: Eli Bendersky date: Fri Jul 13 09:52:39 2012 +0300 summary: Issue #15296: Fix minidom.toxml/toprettyxml for non-unicode encodings. Patch by Serhiy Storchaka, with some minor style adjustments by me. files: Doc/library/xml.dom.minidom.rst | 7 +----- Lib/test/test_minidom.py | 5 ++++ Lib/xml/dom/minidom.py | 22 +++++++++++--------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/Doc/library/xml.dom.minidom.rst b/Doc/library/xml.dom.minidom.rst --- a/Doc/library/xml.dom.minidom.rst +++ b/Doc/library/xml.dom.minidom.rst @@ -147,12 +147,7 @@ the DOM node. With an explicit *encoding* [1]_ argument, the result is a byte - string in the specified encoding. It is recommended that you - always specify an encoding; you may use any encoding you like, but - an argument of "utf-8" is the most common choice, avoiding - :exc:`UnicodeError` exceptions in case of unrepresentable text - data. - + string in the specified encoding. With no *encoding* argument, the result is a Unicode string, and the XML declaration in the resulting string does not specify an encoding. Encoding this string in an encoding other than UTF-8 is diff --git a/Lib/test/test_minidom.py b/Lib/test/test_minidom.py --- a/Lib/test/test_minidom.py +++ b/Lib/test/test_minidom.py @@ -1067,6 +1067,11 @@ b'\xe2\x82\xac') self.assertEqual(doc.toxml('iso-8859-15'), b'\xa4') + self.assertEqual(doc.toxml('us-ascii'), + b'') + self.assertEqual(doc.toxml('utf-16'), + '' + '\u20ac'.encode('utf-16')) # Verify that character decoding errors throw exceptions instead # of crashing diff --git a/Lib/xml/dom/minidom.py b/Lib/xml/dom/minidom.py --- a/Lib/xml/dom/minidom.py +++ b/Lib/xml/dom/minidom.py @@ -14,7 +14,6 @@ * SAX 2 namespaces """ -import codecs import io import xml.dom @@ -47,19 +46,22 @@ return self.toprettyxml("", "", encoding) def toprettyxml(self, indent="\t", newl="\n", encoding=None): - # indent = the indentation string to prepend, per level - # newl = the newline string to append - use_encoding = "utf-8" if encoding is None else encoding - writer = codecs.getwriter(use_encoding)(io.BytesIO()) + if encoding is None: + writer = io.StringIO() + else: + writer = io.TextIOWrapper(io.BytesIO(), + encoding=encoding, + errors="xmlcharrefreplace", + newline='\n') if self.nodeType == Node.DOCUMENT_NODE: # Can pass encoding only to document, to put it into XML header self.writexml(writer, "", indent, newl, encoding) else: self.writexml(writer, "", indent, newl) if encoding is None: - return writer.stream.getvalue().decode(use_encoding) + return writer.getvalue() else: - return writer.stream.getvalue() + return writer.detach().getvalue() def hasChildNodes(self): return bool(self.childNodes) @@ -1788,12 +1790,12 @@ raise xml.dom.NotSupportedErr("cannot import document type nodes") return _clone_node(node, deep, self) - def writexml(self, writer, indent="", addindent="", newl="", - encoding = None): + def writexml(self, writer, indent="", addindent="", newl="", encoding=None): if encoding is None: writer.write(''+newl) else: - writer.write('%s' % (encoding, newl)) + writer.write('%s' % ( + encoding, newl)) for node in self.childNodes: node.writexml(writer, indent, addindent, newl) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 13 09:10:21 2012 From: python-checkins at python.org (eli.bendersky) Date: Fri, 13 Jul 2012 09:10:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Additional_fixes_to_multip?= =?utf-8?q?rocessing_docs_=28for_issue_=2313686=29?= Message-ID: <3WYQC12TtMzP5w@mail.python.org> http://hg.python.org/cpython/rev/1110692aac71 changeset: 78075:1110692aac71 user: Eli Bendersky date: Fri Jul 13 10:10:05 2012 +0300 summary: Additional fixes to multiprocessing docs (for issue #13686) files: Doc/library/multiprocessing.rst | 23 +++++++++----------- 1 files changed, 10 insertions(+), 13 deletions(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -663,8 +663,8 @@ .. method:: task_done() - Indicate that a formerly enqueued task is complete. Used by queue consumer - threads. For each :meth:`~Queue.get` used to fetch a task, a subsequent + Indicate that a formerly enqueued task is complete. Used by queue + consumers. For each :meth:`~Queue.get` used to fetch a task, a subsequent call to :meth:`task_done` tells the queue that the processing on the task is complete. @@ -681,7 +681,7 @@ Block until all items in the queue have been gotten and processed. The count of unfinished tasks goes up whenever an item is added to the - queue. The count goes down whenever a consumer thread calls + queue. The count goes down whenever a consumer calls :meth:`task_done` to indicate that the item was retrieved and all work on it is complete. When the count of unfinished tasks drops to zero, :meth:`~Queue.join` unblocks. @@ -926,12 +926,6 @@ .. class:: Event() A clone of :class:`threading.Event`. - This method returns the state of the internal semaphore on exit, so it - will always return ``True`` except if a timeout is given and the operation - times out. - - .. versionchanged:: 3.1 - Previously, the method always returned ``None``. .. class:: Lock() @@ -977,7 +971,8 @@ .. function:: Value(typecode_or_type, *args, lock=True) Return a :mod:`ctypes` object allocated from shared memory. By default the - return value is actually a synchronized wrapper for the object. + return value is actually a synchronized wrapper for the object. The object + itself can be accessed via the *value* attribute of a :class:`Value`. *typecode_or_type* determines the type of the returned object: it is either a ctypes type or a one character typecode of the kind used by the :mod:`array` @@ -1183,8 +1178,10 @@ ~~~~~~~~ Managers provide a way to create data which can be shared between different -processes. A manager object controls a server process which manages *shared -objects*. Other processes can access the shared objects by using proxies. +processes, including sharing over a network between processes running on +different machines. A manager object controls a server process which manages +*shared objects*. Other processes can access the shared objects by using +proxies. .. function:: multiprocessing.Manager() @@ -2211,7 +2208,7 @@ It is probably best to stick to using queues or pipes for communication between processes rather than using the lower level synchronization - primitives from the :mod:`threading` module. + primitives. Picklability -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 13 09:45:39 2012 From: python-checkins at python.org (ned.deily) Date: Fri, 13 Jul 2012 09:45:39 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=234832=3A_Modify_ID?= =?utf-8?q?LE_to_save_files_with_=2Epy_extension_by?= Message-ID: <3WYQzl0bQlzPDY@mail.python.org> http://hg.python.org/cpython/rev/677a9326b4d4 changeset: 78076:677a9326b4d4 user: Ned Deily date: Mon Jul 09 18:16:11 2012 -0700 summary: Issue #4832: Modify IDLE to save files with .py extension by default on Windows and OS X as it already does with X11 Tk. files: Lib/idlelib/IOBinding.py | 8 ++++++-- Lib/idlelib/NEWS.txt | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/IOBinding.py b/Lib/idlelib/IOBinding.py --- a/Lib/idlelib/IOBinding.py +++ b/Lib/idlelib/IOBinding.py @@ -485,6 +485,8 @@ ("All files", "*"), ] + defaultextension = '.py' if sys.platform == 'darwin' else '' + def askopenfile(self): dir, base = self.defaultfilename("open") if not self.opendialog: @@ -508,8 +510,10 @@ def asksavefile(self): dir, base = self.defaultfilename("save") if not self.savedialog: - self.savedialog = tkFileDialog.SaveAs(master=self.text, - filetypes=self.filetypes) + self.savedialog = tkFileDialog.SaveAs( + master=self.text, + filetypes=self.filetypes, + defaultextension=self.defaultextension) filename = self.savedialog.show(initialdir=dir, initialfile=base) return filename diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,6 +1,9 @@ What's New in IDLE 3.3.0? ========================= +- Issue #4832: Modify IDLE to save files with .py extension by + default on Windows and OS X (Tk 8.5) as it already does with X11 Tk. + - Issue #13532, #15319: Check that arguments to sys.stdout.write are strings. - Issue # 12510: Attempt to get certain tool tips no longer crashes IDLE. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 13 17:26:27 2012 From: python-checkins at python.org (brett.cannon) Date: Fri, 13 Jul 2012 17:26:27 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315053=3A_Make_sur?= =?utf-8?q?e_all_functions_related_to_the_import_lock_have?= Message-ID: <3WYdCR6SXWzP2p@mail.python.org> http://hg.python.org/cpython/rev/c09f454af2c6 changeset: 78077:c09f454af2c6 user: Brett Cannon date: Fri Jul 13 11:26:19 2012 -0400 summary: Issue #15053: Make sure all functions related to the import lock have the Python 3.3 change notice on them in case someone directly links to the function(s). files: Doc/library/imp.rst | 21 ++++++++++++++++----- Misc/NEWS | 3 +++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/Doc/library/imp.rst b/Doc/library/imp.rst --- a/Doc/library/imp.rst +++ b/Doc/library/imp.rst @@ -224,11 +224,6 @@ detail which may vary from release to release. However, Python ensures that circular imports work without any deadlocks. -.. versionchanged:: 3.3 - In Python 3.3, the locking scheme has changed to per-module locks for - the most part. A global import lock is kept for some critical tasks, - such as initializing the per-module locks. - .. function:: lock_held() @@ -243,6 +238,12 @@ exception is made for circular imports, which by construction have to expose an incomplete module object at some point. +.. versionchanged:: 3.3 + The locking scheme has changed to per-module locks for + the most part. A global import lock is kept for some critical tasks, + such as initializing the per-module locks. + + .. function:: acquire_lock() Acquire the interpreter's global import lock for the current thread. @@ -255,12 +256,22 @@ On platforms without threads, this function does nothing. +.. versionchanged:: 3.3 + The locking scheme has changed to per-module locks for + the most part. A global import lock is kept for some critical tasks, + such as initializing the per-module locks. + .. function:: release_lock() Release the interpreter's global import lock. On platforms without threads, this function does nothing. +.. versionchanged:: 3.3 + The locking scheme has changed to per-module locks for + the most part. A global import lock is kept for some critical tasks, + such as initializing the per-module locks. + The following constants with integer values, defined in this module, are used to indicate the search result of :func:`find_module`. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -110,6 +110,9 @@ Documentation ------------- +- Issue #15053: Copy Python 3.3 import lock change notice to all relevant + functions in imp instead of just at the top of the relevant section. + - Issue #15288: Link to the term "loader" in notes in pkgutil about how things won't work as expected in Python 3.3 and mark the requisite functions as "changed" since they will no longer work with modules directly imported by -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 13 19:57:13 2012 From: python-checkins at python.org (brett.cannon) Date: Fri, 13 Jul 2012 19:57:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issues_=2315169=2C_=231459?= =?utf-8?q?9=3A_Make_PyImport=5FExecCodeModuleWithPathnames=28=29_use?= Message-ID: <3WYhYP5QtJzNTp@mail.python.org> http://hg.python.org/cpython/rev/9e164b404983 changeset: 78078:9e164b404983 user: Brett Cannon date: Fri Jul 13 13:57:03 2012 -0400 summary: Issues #15169, #14599: Make PyImport_ExecCodeModuleWithPathnames() use Lib/imp.py for imp.source_from_cache() instead of its own C version. Also change PyImport_ExecCodeModuleObject() to not infer the source path from the bytecode path like PyImport_ExecCodeModuleWithPathnames() does. This makes the function less magical. This also has the side-effect of removing all uses of MAXPATHLEN in Python/import.c which can cause failures on really long filenames. files: Doc/c-api/import.rst | 7 +- Lib/imp.py | 25 +- Lib/importlib/_bootstrap.py | 44 + Misc/NEWS | 9 + Python/import.c | 195 +- Python/importlib.h | 7865 +++++++++++----------- 6 files changed, 4083 insertions(+), 4062 deletions(-) diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -163,9 +163,14 @@ .. c:function:: PyObject* PyImport_ExecCodeModuleWithPathnames(char *name, PyObject *co, char *pathname, char *cpathname) Like :c:func:`PyImport_ExecCodeModuleObject`, but *name*, *pathname* and - *cpathname* are UTF-8 encoded strings. + *cpathname* are UTF-8 encoded strings. Attempts are also made to figure out + what the value for *pathname* should be from *cpathname* if the former is + set to ``NULL``. .. versionadded:: 3.2 + .. versionchanged:: 3.3 + Uses :func:`imp.source_from_cache()` in calculating the source path if + only the bytecode path is provided. .. c:function:: long PyImport_GetMagicNumber() diff --git a/Lib/imp.py b/Lib/imp.py --- a/Lib/imp.py +++ b/Lib/imp.py @@ -13,7 +13,7 @@ # Directly exposed by this module from importlib._bootstrap import new_module -from importlib._bootstrap import cache_from_source +from importlib._bootstrap import cache_from_source, source_from_cache from importlib import _bootstrap @@ -58,29 +58,6 @@ return extensions + source + bytecode -def source_from_cache(path): - """Given the path to a .pyc./.pyo file, return the path to its .py file. - - The .pyc/.pyo file does not need to exist; this simply returns the path to - the .py file calculated to correspond to the .pyc/.pyo file. If path does - not conform to PEP 3147 format, ValueError will be raised. If - sys.implementation.cache_tag is None then NotImplementedError is raised. - - """ - if sys.implementation.cache_tag is None: - raise NotImplementedError('sys.implementation.cache_tag is None') - head, pycache_filename = os.path.split(path) - head, pycache = os.path.split(head) - if pycache != _bootstrap._PYCACHE: - raise ValueError('{} not bottom-level directory in ' - '{!r}'.format(_bootstrap._PYCACHE, path)) - if pycache_filename.count('.') != 2: - raise ValueError('expected only 2 dots in ' - '{!r}'.format(pycache_filename)) - base_filename = pycache_filename.partition('.')[0] - return os.path.join(head, base_filename + machinery.SOURCE_SUFFIXES[0]) - - class NullImporter: """Null import object.""" diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -428,6 +428,50 @@ return _path_join(head, _PYCACHE, filename) +def source_from_cache(path): + """Given the path to a .pyc./.pyo file, return the path to its .py file. + + The .pyc/.pyo file does not need to exist; this simply returns the path to + the .py file calculated to correspond to the .pyc/.pyo file. If path does + not conform to PEP 3147 format, ValueError will be raised. If + sys.implementation.cache_tag is None then NotImplementedError is raised. + + """ + if sys.implementation.cache_tag is None: + raise NotImplementedError('sys.implementation.cache_tag is None') + head, pycache_filename = _path_split(path) + head, pycache = _path_split(head) + if pycache != _PYCACHE: + raise ValueError('{} not bottom-level directory in ' + '{!r}'.format(_PYCACHE, path)) + if pycache_filename.count('.') != 2: + raise ValueError('expected only 2 dots in ' + '{!r}'.format(pycache_filename)) + base_filename = pycache_filename.partition('.')[0] + return _path_join(head, base_filename + SOURCE_SUFFIXES[0]) + + +def _get_sourcefile(bytecode_path): + """Convert a bytecode file path to a source path (if possible). + + This function exists purely for backwards-compatibility for + PyImport_ExecCodeModuleWithFilenames() in the C API. + + """ + if len(bytecode_path) == 0: + return None + rest, _, extension = bytecode_path.rparition('.') + if not rest or extension.lower()[-3:-1] != '.py': + return bytecode_path + + try: + source_path = source_from_cache(bytecode_path) + except (NotImplementedError, ValueError): + source_path = bytcode_path[-1:] + + return source_path if _path_isfile(source_stats) else bytecode_path + + def _verbose_message(message, *args): """Print the message to stderr if -v/PYTHONVERBOSE is turned on.""" if sys.flags.verbose: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -92,6 +92,15 @@ - Issue 10924: Fixed mksalt() to use a RNG that is suitable for cryptographic purpose. +C API +----- + +- Issues #15169, #14599: Strip out the C implementation of + imp.source_from_cache() used by PyImport_ExecCodeModuleWithPathnames() and + used the Python code instead. Leads to PyImport_ExecCodeModuleObject() to not + try to infer the source path from the bytecode path as + PyImport_ExecCodeModuleWithPathnames() does. + Extension Modules ----------------- diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -630,8 +630,6 @@ "sys.modules failed"); } -static PyObject * get_sourcefile(PyObject *filename); -static PyObject *make_source_pathname(PyObject *pathname); /* Execute a code object in a module and return the module object * WITH INCREMENTED REFERENCE COUNT. If an error occurs, name is @@ -668,18 +666,37 @@ if (nameobj == NULL) return NULL; + if (cpathname != NULL) { + cpathobj = PyUnicode_DecodeFSDefault(cpathname); + if (cpathobj == NULL) + goto error; + } + else + cpathobj = NULL; + if (pathname != NULL) { pathobj = PyUnicode_DecodeFSDefault(pathname); if (pathobj == NULL) goto error; - } else + } + else if (cpathobj != NULL) { + PyInterpreterState *interp = PyThreadState_GET()->interp; + _Py_IDENTIFIER(_get_sourcefile); + + if (interp == NULL) { + Py_FatalError("PyImport_ExecCodeModuleWithPathnames: " + "no interpreter!"); + } + + pathobj = _PyObject_CallMethodObjIdArgs(interp->importlib, + &PyId__get_sourcefile, cpathobj, + NULL); + if (pathobj == NULL) + PyErr_Clear(); + } + else pathobj = NULL; - if (cpathname != NULL) { - cpathobj = PyUnicode_DecodeFSDefault(cpathname); - if (cpathobj == NULL) - goto error; - } else - cpathobj = NULL; + m = PyImport_ExecCodeModuleObject(nameobj, co, pathobj, cpathobj); error: Py_DECREF(nameobj); @@ -706,18 +723,13 @@ PyEval_GetBuiltins()) != 0) goto error; } - /* Remember the filename as the __file__ attribute */ if (pathname != NULL) { - v = get_sourcefile(pathname); - if (v == NULL) - PyErr_Clear(); + v = pathname; } - else - v = NULL; - if (v == NULL) { + else { v = ((PyCodeObject *)co)->co_filename; - Py_INCREF(v); } + Py_INCREF(v); if (PyDict_SetItemString(d, "__file__", v) != 0) PyErr_Clear(); /* Not important enough to report */ Py_DECREF(v); @@ -752,100 +764,6 @@ } -/* Like rightmost_sep, but operate on unicode objects. */ -static Py_ssize_t -rightmost_sep_obj(PyObject* o, Py_ssize_t start, Py_ssize_t end) -{ - Py_ssize_t found, i; - Py_UCS4 c; - for (found = -1, i = start; i < end; i++) { - c = PyUnicode_READ_CHAR(o, i); - if (c == SEP -#ifdef ALTSEP - || c == ALTSEP -#endif - ) - { - found = i; - } - } - return found; -} - - -/* Given a pathname to a Python byte compiled file, return the path to the - source file, if the path matches the PEP 3147 format. This does not check - for any file existence, however, if the pyc file name does not match PEP - 3147 style, NULL is returned. buf must be at least as big as pathname; - the resulting path will always be shorter. - - (...)/__pycache__/foo..pyc -> (...)/foo.py */ - -static PyObject* -make_source_pathname(PyObject *path) -{ - Py_ssize_t left, right, dot0, dot1, len; - Py_ssize_t i, j; - PyObject *result; - int kind; - void *data; - - len = PyUnicode_GET_LENGTH(path); - if (len > MAXPATHLEN) - return NULL; - - /* Look back two slashes from the end. In between these two slashes - must be the string __pycache__ or this is not a PEP 3147 style - path. It's possible for there to be only one slash. - */ - right = rightmost_sep_obj(path, 0, len); - if (right == -1) - return NULL; - left = rightmost_sep_obj(path, 0, right); - if (left == -1) - left = 0; - else - left++; - if (right-left != sizeof(CACHEDIR)-1) - return NULL; - for (i = 0; i < sizeof(CACHEDIR)-1; i++) - if (PyUnicode_READ_CHAR(path, left+i) != CACHEDIR[i]) - return NULL; - - /* Now verify that the path component to the right of the last slash - has two dots in it. - */ - dot0 = PyUnicode_FindChar(path, '.', right+1, len, 1); - if (dot0 < 0) - return NULL; - dot1 = PyUnicode_FindChar(path, '.', dot0+1, len, 1); - if (dot1 < 0) - return NULL; - /* Too many dots? */ - if (PyUnicode_FindChar(path, '.', dot1+1, len, 1) != -1) - return NULL; - - /* This is a PEP 3147 path. Start by copying everything from the - start of pathname up to and including the leftmost slash. Then - copy the file's basename, removing the magic tag and adding a .py - suffix. - */ - result = PyUnicode_New(left + (dot0-right) + 2, - PyUnicode_MAX_CHAR_VALUE(path)); - if (!result) - return NULL; - kind = PyUnicode_KIND(result); - data = PyUnicode_DATA(result); - PyUnicode_CopyCharacters(result, 0, path, 0, (i = left)); - PyUnicode_CopyCharacters(result, left, path, right+1, - (j = dot0-right)); - PyUnicode_WRITE(kind, data, i+j, 'p'); - PyUnicode_WRITE(kind, data, i+j+1, 'y'); - assert(_PyUnicode_CheckConsistency(result, 1)); - return result; -} - - static void update_code_filenames(PyCodeObject *co, PyObject *oldname, PyObject *newname) { @@ -911,61 +829,6 @@ } -/* Get source file -> unicode or None - * Returns the path to the py file if available, else the given path - */ -static PyObject * -get_sourcefile(PyObject *filename) -{ - Py_ssize_t len; - PyObject *py; - struct stat statbuf; - int err; - void *data; - unsigned int kind; - - len = PyUnicode_GET_LENGTH(filename); - if (len == 0) - Py_RETURN_NONE; - - /* don't match *.pyc or *.pyo? */ - data = PyUnicode_DATA(filename); - kind = PyUnicode_KIND(filename); - if (len < 5 - || PyUnicode_READ(kind, data, len-4) != '.' - || (PyUnicode_READ(kind, data, len-3) != 'p' - && PyUnicode_READ(kind, data, len-3) != 'P') - || (PyUnicode_READ(kind, data, len-2) != 'y' - && PyUnicode_READ(kind, data, len-2) != 'Y')) - goto unchanged; - - /* Start by trying to turn PEP 3147 path into source path. If that - * fails, just chop off the trailing character, i.e. legacy pyc path - * to py. - */ - py = make_source_pathname(filename); - if (py == NULL) { - PyErr_Clear(); - py = PyUnicode_Substring(filename, 0, len - 1); - } - if (py == NULL) - goto error; - - err = _Py_stat(py, &statbuf); - if (err == -2) - goto error; - if (err == 0 && S_ISREG(statbuf.st_mode)) - return py; - Py_DECREF(py); - goto unchanged; - -error: - PyErr_Clear(); -unchanged: - Py_INCREF(filename); - return filename; -} - /* Forward */ static struct _frozen * find_frozen(PyObject *); diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 13 20:52:52 2012 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 13 Jul 2012 20:52:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_builtin_test_and_simpl?= =?utf-8?q?ify_the_classified_text_tuple=2E?= Message-ID: <3WYjnc5rT7zP87@mail.python.org> http://hg.python.org/cpython/rev/425d5e89fa25 changeset: 78079:425d5e89fa25 user: Raymond Hettinger date: Fri Jul 13 11:52:45 2012 -0700 summary: Fix builtin test and simplify the classified text tuple. files: Tools/scripts/highlight.py | 60 +++++++++++-------------- 1 files changed, 27 insertions(+), 33 deletions(-) diff --git a/Tools/scripts/highlight.py b/Tools/scripts/highlight.py --- a/Tools/scripts/highlight.py +++ b/Tools/scripts/highlight.py @@ -4,12 +4,16 @@ __author__ = 'Raymond Hettinger' import keyword, tokenize, cgi, re, functools +try: + import builtins +except ImportError: + import __builtin__ as builtins #### Analyze Python Source ################################# def is_builtin(s): 'Return True if s is the name of a builtin' - return hasattr(__builtins__, s) + return hasattr(builtins, s) def combine_range(lines, start, end): 'Join content from a range of lines between start and end' @@ -21,9 +25,7 @@ def analyze_python(source): '''Generate and classify chunks of Python for syntax highlighting. - Yields tuples in the form: (leadin_text, category, categorized_text). - The final tuple has empty strings for the category and categorized text. - + Yields tuples in the form: (category, categorized_text). ''' lines = source.splitlines(True) lines.append('') @@ -37,7 +39,7 @@ kind = '' if tok_type == tokenize.COMMENT: kind = 'comment' - elif tok_type == tokenize.OP and tok_str[:1] not in '{}[](),.:;': + elif tok_type == tokenize.OP and tok_str[:1] not in '{}[](),.:;@': kind = 'operator' elif tok_type == tokenize.STRING: kind = 'string' @@ -53,22 +55,20 @@ elif is_builtin(tok_str) and prev_tok_str != '.': kind = 'builtin' if kind: - line_upto_token, written = combine_range(lines, written, (srow, scol)) - line_thru_token, written = combine_range(lines, written, (erow, ecol)) - yield line_upto_token, kind, line_thru_token + text, written = combine_range(lines, written, (srow, scol)) + yield '', text + text, written = combine_range(lines, written, (erow, ecol)) + yield kind, text line_upto_token, written = combine_range(lines, written, (erow, ecol)) - yield line_upto_token, '', '' + yield '', line_upto_token #### Raw Output ########################################### def raw_highlight(classified_text): 'Straight text display of text classifications' result = [] - for line_upto_token, kind, line_thru_token in classified_text: - if line_upto_token: - result.append(' plain: %r\n' % line_upto_token) - if line_thru_token: - result.append('%15s: %r\n' % (kind, line_thru_token)) + for kind, text in classified_text: + result.append('%15s: %r\n' % (kind or 'plain', text)) return ''.join(result) #### ANSI Output ########################################### @@ -88,9 +88,9 @@ 'Add syntax highlighting to source code using ANSI escape sequences' # http://en.wikipedia.org/wiki/ANSI_escape_code result = [] - for line_upto_token, kind, line_thru_token in classified_text: + for kind, text in classified_text: opener, closer = colors.get(kind, ('', '')) - result += [line_upto_token, opener, line_thru_token, closer] + result += [opener, text, closer] return ''.join(result) #### HTML Output ########################################### @@ -98,16 +98,13 @@ def html_highlight(classified_text,opener='
      \n', closer='
      \n'): 'Convert classified text to an HTML fragment' result = [opener] - for line_upto_token, kind, line_thru_token in classified_text: + for kind, text in classified_text: if kind: - result += [cgi.escape(line_upto_token), - '' % kind, - cgi.escape(line_thru_token), - ''] - else: - result += [cgi.escape(line_upto_token), - cgi.escape(line_thru_token)] - result += [closer] + result.append('' % kind) + result.append(cgi.escape(text)) + if kind: + result.append('') + result.append(closer) return ''.join(result) default_css = { @@ -188,15 +185,12 @@ document = default_latex_document): 'Create a complete LaTeX document with colorized source code' result = [] - for line_upto_token, kind, line_thru_token in classified_text: + for kind, text in classified_text: if kind: - result += [latex_escape(line_upto_token), - r'{\color{%s}' % colors[kind], - latex_escape(line_thru_token), - '}'] - else: - result += [latex_escape(line_upto_token), - latex_escape(line_thru_token)] + result.append(r'{\color{%s}' % colors[kind]) + result.append(latex_escape(text)) + if kind: + result.append('}') return default_latex_document % dict(title=title, body=''.join(result)) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 13 21:01:23 2012 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 13 Jul 2012 21:01:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE1MzM4?= =?utf-8?q?=3A_skip_test=5FUNC=5Fpath_when_the_current_user_doesn=27t_have?= =?utf-8?q?_enough?= Message-ID: <3WYjzR2lTfzP68@mail.python.org> http://hg.python.org/cpython/rev/4d480a2a6296 changeset: 78080:4d480a2a6296 branch: 3.2 parent: 78069:a8aa77458e12 user: Antoine Pitrou date: Fri Jul 13 20:54:42 2012 +0200 summary: Issue #15338: skip test_UNC_path when the current user doesn't have enough permissions to access the path. files: Lib/test/test_import.py | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -461,6 +461,13 @@ drive = path[0] unc = "\\\\%s\\%s$"%(hn, drive) unc += path[2:] + try: + os.listdir(unc) + except OSError as e: + if e.errno in (errno.EPERM, errno.EACCES): + # See issue #15338 + self.skipTest("cannot access administrative share %r" % (unc,)) + raise sys.path.append(path) mod = __import__("test_trailing_slash") self.assertEqual(mod.testdata, 'test_trailing_slash') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 13 21:01:25 2012 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 13 Jul 2012 21:01:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2315338=3A_skip_test=5FUNC=5Fpath_when_the_curren?= =?utf-8?q?t_user_doesn=27t_have_enough?= Message-ID: <3WYjzT0MPyzNqK@mail.python.org> http://hg.python.org/cpython/rev/7d5e84a44b82 changeset: 78081:7d5e84a44b82 parent: 78077:c09f454af2c6 parent: 78080:4d480a2a6296 user: Antoine Pitrou date: Fri Jul 13 20:59:19 2012 +0200 summary: Issue #15338: skip test_UNC_path when the current user doesn't have enough permissions to access the path. files: Lib/test/test_import.py | 25 ++++++++++++++----------- 1 files changed, 14 insertions(+), 11 deletions(-) diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -464,19 +464,22 @@ drive = path[0] unc = "\\\\%s\\%s$"%(hn, drive) unc += path[2:] + try: + os.listdir(unc) + except OSError as e: + if e.errno in (errno.EPERM, errno.EACCES): + # See issue #15338 + self.skipTest("cannot access administrative share %r" % (unc,)) + raise sys.path.insert(0, unc) try: - os.listdir(unc) - try: - mod = __import__("test_unc_path") - except ImportError as e: - self.fail("could not import 'test_unc_path' from %r: %r" - % (unc, e)) - self.assertEqual(mod.testdata, 'test_unc_path') - self.assertTrue(mod.__file__.startswith(unc), mod.__file__) - unload("test_unc_path") - finally: - sys.path.remove(unc) + mod = __import__("test_unc_path") + except ImportError as e: + self.fail("could not import 'test_unc_path' from %r: %r" + % (unc, e)) + self.assertEqual(mod.testdata, 'test_unc_path') + self.assertTrue(mod.__file__.startswith(unc), mod.__file__) + unload("test_unc_path") class RelativeImportTests(unittest.TestCase): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 13 21:01:26 2012 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 13 Jul 2012 21:01:26 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge?= Message-ID: <3WYjzV6QxNzP9M@mail.python.org> http://hg.python.org/cpython/rev/482cff0eebda changeset: 78082:482cff0eebda parent: 78081:7d5e84a44b82 parent: 78079:425d5e89fa25 user: Antoine Pitrou date: Fri Jul 13 20:59:35 2012 +0200 summary: Merge files: Doc/c-api/import.rst | 7 +- Lib/imp.py | 25 +- Lib/importlib/_bootstrap.py | 44 + Misc/NEWS | 9 + Python/import.c | 195 +- Python/importlib.h | 7865 +++++++++++----------- Tools/scripts/highlight.py | 60 +- 7 files changed, 4110 insertions(+), 4095 deletions(-) diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -163,9 +163,14 @@ .. c:function:: PyObject* PyImport_ExecCodeModuleWithPathnames(char *name, PyObject *co, char *pathname, char *cpathname) Like :c:func:`PyImport_ExecCodeModuleObject`, but *name*, *pathname* and - *cpathname* are UTF-8 encoded strings. + *cpathname* are UTF-8 encoded strings. Attempts are also made to figure out + what the value for *pathname* should be from *cpathname* if the former is + set to ``NULL``. .. versionadded:: 3.2 + .. versionchanged:: 3.3 + Uses :func:`imp.source_from_cache()` in calculating the source path if + only the bytecode path is provided. .. c:function:: long PyImport_GetMagicNumber() diff --git a/Lib/imp.py b/Lib/imp.py --- a/Lib/imp.py +++ b/Lib/imp.py @@ -13,7 +13,7 @@ # Directly exposed by this module from importlib._bootstrap import new_module -from importlib._bootstrap import cache_from_source +from importlib._bootstrap import cache_from_source, source_from_cache from importlib import _bootstrap @@ -58,29 +58,6 @@ return extensions + source + bytecode -def source_from_cache(path): - """Given the path to a .pyc./.pyo file, return the path to its .py file. - - The .pyc/.pyo file does not need to exist; this simply returns the path to - the .py file calculated to correspond to the .pyc/.pyo file. If path does - not conform to PEP 3147 format, ValueError will be raised. If - sys.implementation.cache_tag is None then NotImplementedError is raised. - - """ - if sys.implementation.cache_tag is None: - raise NotImplementedError('sys.implementation.cache_tag is None') - head, pycache_filename = os.path.split(path) - head, pycache = os.path.split(head) - if pycache != _bootstrap._PYCACHE: - raise ValueError('{} not bottom-level directory in ' - '{!r}'.format(_bootstrap._PYCACHE, path)) - if pycache_filename.count('.') != 2: - raise ValueError('expected only 2 dots in ' - '{!r}'.format(pycache_filename)) - base_filename = pycache_filename.partition('.')[0] - return os.path.join(head, base_filename + machinery.SOURCE_SUFFIXES[0]) - - class NullImporter: """Null import object.""" diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -428,6 +428,50 @@ return _path_join(head, _PYCACHE, filename) +def source_from_cache(path): + """Given the path to a .pyc./.pyo file, return the path to its .py file. + + The .pyc/.pyo file does not need to exist; this simply returns the path to + the .py file calculated to correspond to the .pyc/.pyo file. If path does + not conform to PEP 3147 format, ValueError will be raised. If + sys.implementation.cache_tag is None then NotImplementedError is raised. + + """ + if sys.implementation.cache_tag is None: + raise NotImplementedError('sys.implementation.cache_tag is None') + head, pycache_filename = _path_split(path) + head, pycache = _path_split(head) + if pycache != _PYCACHE: + raise ValueError('{} not bottom-level directory in ' + '{!r}'.format(_PYCACHE, path)) + if pycache_filename.count('.') != 2: + raise ValueError('expected only 2 dots in ' + '{!r}'.format(pycache_filename)) + base_filename = pycache_filename.partition('.')[0] + return _path_join(head, base_filename + SOURCE_SUFFIXES[0]) + + +def _get_sourcefile(bytecode_path): + """Convert a bytecode file path to a source path (if possible). + + This function exists purely for backwards-compatibility for + PyImport_ExecCodeModuleWithFilenames() in the C API. + + """ + if len(bytecode_path) == 0: + return None + rest, _, extension = bytecode_path.rparition('.') + if not rest or extension.lower()[-3:-1] != '.py': + return bytecode_path + + try: + source_path = source_from_cache(bytecode_path) + except (NotImplementedError, ValueError): + source_path = bytcode_path[-1:] + + return source_path if _path_isfile(source_stats) else bytecode_path + + def _verbose_message(message, *args): """Print the message to stderr if -v/PYTHONVERBOSE is turned on.""" if sys.flags.verbose: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -92,6 +92,15 @@ - Issue 10924: Fixed mksalt() to use a RNG that is suitable for cryptographic purpose. +C API +----- + +- Issues #15169, #14599: Strip out the C implementation of + imp.source_from_cache() used by PyImport_ExecCodeModuleWithPathnames() and + used the Python code instead. Leads to PyImport_ExecCodeModuleObject() to not + try to infer the source path from the bytecode path as + PyImport_ExecCodeModuleWithPathnames() does. + Extension Modules ----------------- diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -630,8 +630,6 @@ "sys.modules failed"); } -static PyObject * get_sourcefile(PyObject *filename); -static PyObject *make_source_pathname(PyObject *pathname); /* Execute a code object in a module and return the module object * WITH INCREMENTED REFERENCE COUNT. If an error occurs, name is @@ -668,18 +666,37 @@ if (nameobj == NULL) return NULL; + if (cpathname != NULL) { + cpathobj = PyUnicode_DecodeFSDefault(cpathname); + if (cpathobj == NULL) + goto error; + } + else + cpathobj = NULL; + if (pathname != NULL) { pathobj = PyUnicode_DecodeFSDefault(pathname); if (pathobj == NULL) goto error; - } else + } + else if (cpathobj != NULL) { + PyInterpreterState *interp = PyThreadState_GET()->interp; + _Py_IDENTIFIER(_get_sourcefile); + + if (interp == NULL) { + Py_FatalError("PyImport_ExecCodeModuleWithPathnames: " + "no interpreter!"); + } + + pathobj = _PyObject_CallMethodObjIdArgs(interp->importlib, + &PyId__get_sourcefile, cpathobj, + NULL); + if (pathobj == NULL) + PyErr_Clear(); + } + else pathobj = NULL; - if (cpathname != NULL) { - cpathobj = PyUnicode_DecodeFSDefault(cpathname); - if (cpathobj == NULL) - goto error; - } else - cpathobj = NULL; + m = PyImport_ExecCodeModuleObject(nameobj, co, pathobj, cpathobj); error: Py_DECREF(nameobj); @@ -706,18 +723,13 @@ PyEval_GetBuiltins()) != 0) goto error; } - /* Remember the filename as the __file__ attribute */ if (pathname != NULL) { - v = get_sourcefile(pathname); - if (v == NULL) - PyErr_Clear(); + v = pathname; } - else - v = NULL; - if (v == NULL) { + else { v = ((PyCodeObject *)co)->co_filename; - Py_INCREF(v); } + Py_INCREF(v); if (PyDict_SetItemString(d, "__file__", v) != 0) PyErr_Clear(); /* Not important enough to report */ Py_DECREF(v); @@ -752,100 +764,6 @@ } -/* Like rightmost_sep, but operate on unicode objects. */ -static Py_ssize_t -rightmost_sep_obj(PyObject* o, Py_ssize_t start, Py_ssize_t end) -{ - Py_ssize_t found, i; - Py_UCS4 c; - for (found = -1, i = start; i < end; i++) { - c = PyUnicode_READ_CHAR(o, i); - if (c == SEP -#ifdef ALTSEP - || c == ALTSEP -#endif - ) - { - found = i; - } - } - return found; -} - - -/* Given a pathname to a Python byte compiled file, return the path to the - source file, if the path matches the PEP 3147 format. This does not check - for any file existence, however, if the pyc file name does not match PEP - 3147 style, NULL is returned. buf must be at least as big as pathname; - the resulting path will always be shorter. - - (...)/__pycache__/foo..pyc -> (...)/foo.py */ - -static PyObject* -make_source_pathname(PyObject *path) -{ - Py_ssize_t left, right, dot0, dot1, len; - Py_ssize_t i, j; - PyObject *result; - int kind; - void *data; - - len = PyUnicode_GET_LENGTH(path); - if (len > MAXPATHLEN) - return NULL; - - /* Look back two slashes from the end. In between these two slashes - must be the string __pycache__ or this is not a PEP 3147 style - path. It's possible for there to be only one slash. - */ - right = rightmost_sep_obj(path, 0, len); - if (right == -1) - return NULL; - left = rightmost_sep_obj(path, 0, right); - if (left == -1) - left = 0; - else - left++; - if (right-left != sizeof(CACHEDIR)-1) - return NULL; - for (i = 0; i < sizeof(CACHEDIR)-1; i++) - if (PyUnicode_READ_CHAR(path, left+i) != CACHEDIR[i]) - return NULL; - - /* Now verify that the path component to the right of the last slash - has two dots in it. - */ - dot0 = PyUnicode_FindChar(path, '.', right+1, len, 1); - if (dot0 < 0) - return NULL; - dot1 = PyUnicode_FindChar(path, '.', dot0+1, len, 1); - if (dot1 < 0) - return NULL; - /* Too many dots? */ - if (PyUnicode_FindChar(path, '.', dot1+1, len, 1) != -1) - return NULL; - - /* This is a PEP 3147 path. Start by copying everything from the - start of pathname up to and including the leftmost slash. Then - copy the file's basename, removing the magic tag and adding a .py - suffix. - */ - result = PyUnicode_New(left + (dot0-right) + 2, - PyUnicode_MAX_CHAR_VALUE(path)); - if (!result) - return NULL; - kind = PyUnicode_KIND(result); - data = PyUnicode_DATA(result); - PyUnicode_CopyCharacters(result, 0, path, 0, (i = left)); - PyUnicode_CopyCharacters(result, left, path, right+1, - (j = dot0-right)); - PyUnicode_WRITE(kind, data, i+j, 'p'); - PyUnicode_WRITE(kind, data, i+j+1, 'y'); - assert(_PyUnicode_CheckConsistency(result, 1)); - return result; -} - - static void update_code_filenames(PyCodeObject *co, PyObject *oldname, PyObject *newname) { @@ -911,61 +829,6 @@ } -/* Get source file -> unicode or None - * Returns the path to the py file if available, else the given path - */ -static PyObject * -get_sourcefile(PyObject *filename) -{ - Py_ssize_t len; - PyObject *py; - struct stat statbuf; - int err; - void *data; - unsigned int kind; - - len = PyUnicode_GET_LENGTH(filename); - if (len == 0) - Py_RETURN_NONE; - - /* don't match *.pyc or *.pyo? */ - data = PyUnicode_DATA(filename); - kind = PyUnicode_KIND(filename); - if (len < 5 - || PyUnicode_READ(kind, data, len-4) != '.' - || (PyUnicode_READ(kind, data, len-3) != 'p' - && PyUnicode_READ(kind, data, len-3) != 'P') - || (PyUnicode_READ(kind, data, len-2) != 'y' - && PyUnicode_READ(kind, data, len-2) != 'Y')) - goto unchanged; - - /* Start by trying to turn PEP 3147 path into source path. If that - * fails, just chop off the trailing character, i.e. legacy pyc path - * to py. - */ - py = make_source_pathname(filename); - if (py == NULL) { - PyErr_Clear(); - py = PyUnicode_Substring(filename, 0, len - 1); - } - if (py == NULL) - goto error; - - err = _Py_stat(py, &statbuf); - if (err == -2) - goto error; - if (err == 0 && S_ISREG(statbuf.st_mode)) - return py; - Py_DECREF(py); - goto unchanged; - -error: - PyErr_Clear(); -unchanged: - Py_INCREF(filename); - return filename; -} - /* Forward */ static struct _frozen * find_frozen(PyObject *); diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] diff --git a/Tools/scripts/highlight.py b/Tools/scripts/highlight.py --- a/Tools/scripts/highlight.py +++ b/Tools/scripts/highlight.py @@ -4,12 +4,16 @@ __author__ = 'Raymond Hettinger' import keyword, tokenize, cgi, re, functools +try: + import builtins +except ImportError: + import __builtin__ as builtins #### Analyze Python Source ################################# def is_builtin(s): 'Return True if s is the name of a builtin' - return hasattr(__builtins__, s) + return hasattr(builtins, s) def combine_range(lines, start, end): 'Join content from a range of lines between start and end' @@ -21,9 +25,7 @@ def analyze_python(source): '''Generate and classify chunks of Python for syntax highlighting. - Yields tuples in the form: (leadin_text, category, categorized_text). - The final tuple has empty strings for the category and categorized text. - + Yields tuples in the form: (category, categorized_text). ''' lines = source.splitlines(True) lines.append('') @@ -37,7 +39,7 @@ kind = '' if tok_type == tokenize.COMMENT: kind = 'comment' - elif tok_type == tokenize.OP and tok_str[:1] not in '{}[](),.:;': + elif tok_type == tokenize.OP and tok_str[:1] not in '{}[](),.:;@': kind = 'operator' elif tok_type == tokenize.STRING: kind = 'string' @@ -53,22 +55,20 @@ elif is_builtin(tok_str) and prev_tok_str != '.': kind = 'builtin' if kind: - line_upto_token, written = combine_range(lines, written, (srow, scol)) - line_thru_token, written = combine_range(lines, written, (erow, ecol)) - yield line_upto_token, kind, line_thru_token + text, written = combine_range(lines, written, (srow, scol)) + yield '', text + text, written = combine_range(lines, written, (erow, ecol)) + yield kind, text line_upto_token, written = combine_range(lines, written, (erow, ecol)) - yield line_upto_token, '', '' + yield '', line_upto_token #### Raw Output ########################################### def raw_highlight(classified_text): 'Straight text display of text classifications' result = [] - for line_upto_token, kind, line_thru_token in classified_text: - if line_upto_token: - result.append(' plain: %r\n' % line_upto_token) - if line_thru_token: - result.append('%15s: %r\n' % (kind, line_thru_token)) + for kind, text in classified_text: + result.append('%15s: %r\n' % (kind or 'plain', text)) return ''.join(result) #### ANSI Output ########################################### @@ -88,9 +88,9 @@ 'Add syntax highlighting to source code using ANSI escape sequences' # http://en.wikipedia.org/wiki/ANSI_escape_code result = [] - for line_upto_token, kind, line_thru_token in classified_text: + for kind, text in classified_text: opener, closer = colors.get(kind, ('', '')) - result += [line_upto_token, opener, line_thru_token, closer] + result += [opener, text, closer] return ''.join(result) #### HTML Output ########################################### @@ -98,16 +98,13 @@ def html_highlight(classified_text,opener='
      \n', closer='
      \n'): 'Convert classified text to an HTML fragment' result = [opener] - for line_upto_token, kind, line_thru_token in classified_text: + for kind, text in classified_text: if kind: - result += [cgi.escape(line_upto_token), - '' % kind, - cgi.escape(line_thru_token), - ''] - else: - result += [cgi.escape(line_upto_token), - cgi.escape(line_thru_token)] - result += [closer] + result.append('' % kind) + result.append(cgi.escape(text)) + if kind: + result.append('') + result.append(closer) return ''.join(result) default_css = { @@ -188,15 +185,12 @@ document = default_latex_document): 'Create a complete LaTeX document with colorized source code' result = [] - for line_upto_token, kind, line_thru_token in classified_text: + for kind, text in classified_text: if kind: - result += [latex_escape(line_upto_token), - r'{\color{%s}' % colors[kind], - latex_escape(line_thru_token), - '}'] - else: - result += [latex_escape(line_upto_token), - latex_escape(line_thru_token)] + result.append(r'{\color{%s}' % colors[kind]) + result.append(latex_escape(text)) + if kind: + result.append('}') return default_latex_document % dict(title=title, body=''.join(result)) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 13 21:08:02 2012 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 13 Jul 2012 21:08:02 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE1MzM4?= =?utf-8?q?=3A_skip_test=5FUNC=5Fpath_when_the_current_user_doesn=27t_have?= =?utf-8?q?_enough?= Message-ID: <3WYk763xWYzNb7@mail.python.org> http://hg.python.org/cpython/rev/7eac87fa7a06 changeset: 78083:7eac87fa7a06 branch: 2.7 parent: 78061:93df82c18781 user: Antoine Pitrou date: Fri Jul 13 20:54:42 2012 +0200 summary: Issue #15338: skip test_UNC_path when the current user doesn't have enough permissions to access the path. files: Lib/test/test_import.py | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -427,6 +427,13 @@ drive = path[0] unc = "\\\\%s\\%s$"%(hn, drive) unc += path[2:] + try: + os.listdir(unc) + except OSError as e: + if e.errno in (errno.EPERM, errno.EACCES): + # See issue #15338 + self.skipTest("cannot access administrative share %r" % (unc,)) + raise sys.path.append(path) mod = __import__("test_trailing_slash") self.assertEqual(mod.testdata, 'test_trailing_slash') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 13 21:11:43 2012 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 13 Jul 2012 21:11:43 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE1MzM0?= =?utf-8?q?=3A_skip_test=5Fdynamic=5Fkey_when_run_in_non-interactive_mode?= =?utf-8?q?=2E?= Message-ID: <3WYkCM1kL0zP68@mail.python.org> http://hg.python.org/cpython/rev/ec2caf810e5e changeset: 78084:ec2caf810e5e branch: 3.2 parent: 78080:4d480a2a6296 user: Antoine Pitrou date: Fri Jul 13 21:08:41 2012 +0200 summary: Issue #15334: skip test_dynamic_key when run in non-interactive mode. Patch by Jeremy Kloth. files: Lib/test/test_winreg.py | 1 + Misc/ACKS | 1 + 2 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_winreg.py b/Lib/test/test_winreg.py --- a/Lib/test/test_winreg.py +++ b/Lib/test/test_winreg.py @@ -289,6 +289,7 @@ DeleteKey(HKEY_CURRENT_USER, '\\'.join((test_key_name, name))) DeleteKey(HKEY_CURRENT_USER, test_key_name) + @unittest.skipUnless('PROMPT' in os.environ, "Requires interactive session") def test_dynamic_key(self): # Issue2810, when the value is dynamically generated, these # throw "WindowsError: More data is available" in 2.6 and 3.1 diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -483,6 +483,7 @@ Rafe Kaplan Jacob Kaplan-Moss Jan Kaliszewski +Jeremy Kloth Arkady Koplyarov Lou Kates Hiroaki Kawai -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 13 21:11:59 2012 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 13 Jul 2012 21:11:59 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2315334=3A_skip_test=5Fdynamic=5Fkey_when_run_in_?= =?utf-8?q?non-interactive_mode=2E?= Message-ID: <3WYkCg6KmGzP7r@mail.python.org> http://hg.python.org/cpython/rev/1242ed59573e changeset: 78085:1242ed59573e parent: 78082:482cff0eebda parent: 78084:ec2caf810e5e user: Antoine Pitrou date: Fri Jul 13 21:10:17 2012 +0200 summary: Issue #15334: skip test_dynamic_key when run in non-interactive mode. Patch by Jeremy Kloth. files: Lib/test/test_winreg.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_winreg.py b/Lib/test/test_winreg.py --- a/Lib/test/test_winreg.py +++ b/Lib/test/test_winreg.py @@ -289,6 +289,7 @@ DeleteKey(HKEY_CURRENT_USER, '\\'.join((test_key_name, name))) DeleteKey(HKEY_CURRENT_USER, test_key_name) + @unittest.skipUnless('PROMPT' in os.environ, "Requires interactive session") def test_dynamic_key(self): # Issue2810, when the value is dynamically generated, these # throw "WindowsError: More data is available" in 2.6 and 3.1 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 13 21:15:47 2012 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 13 Jul 2012 21:15:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE1MzM0?= =?utf-8?q?=3A_skip_test=5Fdynamic=5Fkey_when_run_in_non-interactive_mode?= =?utf-8?q?=2E?= Message-ID: <3WYkJ36p0NzP9M@mail.python.org> http://hg.python.org/cpython/rev/9bbc4900301c changeset: 78086:9bbc4900301c branch: 2.7 parent: 78083:7eac87fa7a06 user: Antoine Pitrou date: Fri Jul 13 21:08:41 2012 +0200 summary: Issue #15334: skip test_dynamic_key when run in non-interactive mode. Patch by Jeremy Kloth. files: Lib/test/test_winreg.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_winreg.py b/Lib/test/test_winreg.py --- a/Lib/test/test_winreg.py +++ b/Lib/test/test_winreg.py @@ -280,6 +280,7 @@ DeleteKey(key, name) DeleteKey(HKEY_CURRENT_USER, test_key_name) + @unittest.skipUnless('PROMPT' in os.environ, "Requires interactive session") def test_dynamic_key(self): # Issue2810, when the value is dynamically generated, these # throw "WindowsError: More data is available" in 2.6 and 3.1 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 13 21:15:49 2012 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 13 Jul 2012 21:15:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_Remove_duplica?= =?utf-8?q?te_entry_and_fix_order?= Message-ID: <3WYkJ560LpzPBD@mail.python.org> http://hg.python.org/cpython/rev/2f2286c3b4f7 changeset: 78087:2f2286c3b4f7 branch: 3.2 parent: 78084:ec2caf810e5e user: Antoine Pitrou date: Fri Jul 13 21:13:25 2012 +0200 summary: Remove duplicate entry and fix order files: Misc/ACKS | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -483,8 +483,6 @@ Rafe Kaplan Jacob Kaplan-Moss Jan Kaliszewski -Jeremy Kloth -Arkady Koplyarov Lou Kates Hiroaki Kawai Sebastien Keim @@ -515,6 +513,7 @@ Greg Kochanski Damon Kohler Marko Kohtala +Arkady Koplyarov Vlad Korolev Joseph Koshy Jerzy Kozera -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 13 21:15:51 2012 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 13 Jul 2012 21:15:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Null_merge?= Message-ID: <3WYkJ72gftzPBK@mail.python.org> http://hg.python.org/cpython/rev/eaafae4e275e changeset: 78088:eaafae4e275e parent: 78085:1242ed59573e parent: 78087:2f2286c3b4f7 user: Antoine Pitrou date: Fri Jul 13 21:14:03 2012 +0200 summary: Null merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 13 21:40:49 2012 From: python-checkins at python.org (ezio.melotti) Date: Fri, 13 Jul 2012 21:40:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE1MzQ1OiBmaXgg?= =?utf-8?q?SyntaxError_in_argparse_tutorial_example=2E__Patch_by_Simon_Hay?= =?utf-8?q?ward=2E?= Message-ID: <3WYkrx0lWpzNHC@mail.python.org> http://hg.python.org/cpython/rev/de18c4470ff1 changeset: 78089:de18c4470ff1 branch: 2.7 parent: 78086:9bbc4900301c user: Ezio Melotti date: Fri Jul 13 21:40:25 2012 +0200 summary: #15345: fix SyntaxError in argparse tutorial example. Patch by Simon Hayward. files: Doc/howto/argparse.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/howto/argparse.rst b/Doc/howto/argparse.rst --- a/Doc/howto/argparse.rst +++ b/Doc/howto/argparse.rst @@ -646,7 +646,7 @@ if args.verbosity >= 2: print "Running '{}'".format(__file__) if args.verbosity >= 1: - print "{}^{} == ".format(args.x, args.y), end="" + print "{}^{} ==".format(args.x, args.y), print answer Output: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 13 22:48:24 2012 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 13 Jul 2012 22:48:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Try_other_appr?= =?utf-8?q?oach_to_fix_issue_=2315334=2E?= Message-ID: <3WYmLw6qn5zNbN@mail.python.org> http://hg.python.org/cpython/rev/814927ff4ef2 changeset: 78090:814927ff4ef2 branch: 2.7 user: Antoine Pitrou date: Fri Jul 13 22:46:41 2012 +0200 summary: Try other approach to fix issue #15334. files: Lib/test/test_winreg.py | 11 ++++++++--- 1 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_winreg.py b/Lib/test/test_winreg.py --- a/Lib/test/test_winreg.py +++ b/Lib/test/test_winreg.py @@ -1,7 +1,7 @@ # Test the windows specific win32reg module. # Only win32reg functions not hit here: FlushKey, LoadKey and SaveKey -import os, sys +import os, sys, errno import unittest from test import test_support threading = test_support.import_module("threading") @@ -280,11 +280,16 @@ DeleteKey(key, name) DeleteKey(HKEY_CURRENT_USER, test_key_name) - @unittest.skipUnless('PROMPT' in os.environ, "Requires interactive session") def test_dynamic_key(self): # Issue2810, when the value is dynamically generated, these # throw "WindowsError: More data is available" in 2.6 and 3.1 - EnumValue(HKEY_PERFORMANCE_DATA, 0) + try: + EnumValue(HKEY_PERFORMANCE_DATA, 0) + except OSError as e: + if e.errno in (errno.EPERM, errno.EACCES): + self.skipTest("access denied to registry key " + "(are you running in a non-interactive session?)") + raise QueryValueEx(HKEY_PERFORMANCE_DATA, None) # Reflection requires XP x64/Vista at a minimum. XP doesn't have this stuff -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 13 22:51:40 2012 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 13 Jul 2012 22:51:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_Try_other_appr?= =?utf-8?q?oach_to_fix_issue_=2315334=2E?= Message-ID: <3WYmQh064RzP7r@mail.python.org> http://hg.python.org/cpython/rev/dad89e7479e8 changeset: 78091:dad89e7479e8 branch: 3.2 parent: 78087:2f2286c3b4f7 user: Antoine Pitrou date: Fri Jul 13 22:46:41 2012 +0200 summary: Try other approach to fix issue #15334. files: Lib/test/test_winreg.py | 11 ++++++++--- 1 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_winreg.py b/Lib/test/test_winreg.py --- a/Lib/test/test_winreg.py +++ b/Lib/test/test_winreg.py @@ -1,7 +1,7 @@ # Test the windows specific win32reg module. # Only win32reg functions not hit here: FlushKey, LoadKey and SaveKey -import os, sys +import os, sys, errno import unittest from test import support threading = support.import_module("threading") @@ -289,11 +289,16 @@ DeleteKey(HKEY_CURRENT_USER, '\\'.join((test_key_name, name))) DeleteKey(HKEY_CURRENT_USER, test_key_name) - @unittest.skipUnless('PROMPT' in os.environ, "Requires interactive session") def test_dynamic_key(self): # Issue2810, when the value is dynamically generated, these # throw "WindowsError: More data is available" in 2.6 and 3.1 - EnumValue(HKEY_PERFORMANCE_DATA, 0) + try: + EnumValue(HKEY_PERFORMANCE_DATA, 0) + except OSError as e: + if e.errno in (errno.EPERM, errno.EACCES): + self.skipTest("access denied to registry key " + "(are you running in a non-interactive session?)") + raise QueryValueEx(HKEY_PERFORMANCE_DATA, "") # Reflection requires XP x64/Vista at a minimum. XP doesn't have this stuff -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 13 22:51:41 2012 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 13 Jul 2012 22:51:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Try_other_approach_to_fix_issue_=2315334=2E?= Message-ID: <3WYmQj5fxszP8g@mail.python.org> http://hg.python.org/cpython/rev/b4e4c57637cf changeset: 78092:b4e4c57637cf parent: 78088:eaafae4e275e parent: 78091:dad89e7479e8 user: Antoine Pitrou date: Fri Jul 13 22:49:55 2012 +0200 summary: Try other approach to fix issue #15334. files: Lib/test/test_winreg.py | 11 ++++++++--- 1 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_winreg.py b/Lib/test/test_winreg.py --- a/Lib/test/test_winreg.py +++ b/Lib/test/test_winreg.py @@ -1,7 +1,7 @@ # Test the windows specific win32reg module. # Only win32reg functions not hit here: FlushKey, LoadKey and SaveKey -import os, sys +import os, sys, errno import unittest from test import support threading = support.import_module("threading") @@ -289,11 +289,16 @@ DeleteKey(HKEY_CURRENT_USER, '\\'.join((test_key_name, name))) DeleteKey(HKEY_CURRENT_USER, test_key_name) - @unittest.skipUnless('PROMPT' in os.environ, "Requires interactive session") def test_dynamic_key(self): # Issue2810, when the value is dynamically generated, these # throw "WindowsError: More data is available" in 2.6 and 3.1 - EnumValue(HKEY_PERFORMANCE_DATA, 0) + try: + EnumValue(HKEY_PERFORMANCE_DATA, 0) + except OSError as e: + if e.errno in (errno.EPERM, errno.EACCES): + self.skipTest("access denied to registry key " + "(are you running in a non-interactive session?)") + raise QueryValueEx(HKEY_PERFORMANCE_DATA, "") # Reflection requires XP x64/Vista at a minimum. XP doesn't have this stuff -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 14 00:49:18 2012 From: python-checkins at python.org (ned.deily) Date: Sat, 14 Jul 2012 00:49:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315241=3A_Fix_test?= =?utf-8?q?=5Fprefixes_failure_in_test=5Fvenv_due_to_symlink_in?= Message-ID: <3WYq2Q4d6XzPBD@mail.python.org> http://hg.python.org/cpython/rev/0dbffd3c1317 changeset: 78093:0dbffd3c1317 user: Ned Deily date: Fri Jul 13 15:48:04 2012 -0700 summary: Issue #15241: Fix test_prefixes failure in test_venv due to symlink in tempfile directory path (i.e. on OS X /tmp is actually /private/tmp). files: Lib/test/test_venv.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -20,7 +20,7 @@ """Base class for venv tests.""" def setUp(self): - self.env_dir = tempfile.mkdtemp() + self.env_dir = os.path.realpath(tempfile.mkdtemp()) if os.name == 'nt': self.bindir = 'Scripts' self.pydocname = 'pydoc.py' -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat Jul 14 05:59:36 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 14 Jul 2012 05:59:36 +0200 Subject: [Python-checkins] Daily reference leaks (0dbffd3c1317): sum=2 Message-ID: results for 0dbffd3c1317 on branch "default" -------------------------------------------- test_dbm leaked [0, 2, 0] references, sum=2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogpy_hGn', '-x'] From python-checkins at python.org Sat Jul 14 16:08:04 2012 From: python-checkins at python.org (nick.coghlan) Date: Sat, 14 Jul 2012 16:08:04 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogQ2xvc2UgIzE1MjMw?= =?utf-8?q?=3A_runpy=2Erun=5Fpath_now_sets_=5F=5Fpackage=5F=5F_correctly?= =?utf-8?q?=2E_Also_refactored?= Message-ID: <3WZCQX4FWszPGh@mail.python.org> http://hg.python.org/cpython/rev/3b05cf877124 changeset: 78094:3b05cf877124 branch: 3.2 parent: 78091:dad89e7479e8 user: Nick Coghlan date: Sat Jul 14 23:59:22 2012 +1000 summary: Close #15230: runpy.run_path now sets __package__ correctly. Also refactored the runpy tests to use a more systematic approach files: Lib/runpy.py | 6 +- Lib/test/test_runpy.py | 420 ++++++++++++++++++---------- Misc/NEWS | 5 + 3 files changed, 275 insertions(+), 156 deletions(-) diff --git a/Lib/runpy.py b/Lib/runpy.py --- a/Lib/runpy.py +++ b/Lib/runpy.py @@ -68,6 +68,7 @@ run_globals.update(__name__ = mod_name, __file__ = mod_fname, __cached__ = None, + __doc__ = None, __loader__ = mod_loader, __package__ = pkg_name) exec(code, run_globals) @@ -242,12 +243,14 @@ """ if run_name is None: run_name = "" + pkg_name = run_name.rpartition(".")[0] importer = _get_importer(path_name) if isinstance(importer, imp.NullImporter): # Not a valid sys.path entry, so run the code directly # execfile() doesn't help as we want to allow compiled files code = _get_code_from_file(path_name) - return _run_module_code(code, init_globals, run_name, path_name) + return _run_module_code(code, init_globals, run_name, path_name, + pkg_name=pkg_name) else: # Importer is defined for path, so add it to # the start of sys.path @@ -266,7 +269,6 @@ mod_name, loader, code, fname = _get_main_module_details() finally: sys.modules[main_name] = saved_main - pkg_name = "" with _TempModule(run_name) as temp_module, \ _ModifiedArgv0(path_name): mod_globals = temp_module.module.__dict__ diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -10,80 +10,143 @@ from test.script_helper import ( make_pkg, make_script, make_zip_pkg, make_zip_script, temp_dir) - +import runpy from runpy import _run_code, _run_module_code, run_module, run_path # Note: This module can't safely test _run_module_as_main as it # runs its tests in the current process, which would mess with the # real __main__ module (usually test.regrtest) # See test_cmd_line_script for a test that executes that code path + # Set up the test code and expected results +example_source = """\ +# Check basic code execution +result = ['Top level assignment'] +def f(): + result.append('Lower level reference') +f() +del f +# Check the sys module +import sys +run_argv0 = sys.argv[0] +run_name_in_sys_modules = __name__ in sys.modules +module_in_sys_modules = (run_name_in_sys_modules and + globals() is sys.modules[__name__].__dict__) +# Check nested operation +import runpy +nested = runpy._run_module_code('x=1\\n', mod_name='') +""" -class RunModuleCodeTest(unittest.TestCase): +implicit_namespace = { + "__name__": None, + "__file__": None, + "__cached__": None, + "__package__": None, + "__doc__": None, +} +example_namespace = { + "sys": sys, + "runpy": runpy, + "result": ["Top level assignment", "Lower level reference"], + "run_argv0": sys.argv[0], + "run_name_in_sys_modules": False, + "module_in_sys_modules": False, + "nested": dict(implicit_namespace, + x=1, __name__="", __loader__=None), +} +example_namespace.update(implicit_namespace) + +class CodeExecutionMixin: + # Issue #15230 (run_path not handling run_name correctly) highlighted a + # problem with the way arguments were being passed from higher level APIs + # down to lower level code. This mixin makes it easier to ensure full + # testing occurs at those upper layers as well, not just at the utility + # layer + + def assertNamespaceMatches(self, result_ns, expected_ns): + """Check two namespaces match. + + Ignores any unspecified interpreter created names + """ + # Impls are permitted to add extra names, so filter them out + for k in list(result_ns): + if k.startswith("__") and k.endswith("__"): + if k not in expected_ns: + result_ns.pop(k) + if k not in expected_ns["nested"]: + result_ns["nested"].pop(k) + # Don't use direct dict comparison - the diffs are too hard to debug + self.assertEqual(set(result_ns), set(expected_ns)) + for k in result_ns: + actual = (k, result_ns[k]) + expected = (k, expected_ns[k]) + self.assertEqual(actual, expected) + + def check_code_execution(self, create_namespace, expected_namespace): + """Check that an interface runs the example code correctly + + First argument is a callable accepting the initial globals and + using them to create the actual namespace + Second argument is the expected result + """ + sentinel = object() + expected_ns = expected_namespace.copy() + run_name = expected_ns["__name__"] + saved_argv0 = sys.argv[0] + saved_mod = sys.modules.get(run_name, sentinel) + # Check without initial globals + result_ns = create_namespace(None) + self.assertNamespaceMatches(result_ns, expected_ns) + self.assertIs(sys.argv[0], saved_argv0) + self.assertIs(sys.modules.get(run_name, sentinel), saved_mod) + # And then with initial globals + initial_ns = {"sentinel": sentinel} + expected_ns["sentinel"] = sentinel + result_ns = create_namespace(initial_ns) + self.assertIsNot(result_ns, initial_ns) + self.assertNamespaceMatches(result_ns, expected_ns) + self.assertIs(sys.argv[0], saved_argv0) + self.assertIs(sys.modules.get(run_name, sentinel), saved_mod) + + +class ExecutionLayerTestCase(unittest.TestCase, CodeExecutionMixin): """Unit tests for runpy._run_code and runpy._run_module_code""" - expected_result = ["Top level assignment", "Lower level reference"] - test_source = ( - "# Check basic code execution\n" - "result = ['Top level assignment']\n" - "def f():\n" - " result.append('Lower level reference')\n" - "f()\n" - "# Check the sys module\n" - "import sys\n" - "run_argv0 = sys.argv[0]\n" - "run_name_in_sys_modules = __name__ in sys.modules\n" - "if run_name_in_sys_modules:\n" - " module_in_sys_modules = globals() is sys.modules[__name__].__dict__\n" - "# Check nested operation\n" - "import runpy\n" - "nested = runpy._run_module_code('x=1\\n', mod_name='')\n" - ) - def test_run_code(self): - saved_argv0 = sys.argv[0] - d = _run_code(self.test_source, {}) - self.assertEqual(d["result"], self.expected_result) - self.assertIs(d["__name__"], None) - self.assertIs(d["__file__"], None) - self.assertIs(d["__cached__"], None) - self.assertIs(d["__loader__"], None) - self.assertIs(d["__package__"], None) - self.assertIs(d["run_argv0"], saved_argv0) - self.assertNotIn("run_name", d) - self.assertIs(sys.argv[0], saved_argv0) + expected_ns = example_namespace.copy() + expected_ns.update({ + "__loader__": None, + }) + def create_ns(init_globals): + return _run_code(example_source, {}, init_globals) + self.check_code_execution(create_ns, expected_ns) def test_run_module_code(self): - initial = object() - name = "" - file = "Some other nonsense" - loader = "Now you're just being silly" - package = '' # Treat as a top level module - d1 = dict(initial=initial) - saved_argv0 = sys.argv[0] - d2 = _run_module_code(self.test_source, - d1, - name, - file, - loader, - package) - self.assertNotIn("result", d1) - self.assertIs(d2["initial"], initial) - self.assertEqual(d2["result"], self.expected_result) - self.assertEqual(d2["nested"]["x"], 1) - self.assertIs(d2["__name__"], name) - self.assertTrue(d2["run_name_in_sys_modules"]) - self.assertTrue(d2["module_in_sys_modules"]) - self.assertIs(d2["__file__"], file) - self.assertIs(d2["__cached__"], None) - self.assertIs(d2["run_argv0"], file) - self.assertIs(d2["__loader__"], loader) - self.assertIs(d2["__package__"], package) - self.assertIs(sys.argv[0], saved_argv0) - self.assertNotIn(name, sys.modules) + mod_name = "" + mod_fname = "Some other nonsense" + mod_loader = "Now you're just being silly" + mod_package = '' # Treat as a top level module + expected_ns = example_namespace.copy() + expected_ns.update({ + "__name__": mod_name, + "__file__": mod_fname, + "__loader__": mod_loader, + "__package__": mod_package, + "run_argv0": mod_fname, + "run_name_in_sys_modules": True, + "module_in_sys_modules": True, + }) + def create_ns(init_globals): + return _run_module_code(example_source, + init_globals, + mod_name, + mod_fname, + mod_loader, + mod_package) + self.check_code_execution(create_ns, expected_ns) -class RunModuleTest(unittest.TestCase): +class RunModuleTestCase(unittest.TestCase, CodeExecutionMixin): """Unit tests for runpy.run_module""" def expect_import_error(self, mod_name): @@ -107,7 +170,7 @@ self.expect_import_error("multiprocessing") def test_library_module(self): - run_module("runpy") + self.assertEqual(run_module("runpy")["__name__"], "runpy") def _add_pkg_dir(self, pkg_dir): os.mkdir(pkg_dir) @@ -120,19 +183,19 @@ pkg_name = "__runpy_pkg__" test_fname = mod_base+os.extsep+"py" pkg_dir = sub_dir = tempfile.mkdtemp() - if verbose: print(" Package tree in:", sub_dir) + if verbose > 1: print(" Package tree in:", sub_dir) sys.path.insert(0, pkg_dir) - if verbose: print(" Updated sys.path:", sys.path[0]) + if verbose > 1: print(" Updated sys.path:", sys.path[0]) for i in range(depth): sub_dir = os.path.join(sub_dir, pkg_name) pkg_fname = self._add_pkg_dir(sub_dir) - if verbose: print(" Next level in:", sub_dir) - if verbose: print(" Created:", pkg_fname) + if verbose > 1: print(" Next level in:", sub_dir) + if verbose > 1: print(" Created:", pkg_fname) mod_fname = os.path.join(sub_dir, test_fname) mod_file = open(mod_fname, "w") mod_file.write(source) mod_file.close() - if verbose: print(" Created:", mod_fname) + if verbose > 1: print(" Created:", mod_fname) mod_name = (pkg_name+".")*depth + mod_base return pkg_dir, mod_fname, mod_name @@ -140,73 +203,98 @@ for entry in list(sys.modules): if entry.startswith("__runpy_pkg__"): del sys.modules[entry] - if verbose: print(" Removed sys.modules entries") + if verbose > 1: print(" Removed sys.modules entries") del sys.path[0] - if verbose: print(" Removed sys.path entry") + if verbose > 1: print(" Removed sys.path entry") for root, dirs, files in os.walk(top, topdown=False): for name in files: try: os.remove(os.path.join(root, name)) except OSError as ex: - if verbose: print(ex) # Persist with cleaning up + if verbose > 1: print(ex) # Persist with cleaning up for name in dirs: fullname = os.path.join(root, name) try: os.rmdir(fullname) except OSError as ex: - if verbose: print(ex) # Persist with cleaning up + if verbose > 1: print(ex) # Persist with cleaning up try: os.rmdir(top) - if verbose: print(" Removed package tree") + if verbose > 1: print(" Removed package tree") except OSError as ex: - if verbose: print(ex) # Persist with cleaning up + if verbose > 1: print(ex) # Persist with cleaning up - def _check_module(self, depth): + def _fix_ns_for_legacy_pyc(self, ns, alter_sys): + char_to_add = "c" if __debug__ else "o" + ns["__file__"] += char_to_add + if alter_sys: + ns["run_argv0"] += char_to_add + + + def _check_module(self, depth, alter_sys=False): pkg_dir, mod_fname, mod_name = ( - self._make_pkg("x=1\n", depth)) + self._make_pkg(example_source, depth)) forget(mod_name) + expected_ns = example_namespace.copy() + expected_ns.update({ + "__name__": mod_name, + "__file__": mod_fname, + "__package__": mod_name.rpartition(".")[0], + }) + if alter_sys: + expected_ns.update({ + "run_argv0": mod_fname, + "run_name_in_sys_modules": True, + "module_in_sys_modules": True, + }) + def create_ns(init_globals): + return run_module(mod_name, init_globals, alter_sys=alter_sys) try: - if verbose: print("Running from source:", mod_name) - d1 = run_module(mod_name) # Read from source - self.assertIn("x", d1) - self.assertEqual(d1["x"], 1) - del d1 # Ensure __loader__ entry doesn't keep file open + if verbose > 1: print("Running from source:", mod_name) + self.check_code_execution(create_ns, expected_ns) __import__(mod_name) os.remove(mod_fname) make_legacy_pyc(mod_fname) unload(mod_name) # In case loader caches paths - if verbose: print("Running from compiled:", mod_name) - d2 = run_module(mod_name) # Read from bytecode - self.assertIn("x", d2) - self.assertEqual(d2["x"], 1) - del d2 # Ensure __loader__ entry doesn't keep file open + if verbose > 1: print("Running from compiled:", mod_name) + self._fix_ns_for_legacy_pyc(expected_ns, alter_sys) + self.check_code_execution(create_ns, expected_ns) finally: self._del_pkg(pkg_dir, depth, mod_name) - if verbose: print("Module executed successfully") + if verbose > 1: print("Module executed successfully") - def _check_package(self, depth): + def _check_package(self, depth, alter_sys=False): pkg_dir, mod_fname, mod_name = ( - self._make_pkg("x=1\n", depth, "__main__")) - pkg_name, _, _ = mod_name.rpartition(".") + self._make_pkg(example_source, depth, "__main__")) + pkg_name = mod_name.rpartition(".")[0] forget(mod_name) + expected_ns = example_namespace.copy() + expected_ns.update({ + "__name__": mod_name, + "__file__": mod_fname, + "__package__": pkg_name, + }) + if alter_sys: + expected_ns.update({ + "run_argv0": mod_fname, + "run_name_in_sys_modules": True, + "module_in_sys_modules": True, + }) + def create_ns(init_globals): + return run_module(pkg_name, init_globals, alter_sys=alter_sys) try: - if verbose: print("Running from source:", pkg_name) - d1 = run_module(pkg_name) # Read from source - self.assertIn("x", d1) - self.assertTrue(d1["x"] == 1) - del d1 # Ensure __loader__ entry doesn't keep file open + if verbose > 1: print("Running from source:", pkg_name) + self.check_code_execution(create_ns, expected_ns) __import__(mod_name) os.remove(mod_fname) make_legacy_pyc(mod_fname) unload(mod_name) # In case loader caches paths - if verbose: print("Running from compiled:", pkg_name) - d2 = run_module(pkg_name) # Read from bytecode - self.assertIn("x", d2) - self.assertTrue(d2["x"] == 1) - del d2 # Ensure __loader__ entry doesn't keep file open + if verbose > 1: print("Running from compiled:", pkg_name) + self._fix_ns_for_legacy_pyc(expected_ns, alter_sys) + self.check_code_execution(create_ns, expected_ns) finally: self._del_pkg(pkg_dir, depth, pkg_name) - if verbose: print("Package executed successfully") + if verbose > 1: print("Package executed successfully") def _add_relative_modules(self, base_dir, source, depth): if depth <= 1: @@ -220,18 +308,18 @@ sibling_fname = os.path.join(module_dir, "sibling.py") sibling_file = open(sibling_fname, "w") sibling_file.close() - if verbose: print(" Added sibling module:", sibling_fname) + if verbose > 1: print(" Added sibling module:", sibling_fname) # Add nephew module uncle_dir = os.path.join(parent_dir, "uncle") self._add_pkg_dir(uncle_dir) - if verbose: print(" Added uncle package:", uncle_dir) + if verbose > 1: print(" Added uncle package:", uncle_dir) cousin_dir = os.path.join(uncle_dir, "cousin") self._add_pkg_dir(cousin_dir) - if verbose: print(" Added cousin package:", cousin_dir) + if verbose > 1: print(" Added cousin package:", cousin_dir) nephew_fname = os.path.join(cousin_dir, "nephew.py") nephew_file = open(nephew_fname, "w") nephew_file.close() - if verbose: print(" Added nephew module:", nephew_fname) + if verbose > 1: print(" Added nephew module:", nephew_fname) def _check_relative_imports(self, depth, run_name=None): contents = r"""\ @@ -241,13 +329,17 @@ """ pkg_dir, mod_fname, mod_name = ( self._make_pkg(contents, depth)) + if run_name is None: + expected_name = mod_name + else: + expected_name = run_name try: self._add_relative_modules(pkg_dir, contents, depth) pkg_name = mod_name.rpartition('.')[0] - if verbose: print("Running from source:", mod_name) + if verbose > 1: print("Running from source:", mod_name) d1 = run_module(mod_name, run_name=run_name) # Read from source - self.assertIn("__package__", d1) - self.assertTrue(d1["__package__"] == pkg_name) + self.assertEqual(d1["__name__"], expected_name) + self.assertEqual(d1["__package__"], pkg_name) self.assertIn("sibling", d1) self.assertIn("nephew", d1) del d1 # Ensure __loader__ entry doesn't keep file open @@ -255,77 +347,97 @@ os.remove(mod_fname) make_legacy_pyc(mod_fname) unload(mod_name) # In case the loader caches paths - if verbose: print("Running from compiled:", mod_name) + if verbose > 1: print("Running from compiled:", mod_name) d2 = run_module(mod_name, run_name=run_name) # Read from bytecode - self.assertIn("__package__", d2) - self.assertTrue(d2["__package__"] == pkg_name) + self.assertEqual(d2["__name__"], expected_name) + self.assertEqual(d2["__package__"], pkg_name) self.assertIn("sibling", d2) self.assertIn("nephew", d2) del d2 # Ensure __loader__ entry doesn't keep file open finally: self._del_pkg(pkg_dir, depth, mod_name) - if verbose: print("Module executed successfully") + if verbose > 1: print("Module executed successfully") def test_run_module(self): for depth in range(4): - if verbose: print("Testing package depth:", depth) + if verbose > 1: print("Testing package depth:", depth) self._check_module(depth) def test_run_package(self): for depth in range(1, 4): - if verbose: print("Testing package depth:", depth) + if verbose > 1: print("Testing package depth:", depth) self._check_package(depth) + def test_run_module_alter_sys(self): + for depth in range(4): + if verbose > 1: print("Testing package depth:", depth) + self._check_module(depth, alter_sys=True) + + def test_run_package_alter_sys(self): + for depth in range(1, 4): + if verbose > 1: print("Testing package depth:", depth) + self._check_package(depth, alter_sys=True) + def test_explicit_relative_import(self): for depth in range(2, 5): - if verbose: print("Testing relative imports at depth:", depth) + if verbose > 1: print("Testing relative imports at depth:", depth) self._check_relative_imports(depth) def test_main_relative_import(self): for depth in range(2, 5): - if verbose: print("Testing main relative imports at depth:", depth) + if verbose > 1: print("Testing main relative imports at depth:", depth) self._check_relative_imports(depth, "__main__") + def test_run_name(self): + depth = 1 + run_name = "And now for something completely different" + pkg_dir, mod_fname, mod_name = ( + self._make_pkg(example_source, depth)) + forget(mod_name) + expected_ns = example_namespace.copy() + expected_ns.update({ + "__name__": run_name, + "__file__": mod_fname, + "__package__": mod_name.rpartition(".")[0], + }) + def create_ns(init_globals): + return run_module(mod_name, init_globals, run_name) + try: + self.check_code_execution(create_ns, expected_ns) + finally: + self._del_pkg(pkg_dir, depth, mod_name) -class RunPathTest(unittest.TestCase): + +class RunPathTestCase(unittest.TestCase, CodeExecutionMixin): """Unit tests for runpy.run_path""" - # Based on corresponding tests in test_cmd_line_script - - test_source = """\ -# Script may be run with optimisation enabled, so don't rely on assert -# statements being executed -def assertEqual(lhs, rhs): - if lhs != rhs: - raise AssertionError('%r != %r' % (lhs, rhs)) -def assertIs(lhs, rhs): - if lhs is not rhs: - raise AssertionError('%r is not %r' % (lhs, rhs)) -# Check basic code execution -result = ['Top level assignment'] -def f(): - result.append('Lower level reference') -f() -assertEqual(result, ['Top level assignment', 'Lower level reference']) -# Check the sys module -import sys -assertIs(globals(), sys.modules[__name__].__dict__) -argv0 = sys.argv[0] -""" def _make_test_script(self, script_dir, script_basename, source=None): if source is None: - source = self.test_source + source = example_source return make_script(script_dir, script_basename, source) def _check_script(self, script_name, expected_name, expected_file, - expected_argv0, expected_package): - result = run_path(script_name) - self.assertEqual(result["__name__"], expected_name) - self.assertEqual(result["__file__"], expected_file) - self.assertEqual(result["__cached__"], None) - self.assertIn("argv0", result) - self.assertEqual(result["argv0"], expected_argv0) - self.assertEqual(result["__package__"], expected_package) + expected_argv0): + # First check is without run_name + def create_ns(init_globals): + return run_path(script_name, init_globals) + expected_ns = example_namespace.copy() + expected_ns.update({ + "__name__": expected_name, + "__file__": expected_file, + "__package__": "", + "run_argv0": expected_argv0, + "run_name_in_sys_modules": True, + "module_in_sys_modules": True, + }) + self.check_code_execution(create_ns, expected_ns) + # Second check makes sure run_name works in all cases + run_name = "prove.issue15230.is.fixed" + def create_ns(init_globals): + return run_path(script_name, init_globals, run_name) + expected_ns["__name__"] = run_name + expected_ns["__package__"] = run_name.rpartition(".")[0] + self.check_code_execution(create_ns, expected_ns) def _check_import_error(self, script_name, msg): msg = re.escape(msg) @@ -336,7 +448,7 @@ mod_name = 'script' script_name = self._make_test_script(script_dir, mod_name) self._check_script(script_name, "", script_name, - script_name, None) + script_name) def test_script_compiled(self): with temp_dir() as script_dir: @@ -345,14 +457,14 @@ compiled_name = py_compile.compile(script_name, doraise=True) os.remove(script_name) self._check_script(compiled_name, "", compiled_name, - compiled_name, None) + compiled_name) def test_directory(self): with temp_dir() as script_dir: mod_name = '__main__' script_name = self._make_test_script(script_dir, mod_name) self._check_script(script_dir, "", script_name, - script_dir, '') + script_dir) def test_directory_compiled(self): with temp_dir() as script_dir: @@ -362,7 +474,7 @@ os.remove(script_name) legacy_pyc = make_legacy_pyc(script_name) self._check_script(script_dir, "", legacy_pyc, - script_dir, '') + script_dir) def test_directory_error(self): with temp_dir() as script_dir: @@ -376,7 +488,7 @@ mod_name = '__main__' script_name = self._make_test_script(script_dir, mod_name) zip_name, fname = make_zip_script(script_dir, 'test_zip', script_name) - self._check_script(zip_name, "", fname, zip_name, '') + self._check_script(zip_name, "", fname, zip_name) def test_zipfile_compiled(self): with temp_dir() as script_dir: @@ -385,7 +497,7 @@ compiled_name = py_compile.compile(script_name, doraise=True) zip_name, fname = make_zip_script(script_dir, 'test_zip', compiled_name) - self._check_script(zip_name, "", fname, zip_name, '') + self._check_script(zip_name, "", fname, zip_name) def test_zipfile_error(self): with temp_dir() as script_dir: @@ -419,9 +531,9 @@ def test_main(): run_unittest( - RunModuleCodeTest, - RunModuleTest, - RunPathTest + ExecutionLayerTestCase, + RunModuleTestCase, + RunPathTestCase ) if __name__ == "__main__": diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -87,6 +87,9 @@ Library ------- +- Issue #15230: runpy.run_path now correctly sets __package__ as described + in the documentation + - Issue #14990: Correctly fail with SyntaxError on invalid encoding declaration. @@ -341,6 +344,8 @@ Tests ----- +- Issue #15230: Adopted a more systematic approach in the runpy tests + - Issue #15300: Ensure the temporary test working directories are in the same parent folder when running tests in multiprocess mode from a Python build. Patch by Chris Jerdonek. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 14 16:08:06 2012 From: python-checkins at python.org (nick.coghlan) Date: Sat, 14 Jul 2012 16:08:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Merge_fix_for_=2315230_from_3=2E2?= Message-ID: <3WZCQZ4lbGzPGy@mail.python.org> http://hg.python.org/cpython/rev/8a44e7c0fa30 changeset: 78095:8a44e7c0fa30 parent: 78093:0dbffd3c1317 parent: 78094:3b05cf877124 user: Nick Coghlan date: Sun Jul 15 00:07:43 2012 +1000 summary: Merge fix for #15230 from 3.2 files: Lib/runpy.py | 6 +- Lib/test/test_runpy.py | 420 ++++++++++++++++++---------- Misc/NEWS | 5 + 3 files changed, 275 insertions(+), 156 deletions(-) diff --git a/Lib/runpy.py b/Lib/runpy.py --- a/Lib/runpy.py +++ b/Lib/runpy.py @@ -70,6 +70,7 @@ run_globals.update(__name__ = mod_name, __file__ = mod_fname, __cached__ = None, + __doc__ = None, __loader__ = mod_loader, __package__ = pkg_name) exec(code, run_globals) @@ -233,12 +234,14 @@ """ if run_name is None: run_name = "" + pkg_name = run_name.rpartition(".")[0] importer = _get_importer(path_name) if isinstance(importer, (type(None), imp.NullImporter)): # Not a valid sys.path entry, so run the code directly # execfile() doesn't help as we want to allow compiled files code = _get_code_from_file(path_name) - return _run_module_code(code, init_globals, run_name, path_name) + return _run_module_code(code, init_globals, run_name, path_name, + pkg_name=pkg_name) else: # Importer is defined for path, so add it to # the start of sys.path @@ -257,7 +260,6 @@ mod_name, loader, code, fname = _get_main_module_details() finally: sys.modules[main_name] = saved_main - pkg_name = "" with _TempModule(run_name) as temp_module, \ _ModifiedArgv0(path_name): mod_globals = temp_module.module.__dict__ diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -13,80 +13,143 @@ from test.script_helper import ( make_pkg, make_script, make_zip_pkg, make_zip_script, temp_dir) - +import runpy from runpy import _run_code, _run_module_code, run_module, run_path # Note: This module can't safely test _run_module_as_main as it # runs its tests in the current process, which would mess with the # real __main__ module (usually test.regrtest) # See test_cmd_line_script for a test that executes that code path + # Set up the test code and expected results +example_source = """\ +# Check basic code execution +result = ['Top level assignment'] +def f(): + result.append('Lower level reference') +f() +del f +# Check the sys module +import sys +run_argv0 = sys.argv[0] +run_name_in_sys_modules = __name__ in sys.modules +module_in_sys_modules = (run_name_in_sys_modules and + globals() is sys.modules[__name__].__dict__) +# Check nested operation +import runpy +nested = runpy._run_module_code('x=1\\n', mod_name='') +""" -class RunModuleCodeTest(unittest.TestCase): +implicit_namespace = { + "__name__": None, + "__file__": None, + "__cached__": None, + "__package__": None, + "__doc__": None, +} +example_namespace = { + "sys": sys, + "runpy": runpy, + "result": ["Top level assignment", "Lower level reference"], + "run_argv0": sys.argv[0], + "run_name_in_sys_modules": False, + "module_in_sys_modules": False, + "nested": dict(implicit_namespace, + x=1, __name__="", __loader__=None), +} +example_namespace.update(implicit_namespace) + +class CodeExecutionMixin: + # Issue #15230 (run_path not handling run_name correctly) highlighted a + # problem with the way arguments were being passed from higher level APIs + # down to lower level code. This mixin makes it easier to ensure full + # testing occurs at those upper layers as well, not just at the utility + # layer + + def assertNamespaceMatches(self, result_ns, expected_ns): + """Check two namespaces match. + + Ignores any unspecified interpreter created names + """ + # Impls are permitted to add extra names, so filter them out + for k in list(result_ns): + if k.startswith("__") and k.endswith("__"): + if k not in expected_ns: + result_ns.pop(k) + if k not in expected_ns["nested"]: + result_ns["nested"].pop(k) + # Don't use direct dict comparison - the diffs are too hard to debug + self.assertEqual(set(result_ns), set(expected_ns)) + for k in result_ns: + actual = (k, result_ns[k]) + expected = (k, expected_ns[k]) + self.assertEqual(actual, expected) + + def check_code_execution(self, create_namespace, expected_namespace): + """Check that an interface runs the example code correctly + + First argument is a callable accepting the initial globals and + using them to create the actual namespace + Second argument is the expected result + """ + sentinel = object() + expected_ns = expected_namespace.copy() + run_name = expected_ns["__name__"] + saved_argv0 = sys.argv[0] + saved_mod = sys.modules.get(run_name, sentinel) + # Check without initial globals + result_ns = create_namespace(None) + self.assertNamespaceMatches(result_ns, expected_ns) + self.assertIs(sys.argv[0], saved_argv0) + self.assertIs(sys.modules.get(run_name, sentinel), saved_mod) + # And then with initial globals + initial_ns = {"sentinel": sentinel} + expected_ns["sentinel"] = sentinel + result_ns = create_namespace(initial_ns) + self.assertIsNot(result_ns, initial_ns) + self.assertNamespaceMatches(result_ns, expected_ns) + self.assertIs(sys.argv[0], saved_argv0) + self.assertIs(sys.modules.get(run_name, sentinel), saved_mod) + + +class ExecutionLayerTestCase(unittest.TestCase, CodeExecutionMixin): """Unit tests for runpy._run_code and runpy._run_module_code""" - expected_result = ["Top level assignment", "Lower level reference"] - test_source = ( - "# Check basic code execution\n" - "result = ['Top level assignment']\n" - "def f():\n" - " result.append('Lower level reference')\n" - "f()\n" - "# Check the sys module\n" - "import sys\n" - "run_argv0 = sys.argv[0]\n" - "run_name_in_sys_modules = __name__ in sys.modules\n" - "if run_name_in_sys_modules:\n" - " module_in_sys_modules = globals() is sys.modules[__name__].__dict__\n" - "# Check nested operation\n" - "import runpy\n" - "nested = runpy._run_module_code('x=1\\n', mod_name='')\n" - ) - def test_run_code(self): - saved_argv0 = sys.argv[0] - d = _run_code(self.test_source, {}) - self.assertEqual(d["result"], self.expected_result) - self.assertIs(d["__name__"], None) - self.assertIs(d["__file__"], None) - self.assertIs(d["__cached__"], None) - self.assertIs(d["__loader__"], None) - self.assertIs(d["__package__"], None) - self.assertIs(d["run_argv0"], saved_argv0) - self.assertNotIn("run_name", d) - self.assertIs(sys.argv[0], saved_argv0) + expected_ns = example_namespace.copy() + expected_ns.update({ + "__loader__": None, + }) + def create_ns(init_globals): + return _run_code(example_source, {}, init_globals) + self.check_code_execution(create_ns, expected_ns) def test_run_module_code(self): - initial = object() - name = "" - file = "Some other nonsense" - loader = "Now you're just being silly" - package = '' # Treat as a top level module - d1 = dict(initial=initial) - saved_argv0 = sys.argv[0] - d2 = _run_module_code(self.test_source, - d1, - name, - file, - loader, - package) - self.assertNotIn("result", d1) - self.assertIs(d2["initial"], initial) - self.assertEqual(d2["result"], self.expected_result) - self.assertEqual(d2["nested"]["x"], 1) - self.assertIs(d2["__name__"], name) - self.assertTrue(d2["run_name_in_sys_modules"]) - self.assertTrue(d2["module_in_sys_modules"]) - self.assertIs(d2["__file__"], file) - self.assertIs(d2["__cached__"], None) - self.assertIs(d2["run_argv0"], file) - self.assertIs(d2["__loader__"], loader) - self.assertIs(d2["__package__"], package) - self.assertIs(sys.argv[0], saved_argv0) - self.assertNotIn(name, sys.modules) + mod_name = "" + mod_fname = "Some other nonsense" + mod_loader = "Now you're just being silly" + mod_package = '' # Treat as a top level module + expected_ns = example_namespace.copy() + expected_ns.update({ + "__name__": mod_name, + "__file__": mod_fname, + "__loader__": mod_loader, + "__package__": mod_package, + "run_argv0": mod_fname, + "run_name_in_sys_modules": True, + "module_in_sys_modules": True, + }) + def create_ns(init_globals): + return _run_module_code(example_source, + init_globals, + mod_name, + mod_fname, + mod_loader, + mod_package) + self.check_code_execution(create_ns, expected_ns) -class RunModuleTest(unittest.TestCase): +class RunModuleTestCase(unittest.TestCase, CodeExecutionMixin): """Unit tests for runpy.run_module""" def expect_import_error(self, mod_name): @@ -110,7 +173,7 @@ self.expect_import_error("multiprocessing") def test_library_module(self): - run_module("runpy") + self.assertEqual(run_module("runpy")["__name__"], "runpy") def _add_pkg_dir(self, pkg_dir): os.mkdir(pkg_dir) @@ -122,19 +185,19 @@ pkg_name = "__runpy_pkg__" test_fname = mod_base+os.extsep+"py" pkg_dir = sub_dir = tempfile.mkdtemp() - if verbose: print(" Package tree in:", sub_dir) + if verbose > 1: print(" Package tree in:", sub_dir) sys.path.insert(0, pkg_dir) - if verbose: print(" Updated sys.path:", sys.path[0]) + if verbose > 1: print(" Updated sys.path:", sys.path[0]) for i in range(depth): sub_dir = os.path.join(sub_dir, pkg_name) pkg_fname = self._add_pkg_dir(sub_dir) - if verbose: print(" Next level in:", sub_dir) - if verbose: print(" Created:", pkg_fname) + if verbose > 1: print(" Next level in:", sub_dir) + if verbose > 1: print(" Created:", pkg_fname) mod_fname = os.path.join(sub_dir, test_fname) mod_file = open(mod_fname, "w") mod_file.write(source) mod_file.close() - if verbose: print(" Created:", mod_fname) + if verbose > 1: print(" Created:", mod_fname) mod_name = (pkg_name+".")*depth + mod_base return pkg_dir, mod_fname, mod_name @@ -142,77 +205,102 @@ for entry in list(sys.modules): if entry.startswith("__runpy_pkg__"): del sys.modules[entry] - if verbose: print(" Removed sys.modules entries") + if verbose > 1: print(" Removed sys.modules entries") del sys.path[0] - if verbose: print(" Removed sys.path entry") + if verbose > 1: print(" Removed sys.path entry") for root, dirs, files in os.walk(top, topdown=False): for name in files: try: os.remove(os.path.join(root, name)) except OSError as ex: - if verbose: print(ex) # Persist with cleaning up + if verbose > 1: print(ex) # Persist with cleaning up for name in dirs: fullname = os.path.join(root, name) try: os.rmdir(fullname) except OSError as ex: - if verbose: print(ex) # Persist with cleaning up + if verbose > 1: print(ex) # Persist with cleaning up try: os.rmdir(top) - if verbose: print(" Removed package tree") + if verbose > 1: print(" Removed package tree") except OSError as ex: - if verbose: print(ex) # Persist with cleaning up + if verbose > 1: print(ex) # Persist with cleaning up - def _check_module(self, depth): + def _fix_ns_for_legacy_pyc(self, ns, alter_sys): + char_to_add = "c" if __debug__ else "o" + ns["__file__"] += char_to_add + if alter_sys: + ns["run_argv0"] += char_to_add + + + def _check_module(self, depth, alter_sys=False): pkg_dir, mod_fname, mod_name = ( - self._make_pkg("x=1\n", depth)) + self._make_pkg(example_source, depth)) forget(mod_name) + expected_ns = example_namespace.copy() + expected_ns.update({ + "__name__": mod_name, + "__file__": mod_fname, + "__package__": mod_name.rpartition(".")[0], + }) + if alter_sys: + expected_ns.update({ + "run_argv0": mod_fname, + "run_name_in_sys_modules": True, + "module_in_sys_modules": True, + }) + def create_ns(init_globals): + return run_module(mod_name, init_globals, alter_sys=alter_sys) try: - if verbose: print("Running from source:", mod_name) - d1 = run_module(mod_name) # Read from source - self.assertIn("x", d1) - self.assertEqual(d1["x"], 1) - del d1 # Ensure __loader__ entry doesn't keep file open + if verbose > 1: print("Running from source:", mod_name) + self.check_code_execution(create_ns, expected_ns) importlib.invalidate_caches() __import__(mod_name) os.remove(mod_fname) make_legacy_pyc(mod_fname) unload(mod_name) # In case loader caches paths - if verbose: print("Running from compiled:", mod_name) importlib.invalidate_caches() - d2 = run_module(mod_name) # Read from bytecode - self.assertIn("x", d2) - self.assertEqual(d2["x"], 1) - del d2 # Ensure __loader__ entry doesn't keep file open + if verbose > 1: print("Running from compiled:", mod_name) + self._fix_ns_for_legacy_pyc(expected_ns, alter_sys) + self.check_code_execution(create_ns, expected_ns) finally: self._del_pkg(pkg_dir, depth, mod_name) - if verbose: print("Module executed successfully") + if verbose > 1: print("Module executed successfully") - def _check_package(self, depth): + def _check_package(self, depth, alter_sys=False): pkg_dir, mod_fname, mod_name = ( - self._make_pkg("x=1\n", depth, "__main__")) - pkg_name, _, _ = mod_name.rpartition(".") + self._make_pkg(example_source, depth, "__main__")) + pkg_name = mod_name.rpartition(".")[0] forget(mod_name) + expected_ns = example_namespace.copy() + expected_ns.update({ + "__name__": mod_name, + "__file__": mod_fname, + "__package__": pkg_name, + }) + if alter_sys: + expected_ns.update({ + "run_argv0": mod_fname, + "run_name_in_sys_modules": True, + "module_in_sys_modules": True, + }) + def create_ns(init_globals): + return run_module(pkg_name, init_globals, alter_sys=alter_sys) try: - if verbose: print("Running from source:", pkg_name) - d1 = run_module(pkg_name) # Read from source - self.assertIn("x", d1) - self.assertTrue(d1["x"] == 1) - del d1 # Ensure __loader__ entry doesn't keep file open + if verbose > 1: print("Running from source:", pkg_name) + self.check_code_execution(create_ns, expected_ns) importlib.invalidate_caches() __import__(mod_name) os.remove(mod_fname) make_legacy_pyc(mod_fname) unload(mod_name) # In case loader caches paths - if verbose: print("Running from compiled:", pkg_name) + if verbose > 1: print("Running from compiled:", pkg_name) importlib.invalidate_caches() - d2 = run_module(pkg_name) # Read from bytecode - self.assertIn("x", d2) - self.assertTrue(d2["x"] == 1) - del d2 # Ensure __loader__ entry doesn't keep file open + self._fix_ns_for_legacy_pyc(expected_ns, alter_sys) + self.check_code_execution(create_ns, expected_ns) finally: self._del_pkg(pkg_dir, depth, pkg_name) - if verbose: print("Package executed successfully") + if verbose > 1: print("Package executed successfully") def _add_relative_modules(self, base_dir, source, depth): if depth <= 1: @@ -225,17 +313,17 @@ # Add sibling module sibling_fname = os.path.join(module_dir, "sibling.py") create_empty_file(sibling_fname) - if verbose: print(" Added sibling module:", sibling_fname) + if verbose > 1: print(" Added sibling module:", sibling_fname) # Add nephew module uncle_dir = os.path.join(parent_dir, "uncle") self._add_pkg_dir(uncle_dir) - if verbose: print(" Added uncle package:", uncle_dir) + if verbose > 1: print(" Added uncle package:", uncle_dir) cousin_dir = os.path.join(uncle_dir, "cousin") self._add_pkg_dir(cousin_dir) - if verbose: print(" Added cousin package:", cousin_dir) + if verbose > 1: print(" Added cousin package:", cousin_dir) nephew_fname = os.path.join(cousin_dir, "nephew.py") create_empty_file(nephew_fname) - if verbose: print(" Added nephew module:", nephew_fname) + if verbose > 1: print(" Added nephew module:", nephew_fname) def _check_relative_imports(self, depth, run_name=None): contents = r"""\ @@ -245,13 +333,17 @@ """ pkg_dir, mod_fname, mod_name = ( self._make_pkg(contents, depth)) + if run_name is None: + expected_name = mod_name + else: + expected_name = run_name try: self._add_relative_modules(pkg_dir, contents, depth) pkg_name = mod_name.rpartition('.')[0] - if verbose: print("Running from source:", mod_name) + if verbose > 1: print("Running from source:", mod_name) d1 = run_module(mod_name, run_name=run_name) # Read from source - self.assertIn("__package__", d1) - self.assertTrue(d1["__package__"] == pkg_name) + self.assertEqual(d1["__name__"], expected_name) + self.assertEqual(d1["__package__"], pkg_name) self.assertIn("sibling", d1) self.assertIn("nephew", d1) del d1 # Ensure __loader__ entry doesn't keep file open @@ -260,78 +352,98 @@ os.remove(mod_fname) make_legacy_pyc(mod_fname) unload(mod_name) # In case the loader caches paths - if verbose: print("Running from compiled:", mod_name) + if verbose > 1: print("Running from compiled:", mod_name) importlib.invalidate_caches() d2 = run_module(mod_name, run_name=run_name) # Read from bytecode - self.assertIn("__package__", d2) - self.assertTrue(d2["__package__"] == pkg_name) + self.assertEqual(d2["__name__"], expected_name) + self.assertEqual(d2["__package__"], pkg_name) self.assertIn("sibling", d2) self.assertIn("nephew", d2) del d2 # Ensure __loader__ entry doesn't keep file open finally: self._del_pkg(pkg_dir, depth, mod_name) - if verbose: print("Module executed successfully") + if verbose > 1: print("Module executed successfully") def test_run_module(self): for depth in range(4): - if verbose: print("Testing package depth:", depth) + if verbose > 1: print("Testing package depth:", depth) self._check_module(depth) def test_run_package(self): for depth in range(1, 4): - if verbose: print("Testing package depth:", depth) + if verbose > 1: print("Testing package depth:", depth) self._check_package(depth) + def test_run_module_alter_sys(self): + for depth in range(4): + if verbose > 1: print("Testing package depth:", depth) + self._check_module(depth, alter_sys=True) + + def test_run_package_alter_sys(self): + for depth in range(1, 4): + if verbose > 1: print("Testing package depth:", depth) + self._check_package(depth, alter_sys=True) + def test_explicit_relative_import(self): for depth in range(2, 5): - if verbose: print("Testing relative imports at depth:", depth) + if verbose > 1: print("Testing relative imports at depth:", depth) self._check_relative_imports(depth) def test_main_relative_import(self): for depth in range(2, 5): - if verbose: print("Testing main relative imports at depth:", depth) + if verbose > 1: print("Testing main relative imports at depth:", depth) self._check_relative_imports(depth, "__main__") + def test_run_name(self): + depth = 1 + run_name = "And now for something completely different" + pkg_dir, mod_fname, mod_name = ( + self._make_pkg(example_source, depth)) + forget(mod_name) + expected_ns = example_namespace.copy() + expected_ns.update({ + "__name__": run_name, + "__file__": mod_fname, + "__package__": mod_name.rpartition(".")[0], + }) + def create_ns(init_globals): + return run_module(mod_name, init_globals, run_name) + try: + self.check_code_execution(create_ns, expected_ns) + finally: + self._del_pkg(pkg_dir, depth, mod_name) -class RunPathTest(unittest.TestCase): + +class RunPathTestCase(unittest.TestCase, CodeExecutionMixin): """Unit tests for runpy.run_path""" - # Based on corresponding tests in test_cmd_line_script - - test_source = """\ -# Script may be run with optimisation enabled, so don't rely on assert -# statements being executed -def assertEqual(lhs, rhs): - if lhs != rhs: - raise AssertionError('%r != %r' % (lhs, rhs)) -def assertIs(lhs, rhs): - if lhs is not rhs: - raise AssertionError('%r is not %r' % (lhs, rhs)) -# Check basic code execution -result = ['Top level assignment'] -def f(): - result.append('Lower level reference') -f() -assertEqual(result, ['Top level assignment', 'Lower level reference']) -# Check the sys module -import sys -assertIs(globals(), sys.modules[__name__].__dict__) -argv0 = sys.argv[0] -""" def _make_test_script(self, script_dir, script_basename, source=None): if source is None: - source = self.test_source + source = example_source return make_script(script_dir, script_basename, source) def _check_script(self, script_name, expected_name, expected_file, - expected_argv0, expected_package): - result = run_path(script_name) - self.assertEqual(result["__name__"], expected_name) - self.assertEqual(result["__file__"], expected_file) - self.assertEqual(result["__cached__"], None) - self.assertIn("argv0", result) - self.assertEqual(result["argv0"], expected_argv0) - self.assertEqual(result["__package__"], expected_package) + expected_argv0): + # First check is without run_name + def create_ns(init_globals): + return run_path(script_name, init_globals) + expected_ns = example_namespace.copy() + expected_ns.update({ + "__name__": expected_name, + "__file__": expected_file, + "__package__": "", + "run_argv0": expected_argv0, + "run_name_in_sys_modules": True, + "module_in_sys_modules": True, + }) + self.check_code_execution(create_ns, expected_ns) + # Second check makes sure run_name works in all cases + run_name = "prove.issue15230.is.fixed" + def create_ns(init_globals): + return run_path(script_name, init_globals, run_name) + expected_ns["__name__"] = run_name + expected_ns["__package__"] = run_name.rpartition(".")[0] + self.check_code_execution(create_ns, expected_ns) def _check_import_error(self, script_name, msg): msg = re.escape(msg) @@ -342,7 +454,7 @@ mod_name = 'script' script_name = self._make_test_script(script_dir, mod_name) self._check_script(script_name, "", script_name, - script_name, None) + script_name) def test_script_compiled(self): with temp_dir() as script_dir: @@ -351,14 +463,14 @@ compiled_name = py_compile.compile(script_name, doraise=True) os.remove(script_name) self._check_script(compiled_name, "", compiled_name, - compiled_name, None) + compiled_name) def test_directory(self): with temp_dir() as script_dir: mod_name = '__main__' script_name = self._make_test_script(script_dir, mod_name) self._check_script(script_dir, "", script_name, - script_dir, '') + script_dir) def test_directory_compiled(self): with temp_dir() as script_dir: @@ -368,7 +480,7 @@ os.remove(script_name) legacy_pyc = make_legacy_pyc(script_name) self._check_script(script_dir, "", legacy_pyc, - script_dir, '') + script_dir) def test_directory_error(self): with temp_dir() as script_dir: @@ -382,7 +494,7 @@ mod_name = '__main__' script_name = self._make_test_script(script_dir, mod_name) zip_name, fname = make_zip_script(script_dir, 'test_zip', script_name) - self._check_script(zip_name, "", fname, zip_name, '') + self._check_script(zip_name, "", fname, zip_name) def test_zipfile_compiled(self): with temp_dir() as script_dir: @@ -391,7 +503,7 @@ compiled_name = py_compile.compile(script_name, doraise=True) zip_name, fname = make_zip_script(script_dir, 'test_zip', compiled_name) - self._check_script(zip_name, "", fname, zip_name, '') + self._check_script(zip_name, "", fname, zip_name) def test_zipfile_error(self): with temp_dir() as script_dir: @@ -426,9 +538,9 @@ def test_main(): run_unittest( - RunModuleCodeTest, - RunModuleTest, - RunPathTest + ExecutionLayerTestCase, + RunModuleTestCase, + RunPathTestCase ) if __name__ == "__main__": diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -35,6 +35,9 @@ Library ------- +- Issue #15230: runpy.run_path now correctly sets __package__ as described + in the documentation + - Issue #15315: Support VS 2010 in distutils cygwincompiler. - Issue #15294: Fix a regression in pkgutil.extend_path()'s handling of @@ -133,6 +136,8 @@ Tests ----- +- Issue #15230: Adopted a more systematic approach in the runpy tests + - Issue #15300: Ensure the temporary test working directories are in the same parent folder when running tests in multiprocess mode from a Python build. Patch by Chris Jerdonek. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 14 16:38:59 2012 From: python-checkins at python.org (nick.coghlan) Date: Sat, 14 Jul 2012 16:38:59 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE1MjMw?= =?utf-8?q?=3A_Update_runpy_docs_to_clarify_a_couple_of_points_that_came_u?= =?utf-8?q?p_in?= Message-ID: <3WZD6C3krZzPDY@mail.python.org> http://hg.python.org/cpython/rev/4880aac5c665 changeset: 78096:4880aac5c665 branch: 3.2 parent: 78094:3b05cf877124 user: Nick Coghlan date: Sun Jul 15 00:36:39 2012 +1000 summary: Issue #15230: Update runpy docs to clarify a couple of points that came up in this issue files: Doc/library/runpy.rst | 11 +++++++++++ Misc/NEWS | 3 +++ 2 files changed, 14 insertions(+), 0 deletions(-) diff --git a/Doc/library/runpy.rst b/Doc/library/runpy.rst --- a/Doc/library/runpy.rst +++ b/Doc/library/runpy.rst @@ -14,6 +14,15 @@ line switch that allows scripts to be located using the Python module namespace rather than the filesystem. +Note that this is *not* a sandbox module - all code is executed in the +current process, and any side effects (such as cached imports of other +modules) will remain in place after the functions have returned. + +Furthermore, any functions and classes defined by the executed code are not +guaranteed to work correctly after a :mod:`runpy` function has returned. +If that limitation is not acceptable for a given use case, :mod:`importlib` +is likely to be a more suitable choice than this module. + The :mod:`runpy` module provides two functions: @@ -141,3 +150,5 @@ PEP written and implemented by Nick Coghlan. :ref:`using-on-general` - CPython command line details + + The :func:`importlib.import_module` function diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -384,6 +384,9 @@ Documentation ------------- +- Issue #15230: Clearly document some of the limitations of the runpy + module and nudge readers towards importlib when appropriate. + - Issue #13557: Clarify effect of giving two different namespaces to exec or execfile(). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 14 16:39:01 2012 From: python-checkins at python.org (nick.coghlan) Date: Sat, 14 Jul 2012 16:39:01 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Merge_=2315230_doc_updates_from_3=2E2?= Message-ID: <3WZD6F1HZkzPDs@mail.python.org> http://hg.python.org/cpython/rev/416cd57d38cf changeset: 78097:416cd57d38cf parent: 78095:8a44e7c0fa30 parent: 78096:4880aac5c665 user: Nick Coghlan date: Sun Jul 15 00:38:43 2012 +1000 summary: Merge #15230 doc updates from 3.2 files: Doc/library/runpy.rst | 11 +++++++++++ Misc/NEWS | 5 ++++- 2 files changed, 15 insertions(+), 1 deletions(-) diff --git a/Doc/library/runpy.rst b/Doc/library/runpy.rst --- a/Doc/library/runpy.rst +++ b/Doc/library/runpy.rst @@ -14,6 +14,15 @@ line switch that allows scripts to be located using the Python module namespace rather than the filesystem. +Note that this is *not* a sandbox module - all code is executed in the +current process, and any side effects (such as cached imports of other +modules) will remain in place after the functions have returned. + +Furthermore, any functions and classes defined by the executed code are not +guaranteed to work correctly after a :mod:`runpy` function has returned. +If that limitation is not acceptable for a given use case, :mod:`importlib` +is likely to be a more suitable choice than this module. + The :mod:`runpy` module provides two functions: @@ -141,3 +150,5 @@ PEP written and implemented by Nick Coghlan. :ref:`using-on-general` - CPython command line details + + The :func:`importlib.import_module` function diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -122,6 +122,9 @@ Documentation ------------- +- Issue #15230: Clearly document some of the limitations of the runpy + module and nudge readers towards importlib when appropriate. + - Issue #15053: Copy Python 3.3 import lock change notice to all relevant functions in imp instead of just at the top of the relevant section. @@ -1184,12 +1187,12 @@ Based on patch from Herv? Coatanhay. - Issue #14321: Do not run pgen during the build if files are up to date. + Documentation ------------- - Issue #14034: added the argparse tutorial. - - Issue #14324: Fix configure tests for cross builds. - Issue #14327: Call AC_CANONICAL_HOST in configure.ac and check in -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 14 20:22:44 2012 From: python-checkins at python.org (eli.bendersky) Date: Sat, 14 Jul 2012 20:22:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Some_small_fixes_and_clari?= =?utf-8?q?fications_to_the_io_documentation?= Message-ID: <3WZK4N272gzPDk@mail.python.org> http://hg.python.org/cpython/rev/fefe326af0eb changeset: 78098:fefe326af0eb user: Eli Bendersky date: Sat Jul 14 21:22:25 2012 +0300 summary: Some small fixes and clarifications to the io documentation files: Doc/library/io.rst | 86 +++++++++++++++++---------------- 1 files changed, 44 insertions(+), 42 deletions(-) diff --git a/Doc/library/io.rst b/Doc/library/io.rst --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -34,8 +34,8 @@ ``write()`` method of a text stream. .. versionchanged:: 3.3 - Operations defined in this module used to raise :exc:`IOError`, which is - now an alias of :exc:`OSError`. + Operations that used to raise :exc:`IOError` now raise :exc:`OSError`, since + :exc:`IOError` is now an alias of :exc:`OSError`. Text I/O @@ -55,7 +55,7 @@ f = io.StringIO("some initial text data") -The text stream API is described in detail in the documentation for the +The text stream API is described in detail in the documentation of :class:`TextIOBase`. @@ -209,13 +209,13 @@ Note that calling any method (even inquiries) on a closed stream is undefined. Implementations may raise :exc:`ValueError` in this case. - IOBase (and its subclasses) support the iterator protocol, meaning that an - :class:`IOBase` object can be iterated over yielding the lines in a stream. - Lines are defined slightly differently depending on whether the stream is - a binary stream (yielding bytes), or a text stream (yielding character - strings). See :meth:`~IOBase.readline` below. + :class:`IOBase` (and its subclasses) support the iterator protocol, meaning + that an :class:`IOBase` object can be iterated over yielding the lines in a + stream. Lines are defined slightly differently depending on whether the + stream is a binary stream (yielding bytes), or a text stream (yielding + character strings). See :meth:`~IOBase.readline` below. - IOBase is also a context manager and therefore supports the + :class:`IOBase` is also a context manager and therefore supports the :keyword:`with` statement. In this example, *file* is closed after the :keyword:`with` statement's suite is finished---even if an exception occurs:: @@ -235,7 +235,7 @@ .. attribute:: closed - True if the stream is closed. + ``True`` if the stream is closed. .. method:: fileno() @@ -336,7 +336,7 @@ (this is left to Buffered I/O and Text I/O, described later in this page). In addition to the attributes and methods from :class:`IOBase`, - RawIOBase provides the following methods: + :class:`RawIOBase` provides the following methods: .. method:: read(n=-1) @@ -356,18 +356,18 @@ .. method:: readinto(b) - Read up to len(b) bytes into bytearray *b* and return the number - of bytes read. If the object is in non-blocking mode and no + Read up to ``len(b)`` bytes into :class:`bytearray` *b* and return the + number of bytes read. If the object is in non-blocking mode and no bytes are available, ``None`` is returned. .. method:: write(b) - Write the given bytes or bytearray object, *b*, to the underlying raw - stream and return the number of bytes written. This can be less than - ``len(b)``, depending on specifics of the underlying raw stream, and - especially if it is in non-blocking mode. ``None`` is returned if the - raw stream is set not to block and no single byte could be readily - written to it. + Write the given :class:`bytes` or :class:`bytearray` object, *b*, to the + underlying raw stream and return the number of bytes written. This can + be less than ``len(b)``, depending on specifics of the underlying raw + stream, and especially if it is in non-blocking mode. ``None`` is + returned if the raw stream is set not to block and no single byte could + be readily written to it. .. class:: BufferedIOBase @@ -417,8 +417,8 @@ .. method:: read(n=-1) Read and return up to *n* bytes. If the argument is omitted, ``None``, or - negative, data is read and returned until EOF is reached. An empty bytes - object is returned if the stream is already at EOF. + negative, data is read and returned until EOF is reached. An empty + :class:`bytes` object is returned if the stream is already at EOF. If the argument is positive, and the underlying raw stream is not interactive, multiple raw reads may be issued to satisfy the byte count @@ -438,22 +438,23 @@ .. method:: readinto(b) - Read up to len(b) bytes into bytearray *b* and return the number of bytes - read. + Read up to ``len(b)`` bytes into bytearray *b* and return the number of + bytes read. Like :meth:`read`, multiple reads may be issued to the underlying raw - stream, unless the latter is 'interactive'. + stream, unless the latter is interactive. A :exc:`BlockingIOError` is raised if the underlying raw stream is in non blocking-mode, and has no data available at the moment. .. method:: write(b) - Write the given bytes or bytearray object, *b* and return the number - of bytes written (never less than ``len(b)``, since if the write fails - an :exc:`OSError` will be raised). Depending on the actual - implementation, these bytes may be readily written to the underlying - stream, or held in a buffer for performance and latency reasons. + Write the given :class:`bytes` or :class:`bytearray` object, *b* and + return the number of bytes written (never less than ``len(b)``, since if + the write fails an :exc:`OSError` will be raised). Depending on the + actual implementation, these bytes may be readily written to the + underlying stream, or held in a buffer for performance and latency + reasons. When in non-blocking mode, a :exc:`BlockingIOError` is raised if the data needed to be written to the raw stream but it couldn't accept @@ -471,8 +472,8 @@ The *name* can be one of two things: - * a character string or bytes object representing the path to the file - which will be opened; + * a character string or :class:`bytes` object representing the path to the + file which will be opened; * an integer representing the number of an existing OS-level file descriptor to which the resulting :class:`FileIO` object will give access. @@ -499,7 +500,7 @@ In addition to the attributes and methods from :class:`IOBase` and :class:`RawIOBase`, :class:`FileIO` provides the following data - attributes and methods: + attributes: .. attribute:: mode @@ -547,7 +548,7 @@ .. method:: getvalue() - Return ``bytes`` containing the entire contents of the buffer. + Return :class:`bytes` containing the entire contents of the buffer. .. method:: read1() @@ -591,7 +592,7 @@ A buffer providing higher-level access to a writeable, sequential :class:`RawIOBase` object. It inherits :class:`BufferedIOBase`. - When writing to this object, data is normally held into an internal + When writing to this object, data is normally placed into an internal buffer. The buffer will be written out to the underlying :class:`RawIOBase` object under various conditions, including: @@ -614,9 +615,10 @@ .. method:: write(b) - Write the bytes or bytearray object, *b* and return the number of bytes - written. When in non-blocking mode, a :exc:`BlockingIOError` is raised - if the buffer needs to be written out but the raw stream blocks. + Write the :class:`bytes` or :class:`bytearray` object, *b* and return the + number of bytes written. When in non-blocking mode, a + :exc:`BlockingIOError` is raised if the buffer needs to be written out but + the raw stream blocks. .. class:: BufferedRandom(raw, buffer_size=DEFAULT_BUFFER_SIZE) @@ -685,7 +687,7 @@ The underlying binary buffer (a :class:`BufferedIOBase` instance) that :class:`TextIOBase` deals with. This is not part of the - :class:`TextIOBase` API and may not exist on some implementations. + :class:`TextIOBase` API and may not exist in some implementations. .. method:: detach() @@ -851,8 +853,8 @@ kind of I/O which is performed. For example, on some modern OSes such as Linux, unbuffered disk I/O can be as fast as buffered I/O. The bottom line, however, is that buffered I/O offers predictable performance regardless of the platform -and the backing device. Therefore, it is most always preferable to use buffered -I/O rather than unbuffered I/O for binary datal +and the backing device. Therefore, it is almost always preferable to use +buffered I/O rather than unbuffered I/O for binary data. Text I/O ^^^^^^^^ @@ -887,8 +889,8 @@ :class:`BufferedWriter`, :class:`BufferedRandom` and :class:`BufferedRWPair`) are not reentrant. While reentrant calls will not happen in normal situations, they can arise from doing I/O in a :mod:`signal` handler. If a thread tries to -renter a buffered object which it is already accessing, a :exc:`RuntimeError` is -raised. Note this doesn't prohibit a different thread from entering the +re-enter a buffered object which it is already accessing, a :exc:`RuntimeError` +is raised. Note this doesn't prohibit a different thread from entering the buffered object. The above implicitly extends to text files, since the :func:`open()` function -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 14 20:30:54 2012 From: python-checkins at python.org (brett.cannon) Date: Sat, 14 Jul 2012 20:30:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Minor_grammatical_tweaks?= =?utf-8?q?=2E?= Message-ID: <3WZKFp5MyHzPFg@mail.python.org> http://hg.python.org/cpython/rev/f4bb7d4be22e changeset: 78099:f4bb7d4be22e user: Brett Cannon date: Sat Jul 14 14:30:48 2012 -0400 summary: Minor grammatical tweaks. files: Doc/library/pkgutil.rst | 10 ++++++---- 1 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Doc/library/pkgutil.rst b/Doc/library/pkgutil.rst --- a/Doc/library/pkgutil.rst +++ b/Doc/library/pkgutil.rst @@ -139,13 +139,14 @@ *prefix* is a string to output on the front of every module name on output. .. note:: - Only works with a :term:`finder` which defines a ``iter_modules()`` + Only works with a :term:`finder` which defines an ``iter_modules()`` method, which is non-standard but implemented by classes defined in this module. .. versionchanged:: 3.3 As of Python 3.3, the import system provides finders by default, but they - do not include the ``iter_modules()`` method required by this function. + do not include the non-standard ``iter_modules()`` method required by this + function. .. function:: walk_packages(path=None, prefix='', onerror=None) @@ -176,12 +177,13 @@ walk_packages(ctypes.__path__, ctypes.__name__ + '.') .. note:: - Only works for a :term:`finder` which define a ``iter_modules()`` method, + Only works for a :term:`finder` which define an ``iter_modules()`` method, which is non-standard but implemented by classes defined in this module. .. versionchanged:: 3.3 As of Python 3.3, the import system provides finders by default, but they - do not include the ``iter_modules()`` method required by this function. + do not include the non-standard ``iter_modules()`` method required by this + function. .. function:: get_data(package, resource) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 14 23:12:51 2012 From: python-checkins at python.org (gregory.p.smith) Date: Sat, 14 Jul 2012 23:12:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Update_the_embedded_copy_o?= =?utf-8?q?f_the_expat_XML_parser_to_2=2E1=2E0=2E__It_brings?= Message-ID: <3WZNrg66hNzPDR@mail.python.org> http://hg.python.org/cpython/rev/e4dc8be9a72f changeset: 78100:e4dc8be9a72f user: Gregory P. Smith date: Sat Jul 14 14:12:35 2012 -0700 summary: Update the embedded copy of the expat XML parser to 2.1.0. It brings with it a vareity of bug fixes, both security and behavior. See http://www.libexpat.org/ for the list. NOTE: I already backported the expat hash randomization fix in March. Fixes issue #14340. files: Modules/expat/COPYING | 1 + Modules/expat/amigaconfig.h | 64 --- Modules/expat/ascii.h | 7 + Modules/expat/expat.h | 29 +- Modules/expat/expat_external.h | 10 +- Modules/expat/internal.h | 2 +- Modules/expat/watcomconfig.h | 47 ++ Modules/expat/xmlparse.c | 433 ++++++++++++-------- Modules/expat/xmlrole.c | 12 +- Modules/expat/xmltok.c | 22 +- Modules/expat/xmltok_impl.c | 6 +- Modules/expat/xmltok_ns.c | 9 + 12 files changed, 379 insertions(+), 263 deletions(-) diff --git a/Modules/expat/COPYING b/Modules/expat/COPYING --- a/Modules/expat/COPYING +++ b/Modules/expat/COPYING @@ -1,5 +1,6 @@ Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd and Clark Cooper +Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Expat maintainers. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/Modules/expat/amigaconfig.h b/Modules/expat/amigaconfig.h --- a/Modules/expat/amigaconfig.h +++ b/Modules/expat/amigaconfig.h @@ -10,66 +10,12 @@ /* Define to 1 if you have the header file. */ #undef HAVE_CHECK_H -/* Define to 1 if you have the header file. */ -#undef HAVE_DLFCN_H - -/* Define to 1 if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define to 1 if you have the `getpagesize' function. */ -#undef HAVE_GETPAGESIZE - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - /* Define to 1 if you have the `memmove' function. */ #define HAVE_MEMMOVE 1 -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define to 1 if you have a working `mmap' system call. */ -#undef HAVE_MMAP - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "expat-bugs at mail.libexpat.org" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "expat" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "expat 1.95.8" - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "1.95.8" - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - /* whether byteorder is bigendian */ #define WORDS_BIGENDIAN @@ -83,14 +29,4 @@ /* Define to make XML Namespaces functionality available. */ #define XML_NS -/* Define to empty if `const' does not conform to ANSI C. */ -#undef const - -/* Define to `long' if does not define. */ -#undef off_t - -/* Define to `unsigned' if does not define. */ -#undef size_t - - #endif /* AMIGACONFIG_H */ diff --git a/Modules/expat/ascii.h b/Modules/expat/ascii.h --- a/Modules/expat/ascii.h +++ b/Modules/expat/ascii.h @@ -83,3 +83,10 @@ #define ASCII_LSQB 0x5B #define ASCII_RSQB 0x5D #define ASCII_UNDERSCORE 0x5F +#define ASCII_LPAREN 0x28 +#define ASCII_RPAREN 0x29 +#define ASCII_FF 0x0C +#define ASCII_SLASH 0x2F +#define ASCII_HASH 0x23 +#define ASCII_PIPE 0x7C +#define ASCII_COMMA 0x2C diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -742,6 +742,29 @@ XMLPARSEAPI(int) XML_GetIdAttributeIndex(XML_Parser parser); +#ifdef XML_ATTR_INFO +/* Source file byte offsets for the start and end of attribute names and values. + The value indices are exclusive of surrounding quotes; thus in a UTF-8 source + file an attribute value of "blah" will yield: + info->valueEnd - info->valueStart = 4 bytes. +*/ +typedef struct { + XML_Index nameStart; /* Offset to beginning of the attribute name. */ + XML_Index nameEnd; /* Offset after the attribute name's last byte. */ + XML_Index valueStart; /* Offset to beginning of the attribute value. */ + XML_Index valueEnd; /* Offset after the attribute value's last byte. */ +} XML_AttrInfo; + +/* Returns an array of XML_AttrInfo structures for the attribute/value pairs + passed in last call to the XML_StartElementHandler that were specified + in the start-tag rather than defaulted. Each attribute/value pair counts + as 1; thus the number of entries in the array is + XML_GetSpecifiedAttributeCount(parser) / 2. +*/ +XMLPARSEAPI(const XML_AttrInfo *) +XML_GetAttributeInfo(XML_Parser parser); +#endif + /* Parses some input. Returns XML_STATUS_ERROR if a fatal error is detected. The last call to XML_Parse must have isFinal true; len may be zero for this call (or any other). @@ -994,7 +1017,9 @@ XML_FEATURE_MIN_SIZE, XML_FEATURE_SIZEOF_XML_CHAR, XML_FEATURE_SIZEOF_XML_LCHAR, - XML_FEATURE_NS + XML_FEATURE_NS, + XML_FEATURE_LARGE_SIZE, + XML_FEATURE_ATTR_INFO /* Additional features must be added to the end of this enum. */ }; @@ -1014,7 +1039,7 @@ change to major or minor version. */ #define XML_MAJOR_VERSION 2 -#define XML_MINOR_VERSION 0 +#define XML_MINOR_VERSION 1 #define XML_MICRO_VERSION 0 #ifdef __cplusplus diff --git a/Modules/expat/expat_external.h b/Modules/expat/expat_external.h --- a/Modules/expat/expat_external.h +++ b/Modules/expat/expat_external.h @@ -7,11 +7,7 @@ /* External API definitions */ -/* Namespace external symbols to allow multiple libexpat version to - co-exist. */ -#include "pyexpatns.h" - -#if defined(_MSC_EXTENSIONS) && !defined(__CYGWIN__) +#if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__) #define XML_USE_MSC_EXTENSIONS 1 #endif @@ -38,9 +34,9 @@ system headers may assume the cdecl convention. */ #ifndef XMLCALL -#if defined(XML_USE_MSC_EXTENSIONS) +#if defined(_MSC_VER) #define XMLCALL __cdecl -#elif defined(__GNUC__) && defined(__i386) +#elif defined(__GNUC__) && defined(__i386) && !defined(__INTEL_COMPILER) #define XMLCALL __attribute__((cdecl)) #else /* For any platform which uses this definition and supports more than diff --git a/Modules/expat/internal.h b/Modules/expat/internal.h --- a/Modules/expat/internal.h +++ b/Modules/expat/internal.h @@ -20,7 +20,7 @@ and therefore subject to change. */ -#if defined(__GNUC__) && defined(__i386__) +#if defined(__GNUC__) && defined(__i386__) && !defined(__MINGW32__) /* We'll use this version by default only where we know it helps. regparm() generates warnings on Solaris boxes. See SF bug #692878. diff --git a/Modules/expat/watcomconfig.h b/Modules/expat/watcomconfig.h new file mode 100644 --- /dev/null +++ b/Modules/expat/watcomconfig.h @@ -0,0 +1,47 @@ +/* expat_config.h for use with Open Watcom 1.5 and above. */ + +#ifndef WATCOMCONFIG_H +#define WATCOMCONFIG_H + +#ifdef __NT__ +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN +#endif + +/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */ +#define BYTEORDER 1234 + +/* Define to 1 if you have the `memmove' function. */ +#define HAVE_MEMMOVE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "expat-bugs at mail.libexpat.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "expat" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "expat 2.0.0" + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "2.0.0" + +/* Define to specify how much context to retain around the current parse + point. */ +#define XML_CONTEXT_BYTES 1024 + +/* Define to make parameter entity parsing functionality available. */ +#define XML_DTD 1 + +/* Define to make XML Namespaces functionality available. */ +#define XML_NS 1 + +#endif + diff --git a/Modules/expat/xmlparse.c b/Modules/expat/xmlparse.c --- a/Modules/expat/xmlparse.c +++ b/Modules/expat/xmlparse.c @@ -2,24 +2,27 @@ See the file COPYING for copying permission. */ -#define XML_BUILDING_EXPAT 1 - -#ifdef COMPILED_FROM_DSP -#include "winconfig.h" -#elif defined(MACOS_CLASSIC) -#include "macconfig.h" -#elif defined(__amigaos4__) -#include "amigaconfig.h" -#elif defined(HAVE_EXPAT_CONFIG_H) -#include -#endif /* ndef COMPILED_FROM_DSP */ - #include #include /* memset(), memcpy() */ #include #include /* UINT_MAX */ #include /* time() */ +#define XML_BUILDING_EXPAT 1 + +#ifdef COMPILED_FROM_DSP +#include "winconfig.h" +#elif defined(MACOS_CLASSIC) +#include "macconfig.h" +#elif defined(__amigaos__) +#include "amigaconfig.h" +#elif defined(__WATCOMC__) +#include "watcomconfig.h" +#elif defined(HAVE_EXPAT_CONFIG_H) +#include +#endif /* ndef COMPILED_FROM_DSP */ + +#include "ascii.h" #include "expat.h" #ifdef XML_UNICODE @@ -28,7 +31,8 @@ #define XmlGetInternalEncoding XmlGetUtf16InternalEncoding #define XmlGetInternalEncodingNS XmlGetUtf16InternalEncodingNS #define XmlEncode XmlUtf16Encode -#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((unsigned long)s) & 1)) +/* Using pointer subtraction to convert to integer type. */ +#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((char *)(s) - (char *)NULL) & 1)) typedef unsigned short ICHAR; #else #define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX @@ -325,15 +329,15 @@ static enum XML_Error initializeEncoding(XML_Parser parser); static enum XML_Error -doProlog(XML_Parser parser, const ENCODING *enc, const char *s, - const char *end, int tok, const char *next, const char **nextPtr, +doProlog(XML_Parser parser, const ENCODING *enc, const char *s, + const char *end, int tok, const char *next, const char **nextPtr, XML_Bool haveMore); static enum XML_Error -processInternalEntity(XML_Parser parser, ENTITY *entity, +processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl); static enum XML_Error doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, - const char *start, const char *end, const char **endPtr, + const char *start, const char *end, const char **endPtr, XML_Bool haveMore); static enum XML_Error doCdataSection(XML_Parser parser, const ENCODING *, const char **startPtr, @@ -351,7 +355,7 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, const XML_Char *uri, BINDING **bindingsPtr); static int -defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata, +defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata, XML_Bool isId, const XML_Char *dfltValue, XML_Parser parser); static enum XML_Error storeAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata, @@ -436,6 +440,7 @@ const XML_Memory_Handling_Suite *memsuite, const XML_Char *nameSep, DTD *dtd); + static void parserInit(XML_Parser parser, const XML_Char *encodingName); @@ -535,6 +540,9 @@ NS_ATT *m_nsAtts; unsigned long m_nsAttsVersion; unsigned char m_nsAttsPower; +#ifdef XML_ATTR_INFO + XML_AttrInfo *m_attInfo; +#endif POSITION m_position; STRING_POOL m_tempPool; STRING_POOL m_temp2Pool; @@ -643,6 +651,7 @@ #define nsAtts (parser->m_nsAtts) #define nsAttsVersion (parser->m_nsAttsVersion) #define nsAttsPower (parser->m_nsAttsPower) +#define attInfo (parser->m_attInfo) #define tempPool (parser->m_tempPool) #define temp2Pool (parser->m_temp2Pool) #define groupConnector (parser->m_groupConnector) @@ -673,10 +682,12 @@ } static const XML_Char implicitContext[] = { - 'x', 'm', 'l', '=', 'h', 't', 't', 'p', ':', '/', '/', - 'w', 'w', 'w', '.', 'w', '3', '.', 'o', 'r', 'g', '/', - 'X', 'M', 'L', '/', '1', '9', '9', '8', '/', - 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\0' + ASCII_x, ASCII_m, ASCII_l, ASCII_EQUALS, ASCII_h, ASCII_t, ASCII_t, ASCII_p, + ASCII_COLON, ASCII_SLASH, ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w, + ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD, ASCII_o, ASCII_r, ASCII_g, + ASCII_SLASH, ASCII_X, ASCII_M, ASCII_L, ASCII_SLASH, ASCII_1, ASCII_9, + ASCII_9, ASCII_8, ASCII_SLASH, ASCII_n, ASCII_a, ASCII_m, ASCII_e, + ASCII_s, ASCII_p, ASCII_a, ASCII_c, ASCII_e, '\0' }; static unsigned long @@ -690,23 +701,22 @@ static XML_Bool /* only valid for root parser */ startParsing(XML_Parser parser) { - /* hash functions must be initialized before setContext() is called */ - - if (hash_secret_salt == 0) - hash_secret_salt = generate_hash_secret_salt(); - if (ns) { - /* implicit context only set for root parser, since child - parsers (i.e. external entity parsers) will inherit it - */ - return setContext(parser, implicitContext); - } - return XML_TRUE; + /* hash functions must be initialized before setContext() is called */ + if (hash_secret_salt == 0) + hash_secret_salt = generate_hash_secret_salt(); + if (ns) { + /* implicit context only set for root parser, since child + parsers (i.e. external entity parsers) will inherit it + */ + return setContext(parser, implicitContext); + } + return XML_TRUE; } XML_Parser XMLCALL XML_ParserCreate_MM(const XML_Char *encodingName, - const XML_Memory_Handling_Suite *memsuite, - const XML_Char *nameSep) + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *nameSep) { return parserCreate(encodingName, memsuite, nameSep, NULL); } @@ -753,9 +763,20 @@ FREE(parser); return NULL; } +#ifdef XML_ATTR_INFO + attInfo = (XML_AttrInfo*)MALLOC(attsSize * sizeof(XML_AttrInfo)); + if (attInfo == NULL) { + FREE(atts); + FREE(parser); + return NULL; + } +#endif dataBuf = (XML_Char *)MALLOC(INIT_DATA_BUF_SIZE * sizeof(XML_Char)); if (dataBuf == NULL) { FREE(atts); +#ifdef XML_ATTR_INFO + FREE(attInfo); +#endif FREE(parser); return NULL; } @@ -768,6 +789,9 @@ if (_dtd == NULL) { FREE(dataBuf); FREE(atts); +#ifdef XML_ATTR_INFO + FREE(attInfo); +#endif FREE(parser); return NULL; } @@ -783,7 +807,7 @@ unknownEncodingHandler = NULL; unknownEncodingHandlerData = NULL; - namespaceSeparator = '!'; + namespaceSeparator = ASCII_EXCL; ns = XML_FALSE; ns_triplets = XML_FALSE; @@ -1154,6 +1178,9 @@ #endif /* XML_DTD */ dtdDestroy(_dtd, (XML_Bool)!parentParser, &parser->m_mem); FREE((void *)atts); +#ifdef XML_ATTR_INFO + FREE((void *)attInfo); +#endif FREE(groupConnector); FREE(buffer); FREE(dataBuf); @@ -1234,6 +1261,14 @@ return idAttIndex; } +#ifdef XML_ATTR_INFO +const XML_AttrInfo * XMLCALL +XML_GetAttributeInfo(XML_Parser parser) +{ + return attInfo; +} +#endif + void XMLCALL XML_SetElementHandler(XML_Parser parser, XML_StartElementHandler start, @@ -1499,7 +1534,7 @@ XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position); positionPtr = bufferPtr; return XML_STATUS_SUSPENDED; - case XML_INITIALIZED: + case XML_INITIALIZED: case XML_PARSING: ps_parsing = XML_FINISHED; /* fall through */ @@ -1555,15 +1590,11 @@ : (char *)REALLOC(buffer, len * 2)); if (temp == NULL) { errorCode = XML_ERROR_NO_MEMORY; - return XML_STATUS_ERROR; - } - buffer = temp; - if (!buffer) { - errorCode = XML_ERROR_NO_MEMORY; eventPtr = eventEndPtr = NULL; processor = errorProcessor; return XML_STATUS_ERROR; } + buffer = temp; bufferLim = buffer + len * 2; } memcpy(buffer, end, nLeftOver); @@ -1629,7 +1660,7 @@ case XML_SUSPENDED: result = XML_STATUS_SUSPENDED; break; - case XML_INITIALIZED: + case XML_INITIALIZED: case XML_PARSING: if (isFinal) { ps_parsing = XML_FINISHED; @@ -1719,6 +1750,8 @@ bufferPtr = buffer = newBuf; #endif /* not defined XML_CONTEXT_BYTES */ } + eventPtr = eventEndPtr = NULL; + positionPtr = NULL; } return bufferEnd; } @@ -1776,7 +1809,7 @@ case XML_SUSPENDED: result = XML_STATUS_SUSPENDED; break; - case XML_INITIALIZED: + case XML_INITIALIZED: case XML_PARSING: if (ps_finalBuffer) { ps_parsing = XML_FINISHED; @@ -2001,6 +2034,12 @@ #ifdef XML_NS {XML_FEATURE_NS, XML_L("XML_NS"), 0}, #endif +#ifdef XML_LARGE_SIZE + {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0}, +#endif +#ifdef XML_ATTR_INFO + {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0}, +#endif {XML_FEATURE_END, NULL, 0} }; @@ -2063,7 +2102,7 @@ const char *end, const char **endPtr) { - enum XML_Error result = doContent(parser, 0, encoding, start, end, + enum XML_Error result = doContent(parser, 0, encoding, start, end, endPtr, (XML_Bool)!ps_finalBuffer); if (result == XML_ERROR_NONE) { if (!storeRawNames(parser)) @@ -2145,7 +2184,7 @@ if (result != XML_ERROR_NONE) return result; switch (ps_parsing) { - case XML_SUSPENDED: + case XML_SUSPENDED: *endPtr = next; return XML_ERROR_NONE; case XML_FINISHED: @@ -2179,7 +2218,7 @@ const char *end, const char **endPtr) { - enum XML_Error result = doContent(parser, 1, encoding, start, end, + enum XML_Error result = doContent(parser, 1, encoding, start, end, endPtr, (XML_Bool)!ps_finalBuffer); if (result == XML_ERROR_NONE) { if (!storeRawNames(parser)) @@ -2198,7 +2237,7 @@ XML_Bool haveMore) { /* save one level of indirection */ - DTD * const dtd = _dtd; + DTD * const dtd = _dtd; const char **eventPP; const char **eventEndPP; @@ -2229,8 +2268,8 @@ } else if (defaultHandler) reportDefault(parser, enc, s, end); - /* We are at the end of the final buffer, should we check for - XML_SUSPENDED, XML_FINISHED? + /* We are at the end of the final buffer, should we check for + XML_SUSPENDED, XML_FINISHED? */ if (startTagLevel == 0) return XML_ERROR_NO_ELEMENTS; @@ -2581,8 +2620,8 @@ } else if (defaultHandler) reportDefault(parser, enc, s, end); - /* We are at the end of the final buffer, should we check for - XML_SUSPENDED, XML_FINISHED? + /* We are at the end of the final buffer, should we check for + XML_SUSPENDED, XML_FINISHED? */ if (startTagLevel == 0) { *eventPP = end; @@ -2595,26 +2634,29 @@ *nextPtr = end; return XML_ERROR_NONE; case XML_TOK_DATA_CHARS: - if (characterDataHandler) { - if (MUST_CONVERT(enc, s)) { - for (;;) { - ICHAR *dataPtr = (ICHAR *)dataBuf; - XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd); - *eventEndPP = s; - characterDataHandler(handlerArg, dataBuf, - (int)(dataPtr - (ICHAR *)dataBuf)); - if (s == next) - break; - *eventPP = s; + { + XML_CharacterDataHandler charDataHandler = characterDataHandler; + if (charDataHandler) { + if (MUST_CONVERT(enc, s)) { + for (;;) { + ICHAR *dataPtr = (ICHAR *)dataBuf; + XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd); + *eventEndPP = s; + charDataHandler(handlerArg, dataBuf, + (int)(dataPtr - (ICHAR *)dataBuf)); + if (s == next) + break; + *eventPP = s; + } } + else + charDataHandler(handlerArg, + (XML_Char *)s, + (int)((XML_Char *)next - (XML_Char *)s)); } - else - characterDataHandler(handlerArg, - (XML_Char *)s, - (int)((XML_Char *)next - (XML_Char *)s)); + else if (defaultHandler) + reportDefault(parser, enc, s, next); } - else if (defaultHandler) - reportDefault(parser, enc, s, next); break; case XML_TOK_PI: if (!reportProcessingInstruction(parser, enc, s, next)) @@ -2631,7 +2673,7 @@ } *eventPP = s = next; switch (ps_parsing) { - case XML_SUSPENDED: + case XML_SUSPENDED: *nextPtr = next; return XML_ERROR_NONE; case XML_FINISHED: @@ -2690,23 +2732,44 @@ if (n + nDefaultAtts > attsSize) { int oldAttsSize = attsSize; ATTRIBUTE *temp; +#ifdef XML_ATTR_INFO + XML_AttrInfo *temp2; +#endif attsSize = n + nDefaultAtts + INIT_ATTS_SIZE; temp = (ATTRIBUTE *)REALLOC((void *)atts, attsSize * sizeof(ATTRIBUTE)); if (temp == NULL) return XML_ERROR_NO_MEMORY; atts = temp; +#ifdef XML_ATTR_INFO + temp2 = (XML_AttrInfo *)REALLOC((void *)attInfo, attsSize * sizeof(XML_AttrInfo)); + if (temp2 == NULL) + return XML_ERROR_NO_MEMORY; + attInfo = temp2; +#endif if (n > oldAttsSize) XmlGetAttributes(enc, attStr, n, atts); } appAtts = (const XML_Char **)atts; for (i = 0; i < n; i++) { + ATTRIBUTE *currAtt = &atts[i]; +#ifdef XML_ATTR_INFO + XML_AttrInfo *currAttInfo = &attInfo[i]; +#endif /* add the name and value to the attribute list */ - ATTRIBUTE_ID *attId = getAttributeId(parser, enc, atts[i].name, - atts[i].name - + XmlNameLength(enc, atts[i].name)); + ATTRIBUTE_ID *attId = getAttributeId(parser, enc, currAtt->name, + currAtt->name + + XmlNameLength(enc, currAtt->name)); if (!attId) return XML_ERROR_NO_MEMORY; +#ifdef XML_ATTR_INFO + currAttInfo->nameStart = parseEndByteIndex - (parseEndPtr - currAtt->name); + currAttInfo->nameEnd = currAttInfo->nameStart + + XmlNameLength(enc, currAtt->name); + currAttInfo->valueStart = parseEndByteIndex - + (parseEndPtr - currAtt->valuePtr); + currAttInfo->valueEnd = parseEndByteIndex - (parseEndPtr - currAtt->valueEnd); +#endif /* Detect duplicate attributes by their QNames. This does not work when namespace processing is turned on and different prefixes for the same namespace are used. For this case we have a check further down. @@ -2848,8 +2911,6 @@ unsigned long uriHash = hash_secret_salt; ((XML_Char *)s)[-1] = 0; /* clear flag */ id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0); - if (!id) - return XML_ERROR_NO_MEMORY; b = id->prefix->binding; if (!b) return XML_ERROR_UNBOUND_PREFIX; @@ -2861,7 +2922,7 @@ return XML_ERROR_NO_MEMORY; uriHash = CHAR_HASH(uriHash, c); } - while (*s++ != XML_T(':')) + while (*s++ != XML_T(ASCII_COLON)) ; do { /* copies null terminator */ const XML_Char c = *s; @@ -2935,7 +2996,7 @@ if (!binding) return XML_ERROR_UNBOUND_PREFIX; localPart = tagNamePtr->str; - while (*localPart++ != XML_T(':')) + while (*localPart++ != XML_T(ASCII_COLON)) ; } else if (dtd->defaultPrefix.binding) { @@ -2990,25 +3051,29 @@ const XML_Char *uri, BINDING **bindingsPtr) { static const XML_Char xmlNamespace[] = { - 'h', 't', 't', 'p', ':', '/', '/', - 'w', 'w', 'w', '.', 'w', '3', '.', 'o', 'r', 'g', '/', - 'X', 'M', 'L', '/', '1', '9', '9', '8', '/', - 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\0' + ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, ASCII_SLASH, + ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD, + ASCII_o, ASCII_r, ASCII_g, ASCII_SLASH, ASCII_X, ASCII_M, ASCII_L, + ASCII_SLASH, ASCII_1, ASCII_9, ASCII_9, ASCII_8, ASCII_SLASH, + ASCII_n, ASCII_a, ASCII_m, ASCII_e, ASCII_s, ASCII_p, ASCII_a, ASCII_c, + ASCII_e, '\0' }; - static const int xmlLen = + static const int xmlLen = (int)sizeof(xmlNamespace)/sizeof(XML_Char) - 1; static const XML_Char xmlnsNamespace[] = { - 'h', 't', 't', 'p', ':', '/', '/', - 'w', 'w', 'w', '.', 'w', '3', '.', 'o', 'r', 'g', '/', - '2', '0', '0', '0', '/', 'x', 'm', 'l', 'n', 's', '/', '\0' + ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, ASCII_SLASH, + ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD, + ASCII_o, ASCII_r, ASCII_g, ASCII_SLASH, ASCII_2, ASCII_0, ASCII_0, + ASCII_0, ASCII_SLASH, ASCII_x, ASCII_m, ASCII_l, ASCII_n, ASCII_s, + ASCII_SLASH, '\0' }; - static const int xmlnsLen = + static const int xmlnsLen = (int)sizeof(xmlnsNamespace)/sizeof(XML_Char) - 1; XML_Bool mustBeXML = XML_FALSE; XML_Bool isXML = XML_TRUE; XML_Bool isXMLNS = XML_TRUE; - + BINDING *b; int len; @@ -3017,13 +3082,13 @@ return XML_ERROR_UNDECLARING_PREFIX; if (prefix->name - && prefix->name[0] == XML_T('x') - && prefix->name[1] == XML_T('m') - && prefix->name[2] == XML_T('l')) { + && prefix->name[0] == XML_T(ASCII_x) + && prefix->name[1] == XML_T(ASCII_m) + && prefix->name[2] == XML_T(ASCII_l)) { /* Not allowed to bind xmlns */ - if (prefix->name[3] == XML_T('n') - && prefix->name[4] == XML_T('s') + if (prefix->name[3] == XML_T(ASCII_n) + && prefix->name[4] == XML_T(ASCII_s) && prefix->name[5] == XML_T('\0')) return XML_ERROR_RESERVED_PREFIX_XMLNS; @@ -3035,7 +3100,7 @@ if (isXML && (len > xmlLen || uri[len] != xmlNamespace[len])) isXML = XML_FALSE; - if (!mustBeXML && isXMLNS + if (!mustBeXML && isXMLNS && (len > xmlnsLen || uri[len] != xmlnsNamespace[len])) isXMLNS = XML_FALSE; } @@ -3177,26 +3242,29 @@ reportDefault(parser, enc, s, next); break; case XML_TOK_DATA_CHARS: - if (characterDataHandler) { - if (MUST_CONVERT(enc, s)) { - for (;;) { - ICHAR *dataPtr = (ICHAR *)dataBuf; - XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd); - *eventEndPP = next; - characterDataHandler(handlerArg, dataBuf, - (int)(dataPtr - (ICHAR *)dataBuf)); - if (s == next) - break; - *eventPP = s; + { + XML_CharacterDataHandler charDataHandler = characterDataHandler; + if (charDataHandler) { + if (MUST_CONVERT(enc, s)) { + for (;;) { + ICHAR *dataPtr = (ICHAR *)dataBuf; + XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd); + *eventEndPP = next; + charDataHandler(handlerArg, dataBuf, + (int)(dataPtr - (ICHAR *)dataBuf)); + if (s == next) + break; + *eventPP = s; + } } + else + charDataHandler(handlerArg, + (XML_Char *)s, + (int)((XML_Char *)next - (XML_Char *)s)); } - else - characterDataHandler(handlerArg, - (XML_Char *)s, - (int)((XML_Char *)next - (XML_Char *)s)); + else if (defaultHandler) + reportDefault(parser, enc, s, next); } - else if (defaultHandler) - reportDefault(parser, enc, s, next); break; case XML_TOK_INVALID: *eventPP = next; @@ -3243,7 +3311,7 @@ const char *end, const char **endPtr) { - enum XML_Error result = doIgnoreSection(parser, encoding, &start, end, + enum XML_Error result = doIgnoreSection(parser, encoding, &start, end, endPtr, (XML_Bool)!ps_finalBuffer); if (result != XML_ERROR_NONE) return result; @@ -3525,7 +3593,7 @@ const char *next = start; eventPtr = start; - for (;;) { + for (;;) { tok = XmlPrologTok(encoding, start, end, &next); eventEndPtr = next; if (tok <= 0) { @@ -3553,7 +3621,7 @@ if (result != XML_ERROR_NONE) return result; switch (ps_parsing) { - case XML_SUSPENDED: + case XML_SUSPENDED: *nextPtr = next; return XML_ERROR_NONE; case XML_FINISHED: @@ -3618,7 +3686,7 @@ } processor = prologProcessor; - return doProlog(parser, encoding, s, end, tok, next, + return doProlog(parser, encoding, s, end, tok, next, nextPtr, (XML_Bool)!ps_finalBuffer); } @@ -3668,7 +3736,7 @@ { const char *next = s; int tok = XmlPrologTok(encoding, s, end, &next); - return doProlog(parser, encoding, s, end, tok, next, + return doProlog(parser, encoding, s, end, tok, next, nextPtr, (XML_Bool)!ps_finalBuffer); } @@ -3683,26 +3751,30 @@ XML_Bool haveMore) { #ifdef XML_DTD - static const XML_Char externalSubsetName[] = { '#' , '\0' }; + static const XML_Char externalSubsetName[] = { ASCII_HASH , '\0' }; #endif /* XML_DTD */ - static const XML_Char atypeCDATA[] = { 'C', 'D', 'A', 'T', 'A', '\0' }; - static const XML_Char atypeID[] = { 'I', 'D', '\0' }; - static const XML_Char atypeIDREF[] = { 'I', 'D', 'R', 'E', 'F', '\0' }; - static const XML_Char atypeIDREFS[] = { 'I', 'D', 'R', 'E', 'F', 'S', '\0' }; - static const XML_Char atypeENTITY[] = { 'E', 'N', 'T', 'I', 'T', 'Y', '\0' }; - static const XML_Char atypeENTITIES[] = - { 'E', 'N', 'T', 'I', 'T', 'I', 'E', 'S', '\0' }; + static const XML_Char atypeCDATA[] = + { ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; + static const XML_Char atypeID[] = { ASCII_I, ASCII_D, '\0' }; + static const XML_Char atypeIDREF[] = + { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0' }; + static const XML_Char atypeIDREFS[] = + { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0' }; + static const XML_Char atypeENTITY[] = + { ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0' }; + static const XML_Char atypeENTITIES[] = { ASCII_E, ASCII_N, + ASCII_T, ASCII_I, ASCII_T, ASCII_I, ASCII_E, ASCII_S, '\0' }; static const XML_Char atypeNMTOKEN[] = { - 'N', 'M', 'T', 'O', 'K', 'E', 'N', '\0' }; - static const XML_Char atypeNMTOKENS[] = { - 'N', 'M', 'T', 'O', 'K', 'E', 'N', 'S', '\0' }; - static const XML_Char notationPrefix[] = { - 'N', 'O', 'T', 'A', 'T', 'I', 'O', 'N', '(', '\0' }; - static const XML_Char enumValueSep[] = { '|', '\0' }; - static const XML_Char enumValueStart[] = { '(', '\0' }; + ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0' }; + static const XML_Char atypeNMTOKENS[] = { ASCII_N, ASCII_M, ASCII_T, + ASCII_O, ASCII_K, ASCII_E, ASCII_N, ASCII_S, '\0' }; + static const XML_Char notationPrefix[] = { ASCII_N, ASCII_O, ASCII_T, + ASCII_A, ASCII_T, ASCII_I, ASCII_O, ASCII_N, ASCII_LPAREN, '\0' }; + static const XML_Char enumValueSep[] = { ASCII_PIPE, '\0' }; + static const XML_Char enumValueStart[] = { ASCII_LPAREN, '\0' }; /* save one level of indirection */ - DTD * const dtd = _dtd; + DTD * const dtd = _dtd; const char **eventPP; const char **eventEndPP; @@ -3818,15 +3890,17 @@ #endif /* XML_DTD */ dtd->hasParamEntityRefs = XML_TRUE; if (startDoctypeDeclHandler) { + XML_Char *pubId; if (!XmlIsPublicId(enc, s, next, eventPP)) return XML_ERROR_PUBLICID; - doctypePubid = poolStoreString(&tempPool, enc, - s + enc->minBytesPerChar, - next - enc->minBytesPerChar); - if (!doctypePubid) + pubId = poolStoreString(&tempPool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!pubId) return XML_ERROR_NO_MEMORY; - normalizePublicId((XML_Char *)doctypePubid); + normalizePublicId(pubId); poolFinish(&tempPool); + doctypePubid = pubId; handleDefault = XML_FALSE; goto alreadyChecked; } @@ -3881,8 +3955,8 @@ entity->publicId)) return XML_ERROR_EXTERNAL_ENTITY_HANDLING; if (dtd->paramEntityRead) { - if (!dtd->standalone && - notStandaloneHandler && + if (!dtd->standalone && + notStandaloneHandler && !notStandaloneHandler(handlerArg)) return XML_ERROR_NOT_STANDALONE; } @@ -4010,11 +4084,11 @@ 0, parser)) return XML_ERROR_NO_MEMORY; if (attlistDeclHandler && declAttributeType) { - if (*declAttributeType == XML_T('(') - || (*declAttributeType == XML_T('N') - && declAttributeType[1] == XML_T('O'))) { + if (*declAttributeType == XML_T(ASCII_LPAREN) + || (*declAttributeType == XML_T(ASCII_N) + && declAttributeType[1] == XML_T(ASCII_O))) { /* Enumerated or Notation type */ - if (!poolAppendChar(&tempPool, XML_T(')')) + if (!poolAppendChar(&tempPool, XML_T(ASCII_RPAREN)) || !poolAppendChar(&tempPool, XML_T('\0'))) return XML_ERROR_NO_MEMORY; declAttributeType = tempPool.start; @@ -4047,11 +4121,11 @@ declAttributeIsCdata, XML_FALSE, attVal, parser)) return XML_ERROR_NO_MEMORY; if (attlistDeclHandler && declAttributeType) { - if (*declAttributeType == XML_T('(') - || (*declAttributeType == XML_T('N') - && declAttributeType[1] == XML_T('O'))) { + if (*declAttributeType == XML_T(ASCII_LPAREN) + || (*declAttributeType == XML_T(ASCII_N) + && declAttributeType[1] == XML_T(ASCII_O))) { /* Enumerated or Notation type */ - if (!poolAppendChar(&tempPool, XML_T(')')) + if (!poolAppendChar(&tempPool, XML_T(ASCII_RPAREN)) || !poolAppendChar(&tempPool, XML_T('\0'))) return XML_ERROR_NO_MEMORY; declAttributeType = tempPool.start; @@ -4321,7 +4395,7 @@ switch (tok) { case XML_TOK_PARAM_ENTITY_REF: /* PE references in internal subset are - not allowed within declarations. */ + not allowed within declarations. */ return XML_ERROR_PARAM_ENTITY_REF; case XML_TOK_XML_DECL: return XML_ERROR_MISPLACED_XML_PI; @@ -4379,14 +4453,14 @@ } break; case XML_ROLE_GROUP_SEQUENCE: - if (groupConnector[prologState.level] == '|') + if (groupConnector[prologState.level] == ASCII_PIPE) return XML_ERROR_SYNTAX; - groupConnector[prologState.level] = ','; + groupConnector[prologState.level] = ASCII_COMMA; if (dtd->in_eldecl && elementDeclHandler) handleDefault = XML_FALSE; break; case XML_ROLE_GROUP_CHOICE: - if (groupConnector[prologState.level] == ',') + if (groupConnector[prologState.level] == ASCII_COMMA) return XML_ERROR_SYNTAX; if (dtd->in_eldecl && !groupConnector[prologState.level] @@ -4398,7 +4472,7 @@ if (elementDeclHandler) handleDefault = XML_FALSE; } - groupConnector[prologState.level] = '|'; + groupConnector[prologState.level] = ASCII_PIPE; break; case XML_ROLE_PARAM_ENTITY_REF: #ifdef XML_DTD @@ -4442,7 +4516,7 @@ return XML_ERROR_RECURSIVE_ENTITY_REF; if (entity->textPtr) { enum XML_Error result; - XML_Bool betweenDecl = + XML_Bool betweenDecl = (role == XML_ROLE_PARAM_ENTITY_REF ? XML_TRUE : XML_FALSE); result = processInternalEntity(parser, entity, betweenDecl); if (result != XML_ERROR_NONE) @@ -4637,7 +4711,7 @@ reportDefault(parser, enc, s, next); switch (ps_parsing) { - case XML_SUSPENDED: + case XML_SUSPENDED: *nextPtr = next; return XML_ERROR_NONE; case XML_FINISHED: @@ -4707,7 +4781,7 @@ } eventPtr = s = next; switch (ps_parsing) { - case XML_SUSPENDED: + case XML_SUSPENDED: *nextPtr = next; return XML_ERROR_NONE; case XML_FINISHED: @@ -4750,12 +4824,12 @@ #ifdef XML_DTD if (entity->is_param) { int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next); - result = doProlog(parser, internalEncoding, textStart, textEnd, tok, + result = doProlog(parser, internalEncoding, textStart, textEnd, tok, next, &next, XML_FALSE); } - else + else #endif /* XML_DTD */ - result = doContent(parser, tagLevel, internalEncoding, textStart, + result = doContent(parser, tagLevel, internalEncoding, textStart, textEnd, &next, XML_FALSE); if (result == XML_ERROR_NONE) { @@ -4795,13 +4869,13 @@ #ifdef XML_DTD if (entity->is_param) { int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next); - result = doProlog(parser, internalEncoding, textStart, textEnd, tok, + result = doProlog(parser, internalEncoding, textStart, textEnd, tok, next, &next, XML_FALSE); } else #endif /* XML_DTD */ - result = doContent(parser, openEntity->startTagLevel, internalEncoding, - textStart, textEnd, &next, XML_FALSE); + result = doContent(parser, openEntity->startTagLevel, internalEncoding, + textStart, textEnd, &next, XML_FALSE); if (result != XML_ERROR_NONE) return result; @@ -4822,7 +4896,7 @@ int tok; processor = prologProcessor; tok = XmlPrologTok(encoding, s, end, &next); - return doProlog(parser, encoding, s, end, tok, next, nextPtr, + return doProlog(parser, encoding, s, end, tok, next, nextPtr, (XML_Bool)!ps_finalBuffer); } else @@ -4831,8 +4905,8 @@ processor = contentProcessor; /* see externalEntityContentProcessor vs contentProcessor */ return doContent(parser, parentParser ? 1 : 0, encoding, s, end, - nextPtr, (XML_Bool)!ps_finalBuffer); - } + nextPtr, (XML_Bool)!ps_finalBuffer); + } } static enum XML_Error PTRCALL @@ -4985,7 +5059,7 @@ if (!entity->textPtr) { if (enc == encoding) eventPtr = ptr; - return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF; + return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF; } else { enum XML_Error result; @@ -5328,7 +5402,7 @@ DTD * const dtd = _dtd; /* save one level of indirection */ const XML_Char *name; for (name = elementType->name; *name; name++) { - if (*name == XML_T(':')) { + if (*name == XML_T(ASCII_COLON)) { PREFIX *prefix; const XML_Char *s; for (s = elementType->name; s != name; s++) { @@ -5375,12 +5449,12 @@ poolFinish(&dtd->pool); if (!ns) ; - else if (name[0] == XML_T('x') - && name[1] == XML_T('m') - && name[2] == XML_T('l') - && name[3] == XML_T('n') - && name[4] == XML_T('s') - && (name[5] == XML_T('\0') || name[5] == XML_T(':'))) { + else if (name[0] == XML_T(ASCII_x) + && name[1] == XML_T(ASCII_m) + && name[2] == XML_T(ASCII_l) + && name[3] == XML_T(ASCII_n) + && name[4] == XML_T(ASCII_s) + && (name[5] == XML_T('\0') || name[5] == XML_T(ASCII_COLON))) { if (name[5] == XML_T('\0')) id->prefix = &dtd->defaultPrefix; else @@ -5391,7 +5465,7 @@ int i; for (i = 0; name[i]; i++) { /* attributes without prefix are *not* in the default namespace */ - if (name[i] == XML_T(':')) { + if (name[i] == XML_T(ASCII_COLON)) { int j; for (j = 0; j < i; j++) { if (!poolAppendChar(&dtd->pool, name[j])) @@ -5401,8 +5475,6 @@ return NULL; id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool), sizeof(PREFIX)); - if (!id->prefix) - return NULL; if (id->prefix->name == poolStart(&dtd->pool)) poolFinish(&dtd->pool); else @@ -5415,7 +5487,7 @@ return id; } -#define CONTEXT_SEP XML_T('\f') +#define CONTEXT_SEP XML_T(ASCII_FF) static const XML_Char * getContext(XML_Parser parser) @@ -5427,7 +5499,7 @@ if (dtd->defaultPrefix.binding) { int i; int len; - if (!poolAppendChar(&tempPool, XML_T('='))) + if (!poolAppendChar(&tempPool, XML_T(ASCII_EQUALS))) return NULL; len = dtd->defaultPrefix.binding->uriLen; if (namespaceSeparator) @@ -5453,7 +5525,7 @@ for (s = prefix->name; *s; s++) if (!poolAppendChar(&tempPool, *s)) return NULL; - if (!poolAppendChar(&tempPool, XML_T('='))) + if (!poolAppendChar(&tempPool, XML_T(ASCII_EQUALS))) return NULL; len = prefix->binding->uriLen; if (namespaceSeparator) @@ -5505,7 +5577,7 @@ context = s; poolDiscard(&tempPool); } - else if (*s == XML_T('=')) { + else if (*s == XML_T(ASCII_EQUALS)) { PREFIX *prefix; if (poolLength(&tempPool) == 0) prefix = &dtd->defaultPrefix; @@ -6162,12 +6234,13 @@ } if (pool->blocks && pool->start == pool->blocks->s) { int blockSize = (int)(pool->end - pool->start)*2; - pool->blocks = (BLOCK *) + BLOCK *temp = (BLOCK *) pool->mem->realloc_fcn(pool->blocks, (offsetof(BLOCK, s) + blockSize * sizeof(XML_Char))); - if (pool->blocks == NULL) + if (temp == NULL) return XML_FALSE; + pool->blocks = temp; pool->blocks->size = blockSize; pool->ptr = pool->blocks->s + (pool->ptr - pool->start); pool->start = pool->blocks->s; diff --git a/Modules/expat/xmlrole.c b/Modules/expat/xmlrole.c --- a/Modules/expat/xmlrole.c +++ b/Modules/expat/xmlrole.c @@ -2,20 +2,22 @@ See the file COPYING for copying permission. */ +#include + #ifdef COMPILED_FROM_DSP #include "winconfig.h" #elif defined(MACOS_CLASSIC) #include "macconfig.h" -#elif defined(__amigaos4__) +#elif defined(__amigaos__) #include "amigaconfig.h" +#elif defined(__WATCOMC__) +#include "watcomconfig.h" #else #ifdef HAVE_EXPAT_CONFIG_H #include #endif #endif /* ndef COMPILED_FROM_DSP */ -#include - #include "expat_external.h" #include "internal.h" #include "xmlrole.h" @@ -53,12 +55,16 @@ ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0' }; static const char KW_IDREFS[] = { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0' }; +#ifdef XML_DTD static const char KW_IGNORE[] = { ASCII_I, ASCII_G, ASCII_N, ASCII_O, ASCII_R, ASCII_E, '\0' }; +#endif static const char KW_IMPLIED[] = { ASCII_I, ASCII_M, ASCII_P, ASCII_L, ASCII_I, ASCII_E, ASCII_D, '\0' }; +#ifdef XML_DTD static const char KW_INCLUDE[] = { ASCII_I, ASCII_N, ASCII_C, ASCII_L, ASCII_U, ASCII_D, ASCII_E, '\0' }; +#endif static const char KW_NDATA[] = { ASCII_N, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; static const char KW_NMTOKEN[] = { diff --git a/Modules/expat/xmltok.c b/Modules/expat/xmltok.c --- a/Modules/expat/xmltok.c +++ b/Modules/expat/xmltok.c @@ -2,20 +2,22 @@ See the file COPYING for copying permission. */ +#include + #ifdef COMPILED_FROM_DSP #include "winconfig.h" #elif defined(MACOS_CLASSIC) #include "macconfig.h" -#elif defined(__amigaos4__) +#elif defined(__amigaos__) #include "amigaconfig.h" +#elif defined(__WATCOMC__) +#include "watcomconfig.h" #else #ifdef HAVE_EXPAT_CONFIG_H #include #endif #endif /* ndef COMPILED_FROM_DSP */ -#include - #include "expat_external.h" #include "internal.h" #include "xmltok.h" @@ -295,7 +297,9 @@ #endif #define PREFIX(ident) normal_ ## ident +#define XML_TOK_IMPL_C #include "xmltok_impl.c" +#undef XML_TOK_IMPL_C #undef MINBPC #undef BYTE_TYPE @@ -692,7 +696,9 @@ #define IS_NMSTRT_CHAR(enc, p, n) (0) #define IS_NMSTRT_CHAR_MINBPC(enc, p) LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) +#define XML_TOK_IMPL_C #include "xmltok_impl.c" +#undef XML_TOK_IMPL_C #undef MINBPC #undef BYTE_TYPE @@ -831,7 +837,9 @@ #define IS_NMSTRT_CHAR(enc, p, n) (0) #define IS_NMSTRT_CHAR_MINBPC(enc, p) BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) +#define XML_TOK_IMPL_C #include "xmltok_impl.c" +#undef XML_TOK_IMPL_C #undef MINBPC #undef BYTE_TYPE @@ -1337,7 +1345,7 @@ ENCODING * XmlInitUnknownEncoding(void *mem, int *table, - CONVERTER convert, + CONVERTER convert, void *userData) { int i; @@ -1610,7 +1618,9 @@ #define NS(x) x #define ns(x) x +#define XML_TOK_NS_C #include "xmltok_ns.c" +#undef XML_TOK_NS_C #undef NS #undef ns @@ -1619,7 +1629,9 @@ #define NS(x) x ## NS #define ns(x) x ## _ns +#define XML_TOK_NS_C #include "xmltok_ns.c" +#undef XML_TOK_NS_C #undef NS #undef ns @@ -1627,7 +1639,7 @@ ENCODING * XmlInitUnknownEncodingNS(void *mem, int *table, - CONVERTER convert, + CONVERTER convert, void *userData) { ENCODING *enc = XmlInitUnknownEncoding(mem, table, convert, userData); diff --git a/Modules/expat/xmltok_impl.c b/Modules/expat/xmltok_impl.c --- a/Modules/expat/xmltok_impl.c +++ b/Modules/expat/xmltok_impl.c @@ -2,6 +2,9 @@ See the file COPYING for copying permission. */ +/* This file is included! */ +#ifdef XML_TOK_IMPL_C + #ifndef IS_INVALID_CHAR #define IS_INVALID_CHAR(enc, ptr, n) (0) #endif @@ -882,7 +885,7 @@ const char **nextTokPtr) { if (ptr == end) - return -XML_TOK_PERCENT; + return XML_TOK_PARTIAL; switch (BYTE_TYPE(enc, ptr)) { CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) case BT_S: case BT_LF: case BT_CR: case BT_PERCNT: @@ -1777,3 +1780,4 @@ #undef CHECK_NMSTRT_CASE #undef CHECK_NMSTRT_CASES +#endif /* XML_TOK_IMPL_C */ diff --git a/Modules/expat/xmltok_ns.c b/Modules/expat/xmltok_ns.c --- a/Modules/expat/xmltok_ns.c +++ b/Modules/expat/xmltok_ns.c @@ -1,3 +1,10 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +/* This file is included! */ +#ifdef XML_TOK_NS_C + const ENCODING * NS(XmlGetUtf8InternalEncoding)(void) { @@ -104,3 +111,5 @@ encoding, standalone); } + +#endif /* XML_TOK_NS_C */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 15 00:07:51 2012 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 15 Jul 2012 00:07:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_add_PEP_424_from_Alex_Gaynor?= Message-ID: <3WZQ472WGgzPDc@mail.python.org> http://hg.python.org/peps/rev/9bd954a4ab7b changeset: 4486:9bd954a4ab7b user: Benjamin Peterson date: Sat Jul 14 15:07:48 2012 -0700 summary: add PEP 424 from Alex Gaynor files: pep-0424.txt | 61 ++++++++++++++++++++++++++++++++++++++++ 1 files changed, 61 insertions(+), 0 deletions(-) diff --git a/pep-0424.txt b/pep-0424.txt new file mode 100644 --- /dev/null +++ b/pep-0424.txt @@ -0,0 +1,61 @@ +PEP: 424 +Title: A method for exposing a length hint +Version: $Revision$ +Last-Modified: $Date +Author: Alex Gaynor +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Created: +Python-Version: Who knows! + +Abstract +======== + +CPython currently defines an ``__length_hint__`` method on several types, such +as various iterators. This method is then used by various other functions (such as +``map``) to presize lists based on the estimated returned by +``__length_hint__``. Types can then define ``__length_hint__`` which are not +sized, and thus should not define ``__len__``, but can estimate or compute a +size (such as many iterators). + +Proposal +======== + +This PEP proposes formally documenting ``__length_hint__`` for other +interpreter and non-standard library Python to implement. + +``__length_hint__`` must return an integer, and is not required to be accurate. +It may return a value that is either larger or smaller than the actual size of +the container. It may raise a ``TypeError`` if a specific instance cannot have +its length estimated. It may not return a negative value. + +Rationale +========= + +Being able to pre-allocate lists based on the expected size, as estimated by ``__length_hint__``, can be a significant optimization. CPython has been +observed to run some code faster than PyPy, purely because of this optimization +being present. + +Open questions +============== + +There are two open questions for this PEP: + +* Should ``list`` expose a kwarg in it's constructor for supplying a length + hint. +* Should a function be added either to ``builtins`` or some other module which + calls ``__length_hint__``, like ``builtins.len`` calls ``__len__``. + +Copyright +========= + +This document has been placed into the public domain. + +.. + Local Variables: + mode: indented-text + indent-tabs-mode: nil + sentence-end-double-space: t + fill-column: 70 + coding: utf-8 -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Jul 15 00:08:07 2012 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 15 Jul 2012 00:08:07 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_you=27re_looking_at_3=2E4?= Message-ID: <3WZQ4R6mpXzPDc@mail.python.org> http://hg.python.org/peps/rev/644ba9cd3e82 changeset: 4487:644ba9cd3e82 user: Benjamin Peterson date: Sat Jul 14 15:08:03 2012 -0700 summary: you're looking at 3.4 files: pep-0424.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0424.txt b/pep-0424.txt --- a/pep-0424.txt +++ b/pep-0424.txt @@ -7,7 +7,7 @@ Type: Standards Track Content-Type: text/x-rst Created: -Python-Version: Who knows! +Python-Version: 3.4 Abstract ======== -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Jul 15 00:09:01 2012 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 15 Jul 2012 00:09:01 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_add_created_date?= Message-ID: <3WZQ5T3nVyzPDc@mail.python.org> http://hg.python.org/peps/rev/23760a55afd9 changeset: 4488:23760a55afd9 user: Benjamin Peterson date: Sat Jul 14 15:08:58 2012 -0700 summary: add created date files: pep-0424.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0424.txt b/pep-0424.txt --- a/pep-0424.txt +++ b/pep-0424.txt @@ -6,7 +6,7 @@ Status: Draft Type: Standards Track Content-Type: text/x-rst -Created: +Created: 14-July-2012 Python-Version: 3.4 Abstract -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Jul 15 00:14:04 2012 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 15 Jul 2012 00:14:04 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_add_post-history?= Message-ID: <3WZQCJ09yszPFn@mail.python.org> http://hg.python.org/peps/rev/f47ae8ad6fc5 changeset: 4489:f47ae8ad6fc5 user: Benjamin Peterson date: Sat Jul 14 15:14:00 2012 -0700 summary: add post-history files: pep-0424.txt | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/pep-0424.txt b/pep-0424.txt --- a/pep-0424.txt +++ b/pep-0424.txt @@ -8,6 +8,7 @@ Content-Type: text/x-rst Created: 14-July-2012 Python-Version: 3.4 +Post-History: http://mail.python.org/pipermail/python-dev/2012-July/120920.html Abstract ======== -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Jul 15 01:49:45 2012 From: python-checkins at python.org (alex.gaynor) Date: Sun, 15 Jul 2012 01:49:45 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Updates_to_PEP-0424_following?= =?utf-8?q?_the_discussion=2E?= Message-ID: <3WZSKj1Vl1zPDQ@mail.python.org> http://hg.python.org/peps/rev/d4e77ba5329d changeset: 4490:d4e77ba5329d user: Alex Gaynor date: Sat Jul 14 16:49:42 2012 -0700 summary: Updates to PEP-0424 following the discussion. files: pep-0424.txt | 23 +++++++---------------- 1 files changed, 7 insertions(+), 16 deletions(-) diff --git a/pep-0424.txt b/pep-0424.txt --- a/pep-0424.txt +++ b/pep-0424.txt @@ -14,8 +14,8 @@ ======== CPython currently defines an ``__length_hint__`` method on several types, such -as various iterators. This method is then used by various other functions (such as -``map``) to presize lists based on the estimated returned by +as various iterators. This method is then used by various other functions (such +as ``map``) to presize lists based on the estimated returned by ``__length_hint__``. Types can then define ``__length_hint__`` which are not sized, and thus should not define ``__len__``, but can estimate or compute a size (such as many iterators). @@ -26,10 +26,11 @@ This PEP proposes formally documenting ``__length_hint__`` for other interpreter and non-standard library Python to implement. -``__length_hint__`` must return an integer, and is not required to be accurate. -It may return a value that is either larger or smaller than the actual size of -the container. It may raise a ``TypeError`` if a specific instance cannot have -its length estimated. It may not return a negative value. +``__length_hint__`` must return an integer (else a TypeError is raised), and is +not required to be accurate. It may return a value that is either larger or +smaller than the actual size ofthe container. It may raise a ``TypeError`` if a +specific instance cannot have its length estimated. It may not return a +negative value (else a ValueError is raised). Rationale ========= @@ -38,16 +39,6 @@ observed to run some code faster than PyPy, purely because of this optimization being present. -Open questions -============== - -There are two open questions for this PEP: - -* Should ``list`` expose a kwarg in it's constructor for supplying a length - hint. -* Should a function be added either to ``builtins`` or some other module which - calls ``__length_hint__``, like ``builtins.len`` calls ``__len__``. - Copyright ========= -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Jul 15 02:55:26 2012 From: python-checkins at python.org (larry.hastings) Date: Sun, 15 Jul 2012 02:55:26 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_-_Issue_=2315238=3A_shutil?= =?utf-8?q?=2Ecopystat_now_copies_Linux_=22extended_attributes=22=2E?= Message-ID: <3WZTnV0VW6zNkq@mail.python.org> http://hg.python.org/cpython/rev/5f62c317c202 changeset: 78101:5f62c317c202 user: Larry Hastings date: Sat Jul 14 17:55:11 2012 -0700 summary: - Issue #15238: shutil.copystat now copies Linux "extended attributes". files: Doc/library/shutil.rst | 5 +- Lib/shutil.py | 44 ++++++++++++++-------------- Lib/test/test_shutil.py | 10 ++++++ Misc/NEWS | 2 + 4 files changed, 37 insertions(+), 24 deletions(-) diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -86,10 +86,11 @@ from *src* to *dst*. The file contents, owner, and group are unaffected. *src* and *dst* are path names given as strings. If *src* and *dst* are both symbolic links and *symlinks* true, the stats of the link will be copied as - far as the platform allows. + far as the platform allows. On Linux, :func:`copystat` also copies the + "extended attributes" where possible. .. versionchanged:: 3.3 - Added *symlinks* argument. + Added *symlinks* argument and support for Linux extended attributes. .. function:: copy(src, dst, symlinks=False) diff --git a/Lib/shutil.py b/Lib/shutil.py --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -132,6 +132,27 @@ st = stat_func(src) chmod_func(dst, stat.S_IMODE(st.st_mode)) +if hasattr(os, 'listxattr'): + def _copyxattr(src, dst, symlinks=False): + """Copy extended filesystem attributes from `src` to `dst`. + + Overwrite existing attributes. + + If the optional flag `symlinks` is set, symlinks won't be followed. + + """ + + for name in os.listxattr(src, follow_symlinks=symlinks): + try: + value = os.getxattr(src, name, follow_symlinks=symlinks) + os.setxattr(dst, name, value, follow_symlinks=symlinks) + except OSError as e: + if e.errno not in (errno.EPERM, errno.ENOTSUP, errno.ENODATA): + raise +else: + def _copyxattr(*args, **kwargs): + pass + def copystat(src, dst, symlinks=False): """Copy all stat info (mode bits, atime, mtime, flags) from src to dst. @@ -184,27 +205,7 @@ break else: raise - -if hasattr(os, 'listxattr'): - def _copyxattr(src, dst, symlinks=False): - """Copy extended filesystem attributes from `src` to `dst`. - - Overwrite existing attributes. - - If the optional flag `symlinks` is set, symlinks won't be followed. - - """ - - for name in os.listxattr(src, follow_symlinks=symlinks): - try: - value = os.getxattr(src, name, follow_symlinks=symlinks) - os.setxattr(dst, name, value, follow_symlinks=symlinks) - except OSError as e: - if e.errno not in (errno.EPERM, errno.ENOTSUP, errno.ENODATA): - raise -else: - def _copyxattr(*args, **kwargs): - pass + _copyxattr(src, dst, symlinks=follow) def copy(src, dst, symlinks=False): """Copy data and mode bits ("cp src dst"). Return the file's destination. @@ -235,7 +236,6 @@ dst = os.path.join(dst, os.path.basename(src)) copyfile(src, dst, symlinks=symlinks) copystat(src, dst, symlinks=symlinks) - _copyxattr(src, dst, symlinks=symlinks) return dst def ignore_patterns(*patterns): diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -410,6 +410,16 @@ finally: os.setxattr = orig_setxattr + # test that shutil.copystat copies xattrs + src = os.path.join(tmp_dir, 'the_original') + write_file(src, src) + os.setxattr(src, 'user.the_value', b'fiddly') + dst = os.path.join(tmp_dir, 'the_copy') + write_file(dst, dst) + shutil.copystat(src, dst) + self.assertEqual(os.listxattr(src), ['user.the_value']) + self.assertEqual(os.getxattr(src, 'user.the_value'), b'fiddly') + @support.skip_unless_symlink @support.skip_unless_xattr @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0, diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -35,6 +35,8 @@ Library ------- +- Issue #15238: shutil.copystat now copies Linux "extended attributes". + - Issue #15230: runpy.run_path now correctly sets __package__ as described in the documentation -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 15 02:57:09 2012 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 15 Jul 2012 02:57:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_allow_any_numb?= =?utf-8?q?er_to_be_returned_from_=5F=5Flength=5Fhint=5F=5F_=28closes_=231?= =?utf-8?q?5354=29?= Message-ID: <3WZTqT10T5zNkq@mail.python.org> http://hg.python.org/cpython/rev/872afada51b0 changeset: 78102:872afada51b0 branch: 2.7 parent: 78090:814927ff4ef2 user: Benjamin Peterson date: Sat Jul 14 17:53:55 2012 -0700 summary: allow any number to be returned from __length_hint__ (closes #15354) files: Objects/abstract.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -126,7 +126,7 @@ PyErr_Clear(); return defaultvalue; } - rv = PyLong_Check(ro) ? PyLong_AsSsize_t(ro) : defaultvalue; + rv = PyNumber_Check(ro) ? PyInt_AsSsize_t(ro) : defaultvalue; Py_DECREF(ro); return rv; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 15 02:58:40 2012 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 15 Jul 2012 02:58:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix-up_latex_styling?= Message-ID: <3WZTsD6k3czP1X@mail.python.org> http://hg.python.org/cpython/rev/592307606f51 changeset: 78103:592307606f51 parent: 78101:5f62c317c202 user: Raymond Hettinger date: Sat Jul 14 17:58:29 2012 -0700 summary: Fix-up latex styling files: Tools/scripts/highlight.py | 27 ++++++++++++++----------- 1 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Tools/scripts/highlight.py b/Tools/scripts/highlight.py --- a/Tools/scripts/highlight.py +++ b/Tools/scripts/highlight.py @@ -145,23 +145,25 @@ #### LaTeX Output ########################################## -default_latex_colors = { - 'comment': 'red', - 'string': 'green', - 'docstring': 'green', - 'keyword': 'orange', - 'builtin': 'purple', - 'definition': 'orange', - 'defname': 'blue', - 'operator': 'brown', +default_latex_commands = { + 'comment': '{\color{red}#1}', + 'string': '{\color{ForestGreen}#1}', + 'docstring': '{\emph{\color{ForestGreen}#1}}', + 'keyword': '{\color{orange}#1}', + 'builtin': '{\color{purple}#1}', + 'definition': '{\color{orange}#1}', + 'defname': '{\color{blue}#1}', + 'operator': '{\color{brown}#1}', } default_latex_document = r''' \documentclass{article} \usepackage{alltt} +\usepackage{upquote} \usepackage{color} \usepackage[usenames,dvipsnames]{xcolor} \usepackage[cm]{fullpage} +%(macros)s \begin{document} \center{\LARGE{%(title)s}} \begin{alltt} @@ -181,17 +183,18 @@ return re.sub(r'[\\#$%^&_{}~]', lambda mo: xlat[mo.group()], s) def latex_highlight(classified_text, title = 'python', - colors = default_latex_colors, + commands = default_latex_commands, document = default_latex_document): 'Create a complete LaTeX document with colorized source code' + macros = '\n'.join(r'\newcommand{\py%s}[1]{%s}' % c for c in commands.items()) result = [] for kind, text in classified_text: if kind: - result.append(r'{\color{%s}' % colors[kind]) + result.append(r'\py%s{' % kind) result.append(latex_escape(text)) if kind: result.append('}') - return default_latex_document % dict(title=title, body=''.join(result)) + return default_latex_document % dict(title=title, macros=macros, body=''.join(result)) if __name__ == '__main__': -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 15 03:21:16 2012 From: python-checkins at python.org (larry.hastings) Date: Sun, 15 Jul 2012 03:21:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_-_Issue_=2315233=3A_Python?= =?utf-8?q?_now_guarantees_that_callables_registered_with?= Message-ID: <3WZVMJ3GrfzPHk@mail.python.org> http://hg.python.org/cpython/rev/f8b520b6f654 changeset: 78104:f8b520b6f654 user: Larry Hastings date: Sat Jul 14 18:20:37 2012 -0700 summary: - Issue #15233: Python now guarantees that callables registered with the atexit module will be called in a deterministic order. files: Doc/library/atexit.rst | 13 +++++++------ Misc/NEWS | 3 +++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Doc/library/atexit.rst b/Doc/library/atexit.rst --- a/Doc/library/atexit.rst +++ b/Doc/library/atexit.rst @@ -9,13 +9,14 @@ The :mod:`atexit` module defines functions to register and unregister cleanup functions. Functions thus registered are automatically executed upon normal -interpreter termination. The order in which the functions are called is not -defined; if you have cleanup operations that depend on each other, you should -wrap them in a function and register that one. This keeps :mod:`atexit` simple. +interpreter termination. :mod:`atexit` runs these functions in the *reverse* +order in which they were registered; if you register ``A``, ``B``, and ``C``, +at interpreter termination time they will be run in the order ``C``, ``B``, +``A``. -Note: the functions registered via this module are not called when the program -is killed by a signal not handled by Python, when a Python fatal internal error -is detected, or when :func:`os._exit` is called. +**Note:** The functions registered via this module are not called when the +program is killed by a signal not handled by Python, when a Python fatal +internal error is detected, or when :func:`os._exit` is called. .. function:: register(func, *args, **kargs) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -35,6 +35,9 @@ Library ------- +- Issue #15233: Python now guarantees that callables registered with + the atexit module will be called in a deterministic order. + - Issue #15238: shutil.copystat now copies Linux "extended attributes". - Issue #15230: runpy.run_path now correctly sets __package__ as described -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 15 05:02:44 2012 From: python-checkins at python.org (eli.bendersky) Date: Sun, 15 Jul 2012 05:02:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Close_=231767933=3A_Badly_?= =?utf-8?q?formed_XML_using_etree_and_utf-16=2E_Patch_by_Serhiy?= Message-ID: <3WZXcN0V1ZzPBb@mail.python.org> http://hg.python.org/cpython/rev/6120cf695574 changeset: 78105:6120cf695574 user: Eli Bendersky date: Sun Jul 15 06:02:22 2012 +0300 summary: Close #1767933: Badly formed XML using etree and utf-16. Patch by Serhiy Storchaka, with some minor fixes by me files: Doc/library/xml.etree.elementtree.rst | 1 - Lib/test/test_xml_etree.py | 240 ++++++++++--- Lib/xml/etree/ElementTree.py | 138 ++++--- 3 files changed, 257 insertions(+), 122 deletions(-) diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -659,7 +659,6 @@ should be added to the file. Use False for never, True for always, None for only if not US-ASCII or UTF-8 or Unicode (default is None). *method* is either ``"xml"``, ``"html"`` or ``"text"`` (default is ``"xml"``). - Returns an (optionally) encoded string. This is the XML file that is going to be manipulated:: diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -21,7 +21,7 @@ import weakref from test import support -from test.support import findfile, import_fresh_module, gc_collect +from test.support import TESTFN, findfile, unlink, import_fresh_module, gc_collect pyET = None ET = None @@ -888,65 +888,6 @@ """ ET.XML("" % encoding) -def encoding(): - r""" - Test encoding issues. - - >>> elem = ET.Element("tag") - >>> elem.text = "abc" - >>> serialize(elem) - 'abc' - >>> serialize(elem, encoding="utf-8") - b'abc' - >>> serialize(elem, encoding="us-ascii") - b'abc' - >>> serialize(elem, encoding="iso-8859-1") - b"\nabc" - - >>> elem.text = "<&\"\'>" - >>> serialize(elem) - '<&"\'>' - >>> serialize(elem, encoding="utf-8") - b'<&"\'>' - >>> serialize(elem, encoding="us-ascii") # cdata characters - b'<&"\'>' - >>> serialize(elem, encoding="iso-8859-1") - b'\n<&"\'>' - - >>> elem.attrib["key"] = "<&\"\'>" - >>> elem.text = None - >>> serialize(elem) - '' - >>> serialize(elem, encoding="utf-8") - b'' - >>> serialize(elem, encoding="us-ascii") - b'' - >>> serialize(elem, encoding="iso-8859-1") - b'\n' - - >>> elem.text = '\xe5\xf6\xf6<>' - >>> elem.attrib.clear() - >>> serialize(elem) - '\xe5\xf6\xf6<>' - >>> serialize(elem, encoding="utf-8") - b'\xc3\xa5\xc3\xb6\xc3\xb6<>' - >>> serialize(elem, encoding="us-ascii") - b'åöö<>' - >>> serialize(elem, encoding="iso-8859-1") - b"\n\xe5\xf6\xf6<>" - - >>> elem.attrib["key"] = '\xe5\xf6\xf6<>' - >>> elem.text = None - >>> serialize(elem) - '' - >>> serialize(elem, encoding="utf-8") - b'' - >>> serialize(elem, encoding="us-ascii") - b'' - >>> serialize(elem, encoding="iso-8859-1") - b'\n' - """ - def methods(): r""" Test serialization methods. @@ -2166,16 +2107,185 @@ self.assertEqual(self._subelem_tags(e), ['a1']) -class StringIOTest(unittest.TestCase): +class IOTest(unittest.TestCase): + def tearDown(self): + unlink(TESTFN) + + def test_encoding(self): + # Test encoding issues. + elem = ET.Element("tag") + elem.text = "abc" + self.assertEqual(serialize(elem), 'abc') + self.assertEqual(serialize(elem, encoding="utf-8"), + b'abc') + self.assertEqual(serialize(elem, encoding="us-ascii"), + b'abc') + for enc in ("iso-8859-1", "utf-16", "utf-32"): + self.assertEqual(serialize(elem, encoding=enc), + ("\n" + "abc" % enc).encode(enc)) + + elem = ET.Element("tag") + elem.text = "<&\"\'>" + self.assertEqual(serialize(elem), '<&"\'>') + self.assertEqual(serialize(elem, encoding="utf-8"), + b'<&"\'>') + self.assertEqual(serialize(elem, encoding="us-ascii"), + b'<&"\'>') + for enc in ("iso-8859-1", "utf-16", "utf-32"): + self.assertEqual(serialize(elem, encoding=enc), + ("\n" + "<&\"'>" % enc).encode(enc)) + + elem = ET.Element("tag") + elem.attrib["key"] = "<&\"\'>" + self.assertEqual(serialize(elem), '') + self.assertEqual(serialize(elem, encoding="utf-8"), + b'') + self.assertEqual(serialize(elem, encoding="us-ascii"), + b'') + for enc in ("iso-8859-1", "utf-16", "utf-32"): + self.assertEqual(serialize(elem, encoding=enc), + ("\n" + "" % enc).encode(enc)) + + elem = ET.Element("tag") + elem.text = '\xe5\xf6\xf6<>' + self.assertEqual(serialize(elem), '\xe5\xf6\xf6<>') + self.assertEqual(serialize(elem, encoding="utf-8"), + b'\xc3\xa5\xc3\xb6\xc3\xb6<>') + self.assertEqual(serialize(elem, encoding="us-ascii"), + b'åöö<>') + for enc in ("iso-8859-1", "utf-16", "utf-32"): + self.assertEqual(serialize(elem, encoding=enc), + ("\n" + "???<>" % enc).encode(enc)) + + elem = ET.Element("tag") + elem.attrib["key"] = '\xe5\xf6\xf6<>' + self.assertEqual(serialize(elem), '') + self.assertEqual(serialize(elem, encoding="utf-8"), + b'') + self.assertEqual(serialize(elem, encoding="us-ascii"), + b'') + for enc in ("iso-8859-1", "utf-16", "utf-16le", "utf-16be", "utf-32"): + self.assertEqual(serialize(elem, encoding=enc), + ("\n" + "" % enc).encode(enc)) + + def test_write_to_filename(self): + tree = ET.ElementTree(ET.XML('''''')) + tree.write(TESTFN) + with open(TESTFN, 'rb') as f: + self.assertEqual(f.read(), b'''''') + + def test_write_to_text_file(self): + tree = ET.ElementTree(ET.XML('''''')) + with open(TESTFN, 'w', encoding='utf-8') as f: + tree.write(f, encoding='unicode') + self.assertFalse(f.closed) + with open(TESTFN, 'rb') as f: + self.assertEqual(f.read(), b'''''') + + def test_write_to_binary_file(self): + tree = ET.ElementTree(ET.XML('''''')) + with open(TESTFN, 'wb') as f: + tree.write(f) + self.assertFalse(f.closed) + with open(TESTFN, 'rb') as f: + self.assertEqual(f.read(), b'''''') + + def test_write_to_binary_file_with_bom(self): + tree = ET.ElementTree(ET.XML('''''')) + # test BOM writing to buffered file + with open(TESTFN, 'wb') as f: + tree.write(f, encoding='utf-16') + self.assertFalse(f.closed) + with open(TESTFN, 'rb') as f: + self.assertEqual(f.read(), + '''\n''' + ''''''.encode("utf-16")) + # test BOM writing to non-buffered file + with open(TESTFN, 'wb', buffering=0) as f: + tree.write(f, encoding='utf-16') + self.assertFalse(f.closed) + with open(TESTFN, 'rb') as f: + self.assertEqual(f.read(), + '''\n''' + ''''''.encode("utf-16")) + def test_read_from_stringio(self): tree = ET.ElementTree() + stream = io.StringIO('''''') + tree.parse(stream) + self.assertEqual(tree.getroot().tag, 'site') + + def test_write_to_stringio(self): + tree = ET.ElementTree(ET.XML('''''')) stream = io.StringIO() - stream.write('''''') - stream.seek(0) - tree.parse(stream) + tree.write(stream, encoding='unicode') + self.assertEqual(stream.getvalue(), '''''') + def test_read_from_bytesio(self): + tree = ET.ElementTree() + raw = io.BytesIO(b'''''') + tree.parse(raw) self.assertEqual(tree.getroot().tag, 'site') + def test_write_to_bytesio(self): + tree = ET.ElementTree(ET.XML('''''')) + raw = io.BytesIO() + tree.write(raw) + self.assertEqual(raw.getvalue(), b'''''') + + class dummy: + pass + + def test_read_from_user_text_reader(self): + stream = io.StringIO('''''') + reader = self.dummy() + reader.read = stream.read + tree = ET.ElementTree() + tree.parse(reader) + self.assertEqual(tree.getroot().tag, 'site') + + def test_write_to_user_text_writer(self): + tree = ET.ElementTree(ET.XML('''''')) + stream = io.StringIO() + writer = self.dummy() + writer.write = stream.write + tree.write(writer, encoding='unicode') + self.assertEqual(stream.getvalue(), '''''') + + def test_read_from_user_binary_reader(self): + raw = io.BytesIO(b'''''') + reader = self.dummy() + reader.read = raw.read + tree = ET.ElementTree() + tree.parse(reader) + self.assertEqual(tree.getroot().tag, 'site') + tree = ET.ElementTree() + + def test_write_to_user_binary_writer(self): + tree = ET.ElementTree(ET.XML('''''')) + raw = io.BytesIO() + writer = self.dummy() + writer.write = raw.write + tree.write(writer) + self.assertEqual(raw.getvalue(), b'''''') + + def test_write_to_user_binary_writer_with_bom(self): + tree = ET.ElementTree(ET.XML('''''')) + raw = io.BytesIO() + writer = self.dummy() + writer.write = raw.write + writer.seekable = lambda: True + writer.tell = raw.tell + tree.write(writer, encoding="utf-16") + self.assertEqual(raw.getvalue(), + '''\n''' + ''''''.encode("utf-16")) + class ParseErrorTest(unittest.TestCase): def test_subclass(self): @@ -2299,7 +2409,7 @@ test_classes = [ ElementSlicingTest, BasicElementTest, - StringIOTest, + IOTest, ParseErrorTest, XincludeTest, ElementTreeTest, diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -100,6 +100,8 @@ import sys import re import warnings +import io +import contextlib from . import ElementPath @@ -792,59 +794,38 @@ # None for only if not US-ASCII or UTF-8 or Unicode. None is default. def write(self, file_or_filename, - # keyword arguments encoding=None, xml_declaration=None, default_namespace=None, method=None): - # assert self._root is not None if not method: method = "xml" elif method not in _serialize: - # FIXME: raise an ImportError for c14n if ElementC14N is missing? raise ValueError("unknown method %r" % method) if not encoding: if method == "c14n": encoding = "utf-8" else: encoding = "us-ascii" - elif encoding == str: # lxml.etree compatibility. - encoding = "unicode" else: encoding = encoding.lower() - if hasattr(file_or_filename, "write"): - file = file_or_filename - else: - if encoding != "unicode": - file = open(file_or_filename, "wb") + with _get_writer(file_or_filename, encoding) as write: + if method == "xml" and (xml_declaration or + (xml_declaration is None and + encoding not in ("utf-8", "us-ascii", "unicode"))): + declared_encoding = encoding + if encoding == "unicode": + # Retrieve the default encoding for the xml declaration + import locale + declared_encoding = locale.getpreferredencoding() + write("\n" % ( + declared_encoding,)) + if method == "text": + _serialize_text(write, self._root) else: - file = open(file_or_filename, "w") - if encoding != "unicode": - def write(text): - try: - return file.write(text.encode(encoding, - "xmlcharrefreplace")) - except (TypeError, AttributeError): - _raise_serialization_error(text) - else: - write = file.write - if method == "xml" and (xml_declaration or - (xml_declaration is None and - encoding not in ("utf-8", "us-ascii", "unicode"))): - declared_encoding = encoding - if encoding == "unicode": - # Retrieve the default encoding for the xml declaration - import locale - declared_encoding = locale.getpreferredencoding() - write("\n" % declared_encoding) - if method == "text": - _serialize_text(write, self._root) - else: - qnames, namespaces = _namespaces(self._root, default_namespace) - serialize = _serialize[method] - serialize(write, self._root, qnames, namespaces) - if file_or_filename is not file: - file.close() + qnames, namespaces = _namespaces(self._root, default_namespace) + serialize = _serialize[method] + serialize(write, self._root, qnames, namespaces) def write_c14n(self, file): # lxml.etree compatibility. use output method instead @@ -853,6 +834,58 @@ # -------------------------------------------------------------------- # serialization support + at contextlib.contextmanager +def _get_writer(file_or_filename, encoding): + # returns text write method and release all resourses after using + try: + write = file_or_filename.write + except AttributeError: + # file_or_filename is a file name + if encoding == "unicode": + file = open(file_or_filename, "w") + else: + file = open(file_or_filename, "w", encoding=encoding, + errors="xmlcharrefreplace") + with file: + yield file.write + else: + # file_or_filename is a file-like object + # encoding determines if it is a text or binary writer + if encoding == "unicode": + # use a text writer as is + yield write + else: + # wrap a binary writer with TextIOWrapper + with contextlib.ExitStack() as stack: + if isinstance(file_or_filename, io.BufferedIOBase): + file = file_or_filename + elif isinstance(file_or_filename, io.RawIOBase): + file = io.BufferedWriter(file_or_filename) + # Keep the original file open when the BufferedWriter is + # destroyed + stack.callback(file.detach) + else: + # This is to handle passed objects that aren't in the + # IOBase hierarchy, but just have a write method + file = io.BufferedIOBase() + file.writable = lambda: True + file.write = write + try: + # TextIOWrapper uses this methods to determine + # if BOM (for UTF-16, etc) should be added + file.seekable = file_or_filename.seekable + file.tell = file_or_filename.tell + except AttributeError: + pass + file = io.TextIOWrapper(file, + encoding=encoding, + errors="xmlcharrefreplace", + newline="\n") + # Keep the original file open when the TextIOWrapper is + # destroyed + stack.callback(file.detach) + yield file.write + def _namespaces(elem, default_namespace=None): # identify namespaces used in this tree @@ -1134,22 +1167,13 @@ # @defreturn string def tostring(element, encoding=None, method=None): - class dummy: - pass - data = [] - file = dummy() - file.write = data.append - ElementTree(element).write(file, encoding, method=method) - if encoding in (str, "unicode"): - return "".join(data) - else: - return b"".join(data) + stream = io.StringIO() if encoding == 'unicode' else io.BytesIO() + ElementTree(element).write(stream, encoding, method=method) + return stream.getvalue() ## # Generates a string representation of an XML element, including all -# subelements. If encoding is False, the string is returned as a -# sequence of string fragments; otherwise it is a sequence of -# bytestrings. +# subelements. # # @param element An Element instance. # @keyparam encoding Optional output encoding (default is US-ASCII). @@ -1161,13 +1185,15 @@ # @since 1.3 def tostringlist(element, encoding=None, method=None): - class dummy: - pass data = [] - file = dummy() - file.write = data.append - ElementTree(element).write(file, encoding, method=method) - # FIXME: merge small fragments into larger parts + class DataStream(io.BufferedIOBase): + def writable(self): + return True + + def write(self, b): + data.append(b) + + ElementTree(element).write(DataStream(), encoding, method=method) return data ## -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 15 05:20:04 2012 From: python-checkins at python.org (eli.bendersky) Date: Sun, 15 Jul 2012 05:20:04 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=239458=3A_clarify_t?= =?utf-8?q?he_documentation_of_ElementTree=2Ewrite_with_regards_to_the?= Message-ID: <3WZY0N2gGCzPBq@mail.python.org> http://hg.python.org/cpython/rev/51b5ee7cfa3b changeset: 78106:51b5ee7cfa3b user: Eli Bendersky date: Sun Jul 15 06:19:44 2012 +0300 summary: Issue #9458: clarify the documentation of ElementTree.write with regards to the type of the stream expected for a given encoding files: Doc/library/xml.etree.elementtree.rst | 24 ++++++++++---- 1 files changed, 17 insertions(+), 7 deletions(-) diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -650,15 +650,25 @@ section root element. - .. method:: write(file, encoding="us-ascii", xml_declaration=None, method="xml") + .. method:: write(file, encoding="us-ascii", xml_declaration=None, \ + method="xml") Writes the element tree to a file, as XML. *file* is a file name, or a - :term:`file object` opened for writing. *encoding* [1]_ is the output encoding - (default is US-ASCII). Use ``encoding="unicode"`` to write a Unicode string. - *xml_declaration* controls if an XML declaration - should be added to the file. Use False for never, True for always, None - for only if not US-ASCII or UTF-8 or Unicode (default is None). *method* is - either ``"xml"``, ``"html"`` or ``"text"`` (default is ``"xml"``). + :term:`file object` opened for writing. *encoding* [1]_ is the output + encoding (default is US-ASCII). + *xml_declaration* controls if an XML declaration should be added to the + file. Use ``False`` for never, ``True`` for always, ``None`` + for only if not US-ASCII or UTF-8 or Unicode (default is ``None``). + *method* is either ``"xml"``, ``"html"`` or ``"text"`` (default is + ``"xml"``). + + The output is either a string (:class:`str`) or binary (:class:`bytes`). + This is controlled by the *encoding* argument. If *encoding* is + ``"unicode"``, the output is a string; otherwise, it's binary. Note that + this may conflict with the type of *file* if it's an open + :term:`file object`; make sure you do not try to write a string to a + binary stream and vice versa. + This is the XML file that is going to be manipulated:: -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sun Jul 15 05:59:37 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 15 Jul 2012 05:59:37 +0200 Subject: [Python-checkins] Daily reference leaks (f8b520b6f654): sum=0 Message-ID: results for f8b520b6f654 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogsRs9dL', '-x'] From python-checkins at python.org Sun Jul 15 10:10:07 2012 From: python-checkins at python.org (nick.coghlan) Date: Sun, 15 Jul 2012 10:10:07 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Take_the_first_step_in_res?= =?utf-8?q?olving_the_messy_pkgutil_vs_importlib_edge_cases_by?= Message-ID: <3WZgR32c8lzPBc@mail.python.org> http://hg.python.org/cpython/rev/3987667bf98f changeset: 78107:3987667bf98f user: Nick Coghlan date: Sun Jul 15 18:09:52 2012 +1000 summary: Take the first step in resolving the messy pkgutil vs importlib edge cases by basing pkgutil explicitly on importlib, deprecating its internal import emulation and setting __main__.__loader__ correctly so that runpy still works (Affects #15343, #15314, #15357) files: Doc/library/pkgutil.rst | 61 +++++++----- Lib/pkgutil.py | 94 +++++++++---------- Lib/runpy.py | 56 ++++------- Lib/test/test_cmd_line_script.py | 73 +++++++++++--- Lib/test/test_pkgutil.py | 43 ++++++++- Misc/NEWS | 10 +- Python/pythonrun.c | 65 ++++++++++++- 7 files changed, 260 insertions(+), 142 deletions(-) diff --git a/Doc/library/pkgutil.rst b/Doc/library/pkgutil.rst --- a/Doc/library/pkgutil.rst +++ b/Doc/library/pkgutil.rst @@ -56,21 +56,32 @@ Note that :class:`ImpImporter` does not currently support being used by placement on :data:`sys.meta_path`. + .. deprecated:: 3.3 + This emulation is no longer needed, as the standard import mechanism + is now fully PEP 302 compliant and available in :mod:`importlib` + .. class:: ImpLoader(fullname, file, filename, etc) :pep:`302` Loader that wraps Python's "classic" import algorithm. + .. deprecated:: 3.3 + This emulation is no longer needed, as the standard import mechanism + is now fully PEP 302 compliant and available in :mod:`importlib` + .. function:: find_loader(fullname) - Find a :pep:`302` "loader" object for *fullname*. + Retrieve a :pep:`302` module loader for the given *fullname*. - If *fullname* contains dots, path must be the containing package's - ``__path__``. Returns ``None`` if the module cannot be found or imported. - This function uses :func:`iter_importers`, and is thus subject to the same - limitations regarding platform-specific special import locations such as the - Windows registry. + This is a convenience wrapper around :func:`importlib.find_loader` that + sets the *path* argument correctly when searching for submodules, and + also ensures parent packages (if any) are imported before searching for + submodules. + + .. versionchanged:: 3.3 + Updated to be based directly on :mod:`importlib` rather than relying + on a package internal PEP 302 import emulation. .. function:: get_importer(path_item) @@ -80,13 +91,13 @@ The returned importer is cached in :data:`sys.path_importer_cache` if it was newly created by a path hook. - If there is no importer, a wrapper around the basic import machinery is - returned. This wrapper is never inserted into the importer cache (``None`` - is inserted instead). - The cache (or part of it) can be cleared manually if a rescan of :data:`sys.path_hooks` is necessary. + .. versionchanged:: 3.3 + Updated to be based directly on :mod:`importlib` rather than relying + on a package internal PEP 302 import emulation. + .. function:: get_loader(module_or_name) @@ -102,31 +113,27 @@ limitations regarding platform-specific special import locations such as the Windows registry. + .. versionchanged:: 3.3 + Updated to be based directly on :mod:`importlib` rather than relying + on a package internal PEP 302 import emulation. + .. function:: iter_importers(fullname='') Yield :pep:`302` importers for the given module name. - If fullname contains a '.', the importers will be for the package containing - fullname, otherwise they will be importers for :data:`sys.meta_path`, - :data:`sys.path`, and Python's "classic" import machinery, in that order. If - the named module is in a package, that package is imported as a side effect - of invoking this function. + If fullname contains a '.', the importers will be for the package + containing fullname, otherwise they will be all registered top level + importers (i.e. those on both sys.meta_path and sys.path_hooks). - Non-:pep:`302` mechanisms (e.g. the Windows registry) used by the standard - import machinery to find files in alternative locations are partially - supported, but are searched *after* :data:`sys.path`. Normally, these - locations are searched *before* :data:`sys.path`, preventing :data:`sys.path` - entries from shadowing them. + If the named module is in a package, that package is imported as a side + effect of invoking this function. - For this to cause a visible difference in behaviour, there must be a module - or package name that is accessible via both :data:`sys.path` and one of the - non-:pep:`302` file system mechanisms. In this case, the emulation will find - the former version, while the builtin import mechanism will find the latter. + If no module name is specified, all top level importers are produced. - Items of the following types can be affected by this discrepancy: - ``imp.C_EXTENSION``, ``imp.PY_SOURCE``, ``imp.PY_COMPILED``, - ``imp.PKG_DIRECTORY``. + .. versionchanged:: 3.3 + Updated to be based directly on :mod:`importlib` rather than relying + on a package internal PEP 302 import emulation. .. function:: iter_modules(path=None, prefix='') diff --git a/Lib/pkgutil.py b/Lib/pkgutil.py --- a/Lib/pkgutil.py +++ b/Lib/pkgutil.py @@ -3,7 +3,9 @@ import os import sys import imp +import importlib import os.path +from warnings import warn from types import ModuleType __all__ = [ @@ -168,6 +170,8 @@ """ def __init__(self, path=None): + warn("This emulation is deprecated, use 'importlib' instead", + DeprecationWarning) self.path = path def find_module(self, fullname, path=None): @@ -232,6 +236,8 @@ code = source = None def __init__(self, fullname, file, filename, etc): + warn("This emulation is deprecated, use 'importlib' instead", + DeprecationWarning) self.file = file self.filename = filename self.fullname = fullname @@ -366,10 +372,6 @@ The returned importer is cached in sys.path_importer_cache if it was newly created by a path hook. - If there is no importer, a wrapper around the basic import - machinery is returned. This wrapper is never inserted into - the importer cache (None is inserted instead). - The cache (or part of it) can be cleared manually if a rescan of sys.path_hooks is necessary. """ @@ -384,10 +386,7 @@ except ImportError: pass else: - try: - importer = ImpImporter(path_item) - except ImportError: - importer = None + importer = None return importer @@ -395,55 +394,37 @@ """Yield PEP 302 importers for the given module name If fullname contains a '.', the importers will be for the package - containing fullname, otherwise they will be importers for sys.meta_path, - sys.path, and Python's "classic" import machinery, in that order. If - the named module is in a package, that package is imported as a side + containing fullname, otherwise they will be all registered top level + importers (i.e. those on both sys.meta_path and sys.path_hooks). + + If the named module is in a package, that package is imported as a side effect of invoking this function. - Non PEP 302 mechanisms (e.g. the Windows registry) used by the - standard import machinery to find files in alternative locations - are partially supported, but are searched AFTER sys.path. Normally, - these locations are searched BEFORE sys.path, preventing sys.path - entries from shadowing them. - - For this to cause a visible difference in behaviour, there must - be a module or package name that is accessible via both sys.path - and one of the non PEP 302 file system mechanisms. In this case, - the emulation will find the former version, while the builtin - import mechanism will find the latter. - - Items of the following types can be affected by this discrepancy: - imp.C_EXTENSION, imp.PY_SOURCE, imp.PY_COMPILED, imp.PKG_DIRECTORY + If no module name is specified, all top level importers are produced. """ if fullname.startswith('.'): - raise ImportError("Relative module names not supported") + msg = "Relative module name {!r} not supported".format(fullname) + raise ImportError(msg) if '.' in fullname: # Get the containing package's __path__ - pkg = '.'.join(fullname.split('.')[:-1]) - if pkg not in sys.modules: - __import__(pkg) - path = getattr(sys.modules[pkg], '__path__', None) or [] + pkg_name = fullname.rpartition(".")[0] + pkg = importlib.import_module(pkg) + path = getattr(sys.modules[pkg], '__path__', None) + if path is None: + return else: for importer in sys.meta_path: yield importer path = sys.path for item in path: yield get_importer(item) - if '.' not in fullname: - yield ImpImporter() def get_loader(module_or_name): """Get a PEP 302 "loader" object for module_or_name - If the module or package is accessible via the normal import - mechanism, a wrapper around the relevant part of that machinery - is returned. Returns None if the module cannot be found or imported. + Returns None if the module cannot be found or imported. If the named module is not already imported, its containing package (if any) is imported, in order to establish the package __path__. - - This function uses iter_importers(), and is thus subject to the same - limitations regarding platform-specific special import locations such - as the Windows registry. """ if module_or_name in sys.modules: module_or_name = sys.modules[module_or_name] @@ -457,22 +438,33 @@ fullname = module_or_name return find_loader(fullname) + def find_loader(fullname): """Find a PEP 302 "loader" object for fullname - If fullname contains dots, path must be the containing package's __path__. - Returns None if the module cannot be found or imported. This function uses - iter_importers(), and is thus subject to the same limitations regarding - platform-specific special import locations such as the Windows registry. + This is s convenience wrapper around :func:`importlib.find_loader` that + sets the *path* argument correctly when searching for submodules, and + also ensures parent packages (if any) are imported before searching for + submodules. """ - for importer in iter_importers(fullname): - if importer is None: - continue - loader = importer.find_module(fullname) - if loader is not None: - return loader - - return None + if fullname.startswith('.'): + msg = "Relative module name {!r} not supported".format(fullname) + raise ImportError(msg) + path = None + pkg_name = fullname.rpartition(".")[0] + if pkg_name: + pkg = importlib.import_module(pkg_name) + path = getattr(pkg, "__path__", None) + if path is None: + return None + try: + return importlib.find_loader(fullname, path) + except (ImportError, AttributeError, TypeError, ValueError) as ex: + # This hack fixes an impedance mismatch between pkgutil and + # importlib, where the latter throws other errors for cases where + # pkgutil previously threw ImportError + msg = "Error while finding loader for {!r} ({}: {})" + raise ImportError(msg.format(fullname, type(ex), ex)) from ex def extend_path(path, name): diff --git a/Lib/runpy.py b/Lib/runpy.py --- a/Lib/runpy.py +++ b/Lib/runpy.py @@ -13,11 +13,8 @@ import os import sys import imp -from pkgutil import read_code -try: - from imp import get_loader -except ImportError: - from pkgutil import get_loader +import importlib.machinery +from pkgutil import read_code, get_loader, get_importer __all__ = [ "run_module", "run_path", @@ -154,6 +151,7 @@ # know what the code was looking for info = "can't find '__main__' module in %r" % sys.argv[0] msg = "%s: %s" % (sys.executable, info) + raise sys.exit(msg) pkg_name = mod_name.rpartition('.')[0] main_globals = sys.modules["__main__"].__dict__ @@ -183,36 +181,23 @@ def _get_main_module_details(): # Helper that gives a nicer error message when attempting to # execute a zipfile or directory by invoking __main__.py + # Also moves the standard __main__ out of the way so that the + # preexisting __loader__ entry doesn't cause issues main_name = "__main__" + saved_main = sys.modules[main_name] + del sys.modules[main_name] try: return _get_module_details(main_name) except ImportError as exc: if main_name in str(exc): raise ImportError("can't find %r module in %r" % - (main_name, sys.path[0])) + (main_name, sys.path[0])) from exc raise + finally: + sys.modules[main_name] = saved_main -# XXX (ncoghlan): Perhaps expose the C API function -# as imp.get_importer instead of reimplementing it in Python? -def _get_importer(path_name): - """Python version of PyImport_GetImporter C API function""" - cache = sys.path_importer_cache - try: - importer = cache[path_name] - except KeyError: - for hook in sys.path_hooks: - try: - importer = hook(path_name) - break - except ImportError: - pass - else: - importer = None - cache[path_name] = importer - return importer - -def _get_code_from_file(fname): +def _get_code_from_file(run_name, fname): # Check for a compiled file first with open(fname, "rb") as f: code = read_code(f) @@ -220,7 +205,10 @@ # That didn't work, so try it as normal source code with open(fname, "rb") as f: code = compile(f.read(), fname, 'exec') - return code + loader = importlib.machinery.SourceFileLoader(run_name, fname) + else: + loader = importlib.machinery.SourcelessFileLoader(run_name, fname) + return code, loader def run_path(path_name, init_globals=None, run_name=None): """Execute code located at the specified filesystem location @@ -235,13 +223,13 @@ if run_name is None: run_name = "" pkg_name = run_name.rpartition(".")[0] - importer = _get_importer(path_name) + importer = get_importer(path_name) if isinstance(importer, (type(None), imp.NullImporter)): # Not a valid sys.path entry, so run the code directly # execfile() doesn't help as we want to allow compiled files - code = _get_code_from_file(path_name) + code, mod_loader = _get_code_from_file(run_name, path_name) return _run_module_code(code, init_globals, run_name, path_name, - pkg_name=pkg_name) + mod_loader, pkg_name) else: # Importer is defined for path, so add it to # the start of sys.path @@ -253,13 +241,7 @@ # have no choice and we have to remove it even while we read the # code. If we don't do this, a __loader__ attribute in the # existing __main__ module may prevent location of the new module. - main_name = "__main__" - saved_main = sys.modules[main_name] - del sys.modules[main_name] - try: - mod_name, loader, code, fname = _get_main_module_details() - finally: - sys.modules[main_name] = saved_main + mod_name, loader, code, fname = _get_main_module_details() with _TempModule(run_name) as temp_module, \ _ModifiedArgv0(path_name): mod_globals = temp_module.module.__dict__ diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -1,6 +1,8 @@ # tests command line execution of scripts import importlib +import importlib.machinery +import zipimport import unittest import sys import os @@ -11,7 +13,8 @@ from test import support from test.script_helper import ( make_pkg, make_script, make_zip_pkg, make_zip_script, - assert_python_ok, assert_python_failure, temp_dir) + assert_python_ok, assert_python_failure, temp_dir, + spawn_python, kill_python) verbose = support.verbose @@ -34,6 +37,8 @@ assertEqual(result, ['Top level assignment', 'Lower level reference']) # Check population of magic variables assertEqual(__name__, '__main__') +_loader = __loader__ if isinstance(__loader__, type) else type(__loader__) +print('__loader__==%a' % _loader) print('__file__==%a' % __file__) assertEqual(__cached__, None) print('__package__==%r' % __package__) @@ -85,11 +90,13 @@ class CmdLineTest(unittest.TestCase): def _check_output(self, script_name, exit_code, data, expected_file, expected_argv0, - expected_path0, expected_package): + expected_path0, expected_package, + expected_loader): if verbose > 1: print("Output from test script %r:" % script_name) print(data) self.assertEqual(exit_code, 0) + printed_loader = '__loader__==%a' % expected_loader printed_file = '__file__==%a' % expected_file printed_package = '__package__==%r' % expected_package printed_argv0 = 'sys.argv[0]==%a' % expected_argv0 @@ -101,6 +108,7 @@ print(printed_package) print(printed_argv0) print(printed_cwd) + self.assertIn(printed_loader.encode('utf-8'), data) self.assertIn(printed_file.encode('utf-8'), data) self.assertIn(printed_package.encode('utf-8'), data) self.assertIn(printed_argv0.encode('utf-8'), data) @@ -109,14 +117,15 @@ def _check_script(self, script_name, expected_file, expected_argv0, expected_path0, - expected_package, + expected_package, expected_loader, *cmd_line_switches): if not __debug__: cmd_line_switches += ('-' + 'O' * sys.flags.optimize,) run_args = cmd_line_switches + (script_name,) + tuple(example_args) rc, out, err = assert_python_ok(*run_args) self._check_output(script_name, rc, out + err, expected_file, - expected_argv0, expected_path0, expected_package) + expected_argv0, expected_path0, + expected_package, expected_loader) def _check_import_error(self, script_name, expected_msg, *cmd_line_switches): @@ -128,11 +137,27 @@ print('Expected output: %r' % expected_msg) self.assertIn(expected_msg.encode('utf-8'), err) + def test_dash_c_loader(self): + rc, out, err = assert_python_ok("-c", "print(__loader__)") + expected = repr(importlib.machinery.BuiltinImporter).encode("utf-8") + self.assertIn(expected, out) + + def test_stdin_loader(self): + p = spawn_python() + try: + p.stdin.write(b"print(__loader__)\n") + p.stdin.flush() + finally: + out = kill_python(p) + expected = repr(importlib.machinery.BuiltinImporter).encode("utf-8") + self.assertIn(expected, out) + def test_basic_script(self): with temp_dir() as script_dir: script_name = _make_test_script(script_dir, 'script') self._check_script(script_name, script_name, script_name, - script_dir, None) + script_dir, None, + importlib.machinery.SourceFileLoader) def test_script_compiled(self): with temp_dir() as script_dir: @@ -141,13 +166,15 @@ os.remove(script_name) pyc_file = support.make_legacy_pyc(script_name) self._check_script(pyc_file, pyc_file, - pyc_file, script_dir, None) + pyc_file, script_dir, None, + importlib.machinery.SourcelessFileLoader) def test_directory(self): with temp_dir() as script_dir: script_name = _make_test_script(script_dir, '__main__') self._check_script(script_dir, script_name, script_dir, - script_dir, '') + script_dir, '', + importlib.machinery.SourceFileLoader) def test_directory_compiled(self): with temp_dir() as script_dir: @@ -156,7 +183,8 @@ os.remove(script_name) pyc_file = support.make_legacy_pyc(script_name) self._check_script(script_dir, pyc_file, script_dir, - script_dir, '') + script_dir, '', + importlib.machinery.SourcelessFileLoader) def test_directory_error(self): with temp_dir() as script_dir: @@ -167,14 +195,16 @@ with temp_dir() as script_dir: script_name = _make_test_script(script_dir, '__main__') zip_name, run_name = make_zip_script(script_dir, 'test_zip', script_name) - self._check_script(zip_name, run_name, zip_name, zip_name, '') + self._check_script(zip_name, run_name, zip_name, zip_name, '', + zipimport.zipimporter) def test_zipfile_compiled(self): with temp_dir() as script_dir: script_name = _make_test_script(script_dir, '__main__') compiled_name = py_compile.compile(script_name, doraise=True) zip_name, run_name = make_zip_script(script_dir, 'test_zip', compiled_name) - self._check_script(zip_name, run_name, zip_name, zip_name, '') + self._check_script(zip_name, run_name, zip_name, zip_name, '', + zipimport.zipimporter) def test_zipfile_error(self): with temp_dir() as script_dir: @@ -189,19 +219,24 @@ make_pkg(pkg_dir) script_name = _make_test_script(pkg_dir, 'script') launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg.script') - self._check_script(launch_name, script_name, script_name, script_dir, 'test_pkg') + self._check_script(launch_name, script_name, script_name, + script_dir, 'test_pkg', + importlib.machinery.SourceFileLoader) def test_module_in_package_in_zipfile(self): with temp_dir() as script_dir: zip_name, run_name = _make_test_zip_pkg(script_dir, 'test_zip', 'test_pkg', 'script') launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg.script', zip_name) - self._check_script(launch_name, run_name, run_name, zip_name, 'test_pkg') + self._check_script(launch_name, run_name, run_name, + zip_name, 'test_pkg', zipimport.zipimporter) def test_module_in_subpackage_in_zipfile(self): with temp_dir() as script_dir: zip_name, run_name = _make_test_zip_pkg(script_dir, 'test_zip', 'test_pkg', 'script', depth=2) launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg.test_pkg.script', zip_name) - self._check_script(launch_name, run_name, run_name, zip_name, 'test_pkg.test_pkg') + self._check_script(launch_name, run_name, run_name, + zip_name, 'test_pkg.test_pkg', + zipimport.zipimporter) def test_package(self): with temp_dir() as script_dir: @@ -210,7 +245,8 @@ script_name = _make_test_script(pkg_dir, '__main__') launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg') self._check_script(launch_name, script_name, - script_name, script_dir, 'test_pkg') + script_name, script_dir, 'test_pkg', + importlib.machinery.SourceFileLoader) def test_package_compiled(self): with temp_dir() as script_dir: @@ -222,7 +258,8 @@ pyc_file = support.make_legacy_pyc(script_name) launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg') self._check_script(launch_name, pyc_file, - pyc_file, script_dir, 'test_pkg') + pyc_file, script_dir, 'test_pkg', + importlib.machinery.SourcelessFileLoader) def test_package_error(self): with temp_dir() as script_dir: @@ -259,7 +296,8 @@ expected = "init_argv0==%r" % '-m' self.assertIn(expected.encode('utf-8'), out) self._check_output(script_name, rc, out, - script_name, script_name, '', 'test_pkg') + script_name, script_name, '', 'test_pkg', + importlib.machinery.SourceFileLoader) def test_issue8202_dash_c_file_ignored(self): # Make sure a "-c" file in the current directory @@ -285,7 +323,8 @@ f.write("data") rc, out, err = assert_python_ok('-m', 'other', *example_args) self._check_output(script_name, rc, out, - script_name, script_name, '', '') + script_name, script_name, '', '', + importlib.machinery.SourceFileLoader) def test_dash_m_error_code_is_one(self): # If a module is invoked with the -m command line flag diff --git a/Lib/test/test_pkgutil.py b/Lib/test/test_pkgutil.py --- a/Lib/test/test_pkgutil.py +++ b/Lib/test/test_pkgutil.py @@ -1,4 +1,4 @@ -from test.support import run_unittest, unload +from test.support import run_unittest, unload, check_warnings import unittest import sys import imp @@ -255,12 +255,51 @@ self.assertEqual(d, 2) +class ImportlibMigrationTests(unittest.TestCase): + # With full PEP 302 support in the standard import machinery, the + # PEP 302 emulation in this module is in the process of being + # deprecated in favour of importlib proper + + def check_deprecated(self): + return check_warnings( + ("This emulation is deprecated, use 'importlib' instead", + DeprecationWarning)) + + def test_importer_deprecated(self): + with self.check_deprecated(): + x = pkgutil.ImpImporter("") + + def test_loader_deprecated(self): + with self.check_deprecated(): + x = pkgutil.ImpLoader("", "", "", "") + + def test_get_loader_avoids_emulation(self): + with check_warnings() as w: + self.assertIsNotNone(pkgutil.get_loader("sys")) + self.assertIsNotNone(pkgutil.get_loader("os")) + self.assertIsNotNone(pkgutil.get_loader("test.support")) + self.assertEqual(len(w.warnings), 0) + + def test_get_importer_avoids_emulation(self): + with check_warnings() as w: + self.assertIsNotNone(pkgutil.get_importer(sys.path[0])) + self.assertEqual(len(w.warnings), 0) + + def test_iter_importers_avoids_emulation(self): + with check_warnings() as w: + for importer in pkgutil.iter_importers(): pass + self.assertEqual(len(w.warnings), 0) + + def test_main(): run_unittest(PkgutilTests, PkgutilPEP302Tests, ExtendPathTests, - NestedNamespacePackageTest) + NestedNamespacePackageTest, ImportlibMigrationTests) # this is necessary if test is run repeated (like when finding leaks) import zipimport + import importlib zipimport._zip_directory_cache.clear() + importlib.invalidate_caches() + if __name__ == '__main__': test_main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #15314: __main__.__loader__ is now set correctly during + interpreter startup + - Issue #15111: When a module imported using 'from import' has an ImportError inside itself, don't mask that fact behind a generic ImportError for the module itself. @@ -31,10 +34,15 @@ - Issue #15229: An OSError subclass whose __init__ doesn't call back OSError.__init__ could produce incomplete instances, leading to crashes when calling str() on them. - + Library ------- +- Issue #15314: runpy now sets __main__.__loader__ correctly + +- Issue #15357: The import emulation in pkgutil is now deprecated. pkgutil + uses importlib internally rather than the emulation + - Issue #15233: Python now guarantees that callables registered with the atexit module will be called in a deterministic order. diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -52,7 +52,7 @@ extern grammar _PyParser_Grammar; /* From graminit.c */ /* Forward */ -static void initmain(void); +static void initmain(PyInterpreterState *interp); static int initfsencoding(PyInterpreterState *interp); static void initsite(void); static int initstdio(void); @@ -376,7 +376,7 @@ if (install_sigs) initsigs(); /* Signal handling stuff, including initintr() */ - initmain(); /* Module __main__ */ + initmain(interp); /* Module __main__ */ if (initstdio() < 0) Py_FatalError( "Py_Initialize: can't initialize sys standard streams"); @@ -728,7 +728,7 @@ if (initstdio() < 0) Py_FatalError( "Py_Initialize: can't initialize sys standard streams"); - initmain(); + initmain(interp); if (!Py_NoSiteFlag) initsite(); } @@ -825,7 +825,7 @@ /* Create __main__ module */ static void -initmain(void) +initmain(PyInterpreterState *interp) { PyObject *m, *d; m = PyImport_AddModule("__main__"); @@ -834,11 +834,31 @@ d = PyModule_GetDict(m); if (PyDict_GetItemString(d, "__builtins__") == NULL) { PyObject *bimod = PyImport_ImportModule("builtins"); - if (bimod == NULL || - PyDict_SetItemString(d, "__builtins__", bimod) != 0) - Py_FatalError("can't add __builtins__ to __main__"); + if (bimod == NULL) { + Py_FatalError("Failed to retrieve builtins module"); + } + if (PyDict_SetItemString(d, "__builtins__", bimod) < 0) { + Py_FatalError("Failed to initialize __main__.__builtins__"); + } Py_DECREF(bimod); } + /* Main is a little special - imp.is_builtin("__main__") will return + * False, but BuiltinImporter is still the most appropriate initial + * setting for its __loader__ attribute. A more suitable value will + * be set if __main__ gets further initialized later in the startup + * process. + */ + if (PyDict_GetItemString(d, "__loader__") == NULL) { + PyObject *loader = PyObject_GetAttrString(interp->importlib, + "BuiltinImporter"); + if (loader == NULL) { + Py_FatalError("Failed to retrieve BuiltinImporter"); + } + if (PyDict_SetItemString(d, "__loader__", loader) < 0) { + Py_FatalError("Failed to initialize __main__.__loader__"); + } + Py_DECREF(loader); + } } static int @@ -1331,6 +1351,24 @@ } int +set_main_loader(PyObject *d, const char *filename, const char *loader_name) +{ + PyInterpreterState *interp; + PyThreadState *tstate; + PyObject *loader; + /* Get current thread state and interpreter pointer */ + tstate = PyThreadState_GET(); + interp = tstate->interp; + loader = PyObject_GetAttrString(interp->importlib, loader_name); + if (loader == NULL || + (PyDict_SetItemString(d, "__loader__", loader) < 0)) { + return -1; + } + Py_DECREF(loader); + return 0; +} + +int PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, PyCompilerFlags *flags) { @@ -1373,8 +1411,21 @@ /* Turn on optimization if a .pyo file is given */ if (strcmp(ext, ".pyo") == 0) Py_OptimizeFlag = 1; + + if (set_main_loader(d, filename, "SourcelessFileLoader") < 0) { + fprintf(stderr, "python: failed to set __main__.__loader__\n"); + ret = -1; + goto done; + } v = run_pyc_file(fp, filename, d, d, flags); } else { + /* When running from stdin, leave __main__.__loader__ alone */ + if (strcmp(filename, "") != 0 && + set_main_loader(d, filename, "SourceFileLoader") < 0) { + fprintf(stderr, "python: failed to set __main__.__loader__\n"); + ret = -1; + goto done; + } v = PyRun_FileExFlags(fp, filename, Py_file_input, d, d, closeit, flags); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 15 10:24:52 2012 From: python-checkins at python.org (nick.coghlan) Date: Sun, 15 Jul 2012 10:24:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Note_why_we_can=27t_write_?= =?utf-8?q?an_automated_test_for_the_code_path_that_brings_up_the?= Message-ID: <3WZgm41SfszPBM@mail.python.org> http://hg.python.org/cpython/rev/777bd189f0f1 changeset: 78108:777bd189f0f1 user: Nick Coghlan date: Sun Jul 15 18:24:42 2012 +1000 summary: Note why we can't write an automated test for the code path that brings up the REPL for a bare 'python' call files: Lib/test/test_cmd_line_script.py | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -143,6 +143,9 @@ self.assertIn(expected, out) def test_stdin_loader(self): + # Unfortunately, there's no way to automatically test the fully + # interactive REPL, since that code path only gets executed when + # stdin in an interactive tty. p = spawn_python() try: p.stdin.write(b"print(__loader__)\n") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 15 10:29:33 2012 From: python-checkins at python.org (nick.coghlan) Date: Sun, 15 Jul 2012 10:29:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Remove_a_statement_that_wa?= =?utf-8?q?s_only_added_for_debugging_purposes?= Message-ID: <3WZgsT6G8yzPBq@mail.python.org> http://hg.python.org/cpython/rev/87a2f3149ca5 changeset: 78109:87a2f3149ca5 user: Nick Coghlan date: Sun Jul 15 18:29:24 2012 +1000 summary: Remove a statement that was only added for debugging purposes files: Lib/runpy.py | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Lib/runpy.py b/Lib/runpy.py --- a/Lib/runpy.py +++ b/Lib/runpy.py @@ -151,7 +151,6 @@ # know what the code was looking for info = "can't find '__main__' module in %r" % sys.argv[0] msg = "%s: %s" % (sys.executable, info) - raise sys.exit(msg) pkg_name = mod_name.rpartition('.')[0] main_globals = sys.modules["__main__"].__dict__ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 15 11:10:50 2012 From: python-checkins at python.org (nick.coghlan) Date: Sun, 15 Jul 2012 11:10:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Actually_initialize_=5F=5F?= =?utf-8?q?main=5F=5F=2E=5F=5Floader=5F=5F_with_loader_instances=2C_not_th?= =?utf-8?q?e?= Message-ID: <3WZhn613RWzPJM@mail.python.org> http://hg.python.org/cpython/rev/ba264b26d8d9 changeset: 78110:ba264b26d8d9 user: Nick Coghlan date: Sun Jul 15 19:10:39 2012 +1000 summary: Actually initialize __main__.__loader__ with loader instances, not the corresponding type objects files: Lib/test/test_cmd_line_script.py | 3 ++- Python/pythonrun.c | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -37,7 +37,8 @@ assertEqual(result, ['Top level assignment', 'Lower level reference']) # Check population of magic variables assertEqual(__name__, '__main__') -_loader = __loader__ if isinstance(__loader__, type) else type(__loader__) +from importlib.machinery import BuiltinImporter +_loader = __loader__ if __loader__ is BuiltinImporter else type(__loader__) print('__loader__==%a' % _loader) print('__file__==%a' % __file__) assertEqual(__cached__, None) diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1355,11 +1355,15 @@ { PyInterpreterState *interp; PyThreadState *tstate; - PyObject *loader; + PyObject *loader_type, *loader; /* Get current thread state and interpreter pointer */ tstate = PyThreadState_GET(); interp = tstate->interp; - loader = PyObject_GetAttrString(interp->importlib, loader_name); + loader_type = PyObject_GetAttrString(interp->importlib, loader_name); + if (loader_type == NULL) { + return -1; + } + loader = PyObject_CallFunction(loader_type, "ss", "__main__", filename); if (loader == NULL || (PyDict_SetItemString(d, "__loader__", loader) < 0)) { return -1; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 15 13:19:29 2012 From: python-checkins at python.org (nick.coghlan) Date: Sun, 15 Jul 2012 13:19:29 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315343=3A_Handle_i?= =?utf-8?q?mportlib=2Emachinery=2EFileFinder_instances_in?= Message-ID: <3WZldY6ff3zPHk@mail.python.org> http://hg.python.org/cpython/rev/9101eab6178c changeset: 78111:9101eab6178c user: Nick Coghlan date: Sun Jul 15 21:19:18 2012 +1000 summary: Issue #15343: Handle importlib.machinery.FileFinder instances in pkgutil.walk_packages (et al) files: Doc/library/pkgutil.rst | 35 +++++++++++----------- Lib/pkgutil.py | 43 ++++++++++++++++++++++++++++ Lib/test/test_pkgutil.py | 6 +++- Lib/test/test_runpy.py | 37 +++++++++++++++++++++++- Misc/NEWS | 4 ++ 5 files changed, 106 insertions(+), 19 deletions(-) diff --git a/Doc/library/pkgutil.rst b/Doc/library/pkgutil.rst --- a/Doc/library/pkgutil.rst +++ b/Doc/library/pkgutil.rst @@ -81,7 +81,7 @@ .. versionchanged:: 3.3 Updated to be based directly on :mod:`importlib` rather than relying - on a package internal PEP 302 import emulation. + on the package internal PEP 302 import emulation. .. function:: get_importer(path_item) @@ -96,7 +96,7 @@ .. versionchanged:: 3.3 Updated to be based directly on :mod:`importlib` rather than relying - on a package internal PEP 302 import emulation. + on the package internal PEP 302 import emulation. .. function:: get_loader(module_or_name) @@ -115,7 +115,7 @@ .. versionchanged:: 3.3 Updated to be based directly on :mod:`importlib` rather than relying - on a package internal PEP 302 import emulation. + on the package internal PEP 302 import emulation. .. function:: iter_importers(fullname='') @@ -133,12 +133,12 @@ .. versionchanged:: 3.3 Updated to be based directly on :mod:`importlib` rather than relying - on a package internal PEP 302 import emulation. + on the package internal PEP 302 import emulation. .. function:: iter_modules(path=None, prefix='') - Yields ``(module_loader, name, ispkg)`` for all submodules on *path*, or, if + Yields ``(module_finder, name, ispkg)`` for all submodules on *path*, or, if path is ``None``, all top-level modules on ``sys.path``. *path* should be either ``None`` or a list of paths to look for modules in. @@ -146,19 +146,19 @@ *prefix* is a string to output on the front of every module name on output. .. note:: - Only works with a :term:`finder` which defines an ``iter_modules()`` - method, which is non-standard but implemented by classes defined in this - module. + Only works for a :term:`finder` which defines an ``iter_modules()`` + method. This interface is non-standard, so the module also provides + implementations for :class:`importlib.machinery.FileFinder` and + :class:`zipimport.zipimporter`. .. versionchanged:: 3.3 - As of Python 3.3, the import system provides finders by default, but they - do not include the non-standard ``iter_modules()`` method required by this - function. + Updated to be based directly on :mod:`importlib` rather than relying + on the package internal PEP 302 import emulation. .. function:: walk_packages(path=None, prefix='', onerror=None) - Yields ``(module_loader, name, ispkg)`` for all modules recursively on + Yields ``(module_finder, name, ispkg)`` for all modules recursively on *path*, or, if path is ``None``, all accessible modules. *path* should be either ``None`` or a list of paths to look for modules in. @@ -184,13 +184,14 @@ walk_packages(ctypes.__path__, ctypes.__name__ + '.') .. note:: - Only works for a :term:`finder` which define an ``iter_modules()`` method, - which is non-standard but implemented by classes defined in this module. + Only works for a :term:`finder` which defines an ``iter_modules()`` + method. This interface is non-standard, so the module also provides + implementations for :class:`importlib.machinery.FileFinder` and + :class:`zipimport.zipimporter`. .. versionchanged:: 3.3 - As of Python 3.3, the import system provides finders by default, but they - do not include the non-standard ``iter_modules()`` method required by this - function. + Updated to be based directly on :mod:`importlib` rather than relying + on the package internal PEP 302 import emulation. .. function:: get_data(package, resource) diff --git a/Lib/pkgutil.py b/Lib/pkgutil.py --- a/Lib/pkgutil.py +++ b/Lib/pkgutil.py @@ -157,6 +157,49 @@ iter_importer_modules = simplegeneric(iter_importer_modules) +# Implement a file walker for the normal importlib path hook +def _iter_file_finder_modules(importer, prefix=''): + if importer.path is None or not os.path.isdir(importer.path): + return + + yielded = {} + import inspect + try: + filenames = os.listdir(importer.path) + except OSError: + # ignore unreadable directories like import does + filenames = [] + filenames.sort() # handle packages before same-named modules + + for fn in filenames: + modname = inspect.getmodulename(fn) + if modname=='__init__' or modname in yielded: + continue + + path = os.path.join(importer.path, fn) + ispkg = False + + if not modname and os.path.isdir(path) and '.' not in fn: + modname = fn + try: + dircontents = os.listdir(path) + except OSError: + # ignore unreadable directories like import does + dircontents = [] + for fn in dircontents: + subname = inspect.getmodulename(fn) + if subname=='__init__': + ispkg = True + break + else: + continue # not a package + + if modname and '.' not in modname: + yielded[modname] = 1 + yield prefix + modname, ispkg + +iter_importer_modules.register( + importlib.machinery.FileFinder, _iter_file_finder_modules) class ImpImporter: """PEP 302 Importer that wraps Python's "classic" import algorithm diff --git a/Lib/test/test_pkgutil.py b/Lib/test/test_pkgutil.py --- a/Lib/test/test_pkgutil.py +++ b/Lib/test/test_pkgutil.py @@ -9,7 +9,11 @@ import shutil import zipfile - +# Note: pkgutil.walk_packages is currently tested in test_runpy. This is +# a hack to get a major issue resolved for 3.3b2. Longer term, it should +# be moved back here, perhaps by factoring out the helper code for +# creating interesting package layouts to a separate module. +# Issue #15348 declares this is indeed a dodgy hack ;) class PkgutilTests(unittest.TestCase): diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -13,6 +13,7 @@ from test.script_helper import ( make_pkg, make_script, make_zip_pkg, make_zip_script, temp_dir) + import runpy from runpy import _run_code, _run_module_code, run_module, run_path # Note: This module can't safely test _run_module_as_main as it @@ -148,7 +149,7 @@ mod_package) self.check_code_execution(create_ns, expected_ns) - +# TODO: Use self.addCleanup to get rid of a lot of try-finally blocks class RunModuleTestCase(unittest.TestCase, CodeExecutionMixin): """Unit tests for runpy.run_module""" @@ -413,6 +414,40 @@ finally: self._del_pkg(pkg_dir, depth, mod_name) + def test_pkgutil_walk_packages(self): + # This is a dodgy hack to use the test_runpy infrastructure to test + # issue #15343. Issue #15348 declares this is indeed a dodgy hack ;) + import pkgutil + max_depth = 4 + base_name = "__runpy_pkg__" + package_suffixes = ["uncle", "uncle.cousin"] + module_suffixes = ["uncle.cousin.nephew", base_name + ".sibling"] + expected_packages = set() + expected_modules = set() + for depth in range(1, max_depth): + pkg_name = ".".join([base_name] * depth) + expected_packages.add(pkg_name) + for name in package_suffixes: + expected_packages.add(pkg_name + "." + name) + for name in module_suffixes: + expected_modules.add(pkg_name + "." + name) + pkg_name = ".".join([base_name] * max_depth) + expected_packages.add(pkg_name) + expected_modules.add(pkg_name + ".runpy_test") + pkg_dir, mod_fname, mod_name = ( + self._make_pkg("", max_depth)) + self.addCleanup(self._del_pkg, pkg_dir, max_depth, mod_name) + for depth in range(2, max_depth+1): + self._add_relative_modules(pkg_dir, "", depth) + for finder, mod_name, ispkg in pkgutil.walk_packages([pkg_dir]): + self.assertIsInstance(finder, + importlib.machinery.FileFinder) + if ispkg: + expected_packages.remove(mod_name) + else: + expected_modules.remove(mod_name) + self.assertEqual(len(expected_packages), 0, expected_packages) + self.assertEqual(len(expected_modules), 0, expected_modules) class RunPathTestCase(unittest.TestCase, CodeExecutionMixin): """Unit tests for runpy.run_path""" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -38,6 +38,10 @@ Library ------- +- Issue #15343: pkgutil now includes an iter_importer_modules implementation + for importlib.machinery.FileFinder (similar to the way it already handled + zipimport.zipimporter) + - Issue #15314: runpy now sets __main__.__loader__ correctly - Issue #15357: The import emulation in pkgutil is now deprecated. pkgutil -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 15 14:12:29 2012 From: python-checkins at python.org (nick.coghlan) Date: Sun, 15 Jul 2012 14:12:29 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315343=3A_A_lot_mo?= =?utf-8?q?re_than_just_unicode_decoding_can_go_wrong_when?= Message-ID: <3WZmpj1Mt5zPJf@mail.python.org> http://hg.python.org/cpython/rev/7d202353a728 changeset: 78112:7d202353a728 user: Nick Coghlan date: Sun Jul 15 22:12:14 2012 +1000 summary: Issue #15343: A lot more than just unicode decoding can go wrong when retrieving a source file files: Lib/importlib/_bootstrap.py | 17 +- Lib/pydoc.py | 2 +- Python/importlib.h | 4283 +++++++++++----------- 3 files changed, 2165 insertions(+), 2137 deletions(-) diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -845,12 +845,21 @@ path = self.get_filename(fullname) try: source_bytes = self.get_data(path) - except IOError: + except IOError as exc: raise ImportError("source not available through get_data()", - name=fullname) - encoding = tokenize.detect_encoding(_io.BytesIO(source_bytes).readline) + name=fullname) from exc + readsource = _io.BytesIO(source_bytes).readline + try: + encoding = tokenize.detect_encoding(readsource) + except SyntaxError as exc: + raise ImportError("Failed to detect encoding", + name=fullname) from exc newline_decoder = _io.IncrementalNewlineDecoder(None, True) - return newline_decoder.decode(source_bytes.decode(encoding[0])) + try: + return newline_decoder.decode(source_bytes.decode(encoding[0])) + except UnicodeDecodeError as exc: + raise ImportError("Failed to decode source file", + name=fullname) from exc def get_code(self, fullname): """Concrete implementation of InspectLoader.get_code. diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -2048,7 +2048,7 @@ if hasattr(loader, 'get_source'): try: source = loader.get_source(modname) - except UnicodeDecodeError: + except Exception: if onerror: onerror(modname) continue diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 15 14:17:18 2012 From: python-checkins at python.org (nick.coghlan) Date: Sun, 15 Jul 2012 14:17:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=239319=3A_Remove_th?= =?utf-8?q?e_workaround_for_this_since_fixed_problem_from_pydoc?= Message-ID: <3WZmwG4TMYzPJx@mail.python.org> http://hg.python.org/cpython/rev/ce0687a8383b changeset: 78113:ce0687a8383b user: Nick Coghlan date: Sun Jul 15 22:17:02 2012 +1000 summary: Issue #9319: Remove the workaround for this since fixed problem from pydoc files: Lib/pydoc.py | 8 -------- 1 files changed, 0 insertions(+), 8 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -2029,14 +2029,6 @@ if self.quit: break - # XXX Skipping this file is a workaround for a bug - # that causes python to crash with a segfault. - # http://bugs.python.org/issue9319 - # - # TODO Remove this once the bug is fixed. - if modname in {'test.badsyntax_pep3120', 'badsyntax_pep3120'}: - continue - if key is None: callback(None, modname, '') else: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 15 14:39:48 2012 From: python-checkins at python.org (nick.coghlan) Date: Sun, 15 Jul 2012 14:39:48 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Update_the_pkgutil_porting?= =?utf-8?q?_section_in_What=27s_New=2E_This_should_cause?= Message-ID: <3WZnQD1B50zPK6@mail.python.org> http://hg.python.org/cpython/rev/be795a0dce53 changeset: 78114:be795a0dce53 user: Nick Coghlan date: Sun Jul 15 22:39:39 2012 +1000 summary: Update the pkgutil porting section in What's New. This should cause significantly fewer problems after today's updates files: Doc/whatsnew/3.3.rst | 12 +++++++----- 1 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -1731,11 +1731,13 @@ both the modification time and size of the source file the bytecode file was compiled from. -* :func:`pkgutil.iter_modules` and :func:`pkgutil.walk_packages` no longer work - with modules imported using the default import system. Both functions have - always relied on a non-standard method (``iter_modules()``) to be defined on - loaders to work and the import system now always provides a loader for - modules but does not implement the non-standard method. +* :mod:`pkgutil` has been converted to use :mod:`importlib` internally. This + eliminates many edge cases where the old behaviour of the PEP 302 import + emulation failed to match the behaviour of the real import system. The + import emulation itself is still present, but is now deprecated. The + :func:`pkgutil.iter_importers` and :func:`pkgutil.walk_packages` functions + special case the standard import hooks so they are still supported even + though they do not provide the non-standard ``iter_modules()`` method. Porting C code -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 15 15:13:27 2012 From: python-checkins at python.org (nick.coghlan) Date: Sun, 15 Jul 2012 15:13:27 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_typo_in_a_comment_=28n?= =?utf-8?q?oticed_by_Terry_Reedy=29?= Message-ID: <3WZp931fGGzP31@mail.python.org> http://hg.python.org/cpython/rev/1a08ceae5ef1 changeset: 78115:1a08ceae5ef1 user: Nick Coghlan date: Sun Jul 15 23:13:18 2012 +1000 summary: Fix typo in a comment (noticed by Terry Reedy) files: Lib/test/test_cmd_line_script.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -146,7 +146,7 @@ def test_stdin_loader(self): # Unfortunately, there's no way to automatically test the fully # interactive REPL, since that code path only gets executed when - # stdin in an interactive tty. + # stdin is an interactive tty. p = spawn_python() try: p.stdin.write(b"print(__loader__)\n") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 15 15:18:17 2012 From: python-checkins at python.org (nick.coghlan) Date: Sun, 15 Jul 2012 15:18:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Make_set=5Fmain=5Floader_s?= =?utf-8?q?tatic_=28noticed_by_Antoine_Pitrou=29?= Message-ID: <3WZpGd55ynzP31@mail.python.org> http://hg.python.org/cpython/rev/8bf691d0b004 changeset: 78116:8bf691d0b004 user: Nick Coghlan date: Sun Jul 15 23:18:08 2012 +1000 summary: Make set_main_loader static (noticed by Antoine Pitrou) files: Python/pythonrun.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1351,7 +1351,7 @@ } int -set_main_loader(PyObject *d, const char *filename, const char *loader_name) +static set_main_loader(PyObject *d, const char *filename, const char *loader_name) { PyInterpreterState *interp; PyThreadState *tstate; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 15 15:21:18 2012 From: python-checkins at python.org (nick.coghlan) Date: Sun, 15 Jul 2012 15:21:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Refcounting_fixes?= Message-ID: <3WZpL62T3QzP31@mail.python.org> http://hg.python.org/cpython/rev/27e13497d545 changeset: 78117:27e13497d545 user: Nick Coghlan date: Sun Jul 15 23:21:08 2012 +1000 summary: Refcounting fixes files: Python/pythonrun.c | 10 +++++++--- 1 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1356,6 +1356,7 @@ PyInterpreterState *interp; PyThreadState *tstate; PyObject *loader_type, *loader; + int result = 0; /* Get current thread state and interpreter pointer */ tstate = PyThreadState_GET(); interp = tstate->interp; @@ -1364,12 +1365,15 @@ return -1; } loader = PyObject_CallFunction(loader_type, "ss", "__main__", filename); - if (loader == NULL || - (PyDict_SetItemString(d, "__loader__", loader) < 0)) { + Py_DECREF(loader_type); + if (loader == NULL) { return -1; } + if (PyDict_SetItemString(d, "__loader__", loader) < 0) { + result = -1; + } Py_DECREF(loader); - return 0; + return result; } int -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 15 16:47:57 2012 From: python-checkins at python.org (hynek.schlawack) Date: Sun, 15 Jul 2012 16:47:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogIzE1MTgwOiBDbGFy?= =?utf-8?q?ify_posixpath=2Ejoin=28=29_error_message_when_mixing_str_=26_by?= =?utf-8?q?tes?= Message-ID: <3WZrG54VlvzNNp@mail.python.org> http://hg.python.org/cpython/rev/cf1ac0c9e753 changeset: 78118:cf1ac0c9e753 branch: 3.2 parent: 78096:4880aac5c665 user: Hynek Schlawack date: Sun Jul 15 16:21:30 2012 +0200 summary: #15180: Clarify posixpath.join() error message when mixing str & bytes files: Lib/posixpath.py | 19 +++++++++++++------ Lib/test/test_posixpath.py | 11 +++++++++-- Misc/NEWS | 2 ++ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/Lib/posixpath.py b/Lib/posixpath.py --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -74,13 +74,20 @@ will be discarded.""" sep = _get_sep(a) path = a - for b in p: - if b.startswith(sep): - path = b - elif not path or path.endswith(sep): - path += b + try: + for b in p: + if b.startswith(sep): + path = b + elif not path or path.endswith(sep): + path += b + else: + path += sep + b + except TypeError: + strs = [isinstance(s, str) for s in (a, ) + p] + if any(strs) and not all(strs): + raise TypeError("Can't mix strings and bytes in path components.") else: - path += sep + b + raise return path diff --git a/Lib/test/test_posixpath.py b/Lib/test/test_posixpath.py --- a/Lib/test/test_posixpath.py +++ b/Lib/test/test_posixpath.py @@ -56,8 +56,15 @@ self.assertEqual(posixpath.join(b"/foo/", b"bar/", b"baz/"), b"/foo/bar/baz/") - self.assertRaises(TypeError, posixpath.join, b"bytes", "str") - self.assertRaises(TypeError, posixpath.join, "str", b"bytes") + with self.assertRaises(TypeError) as e: + posixpath.join(b'bytes', 'str') + self.assertIn("Can't mix strings and bytes", e.args[0]) + with self.assertRaises(TypeError) as e: + posixpath.join('str', b'bytes') + self.assertIn("Can't mix strings and bytes", e.args[0]) + with self.assertRaises(TypeError) as e: + posixpath.join('str', bytearray(b'bytes')) + self.assertIn("Can't mix strings and bytes", e.args[0]) def test_split(self): self.assertEqual(posixpath.split("/foo/bar"), ("/foo", "bar")) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -87,6 +87,8 @@ Library ------- +- Issue #15180: Clarify posixpath.join() error message when mixing str & bytes + - Issue #15230: runpy.run_path now correctly sets __package__ as described in the documentation -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 15 16:47:59 2012 From: python-checkins at python.org (hynek.schlawack) Date: Sun, 15 Jul 2012 16:47:59 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_=2315180=3A_Clarify_posixpath=2Ejoin=28=29_error_message?= =?utf-8?q?_when_mixing_str_=26_bytes?= Message-ID: <3WZrG72ktJzP2q@mail.python.org> http://hg.python.org/cpython/rev/1462b963e5ce changeset: 78119:1462b963e5ce parent: 78117:27e13497d545 parent: 78118:cf1ac0c9e753 user: Hynek Schlawack date: Sun Jul 15 16:46:23 2012 +0200 summary: #15180: Clarify posixpath.join() error message when mixing str & bytes files: Lib/posixpath.py | 20 ++++++++++++++------ Lib/test/test_posixpath.py | 11 +++++++++-- Misc/NEWS | 2 ++ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/Lib/posixpath.py b/Lib/posixpath.py --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -74,13 +74,21 @@ will be discarded.""" sep = _get_sep(a) path = a - for b in p: - if b.startswith(sep): - path = b - elif not path or path.endswith(sep): - path += b + try: + for b in p: + if b.startswith(sep): + path = b + elif not path or path.endswith(sep): + path += b + else: + path += sep + b + except TypeError: + strs = [isinstance(s, str) for s in (a, ) + p] + if any(strs) and not all(strs): + raise TypeError("Can't mix strings and bytes in path " + "components.") from None else: - path += sep + b + raise return path diff --git a/Lib/test/test_posixpath.py b/Lib/test/test_posixpath.py --- a/Lib/test/test_posixpath.py +++ b/Lib/test/test_posixpath.py @@ -56,8 +56,15 @@ self.assertEqual(posixpath.join(b"/foo/", b"bar/", b"baz/"), b"/foo/bar/baz/") - self.assertRaises(TypeError, posixpath.join, b"bytes", "str") - self.assertRaises(TypeError, posixpath.join, "str", b"bytes") + with self.assertRaises(TypeError) as e: + posixpath.join(b'bytes', 'str') + self.assertIn("Can't mix strings and bytes", e.args[0]) + with self.assertRaises(TypeError) as e: + posixpath.join('str', b'bytes') + self.assertIn("Can't mix strings and bytes", e.args[0]) + with self.assertRaises(TypeError) as e: + posixpath.join('str', bytearray(b'bytes')) + self.assertIn("Can't mix strings and bytes", e.args[0]) def test_split(self): self.assertEqual(posixpath.split("/foo/bar"), ("/foo", "bar")) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -38,6 +38,8 @@ Library ------- +- Issue #15180: Clarify posixpath.join() error message when mixing str & bytes + - Issue #15343: pkgutil now includes an iter_importer_modules implementation for importlib.machinery.FileFinder (similar to the way it already handled zipimport.zipimporter) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 15 17:13:06 2012 From: python-checkins at python.org (vinay.sajip) Date: Sun, 15 Jul 2012 17:13:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315307=3A_Skipped_?= =?utf-8?q?test=5Fvenv=3Atest=5Fprefixes_when_run_from_a_venv=2E?= Message-ID: <3WZrq62v0NzN5m@mail.python.org> http://hg.python.org/cpython/rev/f954ee489896 changeset: 78120:f954ee489896 user: Vinay Sajip date: Sun Jul 15 16:12:54 2012 +0100 summary: Issue #15307: Skipped test_venv:test_prefixes when run from a venv. files: Lib/test/test_venv.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -87,6 +87,8 @@ print(' %r' % os.listdir(bd)) self.assertTrue(os.path.exists(fn), 'File %r should exist.' % fn) + @unittest.skipIf(sys.prefix != sys.base_prefix, 'Test not appropriate ' + 'in a venv') def test_prefixes(self): """ Test that the prefix values are as expected. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 15 19:58:08 2012 From: python-checkins at python.org (larry.hastings) Date: Sun, 15 Jul 2012 19:58:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315202=3A_Consiste?= =?utf-8?q?ntly_use_the_name_=22follow=5Fsymlinks=22_for?= Message-ID: <3WZwTX5LGbzPH1@mail.python.org> http://hg.python.org/cpython/rev/758a9023d836 changeset: 78121:758a9023d836 user: Larry Hastings date: Sun Jul 15 10:57:38 2012 -0700 summary: Issue #15202: Consistently use the name "follow_symlinks" for new parameters in os and shutil functions. Patch by Serhiy Storchaka. files: Doc/library/os.rst | 6 ++- Doc/library/shutil.rst | 2 +- Lib/os.py | 18 +++++----- Lib/shutil.py | 52 ++++++++++++++-------------- Lib/test/test_os.py | 15 ++++--- Lib/test/test_shutil.py | 28 +++++++------- Misc/NEWS | 3 + 7 files changed, 65 insertions(+), 59 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -2211,7 +2211,7 @@ os.rmdir(os.path.join(root, name)) -.. function:: fwalk(top='.', topdown=True, onerror=None, followlinks=False, *, dir_fd=None) +.. function:: fwalk(top='.', topdown=True, onerror=None, *, follow_symlinks=False, dir_fd=None) .. index:: single: directory; walking @@ -2224,7 +2224,9 @@ and *dirfd* is a file descriptor referring to the directory *dirpath*. This function always supports :ref:`paths relative to directory descriptors - `. + ` and :ref:`not following symlinks `. Note however + that, unlike other functions, the :funk:`fwalk` default value for + *follow_symlinks* is ``False``. .. note:: diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -47,7 +47,7 @@ be copied. -.. function:: copyfile(src, dst, symlinks=False) +.. function:: copyfile(src, dst, *, follow_symlinks=True) Copy the contents (no metadata) of the file named *src* to a file named *dst* and return *dst*. *dst* must be the complete target file name; look at diff --git a/Lib/os.py b/Lib/os.py --- a/Lib/os.py +++ b/Lib/os.py @@ -424,7 +424,7 @@ if {open, stat} <= supports_dir_fd and {listdir, stat} <= supports_fd: - def fwalk(top=".", topdown=True, onerror=None, followlinks=False, *, dir_fd=None): + def fwalk(top=".", topdown=True, onerror=None, *, follow_symlinks=False, dir_fd=None): """Directory tree generator. This behaves exactly like walk(), except that it yields a 4-tuple @@ -435,7 +435,7 @@ and `dirfd` is a file descriptor referring to the directory `dirpath`. The advantage of fwalk() over walk() is that it's safe against symlink - races (when followlinks is False). + races (when follow_symlinks is False). If dir_fd is not None, it should be a file descriptor open to a directory, and top should be relative; top will then be relative to that directory. @@ -462,13 +462,13 @@ orig_st = stat(top, follow_symlinks=False, dir_fd=dir_fd) topfd = open(top, O_RDONLY, dir_fd=dir_fd) try: - if (followlinks or (st.S_ISDIR(orig_st.st_mode) and - path.samestat(orig_st, stat(topfd)))): - yield from _fwalk(topfd, top, topdown, onerror, followlinks) + if (follow_symlinks or (st.S_ISDIR(orig_st.st_mode) and + path.samestat(orig_st, stat(topfd)))): + yield from _fwalk(topfd, top, topdown, onerror, follow_symlinks) finally: close(topfd) - def _fwalk(topfd, toppath, topdown, onerror, followlinks): + def _fwalk(topfd, toppath, topdown, onerror, follow_symlinks): # Note: This uses O(depth of the directory tree) file descriptors: if # necessary, it can be adapted to only require O(1) FDs, see issue # #13734. @@ -499,16 +499,16 @@ for name in dirs: try: - orig_st = stat(name, dir_fd=topfd, follow_symlinks=followlinks) + orig_st = stat(name, dir_fd=topfd, follow_symlinks=follow_symlinks) dirfd = open(name, O_RDONLY, dir_fd=topfd) except error as err: if onerror is not None: onerror(err) return try: - if followlinks or path.samestat(orig_st, stat(dirfd)): + if follow_symlinks or path.samestat(orig_st, stat(dirfd)): dirpath = path.join(toppath, name) - yield from _fwalk(dirfd, dirpath, topdown, onerror, followlinks) + yield from _fwalk(dirfd, dirpath, topdown, onerror, follow_symlinks) finally: close(dirfd) diff --git a/Lib/shutil.py b/Lib/shutil.py --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -82,10 +82,10 @@ return (os.path.normcase(os.path.abspath(src)) == os.path.normcase(os.path.abspath(dst))) -def copyfile(src, dst, symlinks=False): +def copyfile(src, dst, *, follow_symlinks=True): """Copy data from src to dst. - If optional flag `symlinks` is set and `src` is a symbolic link, a new + If follow_symlinks is not set and src is a symbolic link, a new symlink will be created instead of copying the file it points to. """ @@ -103,7 +103,7 @@ if stat.S_ISFIFO(st.st_mode): raise SpecialFileError("`%s` is a named pipe" % fn) - if symlinks and os.path.islink(src): + if not follow_symlinks and os.path.islink(src): os.symlink(os.readlink(src), dst) else: with open(src, 'rb') as fsrc: @@ -111,15 +111,15 @@ copyfileobj(fsrc, fdst) return dst -def copymode(src, dst, symlinks=False): +def copymode(src, dst, *, follow_symlinks=True): """Copy mode bits from src to dst. - If the optional flag `symlinks` is set, symlinks aren't followed if and - only if both `src` and `dst` are symlinks. If `lchmod` isn't available (eg. - Linux), in these cases, this method does nothing. + If follow_symlinks is not set, symlinks aren't followed if and only + if both `src` and `dst` are symlinks. If `lchmod` isn't available + (e.g. Linux) this method does nothing. """ - if symlinks and os.path.islink(src) and os.path.islink(dst): + if not follow_symlinks and os.path.islink(src) and os.path.islink(dst): if hasattr(os, 'lchmod'): stat_func, chmod_func = os.lstat, os.lchmod else: @@ -133,19 +133,19 @@ chmod_func(dst, stat.S_IMODE(st.st_mode)) if hasattr(os, 'listxattr'): - def _copyxattr(src, dst, symlinks=False): + def _copyxattr(src, dst, *, follow_symlinks=True): """Copy extended filesystem attributes from `src` to `dst`. Overwrite existing attributes. - If the optional flag `symlinks` is set, symlinks won't be followed. + If `follow_symlinks` is false, symlinks won't be followed. """ - for name in os.listxattr(src, follow_symlinks=symlinks): + for name in os.listxattr(src, follow_symlinks=follow_symlinks): try: - value = os.getxattr(src, name, follow_symlinks=symlinks) - os.setxattr(dst, name, value, follow_symlinks=symlinks) + value = os.getxattr(src, name, follow_symlinks=follow_symlinks) + os.setxattr(dst, name, value, follow_symlinks=follow_symlinks) except OSError as e: if e.errno not in (errno.EPERM, errno.ENOTSUP, errno.ENODATA): raise @@ -153,10 +153,10 @@ def _copyxattr(*args, **kwargs): pass -def copystat(src, dst, symlinks=False): +def copystat(src, dst, *, follow_symlinks=True): """Copy all stat info (mode bits, atime, mtime, flags) from src to dst. - If the optional flag `symlinks` is set, symlinks aren't followed if and + If the optional flag `follow_symlinks` is not set, symlinks aren't followed if and only if both `src` and `dst` are symlinks. """ @@ -164,7 +164,7 @@ pass # follow symlinks (aka don't not follow symlinks) - follow = not (symlinks and os.path.islink(src) and os.path.islink(dst)) + follow = follow_symlinks or not (os.path.islink(src) and os.path.islink(dst)) if follow: # use the real function if it exists def lookup(name): @@ -205,37 +205,37 @@ break else: raise - _copyxattr(src, dst, symlinks=follow) + _copyxattr(src, dst, follow_symlinks=follow) -def copy(src, dst, symlinks=False): +def copy(src, dst, *, follow_symlinks=True): """Copy data and mode bits ("cp src dst"). Return the file's destination. The destination may be a directory. - If the optional flag `symlinks` is set, symlinks won't be followed. This + If follow_symlinks is false, symlinks won't be followed. This resembles GNU's "cp -P src dst". """ if os.path.isdir(dst): dst = os.path.join(dst, os.path.basename(src)) - copyfile(src, dst, symlinks=symlinks) - copymode(src, dst, symlinks=symlinks) + copyfile(src, dst, follow_symlinks=follow_symlinks) + copymode(src, dst, follow_symlinks=follow_symlinks) return dst -def copy2(src, dst, symlinks=False): +def copy2(src, dst, *, follow_symlinks=True): """Copy data and all stat info ("cp -p src dst"). Return the file's destination." The destination may be a directory. - If the optional flag `symlinks` is set, symlinks won't be followed. This + If follow_symlinks is false, symlinks won't be followed. This resembles GNU's "cp -P src dst". """ if os.path.isdir(dst): dst = os.path.join(dst, os.path.basename(src)) - copyfile(src, dst, symlinks=symlinks) - copystat(src, dst, symlinks=symlinks) + copyfile(src, dst, follow_symlinks=follow_symlinks) + copystat(src, dst, follow_symlinks=follow_symlinks) return dst def ignore_patterns(*patterns): @@ -307,7 +307,7 @@ # code with a custom `copy_function` may rely on copytree # doing the right thing. os.symlink(linkto, dstname) - copystat(srcname, dstname, symlinks=symlinks) + copystat(srcname, dstname, follow_symlinks=not symlinks) else: # ignore dangling symlink if the flag is on if not os.path.exists(linkto) and ignore_dangling_symlinks: diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -758,10 +758,11 @@ """ compare with walk() results. """ - for topdown, followlinks in itertools.product((True, False), repeat=2): - d = {'topdown': topdown, 'followlinks': followlinks} - walk_kwargs.update(d) - fwalk_kwargs.update(d) + walk_kwargs = walk_kwargs.copy() + fwalk_kwargs = fwalk_kwargs.copy() + for topdown, follow_symlinks in itertools.product((True, False), repeat=2): + walk_kwargs.update(topdown=topdown, followlinks=follow_symlinks) + fwalk_kwargs.update(topdown=topdown, follow_symlinks=follow_symlinks) expected = {} for root, dirs, files in os.walk(**walk_kwargs): @@ -787,9 +788,9 @@ def test_yields_correct_dir_fd(self): # check returned file descriptors - for topdown, followlinks in itertools.product((True, False), repeat=2): - args = support.TESTFN, topdown, None, followlinks - for root, dirs, files, rootfd in os.fwalk(*args): + for topdown, follow_symlinks in itertools.product((True, False), repeat=2): + args = support.TESTFN, topdown, None + for root, dirs, files, rootfd in os.fwalk(*args, follow_symlinks=follow_symlinks): # check that the FD is valid os.fstat(rootfd) # redundant check diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -277,17 +277,17 @@ os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG) # link to link os.lchmod(dst_link, stat.S_IRWXO) - shutil.copymode(src_link, dst_link, symlinks=True) + shutil.copymode(src_link, dst_link, follow_symlinks=False) self.assertEqual(os.lstat(src_link).st_mode, os.lstat(dst_link).st_mode) self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode) # src link - use chmod os.lchmod(dst_link, stat.S_IRWXO) - shutil.copymode(src_link, dst, symlinks=True) + shutil.copymode(src_link, dst, follow_symlinks=False) self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode) # dst link - use chmod os.lchmod(dst_link, stat.S_IRWXO) - shutil.copymode(src, dst_link, symlinks=True) + shutil.copymode(src, dst_link, follow_symlinks=False) self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode) @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing') @@ -302,7 +302,7 @@ write_file(dst, 'foo') os.symlink(src, src_link) os.symlink(dst, dst_link) - shutil.copymode(src_link, dst_link, symlinks=True) # silent fail + shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail @support.skip_unless_symlink def test_copystat_symlinks(self): @@ -326,10 +326,10 @@ src_link_stat = os.lstat(src_link) # follow if hasattr(os, 'lchmod'): - shutil.copystat(src_link, dst_link, symlinks=False) + shutil.copystat(src_link, dst_link, follow_symlinks=True) self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode) # don't follow - shutil.copystat(src_link, dst_link, symlinks=True) + shutil.copystat(src_link, dst_link, follow_symlinks=False) dst_link_stat = os.lstat(dst_link) if os.utime in os.supports_follow_symlinks: for attr in 'st_atime', 'st_mtime': @@ -341,7 +341,7 @@ if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'): self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags) # tell to follow but dst is not a link - shutil.copystat(src_link, dst, symlinks=True) + shutil.copystat(src_link, dst, follow_symlinks=False) self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) < 00000.1) @@ -439,10 +439,10 @@ dst_link = os.path.join(tmp_dir, 'qux') write_file(dst, 'bar') os.symlink(dst, dst_link) - shutil._copyxattr(src_link, dst_link, symlinks=True) + shutil._copyxattr(src_link, dst_link, follow_symlinks=False) self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43') self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo') - shutil._copyxattr(src_link, dst, symlinks=True) + shutil._copyxattr(src_link, dst, follow_symlinks=False) self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43') @support.skip_unless_symlink @@ -456,12 +456,12 @@ if hasattr(os, 'lchmod'): os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO) # don't follow - shutil.copy(src_link, dst, symlinks=False) + shutil.copy(src_link, dst, follow_symlinks=True) self.assertFalse(os.path.islink(dst)) self.assertEqual(read_file(src), read_file(dst)) os.remove(dst) # follow - shutil.copy(src_link, dst, symlinks=True) + shutil.copy(src_link, dst, follow_symlinks=False) self.assertTrue(os.path.islink(dst)) self.assertEqual(os.readlink(dst), os.readlink(src_link)) if hasattr(os, 'lchmod'): @@ -483,12 +483,12 @@ src_stat = os.stat(src) src_link_stat = os.lstat(src_link) # follow - shutil.copy2(src_link, dst, symlinks=False) + shutil.copy2(src_link, dst, follow_symlinks=True) self.assertFalse(os.path.islink(dst)) self.assertEqual(read_file(src), read_file(dst)) os.remove(dst) # don't follow - shutil.copy2(src_link, dst, symlinks=True) + shutil.copy2(src_link, dst, follow_symlinks=False) self.assertTrue(os.path.islink(dst)) self.assertEqual(os.readlink(dst), os.readlink(src_link)) dst_stat = os.lstat(dst) @@ -526,7 +526,7 @@ write_file(src, 'foo') os.symlink(src, link) # don't follow - shutil.copyfile(link, dst_link, symlinks=True) + shutil.copyfile(link, dst_link, follow_symlinks=False) self.assertTrue(os.path.islink(dst_link)) self.assertEqual(os.readlink(link), os.readlink(dst_link)) # follow diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #15202: Consistently use the name "follow_symlinks" for + new parameters in os and shutil functions. + - Issue #15314: __main__.__loader__ is now set correctly during interpreter startup -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 15 22:58:24 2012 From: python-checkins at python.org (vinay.sajip) Date: Sun, 15 Jul 2012 22:58:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Closes_=2315361=3A_Correct?= =?utf-8?q?ed_venv_prompt_in_PowerShell_activation_script=2E?= Message-ID: <3Wb0TX434SzP8g@mail.python.org> http://hg.python.org/cpython/rev/0b4d0c2173ad changeset: 78122:0b4d0c2173ad user: Vinay Sajip date: Sun Jul 15 21:58:13 2012 +0100 summary: Closes #15361: Corrected venv prompt in PowerShell activation script. files: Lib/venv/scripts/nt/Activate.ps1 | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/venv/scripts/nt/Activate.ps1 b/Lib/venv/scripts/nt/Activate.ps1 --- a/Lib/venv/scripts/nt/Activate.ps1 +++ b/Lib/venv/scripts/nt/Activate.ps1 @@ -19,7 +19,7 @@ # Set the prompt to include the env name copy-item function:prompt function:_OLD_VIRTUAL_PROMPT function prompt { - Write-Host -NoNewline -ForegroundColor Green [__VENV_NAME__] + Write-Host -NoNewline -ForegroundColor Green '[__VENV_NAME__]' _OLD_VIRTUAL_PROMPT } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 16 01:59:10 2012 From: python-checkins at python.org (larry.hastings) Date: Mon, 16 Jul 2012 01:59:10 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315202=3A_Addition?= =?utf-8?q?al_documentation_fixes_inadvertently_omitted?= Message-ID: <3Wb4V650xBzP52@mail.python.org> http://hg.python.org/cpython/rev/e26113f17309 changeset: 78123:e26113f17309 user: Larry Hastings date: Sun Jul 15 16:58:29 2012 -0700 summary: Issue #15202: Additional documentation fixes inadvertently omitted from previous checkin. files: Doc/library/shutil.rst | 72 ++++++++++++----------------- 1 files changed, 31 insertions(+), 41 deletions(-) diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -59,68 +59,64 @@ such as character or block devices and pipes cannot be copied with this function. *src* and *dst* are path names given as strings. - If *symlinks* is true and *src* is a symbolic link, a new symbolic link will - be created instead of copying the file *src* points to. + If *follow_symlinks* is false and *src* is a symbolic link, + a new symbolic link will be created instead of copying the + file *src* points to. .. versionchanged:: 3.3 :exc:`IOError` used to be raised instead of :exc:`OSError`. - Added *symlinks* argument. + Added *follow_symlinks* argument. + Now returns *dst*. - .. versionchanged:: 3.3 - Added return of the *dst*. - -.. function:: copymode(src, dst, symlinks=False) +.. function:: copymode(src, dst, *, follow_symlinks=True) Copy the permission bits from *src* to *dst*. The file contents, owner, and group are unaffected. *src* and *dst* are path names given as strings. If - *symlinks* is true, *src* a symbolic link and the operating system supports - modes for symbolic links (for example BSD-based ones), the mode of the link - will be copied. + *follow_symlinks* is false, *src* is a symbolic link, and the operating + system supports modes for symbolic links (for example BSD-based ones), + the mode of the link will be copied. .. versionchanged:: 3.3 - Added *symlinks* argument. + Added *follow_symlinks* argument. -.. function:: copystat(src, dst, symlinks=False) +.. function:: copystat(src, dst, *, follow_symlinks=True) Copy the permission bits, last access time, last modification time, and flags from *src* to *dst*. The file contents, owner, and group are unaffected. *src* - and *dst* are path names given as strings. If *src* and *dst* are both - symbolic links and *symlinks* true, the stats of the link will be copied as + and *dst* are path names given as strings. If *follow_symlinks* is false, and + *src* and *dst* are both symbolic links, the stats of the link will be copied as far as the platform allows. On Linux, :func:`copystat` also copies the "extended attributes" where possible. .. versionchanged:: 3.3 - Added *symlinks* argument and support for Linux extended attributes. + Added *follow_symlinks* argument and support for Linux extended attributes. -.. function:: copy(src, dst, symlinks=False) +.. function:: copy(src, dst, *, follow_symlinks=True) Copy the file *src* to the file or directory *dst* and return the file's destination. If *dst* is a directory, a file with the same basename as *src* is created (or overwritten) in the directory specified. Permission bits are copied. *src* and *dst* are path - names given as strings. If *symlinks* is true, symbolic links won't be - followed but recreated instead -- this resembles GNU's :program:`cp -P`. + names given as strings. If *follow_symlinks* is false, symbolic + links won't be followed but recreated instead -- this resembles GNU's + :program:`cp -P`. .. versionchanged:: 3.3 - Added *symlinks* argument. + Added *follow_symlinks* argument. + Now returns *dst*. - .. versionchanged:: 3.3 - Added return of the *dst*. - -.. function:: copy2(src, dst, symlinks=False) +.. function:: copy2(src, dst, *, follow_symlinks=True) Similar to :func:`shutil.copy`, including that the destination is - returned, but metadata is copied as well. This is - similar to the Unix command :program:`cp -p`. If *symlinks* is true, + returned, but metadata is copied as well. This is similar to the Unix + command :program:`cp -p`. If *follow_symlinks* is false, symbolic links won't be followed but recreated instead -- this resembles GNU's :program:`cp -P`. .. versionchanged:: 3.3 - Added *symlinks* argument, try to copy extended file system attributes - too (currently Linux only). - - .. versionchanged:: 3.3 - Added return of the *dst*. + Added *follow_symlinks* argument, try to copy extended + file system attributes too (currently Linux only). + Now returns *dst*. .. function:: ignore_patterns(\*patterns) @@ -167,20 +163,16 @@ as arguments. By default, :func:`shutil.copy2` is used, but any function that supports the same signature (like :func:`shutil.copy`) can be used. + .. versionchanged:: 3.3 + Copy metadata when *symlinks* is false. + Now returns *dst*. + .. versionchanged:: 3.2 Added the *copy_function* argument to be able to provide a custom copy function. - - .. versionchanged:: 3.2 Added the *ignore_dangling_symlinks* argument to silent dangling symlinks errors when *symlinks* is false. - .. versionchanged:: 3.3 - Copy metadata when *symlinks* is false. - - .. versionchanged:: 3.3 - Added return of the *dst*. - .. function:: rmtree(path, ignore_errors=False, onerror=None) @@ -244,9 +236,7 @@ .. versionchanged:: 3.3 Added explicit symlink handling for foreign filesystems, thus adapting it to the behavior of GNU's :program:`mv`. - - .. versionchanged:: 3.3 - Added return of the *dst*. + Now returns *dst*. .. function:: disk_usage(path) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 16 02:12:52 2012 From: python-checkins at python.org (r.david.murray) Date: Mon, 16 Jul 2012 02:12:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_=234640=3A_Add_optparse_te?= =?utf-8?q?sts_for_=27-xxx=27_invalid_when_defining_options=2E?= Message-ID: <3Wb4nw5Cy9zP9n@mail.python.org> http://hg.python.org/cpython/rev/844bb753570f changeset: 78124:844bb753570f user: R David Murray date: Sun Jul 15 20:12:24 2012 -0400 summary: #4640: Add optparse tests for '-xxx' invalid when defining options. Patch by Aaron (hac.man). files: Lib/test/test_optparse.py | 16 ++++++++++++++++ 1 files changed, 16 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_optparse.py b/Lib/test/test_optparse.py --- a/Lib/test/test_optparse.py +++ b/Lib/test/test_optparse.py @@ -318,6 +318,22 @@ ["-b"], {'action': 'store', 'callback_kwargs': 'foo'}) + def test_no_single_dash(self): + self.assertOptionError( + "invalid long option string '-debug': " + "must start with --, followed by non-dash", + ["-debug"]) + + self.assertOptionError( + "option -d: invalid long option string '-debug': must start with" + " --, followed by non-dash", + ["-d", "-debug"]) + + self.assertOptionError( + "invalid long option string '-debug': " + "must start with --, followed by non-dash", + ["-debug", "--debug"]) + class TestOptionParser(BaseTest): def setUp(self): self.parser = OptionParser() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 16 02:33:24 2012 From: python-checkins at python.org (larry.hastings) Date: Mon, 16 Jul 2012 02:33:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Doc_fix=3A_the_text_role_i?= =?utf-8?q?s_called_=22func=22=2C_not_=22funk=22=2E?= Message-ID: <3Wb5Fc5jC9zP9T@mail.python.org> http://hg.python.org/cpython/rev/95519862cac0 changeset: 78125:95519862cac0 user: Larry Hastings date: Sun Jul 15 17:32:36 2012 -0700 summary: Doc fix: the text role is called "func", not "funk". files: Doc/library/os.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -2225,7 +2225,7 @@ This function always supports :ref:`paths relative to directory descriptors ` and :ref:`not following symlinks `. Note however - that, unlike other functions, the :funk:`fwalk` default value for + that, unlike other functions, the :func:`fwalk` default value for *follow_symlinks* is ``False``. .. note:: -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Mon Jul 16 06:02:06 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 16 Jul 2012 06:02:06 +0200 Subject: [Python-checkins] Daily reference leaks (95519862cac0): sum=0 Message-ID: results for 95519862cac0 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogFzCo1_', '-x'] From python-checkins at python.org Mon Jul 16 06:31:35 2012 From: python-checkins at python.org (ned.deily) Date: Mon, 16 Jul 2012 06:31:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2313590=3A_Improve_?= =?utf-8?q?support_for_OS_X_Xcode_4=3A?= Message-ID: <3WbBXR1vJ7zNwj@mail.python.org> http://hg.python.org/cpython/rev/6a1e983647bd changeset: 78126:6a1e983647bd user: Ned Deily date: Sun Jul 15 21:30:03 2012 -0700 summary: Issue #13590: Improve support for OS X Xcode 4: - fix test_distutils and test_sysconfig test failures by aligning sysconfig and distutils.sysconfig tailoring of configure variables (as in 2.7) files: Lib/distutils/sysconfig.py | 29 +++++++++++++++++++-- Lib/distutils/unixccompiler.py | 21 +++------------ Lib/sysconfig.py | 6 ++-- 3 files changed, 33 insertions(+), 23 deletions(-) diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -624,7 +624,7 @@ # are in CFLAGS or LDFLAGS and remove them if they are. # This is needed when building extensions on a 10.3 system # using a universal build of python. - for key in ('LDFLAGS', 'BASECFLAGS', + for key in ('LDFLAGS', 'BASECFLAGS', 'LDSHARED', # a number of derived variables. These need to be # patched up as well. 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): @@ -669,16 +669,39 @@ # that OS release. if 'ARCHFLAGS' in os.environ: arch = os.environ['ARCHFLAGS'] - for key in ('LDFLAGS', 'BASECFLAGS', + for key in ('LDFLAGS', 'BASECFLAGS', 'LDSHARED', # a number of derived variables. These need to be # patched up as well. - 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED', 'LDSHARED'): + 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): flags = _config_vars[key] flags = re.sub('-arch\s+\w+\s', ' ', flags) flags = flags + ' ' + arch _config_vars[key] = flags + # If we're on OSX 10.5 or later and the user tries to + # compiles an extension using an SDK that is not present + # on the current machine it is better to not use an SDK + # than to fail. + # + # The major usecase for this is users using a Python.org + # binary installer on OSX 10.6: that installer uses + # the 10.4u SDK, but that SDK is not installed by default + # when you install Xcode. + # + m = re.search('-isysroot\s+(\S+)', _config_vars['CFLAGS']) + if m is not None: + sdk = m.group(1) + if not os.path.exists(sdk): + for key in ('LDFLAGS', 'BASECFLAGS', 'LDSHARED', + # a number of derived variables. These need to be + # patched up as well. + 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): + + flags = _config_vars[key] + flags = re.sub('-isysroot\s+\S+(\s|$)', ' ', flags) + _config_vars[key] = flags + if args: vals = [] for name in args: diff --git a/Lib/distutils/unixccompiler.py b/Lib/distutils/unixccompiler.py --- a/Lib/distutils/unixccompiler.py +++ b/Lib/distutils/unixccompiler.py @@ -83,8 +83,9 @@ except ValueError: pass - # Check if the SDK that is used during compilation actually exists. - # If not, revert to using the installed headers and hope for the best. + # Check if the SDK that is used during compilation actually exists, + # the universal build requires the usage of a universal SDK and not all + # users have that installed by default. sysroot = None if '-isysroot' in cc_args: idx = cc_args.index('-isysroot') @@ -96,21 +97,7 @@ if sysroot and not os.path.isdir(sysroot): log.warn("Compiling with an SDK that doesn't seem to exist: %s", sysroot) - log.warn("Attempting to compile without the SDK") - while True: - try: - index = cc_args.index('-isysroot') - # Strip this argument and the next one: - del cc_args[index:index+2] - except ValueError: - break - while True: - try: - index = compiler_so.index('-isysroot') - # Strip this argument and the next one: - del compiler_so[index:index+2] - except ValueError: - break + log.warn("Please check your Xcode installation") return compiler_so diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -565,7 +565,7 @@ # are in CFLAGS or LDFLAGS and remove them if they are. # This is needed when building extensions on a 10.3 system # using a universal build of python. - for key in ('LDFLAGS', 'BASECFLAGS', + for key in ('LDFLAGS', 'BASECFLAGS', 'LDSHARED', # a number of derived variables. These need to be # patched up as well. 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): @@ -581,7 +581,7 @@ # that OS release. if 'ARCHFLAGS' in os.environ: arch = os.environ['ARCHFLAGS'] - for key in ('LDFLAGS', 'BASECFLAGS', + for key in ('LDFLAGS', 'BASECFLAGS', 'LDSHARED', # a number of derived variables. These need to be # patched up as well. 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): @@ -606,7 +606,7 @@ if m is not None: sdk = m.group(1) if not os.path.exists(sdk): - for key in ('LDFLAGS', 'BASECFLAGS', + for key in ('LDFLAGS', 'BASECFLAGS', 'LDSHARED', # a number of derived variables. These need to be # patched up as well. 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 16 07:17:55 2012 From: python-checkins at python.org (gregory.p.smith) Date: Mon, 16 Jul 2012 07:17:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fixes_Issue_?= =?utf-8?q?=2314635=3A_telnetlib_will_use_poll=28=29_rather_than_select=28?= =?utf-8?q?=29_when_possible?= Message-ID: <3WbCYv5HvlzP3b@mail.python.org> http://hg.python.org/cpython/rev/c53e3aacb816 changeset: 78127:c53e3aacb816 branch: 2.7 parent: 78102:872afada51b0 user: Gregory P. Smith date: Sun Jul 15 22:16:06 2012 -0700 summary: Fixes Issue #14635: telnetlib will use poll() rather than select() when possible to avoid failing due to the select() file descriptor limit. Contributed by Akintayo Holder and under the Google contributor agreement. files: Lib/telnetlib.py | 130 +++++++++++++++++++++++++ Lib/test/test_telnetlib.py | 91 +++++++++++++++++- Misc/ACKS | 1 + Misc/NEWS | 3 + 4 files changed, 224 insertions(+), 1 deletions(-) diff --git a/Lib/telnetlib.py b/Lib/telnetlib.py --- a/Lib/telnetlib.py +++ b/Lib/telnetlib.py @@ -34,6 +34,7 @@ # Imported modules +import errno import sys import socket import select @@ -205,6 +206,7 @@ self.sb = 0 # flag for SB and SE sequence. self.sbdataq = '' self.option_callback = None + self._has_poll = hasattr(select, 'poll') if host is not None: self.open(host, port, timeout) @@ -287,6 +289,61 @@ is closed and no cooked data is available. """ + if self._has_poll: + return self._read_until_with_poll(match, timeout) + else: + return self._read_until_with_select(match, timeout) + + def _read_until_with_poll(self, match, timeout): + """Read until a given string is encountered or until timeout. + + This method uses select.poll() to implement the timeout. + """ + n = len(match) + call_timeout = timeout + if timeout is not None: + from time import time + time_start = time() + self.process_rawq() + i = self.cookedq.find(match) + if i < 0: + poller = select.poll() + poll_in_or_priority_flags = select.POLLIN | select.POLLPRI + poller.register(self, poll_in_or_priority_flags) + while i < 0 and not self.eof: + try: + ready = poller.poll(call_timeout) + except select.error as e: + if e.errno == errno.EINTR: + if timeout is not None: + elapsed = time() - time_start + call_timeout = timeout-elapsed + continue + raise + for fd, mode in ready: + if mode & poll_in_or_priority_flags: + i = max(0, len(self.cookedq)-n) + self.fill_rawq() + self.process_rawq() + i = self.cookedq.find(match, i) + if timeout is not None: + elapsed = time() - time_start + if elapsed >= timeout: + break + call_timeout = timeout-elapsed + poller.unregister(self) + if i >= 0: + i = i + n + buf = self.cookedq[:i] + self.cookedq = self.cookedq[i:] + return buf + return self.read_very_lazy() + + def _read_until_with_select(self, match, timeout=None): + """Read until a given string is encountered or until timeout. + + The timeout is implemented using select.select(). + """ n = len(match) self.process_rawq() i = self.cookedq.find(match) @@ -589,6 +646,79 @@ results are undeterministic, and may depend on the I/O timing. """ + if self._has_poll: + return self._expect_with_poll(list, timeout) + else: + return self._expect_with_select(list, timeout) + + def _expect_with_poll(self, expect_list, timeout=None): + """Read until one from a list of a regular expressions matches. + + This method uses select.poll() to implement the timeout. + """ + re = None + expect_list = expect_list[:] + indices = range(len(expect_list)) + for i in indices: + if not hasattr(expect_list[i], "search"): + if not re: import re + expect_list[i] = re.compile(expect_list[i]) + call_timeout = timeout + if timeout is not None: + from time import time + time_start = time() + self.process_rawq() + m = None + for i in indices: + m = expect_list[i].search(self.cookedq) + if m: + e = m.end() + text = self.cookedq[:e] + self.cookedq = self.cookedq[e:] + break + if not m: + poller = select.poll() + poll_in_or_priority_flags = select.POLLIN | select.POLLPRI + poller.register(self, poll_in_or_priority_flags) + while not m and not self.eof: + try: + ready = poller.poll(call_timeout) + except select.error as e: + if e.errno == errno.EINTR: + if timeout is not None: + elapsed = time() - time_start + call_timeout = timeout-elapsed + continue + raise + for fd, mode in ready: + if mode & poll_in_or_priority_flags: + self.fill_rawq() + self.process_rawq() + for i in indices: + m = expect_list[i].search(self.cookedq) + if m: + e = m.end() + text = self.cookedq[:e] + self.cookedq = self.cookedq[e:] + break + if timeout is not None: + elapsed = time() - time_start + if elapsed >= timeout: + break + call_timeout = timeout-elapsed + poller.unregister(self) + if m: + return (i, m, text) + text = self.read_very_lazy() + if not text and self.eof: + raise EOFError + return (-1, None, text) + + def _expect_with_select(self, list, timeout=None): + """Read until one from a list of a regular expressions matches. + + The timeout is implemented using select.select(). + """ re = None list = list[:] indices = range(len(list)) diff --git a/Lib/test/test_telnetlib.py b/Lib/test/test_telnetlib.py --- a/Lib/test/test_telnetlib.py +++ b/Lib/test/test_telnetlib.py @@ -135,6 +135,28 @@ self.assertEqual(data, want[0]) self.assertEqual(telnet.read_all(), 'not seen') + def test_read_until_with_poll(self): + """Use select.poll() to implement telnet.read_until().""" + want = ['x' * 10, 'match', 'y' * 10, EOF_sigil] + self.dataq.put(want) + telnet = telnetlib.Telnet(HOST, self.port) + if not telnet._has_poll: + raise unittest.SkipTest('select.poll() is required') + telnet._has_poll = True + self.dataq.join() + data = telnet.read_until('match') + self.assertEqual(data, ''.join(want[:-2])) + + def test_read_until_with_select(self): + """Use select.select() to implement telnet.read_until().""" + want = ['x' * 10, 'match', 'y' * 10, EOF_sigil] + self.dataq.put(want) + telnet = telnetlib.Telnet(HOST, self.port) + telnet._has_poll = False + self.dataq.join() + data = telnet.read_until('match') + self.assertEqual(data, ''.join(want[:-2])) + def test_read_all_A(self): """ read_all() @@ -357,8 +379,75 @@ self.assertEqual('', telnet.read_sb_data()) nego.sb_getter = None # break the nego => telnet cycle + +class ExpectTests(TestCase): + def setUp(self): + self.evt = threading.Event() + self.dataq = Queue.Queue() + self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.sock.settimeout(10) + self.port = test_support.bind_port(self.sock) + self.thread = threading.Thread(target=server, args=(self.evt,self.sock, + self.dataq)) + self.thread.start() + self.evt.wait() + + def tearDown(self): + self.thread.join() + + # use a similar approach to testing timeouts as test_timeout.py + # these will never pass 100% but make the fuzz big enough that it is rare + block_long = 0.6 + block_short = 0.3 + def test_expect_A(self): + """ + expect(expected, [timeout]) + Read until the expected string has been seen, or a timeout is + hit (default is no timeout); may block. + """ + want = ['x' * 10, 'match', 'y' * 10, EOF_sigil] + self.dataq.put(want) + telnet = telnetlib.Telnet(HOST, self.port) + self.dataq.join() + (_,_,data) = telnet.expect(['match']) + self.assertEqual(data, ''.join(want[:-2])) + + def test_expect_B(self): + # test the timeout - it does NOT raise socket.timeout + want = ['hello', self.block_long, 'not seen', EOF_sigil] + self.dataq.put(want) + telnet = telnetlib.Telnet(HOST, self.port) + self.dataq.join() + (_,_,data) = telnet.expect(['not seen'], self.block_short) + self.assertEqual(data, want[0]) + self.assertEqual(telnet.read_all(), 'not seen') + + def test_expect_with_poll(self): + """Use select.poll() to implement telnet.expect().""" + want = ['x' * 10, 'match', 'y' * 10, EOF_sigil] + self.dataq.put(want) + telnet = telnetlib.Telnet(HOST, self.port) + if not telnet._has_poll: + raise unittest.SkipTest('select.poll() is required') + telnet._has_poll = True + self.dataq.join() + (_,_,data) = telnet.expect(['match']) + self.assertEqual(data, ''.join(want[:-2])) + + def test_expect_with_select(self): + """Use select.select() to implement telnet.expect().""" + want = ['x' * 10, 'match', 'y' * 10, EOF_sigil] + self.dataq.put(want) + telnet = telnetlib.Telnet(HOST, self.port) + telnet._has_poll = False + self.dataq.join() + (_,_,data) = telnet.expect(['match']) + self.assertEqual(data, ''.join(want[:-2])) + + def test_main(verbose=None): - test_support.run_unittest(GeneralTests, ReadTests, OptionTests) + test_support.run_unittest(GeneralTests, ReadTests, OptionTests, + ExpectTests) if __name__ == '__main__': test_main() diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -369,6 +369,7 @@ Albert Hofkamp Tomas Hoger Jonathan Hogg +Akintayo Holder Gerrit Holl Shane Holloway Rune Holm diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -84,6 +84,9 @@ Library ------- +- Issue #14635: telnetlib will use poll() rather than select() when possible + to avoid failing due to the select() file descriptor limit. + - Issue #15247: FileIO now raises an error when given a file descriptor pointing to a directory. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 16 07:37:28 2012 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 16 Jul 2012 07:37:28 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_cm=2Eparents_is_property?= =?utf-8?q?=2C_not_a_method?= Message-ID: <3WbD0S3TTjzP4M@mail.python.org> http://hg.python.org/cpython/rev/c00e25a715d2 changeset: 78128:c00e25a715d2 parent: 78126:6a1e983647bd user: Raymond Hettinger date: Sun Jul 15 22:37:20 2012 -0700 summary: cm.parents is property, not a method files: Doc/library/collections.rst | 15 ++++++++------- 1 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -84,14 +84,15 @@ creating subcontexts that can be updated without altering values in any of the parent mappings. - .. method:: parents() + .. attribute:: parents - Returns a new :class:`ChainMap` containing all of the maps in the current - instance except the first one. This is useful for skipping the first map - in the search. The use-cases are similar to those for the - :keyword:`nonlocal` keyword used in :term:`nested scopes `. - The use-cases also parallel those for the builtin :func:`super` function. - A reference to ``d.parents`` is equivalent to: ``ChainMap(*d.maps[1:])``. + Proerty returning a new :class:`ChainMap` containing all of the maps in + the current instance except the first one. This is useful for skipping + the first map in the search. Use cases are similar to those for the + :keyword:`nonlocal` keyword used in :term:`nested scopes `. The use cases also parallel those for the built-in + :func:`super` function. A reference to ``d.parents`` is equivalent to: + ``ChainMap(*d.maps[1:])``. .. seealso:: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 16 08:45:01 2012 From: python-checkins at python.org (gregory.p.smith) Date: Mon, 16 Jul 2012 08:45:01 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_Fixes_Issue_?= =?utf-8?q?=2314635=3A_telnetlib_will_use_poll=28=29_rather_than_select=28?= =?utf-8?q?=29_when_possible?= Message-ID: <3WbFVP2p2RzP5R@mail.python.org> http://hg.python.org/cpython/rev/de229dde486b changeset: 78129:de229dde486b branch: 3.2 parent: 78118:cf1ac0c9e753 user: Gregory P. Smith date: Sun Jul 15 23:42:26 2012 -0700 summary: Fixes Issue #14635: telnetlib will use poll() rather than select() when possible to avoid failing due to the select() file descriptor limit. files: Lib/telnetlib.py | 130 +++++++++++++++++++++++++ Lib/test/test_telnetlib.py | 96 +++++++++++++++++- Misc/ACKS | 1 + Misc/NEWS | 3 + 4 files changed, 223 insertions(+), 7 deletions(-) diff --git a/Lib/telnetlib.py b/Lib/telnetlib.py --- a/Lib/telnetlib.py +++ b/Lib/telnetlib.py @@ -34,6 +34,7 @@ # Imported modules +import errno import sys import socket import select @@ -205,6 +206,7 @@ self.sb = 0 # flag for SB and SE sequence. self.sbdataq = b'' self.option_callback = None + self._has_poll = hasattr(select, 'poll') if host is not None: self.open(host, port, timeout) @@ -287,6 +289,61 @@ is closed and no cooked data is available. """ + if self._has_poll: + return self._read_until_with_poll(match, timeout) + else: + return self._read_until_with_select(match, timeout) + + def _read_until_with_poll(self, match, timeout): + """Read until a given string is encountered or until timeout. + + This method uses select.poll() to implement the timeout. + """ + n = len(match) + call_timeout = timeout + if timeout is not None: + from time import time + time_start = time() + self.process_rawq() + i = self.cookedq.find(match) + if i < 0: + poller = select.poll() + poll_in_or_priority_flags = select.POLLIN | select.POLLPRI + poller.register(self, poll_in_or_priority_flags) + while i < 0 and not self.eof: + try: + ready = poller.poll(call_timeout) + except select.error as e: + if e.errno == errno.EINTR: + if timeout is not None: + elapsed = time() - time_start + call_timeout = timeout-elapsed + continue + raise + for fd, mode in ready: + if mode & poll_in_or_priority_flags: + i = max(0, len(self.cookedq)-n) + self.fill_rawq() + self.process_rawq() + i = self.cookedq.find(match, i) + if timeout is not None: + elapsed = time() - time_start + if elapsed >= timeout: + break + call_timeout = timeout-elapsed + poller.unregister(self) + if i >= 0: + i = i + n + buf = self.cookedq[:i] + self.cookedq = self.cookedq[i:] + return buf + return self.read_very_lazy() + + def _read_until_with_select(self, match, timeout=None): + """Read until a given string is encountered or until timeout. + + The timeout is implemented using select.select(). + """ n = len(match) self.process_rawq() i = self.cookedq.find(match) @@ -589,6 +646,79 @@ results are undeterministic, and may depend on the I/O timing. """ + if self._has_poll: + return self._expect_with_poll(list, timeout) + else: + return self._expect_with_select(list, timeout) + + def _expect_with_poll(self, expect_list, timeout=None): + """Read until one from a list of a regular expressions matches. + + This method uses select.poll() to implement the timeout. + """ + re = None + expect_list = expect_list[:] + indices = range(len(expect_list)) + for i in indices: + if not hasattr(expect_list[i], "search"): + if not re: import re + expect_list[i] = re.compile(expect_list[i]) + call_timeout = timeout + if timeout is not None: + from time import time + time_start = time() + self.process_rawq() + m = None + for i in indices: + m = expect_list[i].search(self.cookedq) + if m: + e = m.end() + text = self.cookedq[:e] + self.cookedq = self.cookedq[e:] + break + if not m: + poller = select.poll() + poll_in_or_priority_flags = select.POLLIN | select.POLLPRI + poller.register(self, poll_in_or_priority_flags) + while not m and not self.eof: + try: + ready = poller.poll(call_timeout) + except select.error as e: + if e.errno == errno.EINTR: + if timeout is not None: + elapsed = time() - time_start + call_timeout = timeout-elapsed + continue + raise + for fd, mode in ready: + if mode & poll_in_or_priority_flags: + self.fill_rawq() + self.process_rawq() + for i in indices: + m = expect_list[i].search(self.cookedq) + if m: + e = m.end() + text = self.cookedq[:e] + self.cookedq = self.cookedq[e:] + break + if timeout is not None: + elapsed = time() - time_start + if elapsed >= timeout: + break + call_timeout = timeout-elapsed + poller.unregister(self) + if m: + return (i, m, text) + text = self.read_very_lazy() + if not text and self.eof: + raise EOFError + return (-1, None, text) + + def _expect_with_select(self, list, timeout=None): + """Read until one from a list of a regular expressions matches. + + The timeout is implemented using select.select(). + """ re = None list = list[:] indices = range(len(list)) diff --git a/Lib/test/test_telnetlib.py b/Lib/test/test_telnetlib.py --- a/Lib/test/test_telnetlib.py +++ b/Lib/test/test_telnetlib.py @@ -75,8 +75,8 @@ class SocketStub(object): ''' a socket proxy that re-defines sendall() ''' - def __init__(self, reads=[]): - self.reads = reads + def __init__(self, reads=()): + self.reads = list(reads) # Intentionally make a copy. self.writes = [] self.block = False def sendall(self, data): @@ -102,7 +102,7 @@ self._messages += out.getvalue() return -def new_select(*s_args): +def mock_select(*s_args): block = False for l in s_args: for fob in l: @@ -113,6 +113,30 @@ else: return s_args +class MockPoller(object): + test_case = None # Set during TestCase setUp. + + def __init__(self): + self._file_objs = [] + + def register(self, fd, eventmask): + self.test_case.assertTrue(hasattr(fd, 'fileno'), fd) + self.test_case.assertEqual(eventmask, select.POLLIN|select.POLLPRI) + self._file_objs.append(fd) + + def poll(self, timeout=None): + block = False + for fob in self._file_objs: + if isinstance(fob, TelnetAlike): + block = fob.sock.block + if block: + return [] + else: + return zip(self._file_objs, [select.POLLIN]*len(self._file_objs)) + + def unregister(self, fd): + self._file_objs.remove(fd) + @contextlib.contextmanager def test_socket(reads): def new_conn(*ignored): @@ -125,7 +149,7 @@ socket.create_connection = old_conn return -def test_telnet(reads=[], cls=TelnetAlike): +def test_telnet(reads=(), cls=TelnetAlike, use_poll=None): ''' return a telnetlib.Telnet object that uses a SocketStub with reads queued up to be read ''' for x in reads: @@ -133,15 +157,28 @@ with test_socket(reads): telnet = cls('dummy', 0) telnet._messages = '' # debuglevel output + if use_poll is not None: + if use_poll and not telnet._has_poll: + raise unittest.SkipTest('select.poll() required.') + telnet._has_poll = use_poll return telnet -class ReadTests(TestCase): + +class ExpectAndReadTestCase(TestCase): def setUp(self): self.old_select = select.select - select.select = new_select + self.old_poll = select.poll + select.select = mock_select + select.poll = MockPoller + MockPoller.test_case = self + def tearDown(self): + MockPoller.test_case = None + select.poll = self.old_poll select.select = self.old_select + +class ReadTests(ExpectAndReadTestCase): def test_read_until(self): """ read_until(expected, timeout=None) @@ -158,6 +195,21 @@ data = telnet.read_until(b'match') self.assertEqual(data, expect) + def test_read_until_with_poll(self): + """Use select.poll() to implement telnet.read_until().""" + want = [b'x' * 10, b'match', b'y' * 10] + telnet = test_telnet(want, use_poll=True) + select.select = lambda *_: self.fail('unexpected select() call.') + data = telnet.read_until(b'match') + self.assertEqual(data, b''.join(want[:-1])) + + def test_read_until_with_select(self): + """Use select.select() to implement telnet.read_until().""" + want = [b'x' * 10, b'match', b'y' * 10] + telnet = test_telnet(want, use_poll=False) + select.poll = lambda *_: self.fail('unexpected poll() call.') + data = telnet.read_until(b'match') + self.assertEqual(data, b''.join(want[:-1])) def test_read_all(self): """ @@ -349,8 +401,38 @@ self.assertRegex(telnet._messages, r'0.*test') +class ExpectTests(ExpectAndReadTestCase): + def test_expect(self): + """ + expect(expected, [timeout]) + Read until the expected string has been seen, or a timeout is + hit (default is no timeout); may block. + """ + want = [b'x' * 10, b'match', b'y' * 10] + telnet = test_telnet(want) + (_,_,data) = telnet.expect([b'match']) + self.assertEqual(data, b''.join(want[:-1])) + + def test_expect_with_poll(self): + """Use select.poll() to implement telnet.expect().""" + want = [b'x' * 10, b'match', b'y' * 10] + telnet = test_telnet(want, use_poll=True) + select.select = lambda *_: self.fail('unexpected select() call.') + (_,_,data) = telnet.expect([b'match']) + self.assertEqual(data, b''.join(want[:-1])) + + def test_expect_with_select(self): + """Use select.select() to implement telnet.expect().""" + want = [b'x' * 10, b'match', b'y' * 10] + telnet = test_telnet(want, use_poll=False) + select.poll = lambda *_: self.fail('unexpected poll() call.') + (_,_,data) = telnet.expect([b'match']) + self.assertEqual(data, b''.join(want[:-1])) + + def test_main(verbose=None): - support.run_unittest(GeneralTests, ReadTests, WriteTests, OptionTests) + support.run_unittest(GeneralTests, ReadTests, WriteTests, OptionTests, + ExpectTests) if __name__ == '__main__': test_main() diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -410,6 +410,7 @@ Albert Hofkamp Tomas Hoger Jonathan Hogg +Akintayo Holder Gerrit Holl Shane Holloway Rune Holm diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -87,6 +87,9 @@ Library ------- +- Issue #14635: telnetlib will use poll() rather than select() when possible + to avoid failing due to the select() file descriptor limit. + - Issue #15180: Clarify posixpath.join() error message when mixing str & bytes - Issue #15230: runpy.run_path now correctly sets __package__ as described -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 16 08:45:03 2012 From: python-checkins at python.org (gregory.p.smith) Date: Mon, 16 Jul 2012 08:45:03 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Fixes_Issue_=2314635=3A_telnetlib_will_use_poll=28=29_ra?= =?utf-8?q?ther_than_select=28=29_when_possible?= Message-ID: <3WbFVR28vPzP7P@mail.python.org> http://hg.python.org/cpython/rev/558e5ed678c3 changeset: 78130:558e5ed678c3 parent: 78128:c00e25a715d2 parent: 78129:de229dde486b user: Gregory P. Smith date: Sun Jul 15 23:44:49 2012 -0700 summary: Fixes Issue #14635: telnetlib will use poll() rather than select() when possible to avoid failing due to the select() file descriptor limit. files: Lib/telnetlib.py | 130 +++++++++++++++++++++++++ Lib/test/test_telnetlib.py | 96 +++++++++++++++++- Misc/ACKS | 1 + Misc/NEWS | 3 + 4 files changed, 223 insertions(+), 7 deletions(-) diff --git a/Lib/telnetlib.py b/Lib/telnetlib.py --- a/Lib/telnetlib.py +++ b/Lib/telnetlib.py @@ -34,6 +34,7 @@ # Imported modules +import errno import sys import socket import select @@ -205,6 +206,7 @@ self.sb = 0 # flag for SB and SE sequence. self.sbdataq = b'' self.option_callback = None + self._has_poll = hasattr(select, 'poll') if host is not None: self.open(host, port, timeout) @@ -287,6 +289,61 @@ is closed and no cooked data is available. """ + if self._has_poll: + return self._read_until_with_poll(match, timeout) + else: + return self._read_until_with_select(match, timeout) + + def _read_until_with_poll(self, match, timeout): + """Read until a given string is encountered or until timeout. + + This method uses select.poll() to implement the timeout. + """ + n = len(match) + call_timeout = timeout + if timeout is not None: + from time import time + time_start = time() + self.process_rawq() + i = self.cookedq.find(match) + if i < 0: + poller = select.poll() + poll_in_or_priority_flags = select.POLLIN | select.POLLPRI + poller.register(self, poll_in_or_priority_flags) + while i < 0 and not self.eof: + try: + ready = poller.poll(call_timeout) + except select.error as e: + if e.errno == errno.EINTR: + if timeout is not None: + elapsed = time() - time_start + call_timeout = timeout-elapsed + continue + raise + for fd, mode in ready: + if mode & poll_in_or_priority_flags: + i = max(0, len(self.cookedq)-n) + self.fill_rawq() + self.process_rawq() + i = self.cookedq.find(match, i) + if timeout is not None: + elapsed = time() - time_start + if elapsed >= timeout: + break + call_timeout = timeout-elapsed + poller.unregister(self) + if i >= 0: + i = i + n + buf = self.cookedq[:i] + self.cookedq = self.cookedq[i:] + return buf + return self.read_very_lazy() + + def _read_until_with_select(self, match, timeout=None): + """Read until a given string is encountered or until timeout. + + The timeout is implemented using select.select(). + """ n = len(match) self.process_rawq() i = self.cookedq.find(match) @@ -589,6 +646,79 @@ results are undeterministic, and may depend on the I/O timing. """ + if self._has_poll: + return self._expect_with_poll(list, timeout) + else: + return self._expect_with_select(list, timeout) + + def _expect_with_poll(self, expect_list, timeout=None): + """Read until one from a list of a regular expressions matches. + + This method uses select.poll() to implement the timeout. + """ + re = None + expect_list = expect_list[:] + indices = range(len(expect_list)) + for i in indices: + if not hasattr(expect_list[i], "search"): + if not re: import re + expect_list[i] = re.compile(expect_list[i]) + call_timeout = timeout + if timeout is not None: + from time import time + time_start = time() + self.process_rawq() + m = None + for i in indices: + m = expect_list[i].search(self.cookedq) + if m: + e = m.end() + text = self.cookedq[:e] + self.cookedq = self.cookedq[e:] + break + if not m: + poller = select.poll() + poll_in_or_priority_flags = select.POLLIN | select.POLLPRI + poller.register(self, poll_in_or_priority_flags) + while not m and not self.eof: + try: + ready = poller.poll(call_timeout) + except select.error as e: + if e.errno == errno.EINTR: + if timeout is not None: + elapsed = time() - time_start + call_timeout = timeout-elapsed + continue + raise + for fd, mode in ready: + if mode & poll_in_or_priority_flags: + self.fill_rawq() + self.process_rawq() + for i in indices: + m = expect_list[i].search(self.cookedq) + if m: + e = m.end() + text = self.cookedq[:e] + self.cookedq = self.cookedq[e:] + break + if timeout is not None: + elapsed = time() - time_start + if elapsed >= timeout: + break + call_timeout = timeout-elapsed + poller.unregister(self) + if m: + return (i, m, text) + text = self.read_very_lazy() + if not text and self.eof: + raise EOFError + return (-1, None, text) + + def _expect_with_select(self, list, timeout=None): + """Read until one from a list of a regular expressions matches. + + The timeout is implemented using select.select(). + """ re = None list = list[:] indices = range(len(list)) diff --git a/Lib/test/test_telnetlib.py b/Lib/test/test_telnetlib.py --- a/Lib/test/test_telnetlib.py +++ b/Lib/test/test_telnetlib.py @@ -76,8 +76,8 @@ class SocketStub(object): ''' a socket proxy that re-defines sendall() ''' - def __init__(self, reads=[]): - self.reads = reads + def __init__(self, reads=()): + self.reads = list(reads) # Intentionally make a copy. self.writes = [] self.block = False def sendall(self, data): @@ -103,7 +103,7 @@ self._messages += out.getvalue() return -def new_select(*s_args): +def mock_select(*s_args): block = False for l in s_args: for fob in l: @@ -114,6 +114,30 @@ else: return s_args +class MockPoller(object): + test_case = None # Set during TestCase setUp. + + def __init__(self): + self._file_objs = [] + + def register(self, fd, eventmask): + self.test_case.assertTrue(hasattr(fd, 'fileno'), fd) + self.test_case.assertEqual(eventmask, select.POLLIN|select.POLLPRI) + self._file_objs.append(fd) + + def poll(self, timeout=None): + block = False + for fob in self._file_objs: + if isinstance(fob, TelnetAlike): + block = fob.sock.block + if block: + return [] + else: + return zip(self._file_objs, [select.POLLIN]*len(self._file_objs)) + + def unregister(self, fd): + self._file_objs.remove(fd) + @contextlib.contextmanager def test_socket(reads): def new_conn(*ignored): @@ -126,7 +150,7 @@ socket.create_connection = old_conn return -def test_telnet(reads=[], cls=TelnetAlike): +def test_telnet(reads=(), cls=TelnetAlike, use_poll=None): ''' return a telnetlib.Telnet object that uses a SocketStub with reads queued up to be read ''' for x in reads: @@ -134,15 +158,28 @@ with test_socket(reads): telnet = cls('dummy', 0) telnet._messages = '' # debuglevel output + if use_poll is not None: + if use_poll and not telnet._has_poll: + raise unittest.SkipTest('select.poll() required.') + telnet._has_poll = use_poll return telnet -class ReadTests(TestCase): + +class ExpectAndReadTestCase(TestCase): def setUp(self): self.old_select = select.select - select.select = new_select + self.old_poll = select.poll + select.select = mock_select + select.poll = MockPoller + MockPoller.test_case = self + def tearDown(self): + MockPoller.test_case = None + select.poll = self.old_poll select.select = self.old_select + +class ReadTests(ExpectAndReadTestCase): def test_read_until(self): """ read_until(expected, timeout=None) @@ -159,6 +196,21 @@ data = telnet.read_until(b'match') self.assertEqual(data, expect) + def test_read_until_with_poll(self): + """Use select.poll() to implement telnet.read_until().""" + want = [b'x' * 10, b'match', b'y' * 10] + telnet = test_telnet(want, use_poll=True) + select.select = lambda *_: self.fail('unexpected select() call.') + data = telnet.read_until(b'match') + self.assertEqual(data, b''.join(want[:-1])) + + def test_read_until_with_select(self): + """Use select.select() to implement telnet.read_until().""" + want = [b'x' * 10, b'match', b'y' * 10] + telnet = test_telnet(want, use_poll=False) + select.poll = lambda *_: self.fail('unexpected poll() call.') + data = telnet.read_until(b'match') + self.assertEqual(data, b''.join(want[:-1])) def test_read_all(self): """ @@ -350,8 +402,38 @@ self.assertRegex(telnet._messages, r'0.*test') +class ExpectTests(ExpectAndReadTestCase): + def test_expect(self): + """ + expect(expected, [timeout]) + Read until the expected string has been seen, or a timeout is + hit (default is no timeout); may block. + """ + want = [b'x' * 10, b'match', b'y' * 10] + telnet = test_telnet(want) + (_,_,data) = telnet.expect([b'match']) + self.assertEqual(data, b''.join(want[:-1])) + + def test_expect_with_poll(self): + """Use select.poll() to implement telnet.expect().""" + want = [b'x' * 10, b'match', b'y' * 10] + telnet = test_telnet(want, use_poll=True) + select.select = lambda *_: self.fail('unexpected select() call.') + (_,_,data) = telnet.expect([b'match']) + self.assertEqual(data, b''.join(want[:-1])) + + def test_expect_with_select(self): + """Use select.select() to implement telnet.expect().""" + want = [b'x' * 10, b'match', b'y' * 10] + telnet = test_telnet(want, use_poll=False) + select.poll = lambda *_: self.fail('unexpected poll() call.') + (_,_,data) = telnet.expect([b'match']) + self.assertEqual(data, b''.join(want[:-1])) + + def test_main(verbose=None): - support.run_unittest(GeneralTests, ReadTests, WriteTests, OptionTests) + support.run_unittest(GeneralTests, ReadTests, WriteTests, OptionTests, + ExpectTests) if __name__ == '__main__': test_main() diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -451,6 +451,7 @@ Albert Hofkamp Tomas Hoger Jonathan Hogg +Akintayo Holder Gerrit Holl Shane Holloway Rune Holm diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -41,6 +41,9 @@ Library ------- +- Issue #14635: telnetlib will use poll() rather than select() when possible + to avoid failing due to the select() file descriptor limit. + - Issue #15180: Clarify posixpath.join() error message when mixing str & bytes - Issue #15343: pkgutil now includes an iter_importer_modules implementation -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 16 08:53:47 2012 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 16 Jul 2012 08:53:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Clean-up_example?= Message-ID: <3WbFhW5W0rzP3b@mail.python.org> http://hg.python.org/cpython/rev/cd8a7ec848e5 changeset: 78131:cd8a7ec848e5 user: Raymond Hettinger date: Sun Jul 15 23:53:32 2012 -0700 summary: Clean-up example files: Doc/library/collections.rst | 16 +++++++++++----- 1 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -130,16 +130,22 @@ import builtins pylookup = ChainMap(locals(), globals(), vars(builtins)) -Example of letting user specified values take precedence over environment -variables which in turn take precedence over default values:: +Example of letting user specified command-line arguments take precedence over +environment variables which in turn take precedence over default values:: import os, argparse - defaults = {'color': 'red', 'user': guest} + + defaults = {'color': 'red', 'user': 'guest'} + parser = argparse.ArgumentParser() parser.add_argument('-u', '--user') parser.add_argument('-c', '--color') - user_specified = vars(parser.parse_args()) - combined = ChainMap(user_specified, os.environ, defaults) + namespace = parser.parse_args() + command_line_args = {k:v for k, v in vars(namespace).items() if v} + + combined = ChainMap(command_line_args, os.environ, defaults) + print(combined['color']) + print(combined['user']) Example patterns for using the :class:`ChainMap` class to simulate nested contexts:: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 16 09:11:12 2012 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 16 Jul 2012 09:11:12 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgMTUzMzc6?= =?utf-8?q?_help=28=29_shown_as_undocumented?= Message-ID: <3WbG4c6jMzzP92@mail.python.org> http://hg.python.org/cpython/rev/076ae30e5dd0 changeset: 78132:076ae30e5dd0 branch: 2.7 parent: 78127:c53e3aacb816 user: Raymond Hettinger date: Mon Jul 16 00:11:05 2012 -0700 summary: Issue 15337: help() shown as undocumented files: Lib/cmd.py | 1 + Lib/test/test_cmd.py | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Lib/cmd.py b/Lib/cmd.py --- a/Lib/cmd.py +++ b/Lib/cmd.py @@ -294,6 +294,7 @@ return list(commands | topics) def do_help(self, arg): + 'List available commands with "help" or detailed help with "help cmd".' if arg: # XXX check arg syntax try: diff --git a/Lib/test/test_cmd.py b/Lib/test/test_cmd.py --- a/Lib/test/test_cmd.py +++ b/Lib/test/test_cmd.py @@ -84,11 +84,11 @@ Documented commands (type help ): ======================================== - add + add help Undocumented commands: ====================== - exit help shell + exit shell Test for the function print_topics(): @@ -125,11 +125,11 @@ Documented commands (type help ): ======================================== - add + add help Undocumented commands: ====================== - exit help shell + exit shell help text for add Hello from postloop -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 16 11:07:47 2012 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 16 Jul 2012 11:07:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_typo?= Message-ID: <3WbJg76nwLzP9L@mail.python.org> http://hg.python.org/cpython/rev/152c34b84473 changeset: 78133:152c34b84473 parent: 78131:cd8a7ec848e5 user: Raymond Hettinger date: Mon Jul 16 02:07:41 2012 -0700 summary: Fix typo files: Doc/library/collections.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -86,7 +86,7 @@ .. attribute:: parents - Proerty returning a new :class:`ChainMap` containing all of the maps in + Property returning a new :class:`ChainMap` containing all of the maps in the current instance except the first one. This is useful for skipping the first map in the search. Use cases are similar to those for the :keyword:`nonlocal` keyword used in :term:`nested scopes http://hg.python.org/cpython/rev/265e36e277f3 changeset: 78134:265e36e277f3 user: Hynek Schlawack date: Mon Jul 16 17:11:10 2012 +0200 summary: #15238: Fix xattr related shutil.copystat tests - Loosen up test as Fedora has implicit xattrs - Actually test the destination for xattrs Should make Fedora buildbot green again. files: Lib/test/test_shutil.py | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -417,8 +417,7 @@ dst = os.path.join(tmp_dir, 'the_copy') write_file(dst, dst) shutil.copystat(src, dst) - self.assertEqual(os.listxattr(src), ['user.the_value']) - self.assertEqual(os.getxattr(src, 'user.the_value'), b'fiddly') + self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly') @support.skip_unless_symlink @support.skip_unless_xattr -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 16 19:25:08 2012 From: python-checkins at python.org (vinay.sajip) Date: Mon, 16 Jul 2012 19:25:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Closes_=2315366=3A_Correct?= =?utf-8?q?ed_computation_of_include_location_for_source_builds=2E?= Message-ID: <3WbWj00CHTzPK6@mail.python.org> http://hg.python.org/cpython/rev/998c8a8f2aea changeset: 78135:998c8a8f2aea user: Vinay Sajip date: Mon Jul 16 18:24:55 2012 +0100 summary: Closes #15366: Corrected computation of include location for source builds. Thanks to Richard Oudkerk for the bug report and patch. files: Lib/distutils/sysconfig.py | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -101,10 +101,11 @@ base = _sys_home or os.path.dirname(os.path.abspath(sys.executable)) if plat_specific: return base + if _sys_home: + incdir = os.path.join(_sys_home, get_config_var('AST_H_DIR')) else: - incdir = os.path.join(_sys_home or get_config_var('srcdir'), - 'Include') - return os.path.normpath(incdir) + incdir = os.path.join(get_config_var('srcdir'), 'Include') + return os.path.normpath(incdir) python_dir = 'python' + get_python_version() + build_flags return os.path.join(prefix, "include", python_dir) elif os.name == "nt": -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 16 19:30:21 2012 From: python-checkins at python.org (vinay.sajip) Date: Mon, 16 Jul 2012 19:30:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Closes_=2315367=3A_Correct?= =?utf-8?q?ed_computation_of_include_locations_for_source_builds_on?= Message-ID: <3WbWq16cvzzPKq@mail.python.org> http://hg.python.org/cpython/rev/a970054a93fb changeset: 78136:a970054a93fb user: Vinay Sajip date: Mon Jul 16 18:30:03 2012 +0100 summary: Closes #15367: Corrected computation of include locations for source builds on Windows. Thanks to Richard Oudkerk for the bug report and patch. files: Lib/distutils/command/build_ext.py | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Lib/distutils/command/build_ext.py b/Lib/distutils/command/build_ext.py --- a/Lib/distutils/command/build_ext.py +++ b/Lib/distutils/command/build_ext.py @@ -8,6 +8,7 @@ from distutils.core import Command from distutils.errors import * from distutils.sysconfig import customize_compiler, get_python_version +from distutils.sysconfig import get_config_h_filename from distutils.dep_util import newer_group from distutils.extension import Extension from distutils.util import get_platform @@ -196,7 +197,10 @@ # Append the source distribution include and library directories, # this allows distutils on windows to work in the source tree - self.include_dirs.append(os.path.join(sys.exec_prefix, 'PC')) + self.include_dirs.append(os.path.dirname(get_config_h_filename())) + _sys_home = getattr(sys, '_home', None) + if _sys_home: + self.library_dirs.append(_sys_home) if MSVC_VERSION >= 9: # Use the .lib files for the correct architecture if self.plat_name == 'win32': -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 16 22:14:15 2012 From: python-checkins at python.org (georg.brandl) Date: Mon, 16 Jul 2012 22:14:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Update_schedule=2E?= Message-ID: <3WbbS72qDvzPHZ@mail.python.org> http://hg.python.org/peps/rev/7838a83c3ad1 changeset: 4491:7838a83c3ad1 user: Georg Brandl date: Mon Jul 16 22:13:48 2012 +0200 summary: Update schedule. files: pep-0398.txt | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pep-0398.txt b/pep-0398.txt --- a/pep-0398.txt +++ b/pep-0398.txt @@ -17,7 +17,7 @@ Python 3.3. The schedule primarily concerns itself with PEP-sized items. Small features may be added up to and including the first beta release. Bugs may be fixed until the final release, which is planned -for August 2012. +for September 2012. Release Manager and Crew @@ -42,10 +42,10 @@ (No new features beyond this point.) -- 3.3.0 beta 2: July 14, 2012 -- 3.3.0 candidate 1: July 28, 2012 -- 3.3.0 candidate 2: August 11, 2012 -- 3.3.0 final: August 25, 2012 +- 3.3.0 beta 2: July 21, 2012 +- 3.3.0 candidate 1: August 4, 2012 +- 3.3.0 candidate 2: August 18, 2012 +- 3.3.0 final: September 1, 2012 .. don't forget to update final date above as well -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Jul 16 22:35:29 2012 From: python-checkins at python.org (gregory.p.smith) Date: Mon, 16 Jul 2012 22:35:29 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_Fix_the_with?= =?utf-8?q?=5Fpoll_tests_for_platforms_without_poll=2E__missing_import=2E?= Message-ID: <3Wbbwd6md3zPHV@mail.python.org> http://hg.python.org/cpython/rev/2a14987d50e5 changeset: 78137:2a14987d50e5 branch: 3.2 parent: 78129:de229dde486b user: Gregory P. Smith date: Mon Jul 16 13:34:50 2012 -0700 summary: Fix the with_poll tests for platforms without poll. missing import. files: Lib/test/test_telnetlib.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_telnetlib.py b/Lib/test/test_telnetlib.py --- a/Lib/test/test_telnetlib.py +++ b/Lib/test/test_telnetlib.py @@ -4,6 +4,7 @@ import time import contextlib +import unittest from unittest import TestCase from test import support threading = support.import_module('threading') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 16 22:35:31 2012 From: python-checkins at python.org (gregory.p.smith) Date: Mon, 16 Jul 2012 22:35:31 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Fix_the_with=5Fpoll_tests_for_platforms_without_poll=2E_?= =?utf-8?q?_missing_import=2E?= Message-ID: <3Wbbwg5GtqzPJT@mail.python.org> http://hg.python.org/cpython/rev/d4b4c66b4604 changeset: 78138:d4b4c66b4604 parent: 78136:a970054a93fb parent: 78137:2a14987d50e5 user: Gregory P. Smith date: Mon Jul 16 13:35:20 2012 -0700 summary: Fix the with_poll tests for platforms without poll. missing import. files: Lib/test/test_telnetlib.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_telnetlib.py b/Lib/test/test_telnetlib.py --- a/Lib/test/test_telnetlib.py +++ b/Lib/test/test_telnetlib.py @@ -4,6 +4,7 @@ import time import contextlib +import unittest from unittest import TestCase from test import support threading = support.import_module('threading') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 16 22:36:13 2012 From: python-checkins at python.org (gregory.p.smith) Date: Mon, 16 Jul 2012 22:36:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fix_the_with?= =?utf-8?q?=5Fpoll_tests_for_platforms_without_poll=2E__missing_import=2E?= Message-ID: <3WbbxT65GKzPHv@mail.python.org> http://hg.python.org/cpython/rev/cd2d4fe57c0e changeset: 78139:cd2d4fe57c0e branch: 2.7 parent: 78132:076ae30e5dd0 user: Gregory P. Smith date: Mon Jul 16 13:36:01 2012 -0700 summary: Fix the with_poll tests for platforms without poll. missing import. files: Lib/test/test_telnetlib.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_telnetlib.py b/Lib/test/test_telnetlib.py --- a/Lib/test/test_telnetlib.py +++ b/Lib/test/test_telnetlib.py @@ -3,6 +3,7 @@ import time import Queue +import unittest from unittest import TestCase from test import test_support threading = test_support.import_module('threading') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 16 22:39:16 2012 From: python-checkins at python.org (gregory.p.smith) Date: Mon, 16 Jul 2012 22:39:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_Fix_unchecked_?= =?utf-8?q?select=2Epoll_reference_in_setUp_and_tearDown_for?= Message-ID: <3Wbc103sHZzNyf@mail.python.org> http://hg.python.org/cpython/rev/0963dec88636 changeset: 78140:0963dec88636 branch: 3.2 parent: 78137:2a14987d50e5 user: Gregory P. Smith date: Mon Jul 16 13:38:45 2012 -0700 summary: Fix unchecked select.poll reference in setUp and tearDown for platforms that don't have it. files: Lib/test/test_telnetlib.py | 12 +++++++----- 1 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_telnetlib.py b/Lib/test/test_telnetlib.py --- a/Lib/test/test_telnetlib.py +++ b/Lib/test/test_telnetlib.py @@ -168,14 +168,16 @@ class ExpectAndReadTestCase(TestCase): def setUp(self): self.old_select = select.select - self.old_poll = select.poll select.select = mock_select - select.poll = MockPoller - MockPoller.test_case = self + if hasattr(select, 'poll'): + self.old_poll = select.poll + select.poll = MockPoller + MockPoller.test_case = self def tearDown(self): - MockPoller.test_case = None - select.poll = self.old_poll + if hasattr(select, 'poll'): + MockPoller.test_case = None + select.poll = self.old_poll select.select = self.old_select -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 16 22:39:18 2012 From: python-checkins at python.org (gregory.p.smith) Date: Mon, 16 Jul 2012 22:39:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Fix_unchecked_select=2Epoll_reference_in_setUp_and_tearD?= =?utf-8?q?own_for?= Message-ID: <3Wbc121YGrzPJ0@mail.python.org> http://hg.python.org/cpython/rev/0112efcd42ce changeset: 78141:0112efcd42ce parent: 78138:d4b4c66b4604 parent: 78140:0963dec88636 user: Gregory P. Smith date: Mon Jul 16 13:39:10 2012 -0700 summary: Fix unchecked select.poll reference in setUp and tearDown for platforms that don't have it. files: Lib/test/test_telnetlib.py | 12 +++++++----- 1 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_telnetlib.py b/Lib/test/test_telnetlib.py --- a/Lib/test/test_telnetlib.py +++ b/Lib/test/test_telnetlib.py @@ -169,14 +169,16 @@ class ExpectAndReadTestCase(TestCase): def setUp(self): self.old_select = select.select - self.old_poll = select.poll select.select = mock_select - select.poll = MockPoller - MockPoller.test_case = self + if hasattr(select, 'poll'): + self.old_poll = select.poll + select.poll = MockPoller + MockPoller.test_case = self def tearDown(self): - MockPoller.test_case = None - select.poll = self.old_poll + if hasattr(select, 'poll'): + MockPoller.test_case = None + select.poll = self.old_poll select.select = self.old_select -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 17 00:48:43 2012 From: python-checkins at python.org (gregory.p.smith) Date: Tue, 17 Jul 2012 00:48:43 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_one_more_test_?= =?utf-8?q?fix_for_systems_without_select=2Epoll=2E__tested_by_deleting?= Message-ID: <3WbftM4K7SzPCX@mail.python.org> http://hg.python.org/cpython/rev/71537aba3a0a changeset: 78142:71537aba3a0a branch: 3.2 parent: 78140:0963dec88636 user: Gregory P. Smith date: Mon Jul 16 15:48:30 2012 -0700 summary: one more test fix for systems without select.poll. tested by deleting select.poll before running. works both ways (finally). this should fix the windows build. files: Lib/test/test_telnetlib.py | 9 ++++++--- 1 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_telnetlib.py b/Lib/test/test_telnetlib.py --- a/Lib/test/test_telnetlib.py +++ b/Lib/test/test_telnetlib.py @@ -169,13 +169,14 @@ def setUp(self): self.old_select = select.select select.select = mock_select + self.old_poll = False if hasattr(select, 'poll'): self.old_poll = select.poll select.poll = MockPoller MockPoller.test_case = self def tearDown(self): - if hasattr(select, 'poll'): + if self.old_poll: MockPoller.test_case = None select.poll = self.old_poll select.select = self.old_select @@ -210,7 +211,8 @@ """Use select.select() to implement telnet.read_until().""" want = [b'x' * 10, b'match', b'y' * 10] telnet = test_telnet(want, use_poll=False) - select.poll = lambda *_: self.fail('unexpected poll() call.') + if self.old_poll: + select.poll = lambda *_: self.fail('unexpected poll() call.') data = telnet.read_until(b'match') self.assertEqual(data, b''.join(want[:-1])) @@ -428,7 +430,8 @@ """Use select.select() to implement telnet.expect().""" want = [b'x' * 10, b'match', b'y' * 10] telnet = test_telnet(want, use_poll=False) - select.poll = lambda *_: self.fail('unexpected poll() call.') + if self.old_poll: + select.poll = lambda *_: self.fail('unexpected poll() call.') (_,_,data) = telnet.expect([b'match']) self.assertEqual(data, b''.join(want[:-1])) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 17 00:49:24 2012 From: python-checkins at python.org (gregory.p.smith) Date: Tue, 17 Jul 2012 00:49:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_one_more_test_fix_for_systems_without_select=2Epoll=2E__?= =?utf-8?q?tested_by_deleting?= Message-ID: <3Wbfv816SczPCX@mail.python.org> http://hg.python.org/cpython/rev/94704db452e8 changeset: 78143:94704db452e8 parent: 78141:0112efcd42ce parent: 78142:71537aba3a0a user: Gregory P. Smith date: Mon Jul 16 15:49:19 2012 -0700 summary: one more test fix for systems without select.poll. tested by deleting select.poll before running. works both ways (finally). this should fix the windows build. files: Lib/test/test_telnetlib.py | 9 ++++++--- 1 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_telnetlib.py b/Lib/test/test_telnetlib.py --- a/Lib/test/test_telnetlib.py +++ b/Lib/test/test_telnetlib.py @@ -170,13 +170,14 @@ def setUp(self): self.old_select = select.select select.select = mock_select + self.old_poll = False if hasattr(select, 'poll'): self.old_poll = select.poll select.poll = MockPoller MockPoller.test_case = self def tearDown(self): - if hasattr(select, 'poll'): + if self.old_poll: MockPoller.test_case = None select.poll = self.old_poll select.select = self.old_select @@ -211,7 +212,8 @@ """Use select.select() to implement telnet.read_until().""" want = [b'x' * 10, b'match', b'y' * 10] telnet = test_telnet(want, use_poll=False) - select.poll = lambda *_: self.fail('unexpected poll() call.') + if self.old_poll: + select.poll = lambda *_: self.fail('unexpected poll() call.') data = telnet.read_until(b'match') self.assertEqual(data, b''.join(want[:-1])) @@ -429,7 +431,8 @@ """Use select.select() to implement telnet.expect().""" want = [b'x' * 10, b'match', b'y' * 10] telnet = test_telnet(want, use_poll=False) - select.poll = lambda *_: self.fail('unexpected poll() call.') + if self.old_poll: + select.poll = lambda *_: self.fail('unexpected poll() call.') (_,_,data) = telnet.expect([b'match']) self.assertEqual(data, b''.join(want[:-1])) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 17 04:31:47 2012 From: python-checkins at python.org (r.david.murray) Date: Tue, 17 Jul 2012 04:31:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE1Mzc1OiByZW1v?= =?utf-8?q?ve_duplicated_word_=27child=27?= Message-ID: <3Wblql3JcGzPJ5@mail.python.org> http://hg.python.org/cpython/rev/227a22288688 changeset: 78144:227a22288688 branch: 2.7 parent: 78139:cd2d4fe57c0e user: R David Murray date: Mon Jul 16 22:31:32 2012 -0400 summary: #15375: remove duplicated word 'child' files: Doc/library/subprocess.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -289,7 +289,7 @@ Popen(['/bin/sh', '-c', args[0], args[1], ...]) - On Windows: the :class:`Popen` class uses CreateProcess() to execute the child + On Windows: the :class:`Popen` class uses CreateProcess() to execute the child program, which operates on strings. If *args* is a sequence, it will be converted to a string in a manner described in :ref:`converting-argument-sequence`. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 17 04:45:36 2012 From: python-checkins at python.org (eli.bendersky) Date: Tue, 17 Jul 2012 04:45:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Preserve_the_invariant_tos?= =?utf-8?b?dHJpbmcoZWxlbSkgPT0gYicnLmpvaW4odG9zdHJpbmdsaXN0KGVsZW0pKSBh?= =?utf-8?q?nd_add_a?= Message-ID: <3Wbm7h0BsXzPCc@mail.python.org> http://hg.python.org/cpython/rev/64ff90e07d71 changeset: 78145:64ff90e07d71 parent: 78143:94704db452e8 user: Eli Bendersky date: Tue Jul 17 05:45:11 2012 +0300 summary: Preserve the invariant tostring(elem) == b''.join(tostringlist(elem)) and add a test to make sure it keeps working files: Lib/test/test_xml_etree.py | 9 +++++++++ Lib/xml/etree/ElementTree.py | 6 ++++++ 2 files changed, 15 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -2286,6 +2286,15 @@ '''\n''' ''''''.encode("utf-16")) + def test_tostringlist_invariant(self): + root = ET.fromstring('foo') + self.assertEqual( + ET.tostring(root, 'unicode'), + ''.join(ET.tostringlist(root, 'unicode'))) + self.assertEqual( + ET.tostring(root, 'utf-16'), + b''.join(ET.tostringlist(root, 'utf-16'))) + class ParseErrorTest(unittest.TestCase): def test_subclass(self): diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -1190,9 +1190,15 @@ def writable(self): return True + def seekable(self): + return True + def write(self, b): data.append(b) + def tell(self): + return len(data) + ElementTree(element).write(DataStream(), encoding, method=method) return data -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Tue Jul 17 05:55:47 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 17 Jul 2012 05:55:47 +0200 Subject: [Python-checkins] Daily reference leaks (94704db452e8): sum=0 Message-ID: results for 94704db452e8 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogRWZ5tO', '-x'] From python-checkins at python.org Tue Jul 17 10:51:34 2012 From: python-checkins at python.org (hynek.schlawack) Date: Tue, 17 Jul 2012 10:51:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_Fix_context_ma?= =?utf-8?q?nager_use_in_posixpath=2Ejoin=28=29_tests?= Message-ID: <3WbwFy5chtzPFw@mail.python.org> http://hg.python.org/cpython/rev/eddafae5e575 changeset: 78146:eddafae5e575 branch: 3.2 parent: 78142:71537aba3a0a user: Hynek Schlawack date: Tue Jul 17 10:48:19 2012 +0200 summary: Fix context manager use in posixpath.join() tests The asserts were useless (and buggy). files: Lib/test/test_posixpath.py | 21 ++++++++++++--------- 1 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_posixpath.py b/Lib/test/test_posixpath.py --- a/Lib/test/test_posixpath.py +++ b/Lib/test/test_posixpath.py @@ -56,15 +56,18 @@ self.assertEqual(posixpath.join(b"/foo/", b"bar/", b"baz/"), b"/foo/bar/baz/") - with self.assertRaises(TypeError) as e: - posixpath.join(b'bytes', 'str') - self.assertIn("Can't mix strings and bytes", e.args[0]) - with self.assertRaises(TypeError) as e: - posixpath.join('str', b'bytes') - self.assertIn("Can't mix strings and bytes", e.args[0]) - with self.assertRaises(TypeError) as e: - posixpath.join('str', bytearray(b'bytes')) - self.assertIn("Can't mix strings and bytes", e.args[0]) + # Check for friendly str/bytes mixing message + for args in [[b'bytes', 'str'], + [bytearray(b'bytes'), 'str']]: + for _ in range(2): + with self.assertRaises(TypeError) as cm: + posixpath.join(*args) + self.assertEqual( + "Can't mix strings and bytes in path components.", + cm.exception.args[0] + ) + args.reverse() # check both orders + def test_split(self): self.assertEqual(posixpath.split("/foo/bar"), ("/foo", "bar")) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 17 10:51:36 2012 From: python-checkins at python.org (hynek.schlawack) Date: Tue, 17 Jul 2012 10:51:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Fix_context_manager_use_in_posixpath=2Ejoin=28=29_tests?= Message-ID: <3WbwG02qmkzPK6@mail.python.org> http://hg.python.org/cpython/rev/59b4e979ad37 changeset: 78147:59b4e979ad37 parent: 78145:64ff90e07d71 parent: 78146:eddafae5e575 user: Hynek Schlawack date: Tue Jul 17 10:50:30 2012 +0200 summary: Fix context manager use in posixpath.join() tests The asserts were useless (and buggy). files: Lib/test/test_posixpath.py | 21 ++++++++++++--------- 1 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_posixpath.py b/Lib/test/test_posixpath.py --- a/Lib/test/test_posixpath.py +++ b/Lib/test/test_posixpath.py @@ -56,15 +56,18 @@ self.assertEqual(posixpath.join(b"/foo/", b"bar/", b"baz/"), b"/foo/bar/baz/") - with self.assertRaises(TypeError) as e: - posixpath.join(b'bytes', 'str') - self.assertIn("Can't mix strings and bytes", e.args[0]) - with self.assertRaises(TypeError) as e: - posixpath.join('str', b'bytes') - self.assertIn("Can't mix strings and bytes", e.args[0]) - with self.assertRaises(TypeError) as e: - posixpath.join('str', bytearray(b'bytes')) - self.assertIn("Can't mix strings and bytes", e.args[0]) + # Check for friendly str/bytes mixing message + for args in [[b'bytes', 'str'], + [bytearray(b'bytes'), 'str']]: + for _ in range(2): + with self.assertRaises(TypeError) as cm: + posixpath.join(*args) + self.assertEqual( + "Can't mix strings and bytes in path components.", + cm.exception.args[0] + ) + args.reverse() # check both orders + def test_split(self): self.assertEqual(posixpath.split("/foo/bar"), ("/foo", "bar")) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 17 12:43:54 2012 From: python-checkins at python.org (nick.coghlan) Date: Tue, 17 Jul 2012 12:43:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE1MjMw?= =?utf-8?q?=3A_Attempt_to_make_the_OS_X_buildbots_happy_by_resolving_the_t?= =?utf-8?q?mp_dir?= Message-ID: <3WbylZ2v5pzPFy@mail.python.org> http://hg.python.org/cpython/rev/07ed744a47f6 changeset: 78148:07ed744a47f6 branch: 3.2 parent: 78146:eddafae5e575 user: Nick Coghlan date: Tue Jul 17 20:42:39 2012 +1000 summary: Issue #15230: Attempt to make the OS X buildbots happy by resolving the tmp dir symlink in the test suite files: Lib/test/test_runpy.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -182,7 +182,7 @@ def _make_pkg(self, source, depth, mod_base="runpy_test"): pkg_name = "__runpy_pkg__" test_fname = mod_base+os.extsep+"py" - pkg_dir = sub_dir = tempfile.mkdtemp() + pkg_dir = sub_dir = os.path.realpath(tempfile.mkdtemp()) if verbose > 1: print(" Package tree in:", sub_dir) sys.path.insert(0, pkg_dir) if verbose > 1: print(" Updated sys.path:", sys.path[0]) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 17 12:43:55 2012 From: python-checkins at python.org (nick.coghlan) Date: Tue, 17 Jul 2012 12:43:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Merge_Issue_=2315230_OS_X_buildbot_fix_from_3=2E2?= Message-ID: <3Wbylb6kHtzPHf@mail.python.org> http://hg.python.org/cpython/rev/cb7e8ee489a1 changeset: 78149:cb7e8ee489a1 parent: 78147:59b4e979ad37 parent: 78148:07ed744a47f6 user: Nick Coghlan date: Tue Jul 17 20:43:40 2012 +1000 summary: Merge Issue #15230 OS X buildbot fix from 3.2 files: Lib/test/test_runpy.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -185,7 +185,7 @@ def _make_pkg(self, source, depth, mod_base="runpy_test"): pkg_name = "__runpy_pkg__" test_fname = mod_base+os.extsep+"py" - pkg_dir = sub_dir = tempfile.mkdtemp() + pkg_dir = sub_dir = os.path.realpath(tempfile.mkdtemp()) if verbose > 1: print(" Package tree in:", sub_dir) sys.path.insert(0, pkg_dir) if verbose > 1: print(" Updated sys.path:", sys.path[0]) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 17 13:10:57 2012 From: python-checkins at python.org (hynek.schlawack) Date: Tue, 17 Jul 2012 13:10:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogIzE1Mzc3OiBNYWtl?= =?utf-8?q?_posixpath=2Ejoin=28=29_more_strict_when_checking_for_str/bytes?= =?utf-8?q?_mix?= Message-ID: <3WbzLn06t9zPJX@mail.python.org> http://hg.python.org/cpython/rev/5553a53a230a changeset: 78150:5553a53a230a branch: 3.2 parent: 78148:07ed744a47f6 user: Hynek Schlawack date: Tue Jul 17 13:05:43 2012 +0200 summary: #15377: Make posixpath.join() more strict when checking for str/bytes mix Based on a patch by Nick Coghlan. files: Lib/posixpath.py | 9 +++++---- Lib/test/test_posixpath.py | 22 +++++++++++++--------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/Lib/posixpath.py b/Lib/posixpath.py --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -83,11 +83,12 @@ else: path += sep + b except TypeError: - strs = [isinstance(s, str) for s in (a, ) + p] - if any(strs) and not all(strs): + valid_types = all(isinstance(s, (str, bytes, bytearray)) + for s in (a, ) + p) + if valid_types: + # Must have a mixture of text and binary data raise TypeError("Can't mix strings and bytes in path components.") - else: - raise + raise return path diff --git a/Lib/test/test_posixpath.py b/Lib/test/test_posixpath.py --- a/Lib/test/test_posixpath.py +++ b/Lib/test/test_posixpath.py @@ -1,6 +1,7 @@ import unittest from test import support, test_genericpath +import itertools import posixpath import os import sys @@ -56,18 +57,21 @@ self.assertEqual(posixpath.join(b"/foo/", b"bar/", b"baz/"), b"/foo/bar/baz/") - # Check for friendly str/bytes mixing message - for args in [[b'bytes', 'str'], - [bytearray(b'bytes'), 'str']]: - for _ in range(2): + def check_error_msg(list_of_args, msg): + """Check posixpath.join raises friendly TypeErrors.""" + for args in (item for perm in list_of_args + for item in itertools.permutations(perm)): with self.assertRaises(TypeError) as cm: posixpath.join(*args) - self.assertEqual( - "Can't mix strings and bytes in path components.", - cm.exception.args[0] - ) - args.reverse() # check both orders + self.assertEqual(msg, cm.exception.args[0]) + check_error_msg([[b'bytes', 'str'], [bytearray(b'bytes'), 'str']], + "Can't mix strings and bytes in path components.") + # regression, see #15377 + with self.assertRaises(TypeError) as cm: + os.path.join(None, 'str') + self.assertNotEqual("Can't mix strings and bytes in path components.", + cm.exception.args[0]) def test_split(self): self.assertEqual(posixpath.split("/foo/bar"), ("/foo", "bar")) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 17 13:10:59 2012 From: python-checkins at python.org (hynek.schlawack) Date: Tue, 17 Jul 2012 13:10:59 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_=2315377=3A_Make_posixpath=2Ejoin=28=29_more_strict_when?= =?utf-8?q?_checking_for_str/bytes_mix?= Message-ID: <3WbzLq4X7qzPJd@mail.python.org> http://hg.python.org/cpython/rev/d087ef80372d changeset: 78151:d087ef80372d parent: 78149:cb7e8ee489a1 parent: 78150:5553a53a230a user: Hynek Schlawack date: Tue Jul 17 13:10:15 2012 +0200 summary: #15377: Make posixpath.join() more strict when checking for str/bytes mix Based on a patch by Nick Coghlan. files: Lib/posixpath.py | 9 +++++---- Lib/test/test_posixpath.py | 22 +++++++++++++--------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/Lib/posixpath.py b/Lib/posixpath.py --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -83,12 +83,13 @@ else: path += sep + b except TypeError: - strs = [isinstance(s, str) for s in (a, ) + p] - if any(strs) and not all(strs): + valid_types = all(isinstance(s, (str, bytes, bytearray)) + for s in (a, ) + p) + if valid_types: + # Must have a mixture of text and binary data raise TypeError("Can't mix strings and bytes in path " "components.") from None - else: - raise + raise return path diff --git a/Lib/test/test_posixpath.py b/Lib/test/test_posixpath.py --- a/Lib/test/test_posixpath.py +++ b/Lib/test/test_posixpath.py @@ -1,3 +1,4 @@ +import itertools import os import posixpath import sys @@ -56,18 +57,21 @@ self.assertEqual(posixpath.join(b"/foo/", b"bar/", b"baz/"), b"/foo/bar/baz/") - # Check for friendly str/bytes mixing message - for args in [[b'bytes', 'str'], - [bytearray(b'bytes'), 'str']]: - for _ in range(2): + def check_error_msg(list_of_args, msg): + """Check posixpath.join raises friendly TypeErrors.""" + for args in (item for perm in list_of_args + for item in itertools.permutations(perm)): with self.assertRaises(TypeError) as cm: posixpath.join(*args) - self.assertEqual( - "Can't mix strings and bytes in path components.", - cm.exception.args[0] - ) - args.reverse() # check both orders + self.assertEqual(msg, cm.exception.args[0]) + check_error_msg([[b'bytes', 'str'], [bytearray(b'bytes'), 'str']], + "Can't mix strings and bytes in path components.") + # regression, see #15377 + with self.assertRaises(TypeError) as cm: + os.path.join(None, 'str') + self.assertNotEqual("Can't mix strings and bytes in path components.", + cm.exception.args[0]) def test_split(self): self.assertEqual(posixpath.split("/foo/bar"), ("/foo", "bar")) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 17 13:25:41 2012 From: python-checkins at python.org (eli.bendersky) Date: Tue, 17 Jul 2012 13:25:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSVNzdWUgIzE0OTg4?= =?utf-8?q?=3A_restore_Python_2=27s_behavior_of_raising_ImportError_when_u?= =?utf-8?q?nable_to?= Message-ID: <3Wbzgn72ckzPJr@mail.python.org> http://hg.python.org/cpython/rev/d896fd0a8ba7 changeset: 78152:d896fd0a8ba7 branch: 3.2 parent: 78142:71537aba3a0a user: Eli Bendersky date: Tue Jul 17 14:20:38 2012 +0300 summary: ISsue #14988: restore Python 2's behavior of raising ImportError when unable to load pyexpat, instead of a SystemError/RuntimeError files: Modules/_elementtree.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -3117,6 +3117,8 @@ expat_capi->MICRO_VERSION != XML_MICRO_VERSION) expat_capi = NULL; } + if (!expat_capi) + return NULL; #endif elementtree_parseerror_obj = PyErr_NewException( -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 17 13:25:44 2012 From: python-checkins at python.org (eli.bendersky) Date: Tue, 17 Jul 2012 13:25:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4yIC0+IDMuMik6?= =?utf-8?q?_merge_heads?= Message-ID: <3Wbzgr0bQ7zPDD@mail.python.org> http://hg.python.org/cpython/rev/9c6e726801cf changeset: 78153:9c6e726801cf branch: 3.2 parent: 78152:d896fd0a8ba7 parent: 78150:5553a53a230a user: Eli Bendersky date: Tue Jul 17 14:22:01 2012 +0300 summary: merge heads files: Lib/posixpath.py | 9 +++++---- Lib/test/test_posixpath.py | 25 ++++++++++++++++--------- Lib/test/test_runpy.py | 2 +- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/Lib/posixpath.py b/Lib/posixpath.py --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -83,11 +83,12 @@ else: path += sep + b except TypeError: - strs = [isinstance(s, str) for s in (a, ) + p] - if any(strs) and not all(strs): + valid_types = all(isinstance(s, (str, bytes, bytearray)) + for s in (a, ) + p) + if valid_types: + # Must have a mixture of text and binary data raise TypeError("Can't mix strings and bytes in path components.") - else: - raise + raise return path diff --git a/Lib/test/test_posixpath.py b/Lib/test/test_posixpath.py --- a/Lib/test/test_posixpath.py +++ b/Lib/test/test_posixpath.py @@ -1,6 +1,7 @@ import unittest from test import support, test_genericpath +import itertools import posixpath import os import sys @@ -56,15 +57,21 @@ self.assertEqual(posixpath.join(b"/foo/", b"bar/", b"baz/"), b"/foo/bar/baz/") - with self.assertRaises(TypeError) as e: - posixpath.join(b'bytes', 'str') - self.assertIn("Can't mix strings and bytes", e.args[0]) - with self.assertRaises(TypeError) as e: - posixpath.join('str', b'bytes') - self.assertIn("Can't mix strings and bytes", e.args[0]) - with self.assertRaises(TypeError) as e: - posixpath.join('str', bytearray(b'bytes')) - self.assertIn("Can't mix strings and bytes", e.args[0]) + def check_error_msg(list_of_args, msg): + """Check posixpath.join raises friendly TypeErrors.""" + for args in (item for perm in list_of_args + for item in itertools.permutations(perm)): + with self.assertRaises(TypeError) as cm: + posixpath.join(*args) + self.assertEqual(msg, cm.exception.args[0]) + + check_error_msg([[b'bytes', 'str'], [bytearray(b'bytes'), 'str']], + "Can't mix strings and bytes in path components.") + # regression, see #15377 + with self.assertRaises(TypeError) as cm: + os.path.join(None, 'str') + self.assertNotEqual("Can't mix strings and bytes in path components.", + cm.exception.args[0]) def test_split(self): self.assertEqual(posixpath.split("/foo/bar"), ("/foo", "bar")) diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -182,7 +182,7 @@ def _make_pkg(self, source, depth, mod_base="runpy_test"): pkg_name = "__runpy_pkg__" test_fname = mod_base+os.extsep+"py" - pkg_dir = sub_dir = tempfile.mkdtemp() + pkg_dir = sub_dir = os.path.realpath(tempfile.mkdtemp()) if verbose > 1: print(" Package tree in:", sub_dir) sys.path.insert(0, pkg_dir) if verbose > 1: print(" Updated sys.path:", sys.path[0]) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 17 13:25:45 2012 From: python-checkins at python.org (eli.bendersky) Date: Tue, 17 Jul 2012 13:25:45 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Merge_for_=2314988?= Message-ID: <3Wbzgs6gZFzPLg@mail.python.org> http://hg.python.org/cpython/rev/c8774ff45733 changeset: 78154:c8774ff45733 parent: 78151:d087ef80372d parent: 78153:9c6e726801cf user: Eli Bendersky date: Tue Jul 17 14:25:14 2012 +0300 summary: Merge for #14988 files: Modules/_elementtree.c | 6 +----- 1 files changed, 1 insertions(+), 5 deletions(-) diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -3514,12 +3514,8 @@ expat_capi = NULL; } } - if (!expat_capi) { - PyErr_SetString( - PyExc_RuntimeError, "cannot load dispatch table from pyexpat" - ); + if (!expat_capi) return NULL; - } elementtree_parseerror_obj = PyErr_NewException( "xml.etree.ElementTree.ParseError", PyExc_SyntaxError, NULL -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 17 13:38:59 2012 From: python-checkins at python.org (nick.coghlan) Date: Tue, 17 Jul 2012 13:38:59 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315314=3A_Tweak_a_?= =?utf-8?q?pkgutil_test_to_hopefully_be_more_Windows_friendly?= Message-ID: <3Wbzz716kZzPKC@mail.python.org> http://hg.python.org/cpython/rev/16e50e85d684 changeset: 78155:16e50e85d684 user: Nick Coghlan date: Tue Jul 17 21:37:58 2012 +1000 summary: Issue #15314: Tweak a pkgutil test to hopefully be more Windows friendly files: Lib/test/test_pkgutil.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_pkgutil.py b/Lib/test/test_pkgutil.py --- a/Lib/test/test_pkgutil.py +++ b/Lib/test/test_pkgutil.py @@ -285,8 +285,9 @@ self.assertEqual(len(w.warnings), 0) def test_get_importer_avoids_emulation(self): + # We use an illegal path so *none* of the path hooks should fire with check_warnings() as w: - self.assertIsNotNone(pkgutil.get_importer(sys.path[0])) + self.assertIsNone(pkgutil.get_importer("*??")) self.assertEqual(len(w.warnings), 0) def test_iter_importers_avoids_emulation(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 17 14:10:20 2012 From: python-checkins at python.org (eli.bendersky) Date: Tue, 17 Jul 2012 14:10:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Optimize_tostringlist_by_t?= =?utf-8?q?aking_the_stream_class_outside_the_function=2E_It=27s_now?= Message-ID: <3Wc0gJ62Z5zPBM@mail.python.org> http://hg.python.org/cpython/rev/51978f89e5ed changeset: 78156:51978f89e5ed user: Eli Bendersky date: Tue Jul 17 15:09:12 2012 +0300 summary: Optimize tostringlist by taking the stream class outside the function. It's now 2x faster on short calls. Related to #1767933 files: Lib/xml/etree/ElementTree.py | 38 +++++++++++++---------- 1 files changed, 22 insertions(+), 16 deletions(-) diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -1184,23 +1184,29 @@ # @defreturn sequence # @since 1.3 +class _ListDataStream(io.BufferedIOBase): + """ An auxiliary stream accumulating into a list reference + """ + def __init__(self, lst): + self.lst = lst + + def writable(self): + return True + + def seekable(self): + return True + + def write(self, b): + self.lst.append(b) + + def tell(self): + return len(self.lst) + def tostringlist(element, encoding=None, method=None): - data = [] - class DataStream(io.BufferedIOBase): - def writable(self): - return True - - def seekable(self): - return True - - def write(self, b): - data.append(b) - - def tell(self): - return len(data) - - ElementTree(element).write(DataStream(), encoding, method=method) - return data + lst = [] + stream = _ListDataStream(lst) + ElementTree(element).write(stream, encoding, method=method) + return lst ## # Writes an element tree or element structure to sys.stdout. This -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 17 14:10:22 2012 From: python-checkins at python.org (eli.bendersky) Date: Tue, 17 Jul 2012 14:10:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_fix_whitespace_woes?= Message-ID: <3Wc0gL1xzQzPFZ@mail.python.org> http://hg.python.org/cpython/rev/63ba0c32b81a changeset: 78157:63ba0c32b81a user: Eli Bendersky date: Tue Jul 17 15:09:56 2012 +0300 summary: fix whitespace woes files: Lib/xml/etree/ElementTree.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -1189,7 +1189,7 @@ """ def __init__(self, lst): self.lst = lst - + def writable(self): return True -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 17 14:30:07 2012 From: python-checkins at python.org (hynek.schlawack) Date: Tue, 17 Jul 2012 14:30:07 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_Use_posixpath?= =?utf-8?q?=2Ejoin=28=29_explicitely_in_posixpath=2Ejoin=28=29_test?= Message-ID: <3Wc16740DQzNR2@mail.python.org> http://hg.python.org/cpython/rev/5470dc81caf9 changeset: 78158:5470dc81caf9 branch: 3.2 parent: 78153:9c6e726801cf user: Hynek Schlawack date: Tue Jul 17 14:28:44 2012 +0200 summary: Use posixpath.join() explicitely in posixpath.join() test Used os.path.join before which has different semantics on Windows. files: Lib/test/test_posixpath.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_posixpath.py b/Lib/test/test_posixpath.py --- a/Lib/test/test_posixpath.py +++ b/Lib/test/test_posixpath.py @@ -69,7 +69,7 @@ "Can't mix strings and bytes in path components.") # regression, see #15377 with self.assertRaises(TypeError) as cm: - os.path.join(None, 'str') + posixpath.join(None, 'str') self.assertNotEqual("Can't mix strings and bytes in path components.", cm.exception.args[0]) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 17 14:30:09 2012 From: python-checkins at python.org (hynek.schlawack) Date: Tue, 17 Jul 2012 14:30:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Use_posixpath=2Ejoin=28=29_explicitely_in_posixpath=2Ejo?= =?utf-8?b?aW4oKSB0ZXN0?= Message-ID: <3Wc1690zL1zNR2@mail.python.org> http://hg.python.org/cpython/rev/fbda36216f24 changeset: 78159:fbda36216f24 parent: 78157:63ba0c32b81a parent: 78158:5470dc81caf9 user: Hynek Schlawack date: Tue Jul 17 14:29:33 2012 +0200 summary: Use posixpath.join() explicitely in posixpath.join() test Used os.path.join before which has different semantics on Windows. files: Lib/test/test_posixpath.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_posixpath.py b/Lib/test/test_posixpath.py --- a/Lib/test/test_posixpath.py +++ b/Lib/test/test_posixpath.py @@ -69,7 +69,7 @@ "Can't mix strings and bytes in path components.") # regression, see #15377 with self.assertRaises(TypeError) as cm: - os.path.join(None, 'str') + posixpath.join(None, 'str') self.assertNotEqual("Can't mix strings and bytes in path components.", cm.exception.args[0]) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 17 18:34:10 2012 From: python-checkins at python.org (vinay.sajip) Date: Tue, 17 Jul 2012 18:34:10 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Closes_=2315307=3A_symlink?= =?utf-8?q?s_now_work_on__OS_X_with_framework_Python_builds=2E_Patch?= Message-ID: <3Wc6Wk6mkSzPPF@mail.python.org> http://hg.python.org/cpython/rev/b79d276041a8 changeset: 78160:b79d276041a8 user: Vinay Sajip date: Tue Jul 17 17:33:46 2012 +0100 summary: Closes #15307: symlinks now work on OS X with framework Python builds. Patch by Ronald Oussoren. files: Doc/library/venv.rst | 2 +- Lib/test/test_venv.py | 52 ++++++++++++++++++++++++------ Lib/venv/__init__.py | 10 +----- Mac/Tools/pythonw.c | 40 ++++++++++++++++++++++- Modules/getpath.c | 16 +++++++-- Modules/main.c | 22 +++++++++++++ 6 files changed, 115 insertions(+), 27 deletions(-) diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -81,7 +81,7 @@ * ``symlinks`` -- a Boolean value indicating whether to attempt to symlink the Python binary (and any necessary DLLs or other binaries, e.g. ``pythonw.exe``), rather than copying. Defaults to ``True`` on Linux and - Unix systems, but ``False`` on Windows and Mac OS X. + Unix systems, but ``False`` on Windows. * ``upgrade`` -- a Boolean value which, if True, will upgrade an existing environment with the running Python - for use when that Python has been diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -154,17 +154,47 @@ """ for usl in (False, True): builder = venv.EnvBuilder(clear=True, symlinks=usl) - if (usl and sys.platform == 'darwin' and - '__PYVENV_LAUNCHER__' in os.environ): - self.assertRaises(ValueError, builder.create, self.env_dir) - else: - builder.create(self.env_dir) - fn = self.get_env_file(self.bindir, self.exe) - # Don't test when False, because e.g. 'python' is always - # symlinked to 'python3.3' in the env, even when symlinking in - # general isn't wanted. - if usl: - self.assertTrue(os.path.islink(fn)) + builder.create(self.env_dir) + fn = self.get_env_file(self.bindir, self.exe) + # Don't test when False, because e.g. 'python' is always + # symlinked to 'python3.3' in the env, even when symlinking in + # general isn't wanted. + if usl: + self.assertTrue(os.path.islink(fn)) + + # If a venv is created from a source build and that venv is used to + # run the test, the pyvenv.cfg in the venv created in the test will + # point to the venv being used to run the test, and we lose the link + # to the source build - so Python can't initialise properly. + @unittest.skipIf(sys.prefix != sys.base_prefix, 'Test not appropriate ' + 'in a venv') + def test_executable(self): + """ + Test that the sys.executable value is as expected. + """ + shutil.rmtree(self.env_dir) + self.run_with_capture(venv.create, self.env_dir) + envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe) + cmd = [envpy, '-c', 'import sys; print(sys.executable)'] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + out, err = p.communicate() + self.assertEqual(out[:-1], envpy.encode()) + + @unittest.skipUnless(can_symlink(), 'Needs symlinks') + def test_executable_symlinks(self): + """ + Test that the sys.executable value is as expected. + """ + shutil.rmtree(self.env_dir) + builder = venv.EnvBuilder(clear=True, symlinks=True) + builder.create(self.env_dir) + envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe) + cmd = [envpy, '-c', 'import sys; print(sys.executable)'] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + out, err = p.communicate() + self.assertEqual(out[:-1], envpy.encode()) def test_main(): run_unittest(BasicTest) diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -82,13 +82,6 @@ :param env_dir: The target directory to create an environment in. """ - if (self.symlinks and - sys.platform == 'darwin' and - sysconfig.get_config_var('PYTHONFRAMEWORK')): - # Symlinking the stub executable in an OSX framework build will - # result in a broken virtual environment. - raise ValueError( - 'Symlinking is not supported on OSX framework Python.') env_dir = os.path.abspath(env_dir) context = self.ensure_directories(env_dir) self.create_configuration(context) @@ -366,8 +359,7 @@ action='store_true', dest='system_site', help='Give the virtual environment access to the ' 'system site-packages dir.') - if os.name == 'nt' or (sys.platform == 'darwin' and - sysconfig.get_config_var('PYTHONFRAMEWORK')): + if os.name == 'nt': use_symlinks = False else: use_symlinks = True diff --git a/Mac/Tools/pythonw.c b/Mac/Tools/pythonw.c --- a/Mac/Tools/pythonw.c +++ b/Mac/Tools/pythonw.c @@ -28,6 +28,7 @@ #include #include #include +#include extern char** environ; @@ -158,9 +159,44 @@ /* Set the original executable path in the environment. */ status = _NSGetExecutablePath(path, &size); if (status == 0) { - if (realpath(path, real_path) != NULL) { - setenv("__PYVENV_LAUNCHER__", real_path, 1); + /* + * Note: don't call 'realpath', that will + * erase symlink information, and that + * breaks "pyvenv --symlink" + * + * It is nice to have the directory name + * as a cleaned up absolute path though, + * therefore call realpath on dirname(path) + */ + char* slash = strrchr(path, '/'); + if (slash) { + char replaced; + replaced = slash[1]; + slash[1] = 0; + if (realpath(path, real_path) == NULL) { + err(1, "realpath: %s", path); + } + slash[1] = replaced; + if (strlcat(real_path, slash, sizeof(real_path)) > sizeof(real_path)) { + errno = EINVAL; + err(1, "realpath: %s", path); + } + + } else { + if (realpath(".", real_path) == NULL) { + err(1, "realpath: %s", path); + } + if (strlcat(real_path, "/", sizeof(real_path)) > sizeof(real_path)) { + errno = EINVAL; + err(1, "realpath: %s", path); + } + if (strlcat(real_path, path, sizeof(real_path)) > sizeof(real_path)) { + errno = EINVAL; + err(1, "realpath: %s", path); + } } + + setenv("__PYVENV_LAUNCHER__", real_path, 1); } /* diff --git a/Modules/getpath.c b/Modules/getpath.c --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -474,6 +474,7 @@ wchar_t *defpath; #ifdef WITH_NEXT_FRAMEWORK NSModule pythonModule; + const char* modPath; #endif #ifdef __APPLE__ #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 @@ -568,8 +569,8 @@ */ pythonModule = NSModuleForSymbol(NSLookupAndBindSymbol("_Py_Initialize")); /* Use dylib functions to find out where the framework was loaded from */ - buf = (wchar_t *)NSLibraryNameForModule(pythonModule); - if (buf != NULL) { + modPath = NSLibraryNameForModule(pythonModule); + if (modPath != NULL) { /* We're in a framework. */ /* See if we might be in the build directory. The framework in the ** build directory is incomplete, it only has the .dylib and a few @@ -578,7 +579,12 @@ ** be running the interpreter in the build directory, so we use the ** build-directory-specific logic to find Lib and such. */ - wcsncpy(argv0_path, buf, MAXPATHLEN); + wchar_t* wbuf = _Py_char2wchar(modPath, NULL); + if (wbuf == NULL) { + Py_FatalError("Cannot decode framework location"); + } + + wcsncpy(argv0_path, wbuf, MAXPATHLEN); reduce(argv0_path); joinpath(argv0_path, lib_python); joinpath(argv0_path, LANDMARK); @@ -589,8 +595,9 @@ } else { /* Use the location of the library as the progpath */ - wcsncpy(argv0_path, buf, MAXPATHLEN); + wcsncpy(argv0_path, wbuf, MAXPATHLEN); } + PyMem_Free(wbuf); } #endif @@ -629,6 +636,7 @@ FILE * env_file = NULL; wcscpy(tmpbuffer, argv0_path); + joinpath(tmpbuffer, env_cfg); env_file = _Py_wfopen(tmpbuffer, L"r"); if (env_file == NULL) { diff --git a/Modules/main.c b/Modules/main.c --- a/Modules/main.c +++ b/Modules/main.c @@ -616,7 +616,29 @@ Py_SetProgramName(buffer); /* buffer is now handed off - do not free */ } else { +#ifdef WITH_NEXT_FRAMEWORK + char* pyvenv_launcher = getenv("__PYVENV_LAUNCHER__"); + + if (pyvenv_launcher && *pyvenv_launcher) { + /* Used by Mac/Tools/pythonw.c to forward + * the argv0 of the stub executable + */ + wchar_t* wbuf = _Py_char2wchar(pyvenv_launcher, NULL); + + if (wbuf == NULL) { + Py_FatalError("Cannot decode __PYVENV_LAUNCHER__"); + } + Py_SetProgramName(wbuf); + + /* Don't free wbuf, the argument to Py_SetProgramName + * must remain valid until the Py_Finalize is called. + */ + } else { + Py_SetProgramName(argv[0]); + } +#else Py_SetProgramName(argv[0]); +#endif } #else Py_SetProgramName(argv[0]); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 18 15:15:12 2012 From: python-checkins at python.org (nick.coghlan) Date: Wed, 18 Jul 2012 15:15:12 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Close_=2315387=3A_inspect?= =?utf-8?q?=2Egetmodulename=28=29_now_uses_a_new?= Message-ID: <3Wcf3h3GZTzPFg@mail.python.org> http://hg.python.org/cpython/rev/af7961e1c362 changeset: 78161:af7961e1c362 user: Nick Coghlan date: Wed Jul 18 23:14:57 2012 +1000 summary: Close #15387: inspect.getmodulename() now uses a new importlib.machinery.all_suffixes() API rather than the deprecated inspect.getmoduleinfo() files: Doc/library/importlib.rst | 13 ++++++++++++- Doc/library/inspect.rst | 15 ++++++++++++--- Lib/importlib/machinery.py | 4 ++++ Lib/inspect.py | 11 +++++++++-- Misc/NEWS | 3 +++ 5 files changed, 40 insertions(+), 6 deletions(-) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -533,12 +533,23 @@ .. attribute:: EXTENSION_SUFFIXES - A list of strings representing the the recognized file suffixes for + A list of strings representing the recognized file suffixes for extension modules. .. versionadded:: 3.3 +.. func:: all_suffixes() + + Returns a combined list of strings representing all file suffixes for + Python modules recognized by the standard import machinery. This is a + helper for code which simply needs to know if a filesystem path + potentially represents a Python module (for example, + :func:`inspect.getmodulename`) + + .. versionadded:: 3.3 + + .. class:: BuiltinImporter An :term:`importer` for built-in modules. All known built-in modules are diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -198,9 +198,18 @@ .. function:: getmodulename(path) Return the name of the module named by the file *path*, without including the - names of enclosing packages. This uses the same algorithm as the interpreter - uses when searching for modules. If the name cannot be matched according to the - interpreter's rules, ``None`` is returned. + names of enclosing packages. The file extension is checked against all of + the entries in :func:`importlib.machinery.all_suffixes`. If it matches, + the final path component is returned with the extension removed. + Otherwise, ``None`` is returned. + + Note that this function *only* returns a meaningful name for actual + Python modules - paths that potentially refer to Python packages will + still return ``None``. + + .. versionchanged:: 3.3 + This function is now based directly on :mod:`importlib` rather than the + deprecated :func:`getmoduleinfo`. .. function:: ismodule(object) diff --git a/Lib/importlib/machinery.py b/Lib/importlib/machinery.py --- a/Lib/importlib/machinery.py +++ b/Lib/importlib/machinery.py @@ -13,3 +13,7 @@ from ._bootstrap import ExtensionFileLoader EXTENSION_SUFFIXES = _imp.extension_suffixes() + +def all_suffixes(): + """Returns a list of all recognized module suffixes for this process""" + return SOURCE_SUFFIXES + BYTECODE_SUFFIXES + EXTENSION_SUFFIXES diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -450,8 +450,15 @@ def getmodulename(path): """Return the module name for a given file, or None.""" - info = getmoduleinfo(path) - if info: return info[0] + fname = os.path.basename(path) + # Check for paths that look like an actual module file + suffixes = [(-len(suffix), suffix) + for suffix in importlib.machinery.all_suffixes()] + suffixes.sort() # try longest suffixes first, in case they overlap + for neglen, suffix in suffixes: + if fname.endswith(suffix): + return fname[:neglen] + return None def getsourcefile(object): """Return the filename that can be used to locate an object's source. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -41,6 +41,9 @@ Library ------- +- Issue #15397: inspect.getmodulename() is now based directly on importlib + via a new importlib.machinery.all_suffixes() API. + - Issue #14635: telnetlib will use poll() rather than select() when possible to avoid failing due to the select() file descriptor limit. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 18 15:59:25 2012 From: python-checkins at python.org (nick.coghlan) Date: Wed, 18 Jul 2012 15:59:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_importlib=2Emachinery?= =?utf-8?q?=2Eall=5Fsuffixes_docs?= Message-ID: <3Wcg2j31dXzP8g@mail.python.org> http://hg.python.org/cpython/rev/11a08c377a3b changeset: 78162:11a08c377a3b user: Nick Coghlan date: Wed Jul 18 23:59:08 2012 +1000 summary: Fix importlib.machinery.all_suffixes docs files: Doc/library/importlib.rst | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -539,13 +539,13 @@ .. versionadded:: 3.3 -.. func:: all_suffixes() +.. function:: all_suffixes() Returns a combined list of strings representing all file suffixes for - Python modules recognized by the standard import machinery. This is a + modules recognized by the standard import machinery. This is a helper for code which simply needs to know if a filesystem path - potentially represents a Python module (for example, - :func:`inspect.getmodulename`) + potentially refers to a module without needing any details on the kind + of module (for example, :func:`inspect.getmodulename`) .. versionadded:: 3.3 -- Repository URL: http://hg.python.org/cpython From jimjjewett at gmail.com Wed Jul 18 18:50:30 2012 From: jimjjewett at gmail.com (Jim Jewett) Date: Wed, 18 Jul 2012 12:50:30 -0400 Subject: [Python-checkins] cpython: Close #15387: inspect.getmodulename() now uses a new In-Reply-To: <3Wcf3h3GZTzPFg@mail.python.org> References: <3Wcf3h3GZTzPFg@mail.python.org> Message-ID: Why is inspect.getmoduleinfo() deprecated? Is it just to remove circular dependencies? FWIW, I much prefer an API like: tell_me_about(object) to one like: for test_data in (X, Y, Z): usable = tester(object, test_data) if valid(usable): return possible_results[test_data] and to me, inspect.getmoduleinfo(path) looks like the first, while checking the various import.machinery.*SUFFIXES looks like the second. -jJ On 7/18/12, nick.coghlan wrote: > http://hg.python.org/cpython/rev/af7961e1c362 > changeset: 78161:af7961e1c362 > user: Nick Coghlan > date: Wed Jul 18 23:14:57 2012 +1000 > summary: > Close #15387: inspect.getmodulename() now uses a new > importlib.machinery.all_suffixes() API rather than the deprecated > inspect.getmoduleinfo() > > files: > Doc/library/importlib.rst | 13 ++++++++++++- > Doc/library/inspect.rst | 15 ++++++++++++--- > Lib/importlib/machinery.py | 4 ++++ > Lib/inspect.py | 11 +++++++++-- > Misc/NEWS | 3 +++ > 5 files changed, 40 insertions(+), 6 deletions(-) > > > diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst > --- a/Doc/library/importlib.rst > +++ b/Doc/library/importlib.rst > @@ -533,12 +533,23 @@ > > .. attribute:: EXTENSION_SUFFIXES > > - A list of strings representing the the recognized file suffixes for > + A list of strings representing the recognized file suffixes for > extension modules. > > .. versionadded:: 3.3 > > > +.. func:: all_suffixes() > + > + Returns a combined list of strings representing all file suffixes for > + Python modules recognized by the standard import machinery. This is a > + helper for code which simply needs to know if a filesystem path > + potentially represents a Python module (for example, > + :func:`inspect.getmodulename`) > + > + .. versionadded:: 3.3 > + > + > .. class:: BuiltinImporter > > An :term:`importer` for built-in modules. All known built-in modules > are > diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst > --- a/Doc/library/inspect.rst > +++ b/Doc/library/inspect.rst > @@ -198,9 +198,18 @@ > .. function:: getmodulename(path) > > Return the name of the module named by the file *path*, without > including the > - names of enclosing packages. This uses the same algorithm as the > interpreter > - uses when searching for modules. If the name cannot be matched > according to the > - interpreter's rules, ``None`` is returned. > + names of enclosing packages. The file extension is checked against all > of > + the entries in :func:`importlib.machinery.all_suffixes`. If it matches, > + the final path component is returned with the extension removed. > + Otherwise, ``None`` is returned. > + > + Note that this function *only* returns a meaningful name for actual > + Python modules - paths that potentially refer to Python packages will > + still return ``None``. > + > + .. versionchanged:: 3.3 > + This function is now based directly on :mod:`importlib` rather than > the > + deprecated :func:`getmoduleinfo`. > > > .. function:: ismodule(object) > diff --git a/Lib/importlib/machinery.py b/Lib/importlib/machinery.py > --- a/Lib/importlib/machinery.py > +++ b/Lib/importlib/machinery.py > @@ -13,3 +13,7 @@ > from ._bootstrap import ExtensionFileLoader > > EXTENSION_SUFFIXES = _imp.extension_suffixes() > + > +def all_suffixes(): > + """Returns a list of all recognized module suffixes for this process""" > + return SOURCE_SUFFIXES + BYTECODE_SUFFIXES + EXTENSION_SUFFIXES > diff --git a/Lib/inspect.py b/Lib/inspect.py > --- a/Lib/inspect.py > +++ b/Lib/inspect.py > @@ -450,8 +450,15 @@ > > def getmodulename(path): > """Return the module name for a given file, or None.""" > - info = getmoduleinfo(path) > - if info: return info[0] > + fname = os.path.basename(path) > + # Check for paths that look like an actual module file > + suffixes = [(-len(suffix), suffix) > + for suffix in importlib.machinery.all_suffixes()] > + suffixes.sort() # try longest suffixes first, in case they overlap > + for neglen, suffix in suffixes: > + if fname.endswith(suffix): > + return fname[:neglen] > + return None > > def getsourcefile(object): > """Return the filename that can be used to locate an object's source. > diff --git a/Misc/NEWS b/Misc/NEWS > --- a/Misc/NEWS > +++ b/Misc/NEWS > @@ -41,6 +41,9 @@ > Library > ------- > > +- Issue #15397: inspect.getmodulename() is now based directly on importlib > + via a new importlib.machinery.all_suffixes() API. > + > - Issue #14635: telnetlib will use poll() rather than select() when > possible > to avoid failing due to the select() file descriptor limit. > > > -- > Repository URL: http://hg.python.org/cpython > From python-checkins at python.org Wed Jul 18 21:29:54 2012 From: python-checkins at python.org (meador.inge) Date: Wed, 18 Jul 2012 21:29:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE1MzY4?= =?utf-8?q?=3A_make_bytecode_generation_deterministic=2E?= Message-ID: <3WcpN213lmzPJf@mail.python.org> http://hg.python.org/cpython/rev/7eb0180c1734 changeset: 78163:7eb0180c1734 branch: 2.7 parent: 78144:227a22288688 user: Meador Inge date: Wed Jul 18 14:09:04 2012 -0500 summary: Issue #15368: make bytecode generation deterministic. files: Misc/NEWS | 5 ++++- Python/compile.c | 24 ++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1,4 +1,4 @@ -Python News +,Python News +++++++++++ What's New in Python 2.7.4 @@ -9,6 +9,9 @@ Core and Builtins ----------------- +- Issue #15368: An issue that caused bytecode generation to be + non-deterministic when using randomized hashing (-R) has been fixed. + - Issue #15033: Fix the exit status bug when modules invoked using -m swith, return the proper failure return value (1). Patch contributed by Jeff Knupp. diff --git a/Python/compile.c b/Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -359,14 +359,31 @@ static PyObject * dictbytype(PyObject *src, int scope_type, int flag, int offset) { - Py_ssize_t pos = 0, i = offset, scope; + Py_ssize_t pos = 0, i = offset, scope, num_keys, key_i; PyObject *k, *v, *dest = PyDict_New(); + PyObject *sorted_keys; assert(offset >= 0); if (dest == NULL) return NULL; - while (PyDict_Next(src, &pos, &k, &v)) { + /* Sort the keys so that we have a deterministic order on the indexes + saved in the returned dictionary. These indexes are used as indexes + into the free and cell var storage. Therefore if they aren't + deterministic, then the generated bytecode is not deterministic. + */ + sorted_keys = PyDict_Keys(src); + if (sorted_keys == NULL) + return NULL; + if (PyList_Sort(sorted_keys) != 0) { + Py_DECREF(sorted_keys); + return NULL; + } + num_keys = PyList_GET_SIZE(src); + + for (key_i = 0; key_i < num_keys; key_i++) { + k = PyList_GET_ITEM(sorted_keys, key_i); + v = PyDict_GetItem(src, k); /* XXX this should probably be a macro in symtable.h */ assert(PyInt_Check(v)); scope = (PyInt_AS_LONG(v) >> SCOPE_OFF) & SCOPE_MASK; @@ -374,12 +391,14 @@ if (scope == scope_type || PyInt_AS_LONG(v) & flag) { PyObject *tuple, *item = PyInt_FromLong(i); if (item == NULL) { + Py_DECREF(sorted_keys); Py_DECREF(dest); return NULL; } i++; tuple = PyTuple_Pack(2, k, k->ob_type); if (!tuple || PyDict_SetItem(dest, tuple, item) < 0) { + Py_DECREF(sorted_keys); Py_DECREF(item); Py_DECREF(dest); Py_XDECREF(tuple); @@ -389,6 +408,7 @@ Py_DECREF(tuple); } } + Py_DECREF(sorted_keys); return dest; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 18 21:29:56 2012 From: python-checkins at python.org (meador.inge) Date: Wed, 18 Jul 2012 21:29:56 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE1MzY4?= =?utf-8?q?=3A_make_bytecode_generation_deterministic=2E?= Message-ID: <3WcpN404m5zPK5@mail.python.org> http://hg.python.org/cpython/rev/79d54fba49b3 changeset: 78164:79d54fba49b3 branch: 3.2 parent: 78158:5470dc81caf9 user: Meador Inge date: Wed Jul 18 14:20:11 2012 -0500 summary: Issue #15368: make bytecode generation deterministic. files: Misc/NEWS | 3 +++ Python/compile.c | 24 ++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #15368: An issue that caused bytecode generation to be + non-deterministic when using randomized hashing (-R) has been fixed. + - Issue #15020: The program name used to search for Python's path is now "python3" under Unix, not "python". diff --git a/Python/compile.c b/Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -367,16 +367,33 @@ static PyObject * dictbytype(PyObject *src, int scope_type, int flag, int offset) { - Py_ssize_t pos = 0, i = offset, scope; + Py_ssize_t pos = 0, i = offset, scope, num_keys, key_i; PyObject *k, *v, *dest = PyDict_New(); + PyObject *sorted_keys; assert(offset >= 0); if (dest == NULL) return NULL; - while (PyDict_Next(src, &pos, &k, &v)) { + /* Sort the keys so that we have a deterministic order on the indexes + saved in the returned dictionary. These indexes are used as indexes + into the free and cell var storage. Therefore if they aren't + deterministic, then the generated bytecode is not deterministic. + */ + sorted_keys = PyDict_Keys(src); + if (sorted_keys == NULL) + return NULL; + if (PyList_Sort(sorted_keys) != 0) { + Py_DECREF(sorted_keys); + return NULL; + } + num_keys = PyList_GET_SIZE(src); + + for (key_i = 0; key_i < num_keys; key_i++) { /* XXX this should probably be a macro in symtable.h */ long vi; + k = PyList_GET_ITEM(sorted_keys, key_i); + v = PyDict_GetItem(src, k); assert(PyLong_Check(v)); vi = PyLong_AS_LONG(v); scope = (vi >> SCOPE_OFFSET) & SCOPE_MASK; @@ -384,12 +401,14 @@ if (scope == scope_type || vi & flag) { PyObject *tuple, *item = PyLong_FromLong(i); if (item == NULL) { + Py_DECREF(sorted_keys); Py_DECREF(dest); return NULL; } i++; tuple = PyTuple_Pack(2, k, k->ob_type); if (!tuple || PyDict_SetItem(dest, tuple, item) < 0) { + Py_DECREF(sorted_keys); Py_DECREF(item); Py_DECREF(dest); Py_XDECREF(tuple); @@ -399,6 +418,7 @@ Py_DECREF(tuple); } } + Py_DECREF(sorted_keys); return dest; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 18 21:29:57 2012 From: python-checkins at python.org (meador.inge) Date: Wed, 18 Jul 2012 21:29:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2315368=3A_make_bytecode_generation_deterministic?= =?utf-8?q?=2E?= Message-ID: <3WcpN54Nq4zPK6@mail.python.org> http://hg.python.org/cpython/rev/578066372485 changeset: 78165:578066372485 parent: 78162:11a08c377a3b parent: 78164:79d54fba49b3 user: Meador Inge date: Wed Jul 18 14:28:55 2012 -0500 summary: Issue #15368: make bytecode generation deterministic. files: Misc/NEWS | 3 +++ Python/compile.c | 24 ++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #15368: An issue that caused bytecode generation to be + non-deterministic has been fixed. + - Issue #15202: Consistently use the name "follow_symlinks" for new parameters in os and shutil functions. diff --git a/Python/compile.c b/Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -397,16 +397,33 @@ static PyObject * dictbytype(PyObject *src, int scope_type, int flag, int offset) { - Py_ssize_t pos = 0, i = offset, scope; + Py_ssize_t pos = 0, i = offset, scope, num_keys, key_i; PyObject *k, *v, *dest = PyDict_New(); + PyObject *sorted_keys; assert(offset >= 0); if (dest == NULL) return NULL; - while (PyDict_Next(src, &pos, &k, &v)) { + /* Sort the keys so that we have a deterministic order on the indexes + saved in the returned dictionary. These indexes are used as indexes + into the free and cell var storage. Therefore if they aren't + deterministic, then the generated bytecode is not deterministic. + */ + sorted_keys = PyDict_Keys(src); + if (sorted_keys == NULL) + return NULL; + if (PyList_Sort(sorted_keys) != 0) { + Py_DECREF(sorted_keys); + return NULL; + } + num_keys = PyList_GET_SIZE(src); + + for (key_i = 0; key_i < num_keys; key_i++) { /* XXX this should probably be a macro in symtable.h */ long vi; + k = PyList_GET_ITEM(sorted_keys, key_i); + v = PyDict_GetItem(src, k); assert(PyLong_Check(v)); vi = PyLong_AS_LONG(v); scope = (vi >> SCOPE_OFFSET) & SCOPE_MASK; @@ -414,12 +431,14 @@ if (scope == scope_type || vi & flag) { PyObject *tuple, *item = PyLong_FromLong(i); if (item == NULL) { + Py_DECREF(sorted_keys); Py_DECREF(dest); return NULL; } i++; tuple = PyTuple_Pack(2, k, k->ob_type); if (!tuple || PyDict_SetItem(dest, tuple, item) < 0) { + Py_DECREF(sorted_keys); Py_DECREF(item); Py_DECREF(dest); Py_XDECREF(tuple); @@ -429,6 +448,7 @@ Py_DECREF(tuple); } } + Py_DECREF(sorted_keys); return dest; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 18 23:51:19 2012 From: python-checkins at python.org (meador.inge) Date: Wed, 18 Jul 2012 23:51:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE1MzY4?= =?utf-8?q?=3A_fixing_variable_typo=2E?= Message-ID: <3WcsWC6TzNzPDV@mail.python.org> http://hg.python.org/cpython/rev/47e074f6ca26 changeset: 78166:47e074f6ca26 branch: 2.7 parent: 78163:7eb0180c1734 user: Meador Inge date: Wed Jul 18 16:32:37 2012 -0500 summary: Issue #15368: fixing variable typo. files: Python/compile.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/compile.c b/Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -379,7 +379,7 @@ Py_DECREF(sorted_keys); return NULL; } - num_keys = PyList_GET_SIZE(src); + num_keys = PyList_GET_SIZE(sorted_keys); for (key_i = 0; key_i < num_keys; key_i++) { k = PyList_GET_ITEM(sorted_keys, key_i); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 18 23:51:21 2012 From: python-checkins at python.org (meador.inge) Date: Wed, 18 Jul 2012 23:51:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE1MzY4?= =?utf-8?q?=3A_fixing_variable_typo=2E?= Message-ID: <3WcsWF4J5ZzPDV@mail.python.org> http://hg.python.org/cpython/rev/1c46f2ede4cb changeset: 78167:1c46f2ede4cb branch: 3.2 parent: 78164:79d54fba49b3 user: Meador Inge date: Wed Jul 18 16:41:03 2012 -0500 summary: Issue #15368: fixing variable typo. files: Python/compile.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/compile.c b/Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -387,7 +387,7 @@ Py_DECREF(sorted_keys); return NULL; } - num_keys = PyList_GET_SIZE(src); + num_keys = PyList_GET_SIZE(sorted_keys); for (key_i = 0; key_i < num_keys; key_i++) { /* XXX this should probably be a macro in symtable.h */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 18 23:51:23 2012 From: python-checkins at python.org (meador.inge) Date: Wed, 18 Jul 2012 23:51:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2315368=3A_fixing_variable_typo=2E?= Message-ID: <3WcsWH1mjhzPMK@mail.python.org> http://hg.python.org/cpython/rev/6502de91610d changeset: 78168:6502de91610d parent: 78165:578066372485 parent: 78167:1c46f2ede4cb user: Meador Inge date: Wed Jul 18 16:49:07 2012 -0500 summary: Issue #15368: fixing variable typo. files: Python/compile.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/compile.c b/Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -417,7 +417,7 @@ Py_DECREF(sorted_keys); return NULL; } - num_keys = PyList_GET_SIZE(src); + num_keys = PyList_GET_SIZE(sorted_keys); for (key_i = 0; key_i < num_keys; key_i++) { /* XXX this should probably be a macro in symtable.h */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 19 00:12:51 2012 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 19 Jul 2012 00:12:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_remove_unused_variable?= Message-ID: <3Wct032sX3zPLx@mail.python.org> http://hg.python.org/cpython/rev/bba20ce29d26 changeset: 78169:bba20ce29d26 user: Benjamin Peterson date: Wed Jul 18 15:12:47 2012 -0700 summary: remove unused variable files: Python/compile.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/compile.c b/Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -397,7 +397,7 @@ static PyObject * dictbytype(PyObject *src, int scope_type, int flag, int offset) { - Py_ssize_t pos = 0, i = offset, scope, num_keys, key_i; + Py_ssize_t i = offset, scope, num_keys, key_i; PyObject *k, *v, *dest = PyDict_New(); PyObject *sorted_keys; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 19 01:10:33 2012 From: python-checkins at python.org (meador.inge) Date: Thu, 19 Jul 2012 01:10:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_remove_unused_?= =?utf-8?q?variable?= Message-ID: <3WcvGd3S7jzPM5@mail.python.org> http://hg.python.org/cpython/rev/9a3861db4341 changeset: 78170:9a3861db4341 branch: 2.7 parent: 78166:47e074f6ca26 user: Meador Inge date: Wed Jul 18 17:48:34 2012 -0500 summary: remove unused variable files: Python/compile.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/compile.c b/Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -359,7 +359,7 @@ static PyObject * dictbytype(PyObject *src, int scope_type, int flag, int offset) { - Py_ssize_t pos = 0, i = offset, scope, num_keys, key_i; + Py_ssize_t i = offset, scope, num_keys, key_i; PyObject *k, *v, *dest = PyDict_New(); PyObject *sorted_keys; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 19 01:10:36 2012 From: python-checkins at python.org (meador.inge) Date: Thu, 19 Jul 2012 01:10:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_remove_unused_?= =?utf-8?q?variable?= Message-ID: <3WcvGh0HCSzPLs@mail.python.org> http://hg.python.org/cpython/rev/1577e66a6642 changeset: 78171:1577e66a6642 branch: 3.2 parent: 78167:1c46f2ede4cb user: Meador Inge date: Wed Jul 18 17:57:46 2012 -0500 summary: remove unused variable files: Python/compile.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/compile.c b/Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -367,7 +367,7 @@ static PyObject * dictbytype(PyObject *src, int scope_type, int flag, int offset) { - Py_ssize_t pos = 0, i = offset, scope, num_keys, key_i; + Py_ssize_t i = offset, scope, num_keys, key_i; PyObject *k, *v, *dest = PyDict_New(); PyObject *sorted_keys; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 19 01:10:37 2012 From: python-checkins at python.org (meador.inge) Date: Thu, 19 Jul 2012 01:10:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_remove_unused_variable?= Message-ID: <3WcvGj3D1SzP7C@mail.python.org> http://hg.python.org/cpython/rev/2b0e4c640ec7 changeset: 78172:2b0e4c640ec7 parent: 78169:bba20ce29d26 parent: 78171:1577e66a6642 user: Meador Inge date: Wed Jul 18 18:08:49 2012 -0500 summary: remove unused variable files: -- Repository URL: http://hg.python.org/cpython From ncoghlan at gmail.com Thu Jul 19 01:31:52 2012 From: ncoghlan at gmail.com (Nick Coghlan) Date: Thu, 19 Jul 2012 09:31:52 +1000 Subject: [Python-checkins] cpython: Close #15387: inspect.getmodulename() now uses a new In-Reply-To: References: <3Wcf3h3GZTzPFg@mail.python.org> Message-ID: Because the concepts it is based on are no longer used internally - determining the kind of module is now the province of importlib's finders and loaders. -- Sent from my phone, thus the relative brevity :) On Jul 19, 2012 2:50 AM, "Jim Jewett" wrote: > Why is inspect.getmoduleinfo() deprecated? Is it just to remove > circular dependencies? > > FWIW, I much prefer an API like: > > tell_me_about(object) > > to one like: > > for test_data in (X, Y, Z): > usable = tester(object, test_data) > if valid(usable): > return possible_results[test_data] > > and to me, inspect.getmoduleinfo(path) looks like the first, while > checking the various import.machinery.*SUFFIXES looks like the second. > > -jJ > > On 7/18/12, nick.coghlan wrote: > > http://hg.python.org/cpython/rev/af7961e1c362 > > changeset: 78161:af7961e1c362 > > user: Nick Coghlan > > date: Wed Jul 18 23:14:57 2012 +1000 > > summary: > > Close #15387: inspect.getmodulename() now uses a new > > importlib.machinery.all_suffixes() API rather than the deprecated > > inspect.getmoduleinfo() > > > > files: > > Doc/library/importlib.rst | 13 ++++++++++++- > > Doc/library/inspect.rst | 15 ++++++++++++--- > > Lib/importlib/machinery.py | 4 ++++ > > Lib/inspect.py | 11 +++++++++-- > > Misc/NEWS | 3 +++ > > 5 files changed, 40 insertions(+), 6 deletions(-) > > > > > > diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst > > --- a/Doc/library/importlib.rst > > +++ b/Doc/library/importlib.rst > > @@ -533,12 +533,23 @@ > > > > .. attribute:: EXTENSION_SUFFIXES > > > > - A list of strings representing the the recognized file suffixes for > > + A list of strings representing the recognized file suffixes for > > extension modules. > > > > .. versionadded:: 3.3 > > > > > > +.. func:: all_suffixes() > > + > > + Returns a combined list of strings representing all file suffixes for > > + Python modules recognized by the standard import machinery. This is a > > + helper for code which simply needs to know if a filesystem path > > + potentially represents a Python module (for example, > > + :func:`inspect.getmodulename`) > > + > > + .. versionadded:: 3.3 > > + > > + > > .. class:: BuiltinImporter > > > > An :term:`importer` for built-in modules. All known built-in modules > > are > > diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst > > --- a/Doc/library/inspect.rst > > +++ b/Doc/library/inspect.rst > > @@ -198,9 +198,18 @@ > > .. function:: getmodulename(path) > > > > Return the name of the module named by the file *path*, without > > including the > > - names of enclosing packages. This uses the same algorithm as the > > interpreter > > - uses when searching for modules. If the name cannot be matched > > according to the > > - interpreter's rules, ``None`` is returned. > > + names of enclosing packages. The file extension is checked against > all > > of > > + the entries in :func:`importlib.machinery.all_suffixes`. If it > matches, > > + the final path component is returned with the extension removed. > > + Otherwise, ``None`` is returned. > > + > > + Note that this function *only* returns a meaningful name for actual > > + Python modules - paths that potentially refer to Python packages will > > + still return ``None``. > > + > > + .. versionchanged:: 3.3 > > + This function is now based directly on :mod:`importlib` rather > than > > the > > + deprecated :func:`getmoduleinfo`. > > > > > > .. function:: ismodule(object) > > diff --git a/Lib/importlib/machinery.py b/Lib/importlib/machinery.py > > --- a/Lib/importlib/machinery.py > > +++ b/Lib/importlib/machinery.py > > @@ -13,3 +13,7 @@ > > from ._bootstrap import ExtensionFileLoader > > > > EXTENSION_SUFFIXES = _imp.extension_suffixes() > > + > > +def all_suffixes(): > > + """Returns a list of all recognized module suffixes for this > process""" > > + return SOURCE_SUFFIXES + BYTECODE_SUFFIXES + EXTENSION_SUFFIXES > > diff --git a/Lib/inspect.py b/Lib/inspect.py > > --- a/Lib/inspect.py > > +++ b/Lib/inspect.py > > @@ -450,8 +450,15 @@ > > > > def getmodulename(path): > > """Return the module name for a given file, or None.""" > > - info = getmoduleinfo(path) > > - if info: return info[0] > > + fname = os.path.basename(path) > > + # Check for paths that look like an actual module file > > + suffixes = [(-len(suffix), suffix) > > + for suffix in importlib.machinery.all_suffixes()] > > + suffixes.sort() # try longest suffixes first, in case they overlap > > + for neglen, suffix in suffixes: > > + if fname.endswith(suffix): > > + return fname[:neglen] > > + return None > > > > def getsourcefile(object): > > """Return the filename that can be used to locate an object's > source. > > diff --git a/Misc/NEWS b/Misc/NEWS > > --- a/Misc/NEWS > > +++ b/Misc/NEWS > > @@ -41,6 +41,9 @@ > > Library > > ------- > > > > +- Issue #15397: inspect.getmodulename() is now based directly on > importlib > > + via a new importlib.machinery.all_suffixes() API. > > + > > - Issue #14635: telnetlib will use poll() rather than select() when > > possible > > to avoid failing due to the select() file descriptor limit. > > > > > > -- > > Repository URL: http://hg.python.org/cpython > > > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > http://mail.python.org/mailman/listinfo/python-checkins > -------------- next part -------------- An HTML attachment was scrubbed... URL: From python-checkins at python.org Thu Jul 19 01:44:26 2012 From: python-checkins at python.org (r.david.murray) Date: Thu, 19 Jul 2012 01:44:26 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogQ2xvc2VzICM5MjU0?= =?utf-8?q?=3A_backport_=5F=5Fimport=5F=5F_docstring/doc_mentions_of_impor?= =?utf-8?q?tlib=2E?= Message-ID: <3Wcw1k6lKbzPGT@mail.python.org> http://hg.python.org/cpython/rev/751f28564a45 changeset: 78173:751f28564a45 branch: 2.7 parent: 78170:9a3861db4341 user: R David Murray date: Wed Jul 18 19:44:08 2012 -0400 summary: Closes #9254: backport __import__ docstring/doc mentions of importlib. Patch by ?ric Araujo. files: Doc/library/functions.rst | 11 ++--------- Python/bltinmodule.c | 8 ++++++-- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1558,7 +1558,7 @@ .. note:: This is an advanced function that is not needed in everyday Python - programming. + programming, unlike :func:`importlib.import_module`. This function is invoked by the :keyword:`import` statement. It can be replaced (by importing the :mod:`__builtin__` module and assigning to @@ -1609,15 +1609,8 @@ names. If you simply want to import a module (potentially within a package) by name, - you can call :func:`__import__` and then look it up in :data:`sys.modules`:: + use :func:`importlib.import_module`. - >>> import sys - >>> name = 'foo.bar.baz' - >>> __import__(name) - - >>> baz = sys.modules[name] - >>> baz - .. versionchanged:: 2.5 The level parameter was added. diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -53,8 +53,12 @@ PyDoc_STRVAR(import_doc, "__import__(name, globals={}, locals={}, fromlist=[], level=-1) -> module\n\ \n\ -Import a module. The globals are only used to determine the context;\n\ -they are not modified. The locals are currently unused. The fromlist\n\ +Import a module. Because this function is meant for use by the Python\n\ +interpreter and not for general use it is better to use\n\ +importlib.import_module() to programmatically import a module.\n\ +\n\ +The globals argument is only used to determine the context;\n\ +they are not modified. The locals argument is unused. The fromlist\n\ should be a list of names to emulate ``from name import ...'', or an\n\ empty list to emulate ``import name''.\n\ When importing a module from a package, note that __import__('A.B', ...)\n\ -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Thu Jul 19 06:03:07 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 19 Jul 2012 06:03:07 +0200 Subject: [Python-checkins] Daily reference leaks (2b0e4c640ec7): sum=0 Message-ID: results for 2b0e4c640ec7 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/refloglEGTBj', '-x'] From python-checkins at python.org Thu Jul 19 07:15:41 2012 From: python-checkins at python.org (meador.inge) Date: Thu, 19 Jul 2012 07:15:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzY0OTM6?= =?utf-8?q?_Fix_handling_of_c=5Fuint32_bitfields_with_width_of_32_on_Windo?= =?utf-8?b?d3Mu?= Message-ID: <3Wd3Mx0Hj9zNwg@mail.python.org> http://hg.python.org/cpython/rev/77401bd4f567 changeset: 78174:77401bd4f567 branch: 2.7 user: Meador Inge date: Wed Jul 18 23:51:05 2012 -0500 summary: Issue #6493: Fix handling of c_uint32 bitfields with width of 32 on Windows. files: Lib/ctypes/test/test_bitfields.py | 20 +++++++ Misc/NEWS | 3 + Modules/_ctypes/cfield.c | 51 ++++++++---------- 3 files changed, 46 insertions(+), 28 deletions(-) diff --git a/Lib/ctypes/test/test_bitfields.py b/Lib/ctypes/test/test_bitfields.py --- a/Lib/ctypes/test/test_bitfields.py +++ b/Lib/ctypes/test/test_bitfields.py @@ -240,5 +240,25 @@ _anonymous_ = ["_"] _fields_ = [("_", X)] + @unittest.skipUnless(hasattr(ctypes, "c_uint32"), "c_int32 is required") + def test_uint32(self): + class X(Structure): + _fields_ = [("a", c_uint32, 32)] + x = X() + x.a = 10 + self.assertEquals(x.a, 10) + x.a = 0xFDCBA987 + self.assertEquals(x.a, 0xFDCBA987) + + @unittest.skipUnless(hasattr(ctypes, "c_uint64"), "c_int64 is required") + def test_uint64(self): + class X(Structure): + _fields_ = [("a", c_uint64, 64)] + x = X() + x.a = 10 + self.assertEquals(x.a, 10) + x.a = 0xFEDCBA9876543211 + self.assertEquals(x.a, 0xFEDCBA9876543211) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -87,6 +87,9 @@ Library ------- +- Issue #6493: An issue in ctypes on Windows that caused structure bitfields + of type ctypes.c_uint32 and width 32 to incorrectly be set has been fixed. + - Issue #14635: telnetlib will use poll() rather than select() when possible to avoid failing due to the select() file descriptor limit. diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -431,12 +431,8 @@ #define LOW_BIT(x) ((x) & 0xFFFF) #define NUM_BITS(x) ((x) >> 16) -/* This seems nore a compiler issue than a Windows/non-Windows one */ -#ifdef MS_WIN32 -# define BIT_MASK(size) ((1 << NUM_BITS(size))-1) -#else -# define BIT_MASK(size) ((1LL << NUM_BITS(size))-1) -#endif +/* Doesn't work if NUM_BITS(size) == 0, but it never happens in SET() call. */ +#define BIT_MASK(type, size) (((((type)1 << (NUM_BITS(size) - 1)) - 1) << 1) + 1) /* This macro CHANGES the first parameter IN PLACE. For proper sign handling, we must first shift left, then right. @@ -448,10 +444,10 @@ } /* This macro RETURNS the first parameter with the bit field CHANGED. */ -#define SET(x, v, size) \ +#define SET(type, x, v, size) \ (NUM_BITS(size) ? \ - ( ( x & ~(BIT_MASK(size) << LOW_BIT(size)) ) | ( (v & BIT_MASK(size)) << LOW_BIT(size) ) ) \ - : v) + ( ( (type)x & ~(BIT_MASK(type, size) << LOW_BIT(size)) ) | ( ((type)v & BIT_MASK(type, size)) << LOW_BIT(size) ) ) \ + : (type)v) /* byte swapping macros */ #define SWAP_2(v) \ @@ -523,7 +519,7 @@ long val; if (get_long(value, &val) < 0) return NULL; - *(signed char *)ptr = (signed char)SET(*(signed char *)ptr, (signed char)val, size); + *(signed char *)ptr = SET(signed char, *(signed char *)ptr, val, size); _RET(value); } @@ -542,8 +538,7 @@ unsigned long val; if (get_ulong(value, &val) < 0) return NULL; - *(unsigned char *)ptr = (unsigned char)SET(*(unsigned char*)ptr, - (unsigned short)val, size); + *(unsigned char *)ptr = SET(unsigned char, *(unsigned char*)ptr, val, size); _RET(value); } @@ -564,7 +559,7 @@ if (get_long(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, (short)val, size); + x = SET(short, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -579,7 +574,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_2(field); - field = SET(field, (short)val, size); + field = SET(short, field, val, size); field = SWAP_2(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -612,7 +607,7 @@ if (get_ulong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, (unsigned short)val, size); + x = SET(unsigned short, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -626,7 +621,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_2(field); - field = SET(field, (unsigned short)val, size); + field = SET(unsigned short, field, val, size); field = SWAP_2(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -660,7 +655,7 @@ if (get_long(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, (int)val, size); + x = SET(int, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -674,7 +669,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_INT(field); - field = SET(field, (int)val, size); + field = SET(int, field, val, size); field = SWAP_INT(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -761,7 +756,7 @@ if (get_ulong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, (unsigned int)val, size); + x = SET(unsigned int, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -774,7 +769,7 @@ if (get_ulong(value, &val) < 0) return NULL; memcpy(&field, ptr, sizeof(field)); - field = (unsigned int)SET(field, (unsigned int)val, size); + field = SET(unsigned int, field, (unsigned int)val, size); field = SWAP_INT(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -808,7 +803,7 @@ if (get_long(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, val, size); + x = SET(long, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -822,7 +817,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_LONG(field); - field = (long)SET(field, val, size); + field = SET(long, field, val, size); field = SWAP_LONG(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -856,7 +851,7 @@ if (get_ulong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, val, size); + x = SET(unsigned long, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -870,7 +865,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_LONG(field); - field = (unsigned long)SET(field, val, size); + field = SET(unsigned long, field, val, size); field = SWAP_LONG(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -905,7 +900,7 @@ if (get_longlong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, val, size); + x = SET(PY_LONG_LONG, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -919,7 +914,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_8(field); - field = (PY_LONG_LONG)SET(field, val, size); + field = SET(PY_LONG_LONG, field, val, size); field = SWAP_8(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -952,7 +947,7 @@ if (get_ulonglong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, val, size); + x = SET(PY_LONG_LONG, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -966,7 +961,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_8(field); - field = (unsigned PY_LONG_LONG)SET(field, val, size); + field = SET(unsigned PY_LONG_LONG, field, val, size); field = SWAP_8(field); memcpy(ptr, &field, sizeof(field)); _RET(value); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 19 07:15:43 2012 From: python-checkins at python.org (meador.inge) Date: Thu, 19 Jul 2012 07:15:43 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzY0OTM6?= =?utf-8?q?_Fix_handling_of_c=5Fuint32_bitfields_with_width_of_32_on_Windo?= =?utf-8?b?d3Mu?= Message-ID: <3Wd3Mz6PD2zPLk@mail.python.org> http://hg.python.org/cpython/rev/153ae76b963e changeset: 78175:153ae76b963e branch: 3.2 parent: 78171:1577e66a6642 user: Meador Inge date: Thu Jul 19 00:01:22 2012 -0500 summary: Issue #6493: Fix handling of c_uint32 bitfields with width of 32 on Windows. files: Lib/ctypes/test/test_bitfields.py | 20 +++++++ Misc/NEWS | 3 + Modules/_ctypes/cfield.c | 51 ++++++++---------- 3 files changed, 46 insertions(+), 28 deletions(-) diff --git a/Lib/ctypes/test/test_bitfields.py b/Lib/ctypes/test/test_bitfields.py --- a/Lib/ctypes/test/test_bitfields.py +++ b/Lib/ctypes/test/test_bitfields.py @@ -240,5 +240,25 @@ _anonymous_ = ["_"] _fields_ = [("_", X)] + @unittest.skipUnless(hasattr(ctypes, "c_uint32"), "c_int32 is required") + def test_uint32(self): + class X(Structure): + _fields_ = [("a", c_uint32, 32)] + x = X() + x.a = 10 + self.assertEquals(x.a, 10) + x.a = 0xFDCBA987 + self.assertEquals(x.a, 0xFDCBA987) + + @unittest.skipUnless(hasattr(ctypes, "c_uint64"), "c_int64 is required") + def test_uint64(self): + class X(Structure): + _fields_ = [("a", c_uint64, 64)] + x = X() + x.a = 10 + self.assertEquals(x.a, 10) + x.a = 0xFEDCBA9876543211 + self.assertEquals(x.a, 0xFEDCBA9876543211) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -340,6 +340,9 @@ Extension Modules ----------------- +- Issue #6493: An issue in ctypes on Windows that caused structure bitfields + of type ctypes.c_uint32 and width 32 to incorrectly be set has been fixed. + - Issue #15000: Support the "unique" x32 architecture in _posixsubprocess.c. - Issue #9041: An issue in ctypes.c_longdouble, ctypes.c_double, and diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -430,12 +430,8 @@ #define LOW_BIT(x) ((x) & 0xFFFF) #define NUM_BITS(x) ((x) >> 16) -/* This seems nore a compiler issue than a Windows/non-Windows one */ -#ifdef MS_WIN32 -# define BIT_MASK(size) ((1 << NUM_BITS(size))-1) -#else -# define BIT_MASK(size) ((1LL << NUM_BITS(size))-1) -#endif +/* Doesn't work if NUM_BITS(size) == 0, but it never happens in SET() call. */ +#define BIT_MASK(type, size) (((((type)1 << (NUM_BITS(size) - 1)) - 1) << 1) + 1) /* This macro CHANGES the first parameter IN PLACE. For proper sign handling, we must first shift left, then right. @@ -447,10 +443,10 @@ } /* This macro RETURNS the first parameter with the bit field CHANGED. */ -#define SET(x, v, size) \ +#define SET(type, x, v, size) \ (NUM_BITS(size) ? \ - ( ( x & ~(BIT_MASK(size) << LOW_BIT(size)) ) | ( (v & BIT_MASK(size)) << LOW_BIT(size) ) ) \ - : v) + ( ( (type)x & ~(BIT_MASK(type, size) << LOW_BIT(size)) ) | ( ((type)v & BIT_MASK(type, size)) << LOW_BIT(size) ) ) \ + : (type)v) /* byte swapping macros */ #define SWAP_2(v) \ @@ -522,7 +518,7 @@ long val; if (get_long(value, &val) < 0) return NULL; - *(signed char *)ptr = (signed char)SET(*(signed char *)ptr, (signed char)val, size); + *(signed char *)ptr = SET(signed char, *(signed char *)ptr, val, size); _RET(value); } @@ -541,8 +537,7 @@ unsigned long val; if (get_ulong(value, &val) < 0) return NULL; - *(unsigned char *)ptr = (unsigned char)SET(*(unsigned char*)ptr, - (unsigned short)val, size); + *(unsigned char *)ptr = SET(unsigned char, *(unsigned char*)ptr, val, size); _RET(value); } @@ -563,7 +558,7 @@ if (get_long(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, (short)val, size); + x = SET(short, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -578,7 +573,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_2(field); - field = SET(field, (short)val, size); + field = SET(short, field, val, size); field = SWAP_2(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -611,7 +606,7 @@ if (get_ulong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, (unsigned short)val, size); + x = SET(unsigned short, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -625,7 +620,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_2(field); - field = SET(field, (unsigned short)val, size); + field = SET(unsigned short, field, val, size); field = SWAP_2(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -659,7 +654,7 @@ if (get_long(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, (int)val, size); + x = SET(int, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -673,7 +668,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_INT(field); - field = SET(field, (int)val, size); + field = SET(int, field, val, size); field = SWAP_INT(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -760,7 +755,7 @@ if (get_ulong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, (unsigned int)val, size); + x = SET(unsigned int, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -773,7 +768,7 @@ if (get_ulong(value, &val) < 0) return NULL; memcpy(&field, ptr, sizeof(field)); - field = (unsigned int)SET(field, (unsigned int)val, size); + field = SET(unsigned int, field, (unsigned int)val, size); field = SWAP_INT(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -807,7 +802,7 @@ if (get_long(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, val, size); + x = SET(long, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -821,7 +816,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_LONG(field); - field = (long)SET(field, val, size); + field = SET(long, field, val, size); field = SWAP_LONG(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -855,7 +850,7 @@ if (get_ulong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, val, size); + x = SET(unsigned long, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -869,7 +864,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_LONG(field); - field = (unsigned long)SET(field, val, size); + field = SET(unsigned long, field, val, size); field = SWAP_LONG(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -904,7 +899,7 @@ if (get_longlong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, val, size); + x = SET(PY_LONG_LONG, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -918,7 +913,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_8(field); - field = (PY_LONG_LONG)SET(field, val, size); + field = SET(PY_LONG_LONG, field, val, size); field = SWAP_8(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -951,7 +946,7 @@ if (get_ulonglong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, val, size); + x = SET(PY_LONG_LONG, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -965,7 +960,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_8(field); - field = (unsigned PY_LONG_LONG)SET(field, val, size); + field = SET(unsigned PY_LONG_LONG, field, val, size); field = SWAP_8(field); memcpy(ptr, &field, sizeof(field)); _RET(value); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 19 07:15:45 2012 From: python-checkins at python.org (meador.inge) Date: Thu, 19 Jul 2012 07:15:45 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Issue_=236493=3A_Fix_handling_of_c=5Fuint32_bitfields_wi?= =?utf-8?q?th_width_of_32_on_Windows=2E?= Message-ID: <3Wd3N14SPnzPMW@mail.python.org> http://hg.python.org/cpython/rev/3fbfa61634de changeset: 78176:3fbfa61634de parent: 78172:2b0e4c640ec7 parent: 78175:153ae76b963e user: Meador Inge date: Thu Jul 19 00:14:35 2012 -0500 summary: Issue #6493: Fix handling of c_uint32 bitfields with width of 32 on Windows. files: Lib/ctypes/test/test_bitfields.py | 20 +++++++ Misc/NEWS | 3 + Modules/_ctypes/cfield.c | 51 ++++++++---------- 3 files changed, 46 insertions(+), 28 deletions(-) diff --git a/Lib/ctypes/test/test_bitfields.py b/Lib/ctypes/test/test_bitfields.py --- a/Lib/ctypes/test/test_bitfields.py +++ b/Lib/ctypes/test/test_bitfields.py @@ -240,5 +240,25 @@ _anonymous_ = ["_"] _fields_ = [("_", X)] + @unittest.skipUnless(hasattr(ctypes, "c_uint32"), "c_int32 is required") + def test_uint32(self): + class X(Structure): + _fields_ = [("a", c_uint32, 32)] + x = X() + x.a = 10 + self.assertEquals(x.a, 10) + x.a = 0xFDCBA987 + self.assertEquals(x.a, 0xFDCBA987) + + @unittest.skipUnless(hasattr(ctypes, "c_uint64"), "c_int64 is required") + def test_uint64(self): + class X(Structure): + _fields_ = [("a", c_uint64, 64)] + x = X() + x.a = 10 + self.assertEquals(x.a, 10) + x.a = 0xFEDCBA9876543211 + self.assertEquals(x.a, 0xFEDCBA9876543211) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -138,6 +138,9 @@ Extension Modules ----------------- +- Issue #6493: An issue in ctypes on Windows that caused structure bitfields + of type ctypes.c_uint32 and width 32 to incorrectly be set has been fixed. + - Issue #15194: Update libffi to the 3.0.11 release. Tools/Demos diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -427,12 +427,8 @@ #define LOW_BIT(x) ((x) & 0xFFFF) #define NUM_BITS(x) ((x) >> 16) -/* This seems nore a compiler issue than a Windows/non-Windows one */ -#ifdef MS_WIN32 -# define BIT_MASK(size) ((1 << NUM_BITS(size))-1) -#else -# define BIT_MASK(size) ((1LL << NUM_BITS(size))-1) -#endif +/* Doesn't work if NUM_BITS(size) == 0, but it never happens in SET() call. */ +#define BIT_MASK(type, size) (((((type)1 << (NUM_BITS(size) - 1)) - 1) << 1) + 1) /* This macro CHANGES the first parameter IN PLACE. For proper sign handling, we must first shift left, then right. @@ -444,10 +440,10 @@ } /* This macro RETURNS the first parameter with the bit field CHANGED. */ -#define SET(x, v, size) \ +#define SET(type, x, v, size) \ (NUM_BITS(size) ? \ - ( ( x & ~(BIT_MASK(size) << LOW_BIT(size)) ) | ( (v & BIT_MASK(size)) << LOW_BIT(size) ) ) \ - : v) + ( ( (type)x & ~(BIT_MASK(type, size) << LOW_BIT(size)) ) | ( ((type)v & BIT_MASK(type, size)) << LOW_BIT(size) ) ) \ + : (type)v) /* byte swapping macros */ #define SWAP_2(v) \ @@ -519,7 +515,7 @@ long val; if (get_long(value, &val) < 0) return NULL; - *(signed char *)ptr = (signed char)SET(*(signed char *)ptr, (signed char)val, size); + *(signed char *)ptr = SET(signed char, *(signed char *)ptr, val, size); _RET(value); } @@ -538,8 +534,7 @@ unsigned long val; if (get_ulong(value, &val) < 0) return NULL; - *(unsigned char *)ptr = (unsigned char)SET(*(unsigned char*)ptr, - (unsigned short)val, size); + *(unsigned char *)ptr = SET(unsigned char, *(unsigned char*)ptr, val, size); _RET(value); } @@ -560,7 +555,7 @@ if (get_long(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, (short)val, size); + x = SET(short, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -575,7 +570,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_2(field); - field = SET(field, (short)val, size); + field = SET(short, field, val, size); field = SWAP_2(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -608,7 +603,7 @@ if (get_ulong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, (unsigned short)val, size); + x = SET(unsigned short, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -622,7 +617,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_2(field); - field = SET(field, (unsigned short)val, size); + field = SET(unsigned short, field, val, size); field = SWAP_2(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -656,7 +651,7 @@ if (get_long(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, (int)val, size); + x = SET(int, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -670,7 +665,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_INT(field); - field = SET(field, (int)val, size); + field = SET(int, field, val, size); field = SWAP_INT(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -757,7 +752,7 @@ if (get_ulong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, (unsigned int)val, size); + x = SET(unsigned int, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -770,7 +765,7 @@ if (get_ulong(value, &val) < 0) return NULL; memcpy(&field, ptr, sizeof(field)); - field = (unsigned int)SET(field, (unsigned int)val, size); + field = SET(unsigned int, field, (unsigned int)val, size); field = SWAP_INT(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -804,7 +799,7 @@ if (get_long(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, val, size); + x = SET(long, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -818,7 +813,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_LONG(field); - field = (long)SET(field, val, size); + field = SET(long, field, val, size); field = SWAP_LONG(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -852,7 +847,7 @@ if (get_ulong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, val, size); + x = SET(unsigned long, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -866,7 +861,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_LONG(field); - field = (unsigned long)SET(field, val, size); + field = SET(unsigned long, field, val, size); field = SWAP_LONG(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -901,7 +896,7 @@ if (get_longlong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, val, size); + x = SET(PY_LONG_LONG, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -915,7 +910,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_8(field); - field = (PY_LONG_LONG)SET(field, val, size); + field = SET(PY_LONG_LONG, field, val, size); field = SWAP_8(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -948,7 +943,7 @@ if (get_ulonglong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, val, size); + x = SET(PY_LONG_LONG, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -962,7 +957,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_8(field); - field = (unsigned PY_LONG_LONG)SET(field, val, size); + field = SET(unsigned PY_LONG_LONG, field, val, size); field = SWAP_8(field); memcpy(ptr, &field, sizeof(field)); _RET(value); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 19 20:26:38 2012 From: python-checkins at python.org (hynek.schlawack) Date: Thu, 19 Jul 2012 20:26:38 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_=231492704=3A_Make_shutil?= =?utf-8?q?=2Ecopyfile=28=29_raise_a_distinct_SameFileError?= Message-ID: <3WdNwZ1F4KzPCr@mail.python.org> http://hg.python.org/cpython/rev/9e94eb39aaad changeset: 78177:9e94eb39aaad user: Hynek Schlawack date: Thu Jul 19 20:23:49 2012 +0200 summary: #1492704: Make shutil.copyfile() raise a distinct SameFileError Patch by Atsuo Ishimoto. files: Doc/library/shutil.rst | 12 +++++++++++- Lib/shutil.py | 8 +++++++- Lib/test/test_shutil.py | 15 ++++++++++++--- Misc/NEWS | 3 +++ 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -52,7 +52,7 @@ Copy the contents (no metadata) of the file named *src* to a file named *dst* and return *dst*. *dst* must be the complete target file name; look at :func:`shutil.copy` for a copy that accepts a target directory path. If - *src* and *dst* are the same files, :exc:`Error` is raised. + *src* and *dst* are the same files, :exc:`SameFileError` is raised. The destination location must be writable; otherwise, an :exc:`OSError` exception will be raised. If *dst* already exists, it will be replaced. Special files @@ -67,6 +67,16 @@ :exc:`IOError` used to be raised instead of :exc:`OSError`. Added *follow_symlinks* argument. Now returns *dst*. + Raise :exc:`SameFileError` instead of :exc:`Error`. + + +.. exception:: SameFileError + + This exception is raised if source and destination in :func:`copyfile` + are the same file. + + .. versionadded:: 3.3 + .. function:: copymode(src, dst, *, follow_symlinks=True) diff --git a/Lib/shutil.py b/Lib/shutil.py --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -42,6 +42,9 @@ class Error(EnvironmentError): pass +class SameFileError(Error): + """Raised when source and destination are the same file.""" + class SpecialFileError(EnvironmentError): """Raised when trying to do a kind of operation (e.g. copying) which is not supported on a special file (e.g. a named pipe)""" @@ -90,7 +93,7 @@ """ if _samefile(src, dst): - raise Error("`%s` and `%s` are the same file" % (src, dst)) + raise SameFileError("{!r} and {!r} are the same file".format(src, dst)) for fn in [src, dst]: try: @@ -215,6 +218,9 @@ If follow_symlinks is false, symlinks won't be followed. This resembles GNU's "cp -P src dst". + If source and destination are the same file, a SameFileError will be + raised. + """ if os.path.isdir(dst): dst = os.path.join(dst, os.path.basename(src)) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -18,7 +18,8 @@ register_archive_format, unregister_archive_format, get_archive_formats, Error, unpack_archive, register_unpack_format, RegistryError, - unregister_unpack_format, get_unpack_formats) + unregister_unpack_format, get_unpack_formats, + SameFileError) import tarfile import warnings @@ -688,7 +689,7 @@ with open(src, 'w') as f: f.write('cheddar') os.link(src, dst) - self.assertRaises(shutil.Error, shutil.copyfile, src, dst) + self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst) with open(src, 'r') as f: self.assertEqual(f.read(), 'cheddar') os.remove(dst) @@ -708,7 +709,7 @@ # to TESTFN/TESTFN/cheese, while it should point at # TESTFN/cheese. os.symlink('cheese', dst) - self.assertRaises(shutil.Error, shutil.copyfile, src, dst) + self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst) with open(src, 'r') as f: self.assertEqual(f.read(), 'cheddar') os.remove(dst) @@ -1215,6 +1216,14 @@ self.assertTrue(os.path.exists(rv)) self.assertEqual(read_file(src_file), read_file(dst_file)) + def test_copyfile_same_file(self): + # copyfile() should raise SameFileError if the source and destination + # are the same. + src_dir = self.mkdtemp() + src_file = os.path.join(src_dir, 'foo') + write_file(src_file, 'foo') + self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file) + def test_copytree_return_value(self): # copytree returns its destination path. src_dir = self.mkdtemp() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -44,6 +44,9 @@ Library ------- +- Issue #1492704: shutil.copyfile() raises a distinct SameFileError now if + source and destination are the same file. Patch by Atsuo Ishimoto. + - Issue #15397: inspect.getmodulename() is now based directly on importlib via a new importlib.machinery.all_suffixes() API. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 19 20:52:41 2012 From: python-checkins at python.org (meador.inge) Date: Thu, 19 Jul 2012 20:52:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE1Mzk0?= =?utf-8?q?=3A_Fix_ref_leaks_in_PyModule=5FCreate=2E?= Message-ID: <3WdPVd4xwFzPMk@mail.python.org> http://hg.python.org/cpython/rev/7140d97d36fd changeset: 78178:7140d97d36fd branch: 3.2 parent: 78175:153ae76b963e user: Meador Inge date: Thu Jul 19 13:45:43 2012 -0500 summary: Issue #15394: Fix ref leaks in PyModule_Create. Patch by Julia Lawall. files: Misc/ACKS | 1 + Misc/NEWS | 3 +++ Objects/moduleobject.c | 8 +++++++- 3 files changed, 11 insertions(+), 1 deletions(-) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -542,6 +542,7 @@ Piers Lauder Ben Laurie Simon Law +Julia Lawall Chris Lawrence Brian Leair James Lee diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #15394: An issue in PyModule_Create that caused references to + be leaked on some error paths has been fixed. Patch by Julia Lawall. + - Issue #15368: An issue that caused bytecode generation to be non-deterministic when using randomized hashing (-R) has been fixed. diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -117,8 +117,10 @@ d = PyModule_GetDict((PyObject*)m); if (module->m_methods != NULL) { n = PyUnicode_FromString(name); - if (n == NULL) + if (n == NULL) { + Py_DECREF(m); return NULL; + } for (ml = module->m_methods; ml->ml_name != NULL; ml++) { if ((ml->ml_flags & METH_CLASS) || (ml->ml_flags & METH_STATIC)) { @@ -126,16 +128,19 @@ "module functions cannot set" " METH_CLASS or METH_STATIC"); Py_DECREF(n); + Py_DECREF(m); return NULL; } v = PyCFunction_NewEx(ml, (PyObject*)m, n); if (v == NULL) { Py_DECREF(n); + Py_DECREF(m); return NULL; } if (PyDict_SetItemString(d, ml->ml_name, v) != 0) { Py_DECREF(v); Py_DECREF(n); + Py_DECREF(m); return NULL; } Py_DECREF(v); @@ -146,6 +151,7 @@ v = PyUnicode_FromString(module->m_doc); if (v == NULL || PyDict_SetItemString(d, "__doc__", v) != 0) { Py_XDECREF(v); + Py_DECREF(m); return NULL; } Py_DECREF(v); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 19 20:52:43 2012 From: python-checkins at python.org (meador.inge) Date: Thu, 19 Jul 2012 20:52:43 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2315394=3A_Fix_ref_leaks_in_PyModule=5FCreate=2E?= Message-ID: <3WdPVg2Wr2zP31@mail.python.org> http://hg.python.org/cpython/rev/571777bf5527 changeset: 78179:571777bf5527 parent: 78177:9e94eb39aaad parent: 78178:7140d97d36fd user: Meador Inge date: Thu Jul 19 13:51:59 2012 -0500 summary: Issue #15394: Fix ref leaks in PyModule_Create. Patch by Julia Lawall. files: Misc/ACKS | 1 + Misc/NEWS | 3 +++ Objects/moduleobject.c | 8 +++++++- 3 files changed, 11 insertions(+), 1 deletions(-) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -601,6 +601,7 @@ Piers Lauder Ben Laurie Simon Law +Julia Lawall Chris Lawrence Brian Leair Mathieu Leduc-Hamel diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #15394: An issue in PyModule_Create that caused references to + be leaked on some error paths has been fixed. Patch by Julia Lawall. + - Issue #15368: An issue that caused bytecode generation to be non-deterministic has been fixed. diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -126,8 +126,10 @@ d = PyModule_GetDict((PyObject*)m); if (module->m_methods != NULL) { n = PyUnicode_FromString(name); - if (n == NULL) + if (n == NULL) { + Py_DECREF(m); return NULL; + } for (ml = module->m_methods; ml->ml_name != NULL; ml++) { if ((ml->ml_flags & METH_CLASS) || (ml->ml_flags & METH_STATIC)) { @@ -135,16 +137,19 @@ "module functions cannot set" " METH_CLASS or METH_STATIC"); Py_DECREF(n); + Py_DECREF(m); return NULL; } v = PyCFunction_NewEx(ml, (PyObject*)m, n); if (v == NULL) { Py_DECREF(n); + Py_DECREF(m); return NULL; } if (PyDict_SetItemString(d, ml->ml_name, v) != 0) { Py_DECREF(v); Py_DECREF(n); + Py_DECREF(m); return NULL; } Py_DECREF(v); @@ -155,6 +160,7 @@ v = PyUnicode_FromString(module->m_doc); if (v == NULL || PyDict_SetItemString(d, "__doc__", v) != 0) { Py_XDECREF(v); + Py_DECREF(m); return NULL; } Py_DECREF(v); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 19 21:19:10 2012 From: python-checkins at python.org (jesus.cea) Date: Thu, 19 Jul 2012 21:19:10 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogQ2xvc2VzICMxNTM5?= =?utf-8?q?6=3A_memory_leak_in_tkinter?= Message-ID: <3WdQ5B4HGVzNwj@mail.python.org> http://hg.python.org/cpython/rev/b584c58c2286 changeset: 78180:b584c58c2286 branch: 3.2 parent: 78178:7140d97d36fd user: Jesus Cea date: Thu Jul 19 21:18:07 2012 +0200 summary: Closes #15396: memory leak in tkinter files: Doc/ACKS.txt | 1 + Modules/_tkinter.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Doc/ACKS.txt b/Doc/ACKS.txt --- a/Doc/ACKS.txt +++ b/Doc/ACKS.txt @@ -120,6 +120,7 @@ * Thomas Lamb * Detlef Lannert * Piers Lauder + * Julia Lawall * Glyph Lefkowitz * Robert Lehmann * Marc-Andr? Lemburg diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -3135,8 +3135,10 @@ PyDict_SetItemString(d, "TkappType", (PyObject *)&Tkapp_Type); - if (PyType_Ready(&Tktt_Type) < 0) + if (PyType_Ready(&Tktt_Type) < 0) { + Py_DECREF(m); return NULL; + } PyDict_SetItemString(d, "TkttType", (PyObject *)&Tktt_Type); Py_TYPE(&PyTclObject_Type) = &PyType_Type; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 19 21:19:12 2012 From: python-checkins at python.org (jesus.cea) Date: Thu, 19 Jul 2012 21:19:12 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_MERGE=3A_Closes_=2315396=3A_memory_leak_in_tkinter?= Message-ID: <3WdQ5D1xPGzP7K@mail.python.org> http://hg.python.org/cpython/rev/b2dac78db1c9 changeset: 78181:b2dac78db1c9 parent: 78179:571777bf5527 parent: 78180:b584c58c2286 user: Jesus Cea date: Thu Jul 19 21:18:45 2012 +0200 summary: MERGE: Closes #15396: memory leak in tkinter files: Doc/ACKS.txt | 1 + Modules/_tkinter.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Doc/ACKS.txt b/Doc/ACKS.txt --- a/Doc/ACKS.txt +++ b/Doc/ACKS.txt @@ -121,6 +121,7 @@ * Thomas Lamb * Detlef Lannert * Piers Lauder + * Julia Lawall * Glyph Lefkowitz * Robert Lehmann * Marc-Andr? Lemburg diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -3133,8 +3133,10 @@ PyDict_SetItemString(d, "TkappType", (PyObject *)&Tkapp_Type); - if (PyType_Ready(&Tktt_Type) < 0) + if (PyType_Ready(&Tktt_Type) < 0) { + Py_DECREF(m); return NULL; + } PyDict_SetItemString(d, "TkttType", (PyObject *)&Tktt_Type); Py_TYPE(&PyTclObject_Type) = &PyType_Type; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 19 21:33:20 2012 From: python-checkins at python.org (jesus.cea) Date: Thu, 19 Jul 2012 21:33:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogQ2xvc2VzICMxNTM5?= =?utf-8?q?5=3A_memory_leaks_in_selectmodule=2Ec?= Message-ID: <3WdQPX5dx7zPMx@mail.python.org> http://hg.python.org/cpython/rev/bc9b2956bb8b changeset: 78182:bc9b2956bb8b branch: 3.2 parent: 78180:b584c58c2286 user: Jesus Cea date: Thu Jul 19 21:31:26 2012 +0200 summary: Closes #15395: memory leaks in selectmodule.c files: Modules/selectmodule.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -101,7 +101,7 @@ /* any intervening fileno() calls could decr this refcnt */ if (!(o = PySequence_Fast_GET_ITEM(fast_seq, i))) - return -1; + goto finally; Py_INCREF(o); v = PyObject_AsFileDescriptor( o ); @@ -421,6 +421,7 @@ if (PyDict_GetItem(self->dict, key) == NULL) { errno = ENOENT; PyErr_SetFromErrno(PyExc_IOError); + Py_DECREF(key); return NULL; } value = PyLong_FromLong(events); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 19 21:33:22 2012 From: python-checkins at python.org (jesus.cea) Date: Thu, 19 Jul 2012 21:33:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_MERGE=3A_Closes_=2315395=3A_memory_leaks_in_selectmodule?= =?utf-8?q?=2Ec?= Message-ID: <3WdQPZ2FGDzPNY@mail.python.org> http://hg.python.org/cpython/rev/9985b4651436 changeset: 78183:9985b4651436 parent: 78181:b2dac78db1c9 parent: 78182:bc9b2956bb8b user: Jesus Cea date: Thu Jul 19 21:32:07 2012 +0200 summary: MERGE: Closes #15395: memory leaks in selectmodule.c files: Modules/selectmodule.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -107,7 +107,7 @@ /* any intervening fileno() calls could decr this refcnt */ if (!(o = PySequence_Fast_GET_ITEM(fast_seq, i))) - return -1; + goto finally; Py_INCREF(o); v = PyObject_AsFileDescriptor( o ); @@ -438,6 +438,7 @@ if (PyDict_GetItem(self->dict, key) == NULL) { errno = ENOENT; PyErr_SetFromErrno(PyExc_OSError); + Py_DECREF(key); return NULL; } value = PyLong_FromLong(events); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 19 21:43:40 2012 From: python-checkins at python.org (hynek.schlawack) Date: Thu, 19 Jul 2012 21:43:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_=231492704=3A_Backout_and_?= =?utf-8?q?wait_for_3=2E4?= Message-ID: <3WdQdS3bZzzM9v@mail.python.org> http://hg.python.org/cpython/rev/3adb4ee4b794 changeset: 78184:3adb4ee4b794 user: Hynek Schlawack date: Thu Jul 19 21:41:02 2012 +0200 summary: #1492704: Backout and wait for 3.4 files: Doc/library/shutil.rst | 12 +----------- Lib/shutil.py | 8 +------- Lib/test/test_shutil.py | 15 +++------------ Misc/NEWS | 3 --- 4 files changed, 5 insertions(+), 33 deletions(-) diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -52,7 +52,7 @@ Copy the contents (no metadata) of the file named *src* to a file named *dst* and return *dst*. *dst* must be the complete target file name; look at :func:`shutil.copy` for a copy that accepts a target directory path. If - *src* and *dst* are the same files, :exc:`SameFileError` is raised. + *src* and *dst* are the same files, :exc:`Error` is raised. The destination location must be writable; otherwise, an :exc:`OSError` exception will be raised. If *dst* already exists, it will be replaced. Special files @@ -67,16 +67,6 @@ :exc:`IOError` used to be raised instead of :exc:`OSError`. Added *follow_symlinks* argument. Now returns *dst*. - Raise :exc:`SameFileError` instead of :exc:`Error`. - - -.. exception:: SameFileError - - This exception is raised if source and destination in :func:`copyfile` - are the same file. - - .. versionadded:: 3.3 - .. function:: copymode(src, dst, *, follow_symlinks=True) diff --git a/Lib/shutil.py b/Lib/shutil.py --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -42,9 +42,6 @@ class Error(EnvironmentError): pass -class SameFileError(Error): - """Raised when source and destination are the same file.""" - class SpecialFileError(EnvironmentError): """Raised when trying to do a kind of operation (e.g. copying) which is not supported on a special file (e.g. a named pipe)""" @@ -93,7 +90,7 @@ """ if _samefile(src, dst): - raise SameFileError("{!r} and {!r} are the same file".format(src, dst)) + raise Error("`%s` and `%s` are the same file" % (src, dst)) for fn in [src, dst]: try: @@ -218,9 +215,6 @@ If follow_symlinks is false, symlinks won't be followed. This resembles GNU's "cp -P src dst". - If source and destination are the same file, a SameFileError will be - raised. - """ if os.path.isdir(dst): dst = os.path.join(dst, os.path.basename(src)) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -18,8 +18,7 @@ register_archive_format, unregister_archive_format, get_archive_formats, Error, unpack_archive, register_unpack_format, RegistryError, - unregister_unpack_format, get_unpack_formats, - SameFileError) + unregister_unpack_format, get_unpack_formats) import tarfile import warnings @@ -689,7 +688,7 @@ with open(src, 'w') as f: f.write('cheddar') os.link(src, dst) - self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst) + self.assertRaises(shutil.Error, shutil.copyfile, src, dst) with open(src, 'r') as f: self.assertEqual(f.read(), 'cheddar') os.remove(dst) @@ -709,7 +708,7 @@ # to TESTFN/TESTFN/cheese, while it should point at # TESTFN/cheese. os.symlink('cheese', dst) - self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst) + self.assertRaises(shutil.Error, shutil.copyfile, src, dst) with open(src, 'r') as f: self.assertEqual(f.read(), 'cheddar') os.remove(dst) @@ -1216,14 +1215,6 @@ self.assertTrue(os.path.exists(rv)) self.assertEqual(read_file(src_file), read_file(dst_file)) - def test_copyfile_same_file(self): - # copyfile() should raise SameFileError if the source and destination - # are the same. - src_dir = self.mkdtemp() - src_file = os.path.join(src_dir, 'foo') - write_file(src_file, 'foo') - self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file) - def test_copytree_return_value(self): # copytree returns its destination path. src_dir = self.mkdtemp() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -47,9 +47,6 @@ Library ------- -- Issue #1492704: shutil.copyfile() raises a distinct SameFileError now if - source and destination are the same file. Patch by Atsuo Ishimoto. - - Issue #15397: inspect.getmodulename() is now based directly on importlib via a new importlib.machinery.all_suffixes() API. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 19 23:02:59 2012 From: python-checkins at python.org (kristjan.jonsson) Date: Thu, 19 Jul 2012 23:02:59 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315365=3A__Make_tr?= =?utf-8?q?aceback_reporting_ignore_any_errors_when_printing_out?= Message-ID: <3WdSNz3QWLzNwg@mail.python.org> http://hg.python.org/cpython/rev/54524897fafc changeset: 78185:54524897fafc user: Kristj?n Valur J?nsson date: Thu Jul 19 21:02:03 2012 +0000 summary: Issue #15365: Make traceback reporting ignore any errors when printing out the source line. Such errors can't be reported anyway. This makes error reporting work, even if the "io" module can't be loaded. files: Python/traceback.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Python/traceback.c b/Python/traceback.c --- a/Python/traceback.c +++ b/Python/traceback.c @@ -344,7 +344,10 @@ Py_DECREF(line); if (err != 0) return err; - return _Py_DisplaySourceLine(f, filename, lineno, 4); + /* ignore errors since we can't report them, can we? */ + if (_Py_DisplaySourceLine(f, filename, lineno, 4)) + PyErr_Clear(); + return err; } static int -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 20 04:33:57 2012 From: python-checkins at python.org (meador.inge) Date: Fri, 20 Jul 2012 04:33:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315401=3A_Fix_typo?= =?utf-8?q?_in_inspect=2Egetclosurevars_docstring=2E?= Message-ID: <3Wdbks494xzPBM@mail.python.org> http://hg.python.org/cpython/rev/abc26b51fbfc changeset: 78186:abc26b51fbfc user: Meador Inge date: Thu Jul 19 21:33:21 2012 -0500 summary: Issue #15401: Fix typo in inspect.getclosurevars docstring. files: Lib/inspect.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1050,7 +1050,7 @@ """ Get the mapping of free variables to their current values. - Returns a named tuple of dics mapping the current nonlocal, global + Returns a named tuple of dicts mapping the current nonlocal, global and builtin references as seen by the body of the function. A final set of unbound names that could not be resolved is also provided. """ -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri Jul 20 06:02:07 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 20 Jul 2012 06:02:07 +0200 Subject: [Python-checkins] Daily reference leaks (54524897fafc): sum=0 Message-ID: results for 54524897fafc on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog21Fk0k', '-x'] From python-checkins at python.org Fri Jul 20 10:51:36 2012 From: python-checkins at python.org (vinay.sajip) Date: Fri, 20 Jul 2012 10:51:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE1Mzk5?= =?utf-8?q?=3A_Added_versionchanged_for_processName=2E?= Message-ID: <3Wdm6c0Cs8zPP7@mail.python.org> http://hg.python.org/cpython/rev/204be25f24bd changeset: 78187:204be25f24bd branch: 2.7 parent: 78174:77401bd4f567 user: Vinay Sajip date: Fri Jul 20 09:48:46 2012 +0100 summary: Issue #15399: Added versionchanged for processName. files: Doc/library/logging.rst | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -629,6 +629,9 @@ .. versionchanged:: 2.5 *funcName* was added. +.. versionchanged:: 2.6 + *processName* was added. + .. _logger-adapter: LoggerAdapter Objects -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 20 10:51:37 2012 From: python-checkins at python.org (vinay.sajip) Date: Fri, 20 Jul 2012 10:51:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE1Mzk5?= =?utf-8?q?=3A_Added_versionchanged_for_processName=2E?= Message-ID: <3Wdm6d4zzVzPPS@mail.python.org> http://hg.python.org/cpython/rev/6b771075cfa3 changeset: 78188:6b771075cfa3 branch: 3.2 parent: 78182:bc9b2956bb8b user: Vinay Sajip date: Fri Jul 20 09:50:18 2012 +0100 summary: Issue #15399: Added versionchanged for processName. files: Doc/library/logging.rst | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -730,6 +730,9 @@ | threadName | ``%(threadName)s`` | Thread name (if available). | +----------------+-------------------------+-----------------------------------------------+ +.. versionchanged:: 3.1 + *processName* was added. + .. _logger-adapter: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 20 10:51:39 2012 From: python-checkins at python.org (vinay.sajip) Date: Fri, 20 Jul 2012 10:51:39 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Closes_=2315399=3A_merged_documentation_fix_from_3=2E2?= =?utf-8?q?=2E?= Message-ID: <3Wdm6g1nkWzPPM@mail.python.org> http://hg.python.org/cpython/rev/4b5e8f7d1ac4 changeset: 78189:4b5e8f7d1ac4 parent: 78186:abc26b51fbfc parent: 78188:6b771075cfa3 user: Vinay Sajip date: Fri Jul 20 09:51:20 2012 +0100 summary: Closes #15399: merged documentation fix from 3.2. files: Doc/library/logging.rst | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -746,6 +746,9 @@ | threadName | ``%(threadName)s`` | Thread name (if available). | +----------------+-------------------------+-----------------------------------------------+ +.. versionchanged:: 3.1 + *processName* was added. + .. _logger-adapter: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 20 12:35:36 2012 From: python-checkins at python.org (stefan.krah) Date: Fri, 20 Jul 2012 12:35:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_Visual_Studio_warning?= =?utf-8?q?=2E?= Message-ID: <3WdpQc585gzPPr@mail.python.org> http://hg.python.org/cpython/rev/8563cdf83bb9 changeset: 78190:8563cdf83bb9 user: Stefan Krah date: Fri Jul 20 12:34:18 2012 +0200 summary: Fix Visual Studio warning. files: Modules/_decimal/libmpdec/mpdecimal.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_decimal/libmpdec/mpdecimal.c b/Modules/_decimal/libmpdec/mpdecimal.c --- a/Modules/_decimal/libmpdec/mpdecimal.c +++ b/Modules/_decimal/libmpdec/mpdecimal.c @@ -7540,7 +7540,7 @@ ideal_exp += shift; } else { - int lsd = mpd_lsd(result->data[0]); + int lsd = (int)mpd_lsd(result->data[0]); if (lsd == 0 || lsd == 5) { result->data[0] += 1; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 20 13:57:54 2012 From: python-checkins at python.org (andrew.svetlov) Date: Fri, 20 Jul 2012 13:57:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE1NDA0?= =?utf-8?q?=3A_Refleak_in_PyMethodObject_repr=2E?= Message-ID: <3WdrFZ2xcNzPH6@mail.python.org> http://hg.python.org/cpython/rev/4b724884c81f changeset: 78191:4b724884c81f branch: 3.2 parent: 78188:6b771075cfa3 user: Andrew Svetlov date: Fri Jul 20 14:51:45 2012 +0300 summary: Issue #15404: Refleak in PyMethodObject repr. files: Misc/NEWS | 2 ++ Objects/classobject.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #15404: Refleak in PyMethodObject repr. + - Issue #15394: An issue in PyModule_Create that caused references to be leaked on some error paths has been fixed. Patch by Julia Lawall. diff --git a/Objects/classobject.c b/Objects/classobject.c --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -243,8 +243,10 @@ else { klassname = PyObject_GetAttrString(klass, "__name__"); if (klassname == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { + Py_XDECREF(funcname); return NULL; + } PyErr_Clear(); } else if (!PyUnicode_Check(klassname)) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 20 13:57:57 2012 From: python-checkins at python.org (andrew.svetlov) Date: Fri, 20 Jul 2012 13:57:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy4y?= Message-ID: <3WdrFd3CNjzPH6@mail.python.org> http://hg.python.org/cpython/rev/dc75d5b4bb9c changeset: 78192:dc75d5b4bb9c parent: 78189:4b5e8f7d1ac4 parent: 78191:4b724884c81f user: Andrew Svetlov date: Fri Jul 20 14:52:54 2012 +0300 summary: Merge 3.2 files: Misc/NEWS | 2 ++ Objects/classobject.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #15404: Refleak in PyMethodObject repr. + - Issue #15394: An issue in PyModule_Create that caused references to be leaked on some error paths has been fixed. Patch by Julia Lawall. diff --git a/Objects/classobject.c b/Objects/classobject.c --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -244,8 +244,10 @@ else { klassname = _PyObject_GetAttrId(klass, &PyId___name__); if (klassname == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { + Py_XDECREF(funcname); return NULL; + } PyErr_Clear(); } else if (!PyUnicode_Check(klassname)) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 20 13:58:00 2012 From: python-checkins at python.org (andrew.svetlov) Date: Fri, 20 Jul 2012 13:58:00 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge_heads?= Message-ID: <3WdrFh66Q0zPNt@mail.python.org> http://hg.python.org/cpython/rev/870112887ceb changeset: 78193:870112887ceb parent: 78192:dc75d5b4bb9c parent: 78190:8563cdf83bb9 user: Andrew Svetlov date: Fri Jul 20 14:55:20 2012 +0300 summary: Merge heads files: Modules/_decimal/libmpdec/mpdecimal.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_decimal/libmpdec/mpdecimal.c b/Modules/_decimal/libmpdec/mpdecimal.c --- a/Modules/_decimal/libmpdec/mpdecimal.c +++ b/Modules/_decimal/libmpdec/mpdecimal.c @@ -7540,7 +7540,7 @@ ideal_exp += shift; } else { - int lsd = mpd_lsd(result->data[0]); + int lsd = (int)mpd_lsd(result->data[0]); if (lsd == 0 || lsd == 5) { result->data[0] += 1; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 20 14:41:55 2012 From: python-checkins at python.org (ronald.oussoren) Date: Fri, 20 Jul 2012 14:41:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Add_missing_NEWS_entry_for?= =?utf-8?q?_changeset_b79d276041a8?= Message-ID: <3WdsDM09L2zPFh@mail.python.org> http://hg.python.org/cpython/rev/02bc229c5278 changeset: 78194:02bc229c5278 user: Ronald Oussoren date: Fri Jul 20 14:41:06 2012 +0200 summary: Add missing NEWS entry for changeset b79d276041a8 files: Misc/NEWS | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -45,6 +45,9 @@ - Issue #15229: An OSError subclass whose __init__ doesn't call back OSError.__init__ could produce incomplete instances, leading to crashes when calling str() on them. + +- Issue 15307: Virtual environments now use symlinks with framework builds + on Mac OS X, like other POSIX builds. Library ------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 20 15:40:20 2012 From: python-checkins at python.org (nick.coghlan) Date: Fri, 20 Jul 2012 15:40:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Close_=2315386=3A_There_wa?= =?utf-8?q?s_a_loophole_that_meant_importlib=2Emachinery_and_imp_would?= Message-ID: <3WdtWm3PTfzPMT@mail.python.org> http://hg.python.org/cpython/rev/4431dc4bb770 changeset: 78195:4431dc4bb770 user: Nick Coghlan date: Fri Jul 20 23:40:09 2012 +1000 summary: Close #15386: There was a loophole that meant importlib.machinery and imp would sometimes reference an uninitialised copy of importlib._bootstrap files: Lib/importlib/__init__.py | 13 +++++++++++-- Lib/pkgutil.py | 2 +- Lib/runpy.py | 2 +- Lib/test/regrtest.py | 3 +++ Lib/test/test_import.py | 12 +++++++++++- 5 files changed, 27 insertions(+), 5 deletions(-) diff --git a/Lib/importlib/__init__.py b/Lib/importlib/__init__.py --- a/Lib/importlib/__init__.py +++ b/Lib/importlib/__init__.py @@ -2,14 +2,21 @@ __all__ = ['__import__', 'import_module', 'invalidate_caches'] # Bootstrap help ##################################################### -import imp + +# Until bootstrapping is complete, DO NOT import any modules that attempt +# to import importlib._bootstrap (directly or indirectly). Since this +# partially initialised package would be present in sys.modules, those +# modules would get an uninitialised copy of the source version, instead +# of a fully initialised version (either the frozen one or the one +# initialised below if the frozen one is not available). +import _imp # Just the builtin component, NOT the full Python module import sys try: import _frozen_importlib as _bootstrap except ImportError: from . import _bootstrap - _bootstrap._setup(sys, imp) + _bootstrap._setup(sys, _imp) else: # importlib._bootstrap is the built-in import, ensure we don't create # a second copy of the module. @@ -22,6 +29,8 @@ _w_long = _bootstrap._w_long _r_long = _bootstrap._r_long +# Fully bootstrapped at this point, import whatever you like, circular +# dependencies and startup overhead minimisation permitting :) # Public API ######################################################### diff --git a/Lib/pkgutil.py b/Lib/pkgutil.py --- a/Lib/pkgutil.py +++ b/Lib/pkgutil.py @@ -2,8 +2,8 @@ import os import sys +import importlib import imp -import importlib import os.path from warnings import warn from types import ModuleType diff --git a/Lib/runpy.py b/Lib/runpy.py --- a/Lib/runpy.py +++ b/Lib/runpy.py @@ -12,8 +12,8 @@ import os import sys +import importlib.machinery # importlib first so we can test #15386 via -m import imp -import importlib.machinery from pkgutil import read_code, get_loader, get_importer __all__ = [ diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -165,6 +165,9 @@ option '-uall,-gui'. """ +# We import importlib *ASAP* in order to test #15386 +import importlib + import builtins import faulthandler import getopt diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -1,8 +1,9 @@ +# We import importlib *ASAP* in order to test #15386 +import importlib import builtins import imp from importlib.test.import_ import test_suite as importlib_import_test_suite from importlib.test.import_ import util as importlib_util -import importlib import marshal import os import platform @@ -777,6 +778,15 @@ self.assertEqual(mod.__package__, 'importlib') self.assertTrue(mod.__file__.endswith('_bootstrap.py'), mod.__file__) + def test_there_can_be_only_one(self): + # Issue #15386 revealed a tricky loophole in the bootstrapping + # This test is technically redundant, since the bug caused importing + # this test module to crash completely, but it helps prove the point + from importlib import machinery + mod = sys.modules['_frozen_importlib'] + self.assertIs(machinery.FileFinder, mod.FileFinder) + self.assertIs(imp.new_module, mod.new_module) + class ImportTracebackTests(unittest.TestCase): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 20 19:55:13 2012 From: python-checkins at python.org (meador.inge) Date: Fri, 20 Jul 2012 19:55:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE1NDA2?= =?utf-8?q?=3A_Fix_deprecation_warning_in_ctypes_test=5Fbitfields=2Epy?= Message-ID: <3Wf09s5hF3zP0W@mail.python.org> http://hg.python.org/cpython/rev/fb181698775d changeset: 78196:fb181698775d branch: 3.2 parent: 78191:4b724884c81f user: Meador Inge date: Fri Jul 20 12:48:34 2012 -0500 summary: Issue #15406: Fix deprecation warning in ctypes test_bitfields.py Patch by Fl?vio Ribeiro. files: Lib/ctypes/test/test_bitfields.py | 8 ++++---- Misc/ACKS | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Lib/ctypes/test/test_bitfields.py b/Lib/ctypes/test/test_bitfields.py --- a/Lib/ctypes/test/test_bitfields.py +++ b/Lib/ctypes/test/test_bitfields.py @@ -246,9 +246,9 @@ _fields_ = [("a", c_uint32, 32)] x = X() x.a = 10 - self.assertEquals(x.a, 10) + self.assertEqual(x.a, 10) x.a = 0xFDCBA987 - self.assertEquals(x.a, 0xFDCBA987) + self.assertEqual(x.a, 0xFDCBA987) @unittest.skipUnless(hasattr(ctypes, "c_uint64"), "c_int64 is required") def test_uint64(self): @@ -256,9 +256,9 @@ _fields_ = [("a", c_uint64, 64)] x = X() x.a = 10 - self.assertEquals(x.a, 10) + self.assertEqual(x.a, 10) x.a = 0xFEDCBA9876543211 - self.assertEquals(x.a, 0xFEDCBA9876543211) + self.assertEqual(x.a, 0xFEDCBA9876543211) if __name__ == "__main__": unittest.main() diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -778,6 +778,7 @@ Bernhard Reiter Steven Reiz Roeland Rengelink +Fl?vio Ribeiro Tim Rice Francesco Ricciardi Jan Pieter Riegel -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 20 19:55:15 2012 From: python-checkins at python.org (meador.inge) Date: Fri, 20 Jul 2012 19:55:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2315406=3A_Fix_deprecation_warning_in_ctypes_test?= =?utf-8?q?=5Fbitfields=2Epy?= Message-ID: <3Wf09v31g6zPPp@mail.python.org> http://hg.python.org/cpython/rev/f93efd4c45bd changeset: 78197:f93efd4c45bd parent: 78195:4431dc4bb770 parent: 78196:fb181698775d user: Meador Inge date: Fri Jul 20 12:52:42 2012 -0500 summary: Issue #15406: Fix deprecation warning in ctypes test_bitfields.py Patch by Fl?vio Ribeiro. files: Lib/ctypes/test/test_bitfields.py | 8 ++++---- Misc/ACKS | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Lib/ctypes/test/test_bitfields.py b/Lib/ctypes/test/test_bitfields.py --- a/Lib/ctypes/test/test_bitfields.py +++ b/Lib/ctypes/test/test_bitfields.py @@ -246,9 +246,9 @@ _fields_ = [("a", c_uint32, 32)] x = X() x.a = 10 - self.assertEquals(x.a, 10) + self.assertEqual(x.a, 10) x.a = 0xFDCBA987 - self.assertEquals(x.a, 0xFDCBA987) + self.assertEqual(x.a, 0xFDCBA987) @unittest.skipUnless(hasattr(ctypes, "c_uint64"), "c_int64 is required") def test_uint64(self): @@ -256,9 +256,9 @@ _fields_ = [("a", c_uint64, 64)] x = X() x.a = 10 - self.assertEquals(x.a, 10) + self.assertEqual(x.a, 10) x.a = 0xFEDCBA9876543211 - self.assertEquals(x.a, 0xFEDCBA9876543211) + self.assertEqual(x.a, 0xFEDCBA9876543211) if __name__ == "__main__": unittest.main() diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -866,6 +866,7 @@ Steven Reiz Roeland Rengelink Antoine Reversat +Fl?vio Ribeiro Francesco Ricciardi Tim Rice Jan Pieter Riegel -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 20 20:22:35 2012 From: python-checkins at python.org (brett.cannon) Date: Fri, 20 Jul 2012 20:22:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Running_the_importlib_test?= =?utf-8?q?s_from_test=5Fimport_is_redundant_as_there_is?= Message-ID: <3Wf0nR2gd4zPNS@mail.python.org> http://hg.python.org/cpython/rev/2719a077f03d changeset: 78198:2719a077f03d parent: 78195:4431dc4bb770 user: Brett Cannon date: Fri Jul 20 14:01:34 2012 -0400 summary: Running the importlib tests from test_import is redundant as there is no difference anymore between __import__ and importlib.__import__. files: Lib/test/test_import.py | 19 ++++++------------- 1 files changed, 6 insertions(+), 13 deletions(-) diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -2,7 +2,6 @@ import importlib import builtins import imp -from importlib.test.import_ import test_suite as importlib_import_test_suite from importlib.test.import_ import util as importlib_util import marshal import os @@ -881,18 +880,12 @@ def test_main(verbose=None): - flag = importlib_util.using___import__ - try: - importlib_util.using___import__ = True - run_unittest(ImportTests, PycacheTests, - PycRewritingTests, PathsTests, RelativeImportTests, - OverridingImportBuiltinTests, - ImportlibBootstrapTests, - TestSymbolicallyLinkedPackage, - ImportTracebackTests, - importlib_import_test_suite()) - finally: - importlib_util.using___import__ = flag + run_unittest(ImportTests, PycacheTests, + PycRewritingTests, PathsTests, RelativeImportTests, + OverridingImportBuiltinTests, + ImportlibBootstrapTests, + TestSymbolicallyLinkedPackage, + ImportTracebackTests) if __name__ == '__main__': -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 20 20:22:37 2012 From: python-checkins at python.org (brett.cannon) Date: Fri, 20 Jul 2012 20:22:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315091=3A_Call_imp?= =?utf-8?q?ortlib=2Einvalidate=5Fcaches=28=29_and_reactivate_a_test?= Message-ID: <3Wf0nT259czPPy@mail.python.org> http://hg.python.org/cpython/rev/721b701feb4a changeset: 78199:721b701feb4a user: Brett Cannon date: Fri Jul 20 14:22:04 2012 -0400 summary: Issue #15091: Call importlib.invalidate_caches() and reactivate a test of importing a symlinked package. files: Lib/test/test_import.py | 42 ++++++++++------------------ Misc/NEWS | 5 ++- 2 files changed, 19 insertions(+), 28 deletions(-) diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -704,36 +704,34 @@ class TestSymbolicallyLinkedPackage(unittest.TestCase): package_name = 'sample' + tagged = package_name + '-tagged' def setUp(self): - if os.path.exists(self.tagged): - shutil.rmtree(self.tagged) - if os.path.exists(self.package_name): - os.remove(self.package_name) + test.support.rmtree(self.tagged) + test.support.rmtree(self.package_name) self.orig_sys_path = sys.path[:] # create a sample package; imagine you have a package with a tag and # you want to symbolically link it from its untagged name. os.mkdir(self.tagged) + self.addCleanup(test.support.rmtree, self.tagged) init_file = os.path.join(self.tagged, '__init__.py') - open(init_file, 'w').close() - self.assertEqual(os.path.exists(init_file), True) + test.support.create_empty_file(init_file) + assert os.path.exists(init_file) # now create a symlink to the tagged package # sample -> sample-tagged os.symlink(self.tagged, self.package_name) + self.addCleanup(test.support.unlink, self.package_name) + importlib.invalidate_caches() # disabled because os.isdir currently fails (see issue 15093) # self.assertEqual(os.path.isdir(self.package_name), True) - self.assertEqual( - os.path.isfile(os.path.join(self.package_name, '__init__.py')), - True, - ) + assert os.path.isfile(os.path.join(self.package_name, '__init__.py')) - @property - def tagged(self): - return self.package_name + '-tagged' + def tearDown(self): + sys.path[:] = self.orig_sys_path # regression test for issue6727 @unittest.skipUnless( @@ -741,24 +739,14 @@ or sys.getwindowsversion() >= (6, 0), "Windows Vista or later required") @test.support.skip_unless_symlink - @unittest.skipUnless( - sys.platform == 'win32', - "Test failing on Unix (see issue15091)" - ) def test_symlinked_dir_importable(self): # make sure sample can only be imported from the current directory. sys.path[:] = ['.'] + assert os.path.exists(self.package_name) + assert os.path.exists(os.path.join(self.package_name, '__init__.py')) - # and try to import the package - __import__(self.package_name) - - def tearDown(self): - # now cleanup - if os.path.exists(self.package_name): - os.remove(self.package_name) - if os.path.exists(self.tagged): - shutil.rmtree(self.tagged) - sys.path[:] = self.orig_sys_path + # Try to import the package + importlib.import_module(self.package_name) @cpython_only diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -181,7 +181,10 @@ Tests ----- -- Issue #15230: Adopted a more systematic approach in the runpy tests +- Issue #15091: Reactivate a test on UNIX which was failing thanks to a + forgotten importlib.invalidate_caches() call. + +- Issue #15230: Adopted a more systematic approach in the runpy tests. - Issue #15300: Ensure the temporary test working directories are in the same parent folder when running tests in multiprocess mode from a Python build. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 20 20:22:38 2012 From: python-checkins at python.org (brett.cannon) Date: Fri, 20 Jul 2012 20:22:38 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge?= Message-ID: <3Wf0nV5KpTzPPy@mail.python.org> http://hg.python.org/cpython/rev/3c59edd377f6 changeset: 78200:3c59edd377f6 parent: 78199:721b701feb4a parent: 78197:f93efd4c45bd user: Brett Cannon date: Fri Jul 20 14:22:27 2012 -0400 summary: Merge files: Lib/ctypes/test/test_bitfields.py | 8 ++++---- Misc/ACKS | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Lib/ctypes/test/test_bitfields.py b/Lib/ctypes/test/test_bitfields.py --- a/Lib/ctypes/test/test_bitfields.py +++ b/Lib/ctypes/test/test_bitfields.py @@ -246,9 +246,9 @@ _fields_ = [("a", c_uint32, 32)] x = X() x.a = 10 - self.assertEquals(x.a, 10) + self.assertEqual(x.a, 10) x.a = 0xFDCBA987 - self.assertEquals(x.a, 0xFDCBA987) + self.assertEqual(x.a, 0xFDCBA987) @unittest.skipUnless(hasattr(ctypes, "c_uint64"), "c_int64 is required") def test_uint64(self): @@ -256,9 +256,9 @@ _fields_ = [("a", c_uint64, 64)] x = X() x.a = 10 - self.assertEquals(x.a, 10) + self.assertEqual(x.a, 10) x.a = 0xFEDCBA9876543211 - self.assertEquals(x.a, 0xFEDCBA9876543211) + self.assertEqual(x.a, 0xFEDCBA9876543211) if __name__ == "__main__": unittest.main() diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -866,6 +866,7 @@ Steven Reiz Roeland Rengelink Antoine Reversat +Fl?vio Ribeiro Francesco Ricciardi Tim Rice Jan Pieter Riegel -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 20 20:49:03 2012 From: python-checkins at python.org (brett.cannon) Date: Fri, 20 Jul 2012 20:49:03 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315168=3A_Move_imp?= =?utf-8?q?ortlb=2Etest_to_test=2Etest=5Fimportlib=2E?= Message-ID: <3Wf1Mz3DGzzPPy@mail.python.org> http://hg.python.org/cpython/rev/4cebcfc97774 changeset: 78201:4cebcfc97774 user: Brett Cannon date: Fri Jul 20 14:48:53 2012 -0400 summary: Issue #15168: Move importlb.test to test.test_importlib. This should make the Linux distros happy as it is now easier to leave importlib's tests out of their base Python distribution. files: Lib/test/test_importlib.py | 5 -- Lib/importlib/test/__init__.py | 8 +++ Lib/importlib/test/__main__.py | 12 +----- Lib/importlib/test/abc.py | 0 Lib/importlib/test/benchmark.py | 0 Lib/importlib/test/builtin/__init__.py | 4 +- Lib/importlib/test/builtin/test_finder.py | 0 Lib/importlib/test/builtin/test_loader.py | 0 Lib/importlib/test/builtin/util.py | 0 Lib/importlib/test/extension/__init__.py | 4 +- Lib/importlib/test/extension/test_case_sensitivity.py | 0 Lib/importlib/test/extension/test_finder.py | 0 Lib/importlib/test/extension/test_loader.py | 0 Lib/importlib/test/extension/test_path_hook.py | 0 Lib/importlib/test/extension/util.py | 0 Lib/importlib/test/frozen/__init__.py | 4 +- Lib/importlib/test/frozen/test_finder.py | 2 +- Lib/importlib/test/frozen/test_loader.py | 0 Lib/importlib/test/import_/__init__.py | 4 +- Lib/importlib/test/import_/test___package__.py | 0 Lib/importlib/test/import_/test_api.py | 0 Lib/importlib/test/import_/test_caching.py | 0 Lib/importlib/test/import_/test_fromlist.py | 0 Lib/importlib/test/import_/test_meta_path.py | 0 Lib/importlib/test/import_/test_packages.py | 0 Lib/importlib/test/import_/test_path.py | 0 Lib/importlib/test/import_/test_relative_imports.py | 0 Lib/importlib/test/import_/util.py | 0 Lib/importlib/test/regrtest.py | 0 Lib/importlib/test/source/__init__.py | 4 +- Lib/importlib/test/source/test_abc_loader.py | 0 Lib/importlib/test/source/test_case_sensitivity.py | 0 Lib/importlib/test/source/test_file_loader.py | 22 +++++----- Lib/importlib/test/source/test_finder.py | 0 Lib/importlib/test/source/test_path_hook.py | 0 Lib/importlib/test/source/test_source_encoding.py | 0 Lib/importlib/test/source/util.py | 0 Lib/importlib/test/test_abc.py | 0 Lib/importlib/test/test_api.py | 0 Lib/importlib/test/test_locks.py | 0 Lib/importlib/test/test_util.py | 0 Lib/importlib/test/util.py | 0 Misc/NEWS | 2 + 43 files changed, 33 insertions(+), 38 deletions(-) diff --git a/Lib/test/test_importlib.py b/Lib/test/test_importlib.py deleted file mode 100644 --- a/Lib/test/test_importlib.py +++ /dev/null @@ -1,5 +0,0 @@ -from importlib.test.__main__ import test_main - - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/__init__.py b/Lib/test/test_importlib/__init__.py rename from Lib/importlib/test/__init__.py rename to Lib/test/test_importlib/__init__.py --- a/Lib/importlib/test/__init__.py +++ b/Lib/test/test_importlib/__init__.py @@ -1,5 +1,6 @@ import os import sys +from .. import support import unittest def test_suite(package=__package__, directory=os.path.dirname(__file__)): @@ -23,3 +24,10 @@ else: continue return suite + + +def test_main(): + start_dir = os.path.dirname(__file__) + top_dir = os.path.dirname(os.path.dirname(start_dir)) + test_loader = unittest.TestLoader() + support.run_unittest(test_loader.discover(start_dir, top_level_dir=top_dir)) diff --git a/Lib/importlib/test/__main__.py b/Lib/test/test_importlib/__main__.py rename from Lib/importlib/test/__main__.py rename to Lib/test/test_importlib/__main__.py --- a/Lib/importlib/test/__main__.py +++ b/Lib/test/test_importlib/__main__.py @@ -4,17 +4,7 @@ builtins.__import__ instead of importlib.__import__. """ -from importlib.test.import_ import util -import os.path -from test.support import run_unittest -import unittest - - -def test_main(): - start_dir = os.path.dirname(__file__) - top_dir = os.path.dirname(os.path.dirname(start_dir)) - test_loader = unittest.TestLoader() - run_unittest(test_loader.discover(start_dir, top_level_dir=top_dir)) +from . import test_main if __name__ == '__main__': diff --git a/Lib/importlib/test/abc.py b/Lib/test/test_importlib/abc.py rename from Lib/importlib/test/abc.py rename to Lib/test/test_importlib/abc.py diff --git a/Lib/importlib/test/benchmark.py b/Lib/test/test_importlib/benchmark.py rename from Lib/importlib/test/benchmark.py rename to Lib/test/test_importlib/benchmark.py diff --git a/Lib/importlib/test/builtin/__init__.py b/Lib/test/test_importlib/builtin/__init__.py rename from Lib/importlib/test/builtin/__init__.py rename to Lib/test/test_importlib/builtin/__init__.py --- a/Lib/importlib/test/builtin/__init__.py +++ b/Lib/test/test_importlib/builtin/__init__.py @@ -1,10 +1,10 @@ -import importlib.test +from .. import test_suite import os def test_suite(): directory = os.path.dirname(__file__) - return importlib.test.test_suite('importlib.test.builtin', directory) + return test_suite('importlib.test.builtin', directory) if __name__ == '__main__': diff --git a/Lib/importlib/test/builtin/test_finder.py b/Lib/test/test_importlib/builtin/test_finder.py rename from Lib/importlib/test/builtin/test_finder.py rename to Lib/test/test_importlib/builtin/test_finder.py diff --git a/Lib/importlib/test/builtin/test_loader.py b/Lib/test/test_importlib/builtin/test_loader.py rename from Lib/importlib/test/builtin/test_loader.py rename to Lib/test/test_importlib/builtin/test_loader.py diff --git a/Lib/importlib/test/builtin/util.py b/Lib/test/test_importlib/builtin/util.py rename from Lib/importlib/test/builtin/util.py rename to Lib/test/test_importlib/builtin/util.py diff --git a/Lib/importlib/test/extension/__init__.py b/Lib/test/test_importlib/extension/__init__.py rename from Lib/importlib/test/extension/__init__.py rename to Lib/test/test_importlib/extension/__init__.py --- a/Lib/importlib/test/extension/__init__.py +++ b/Lib/test/test_importlib/extension/__init__.py @@ -1,11 +1,11 @@ -import importlib.test +from .. import test_suite import os.path import unittest def test_suite(): directory = os.path.dirname(__file__) - return importlib.test.test_suite('importlib.test.extension', directory) + return test_suite('importlib.test.extension', directory) if __name__ == '__main__': diff --git a/Lib/importlib/test/extension/test_case_sensitivity.py b/Lib/test/test_importlib/extension/test_case_sensitivity.py rename from Lib/importlib/test/extension/test_case_sensitivity.py rename to Lib/test/test_importlib/extension/test_case_sensitivity.py diff --git a/Lib/importlib/test/extension/test_finder.py b/Lib/test/test_importlib/extension/test_finder.py rename from Lib/importlib/test/extension/test_finder.py rename to Lib/test/test_importlib/extension/test_finder.py diff --git a/Lib/importlib/test/extension/test_loader.py b/Lib/test/test_importlib/extension/test_loader.py rename from Lib/importlib/test/extension/test_loader.py rename to Lib/test/test_importlib/extension/test_loader.py diff --git a/Lib/importlib/test/extension/test_path_hook.py b/Lib/test/test_importlib/extension/test_path_hook.py rename from Lib/importlib/test/extension/test_path_hook.py rename to Lib/test/test_importlib/extension/test_path_hook.py diff --git a/Lib/importlib/test/extension/util.py b/Lib/test/test_importlib/extension/util.py rename from Lib/importlib/test/extension/util.py rename to Lib/test/test_importlib/extension/util.py diff --git a/Lib/importlib/test/frozen/__init__.py b/Lib/test/test_importlib/frozen/__init__.py rename from Lib/importlib/test/frozen/__init__.py rename to Lib/test/test_importlib/frozen/__init__.py --- a/Lib/importlib/test/frozen/__init__.py +++ b/Lib/test/test_importlib/frozen/__init__.py @@ -1,11 +1,11 @@ -import importlib.test +from .. import test_suite import os.path import unittest def test_suite(): directory = os.path.dirname(__file__) - return importlib.test.test_suite('importlib.test.frozen', directory) + return test_suite('importlib.test.frozen', directory) if __name__ == '__main__': diff --git a/Lib/importlib/test/frozen/test_finder.py b/Lib/test/test_importlib/frozen/test_finder.py rename from Lib/importlib/test/frozen/test_finder.py rename to Lib/test/test_importlib/frozen/test_finder.py --- a/Lib/importlib/test/frozen/test_finder.py +++ b/Lib/test/test_importlib/frozen/test_finder.py @@ -1,4 +1,4 @@ -from ... import machinery +from importlib import machinery from .. import abc import unittest diff --git a/Lib/importlib/test/frozen/test_loader.py b/Lib/test/test_importlib/frozen/test_loader.py rename from Lib/importlib/test/frozen/test_loader.py rename to Lib/test/test_importlib/frozen/test_loader.py diff --git a/Lib/importlib/test/import_/__init__.py b/Lib/test/test_importlib/import_/__init__.py rename from Lib/importlib/test/import_/__init__.py rename to Lib/test/test_importlib/import_/__init__.py --- a/Lib/importlib/test/import_/__init__.py +++ b/Lib/test/test_importlib/import_/__init__.py @@ -1,11 +1,11 @@ -import importlib.test +from .. import test_suite import os.path import unittest def test_suite(): directory = os.path.dirname(__file__) - return importlib.test.test_suite('importlib.test.import_', directory) + return test_suite('importlib.test.import_', directory) if __name__ == '__main__': diff --git a/Lib/importlib/test/import_/test___package__.py b/Lib/test/test_importlib/import_/test___package__.py rename from Lib/importlib/test/import_/test___package__.py rename to Lib/test/test_importlib/import_/test___package__.py diff --git a/Lib/importlib/test/import_/test_api.py b/Lib/test/test_importlib/import_/test_api.py rename from Lib/importlib/test/import_/test_api.py rename to Lib/test/test_importlib/import_/test_api.py diff --git a/Lib/importlib/test/import_/test_caching.py b/Lib/test/test_importlib/import_/test_caching.py rename from Lib/importlib/test/import_/test_caching.py rename to Lib/test/test_importlib/import_/test_caching.py diff --git a/Lib/importlib/test/import_/test_fromlist.py b/Lib/test/test_importlib/import_/test_fromlist.py rename from Lib/importlib/test/import_/test_fromlist.py rename to Lib/test/test_importlib/import_/test_fromlist.py diff --git a/Lib/importlib/test/import_/test_meta_path.py b/Lib/test/test_importlib/import_/test_meta_path.py rename from Lib/importlib/test/import_/test_meta_path.py rename to Lib/test/test_importlib/import_/test_meta_path.py diff --git a/Lib/importlib/test/import_/test_packages.py b/Lib/test/test_importlib/import_/test_packages.py rename from Lib/importlib/test/import_/test_packages.py rename to Lib/test/test_importlib/import_/test_packages.py diff --git a/Lib/importlib/test/import_/test_path.py b/Lib/test/test_importlib/import_/test_path.py rename from Lib/importlib/test/import_/test_path.py rename to Lib/test/test_importlib/import_/test_path.py diff --git a/Lib/importlib/test/import_/test_relative_imports.py b/Lib/test/test_importlib/import_/test_relative_imports.py rename from Lib/importlib/test/import_/test_relative_imports.py rename to Lib/test/test_importlib/import_/test_relative_imports.py diff --git a/Lib/importlib/test/import_/util.py b/Lib/test/test_importlib/import_/util.py rename from Lib/importlib/test/import_/util.py rename to Lib/test/test_importlib/import_/util.py diff --git a/Lib/importlib/test/regrtest.py b/Lib/test/test_importlib/regrtest.py rename from Lib/importlib/test/regrtest.py rename to Lib/test/test_importlib/regrtest.py diff --git a/Lib/importlib/test/source/__init__.py b/Lib/test/test_importlib/source/__init__.py rename from Lib/importlib/test/source/__init__.py rename to Lib/test/test_importlib/source/__init__.py --- a/Lib/importlib/test/source/__init__.py +++ b/Lib/test/test_importlib/source/__init__.py @@ -1,11 +1,11 @@ -import importlib.test +from .. import test_suite import os.path import unittest def test_suite(): directory = os.path.dirname(__file__) - return importlib.test.test_suite('importlib.test.source', directory) + return test.test_suite('importlib.test.source', directory) if __name__ == '__main__': diff --git a/Lib/importlib/test/source/test_abc_loader.py b/Lib/test/test_importlib/source/test_abc_loader.py rename from Lib/importlib/test/source/test_abc_loader.py rename to Lib/test/test_importlib/source/test_abc_loader.py diff --git a/Lib/importlib/test/source/test_case_sensitivity.py b/Lib/test/test_importlib/source/test_case_sensitivity.py rename from Lib/importlib/test/source/test_case_sensitivity.py rename to Lib/test/test_importlib/source/test_case_sensitivity.py diff --git a/Lib/importlib/test/source/test_file_loader.py b/Lib/test/test_importlib/source/test_file_loader.py rename from Lib/importlib/test/source/test_file_loader.py rename to Lib/test/test_importlib/source/test_file_loader.py --- a/Lib/importlib/test/source/test_file_loader.py +++ b/Lib/test/test_importlib/source/test_file_loader.py @@ -1,4 +1,4 @@ -from ... import _bootstrap +from importlib import machinery import importlib import importlib.abc from .. import abc @@ -62,7 +62,7 @@ # [basic] def test_module(self): with source_util.create_modules('_temp') as mapping: - loader = _bootstrap.SourceFileLoader('_temp', mapping['_temp']) + loader = machinery.SourceFileLoader('_temp', mapping['_temp']) module = loader.load_module('_temp') self.assertIn('_temp', sys.modules) check = {'__name__': '_temp', '__file__': mapping['_temp'], @@ -72,7 +72,7 @@ def test_package(self): with source_util.create_modules('_pkg.__init__') as mapping: - loader = _bootstrap.SourceFileLoader('_pkg', + loader = machinery.SourceFileLoader('_pkg', mapping['_pkg.__init__']) module = loader.load_module('_pkg') self.assertIn('_pkg', sys.modules) @@ -85,7 +85,7 @@ def test_lacking_parent(self): with source_util.create_modules('_pkg.__init__', '_pkg.mod')as mapping: - loader = _bootstrap.SourceFileLoader('_pkg.mod', + loader = machinery.SourceFileLoader('_pkg.mod', mapping['_pkg.mod']) module = loader.load_module('_pkg.mod') self.assertIn('_pkg.mod', sys.modules) @@ -100,7 +100,7 @@ def test_module_reuse(self): with source_util.create_modules('_temp') as mapping: - loader = _bootstrap.SourceFileLoader('_temp', mapping['_temp']) + loader = machinery.SourceFileLoader('_temp', mapping['_temp']) module = loader.load_module('_temp') module_id = id(module) module_dict_id = id(module.__dict__) @@ -125,7 +125,7 @@ setattr(orig_module, attr, value) with open(mapping[name], 'w') as file: file.write('+++ bad syntax +++') - loader = _bootstrap.SourceFileLoader('_temp', mapping['_temp']) + loader = machinery.SourceFileLoader('_temp', mapping['_temp']) with self.assertRaises(SyntaxError): loader.load_module(name) for attr in attributes: @@ -136,7 +136,7 @@ with source_util.create_modules('_temp') as mapping: with open(mapping['_temp'], 'w') as file: file.write('=') - loader = _bootstrap.SourceFileLoader('_temp', mapping['_temp']) + loader = machinery.SourceFileLoader('_temp', mapping['_temp']) with self.assertRaises(SyntaxError): loader.load_module('_temp') self.assertNotIn('_temp', sys.modules) @@ -149,7 +149,7 @@ file.write("# test file for importlib") try: with util.uncache('_temp'): - loader = _bootstrap.SourceFileLoader('_temp', file_path) + loader = machinery.SourceFileLoader('_temp', file_path) mod = loader.load_module('_temp') self.assertEqual(file_path, mod.__file__) self.assertEqual(imp.cache_from_source(file_path), @@ -175,7 +175,7 @@ if e.errno != getattr(errno, 'EOVERFLOW', None): raise self.skipTest("cannot set modification time to large integer ({})".format(e)) - loader = _bootstrap.SourceFileLoader('_temp', mapping['_temp']) + loader = machinery.SourceFileLoader('_temp', mapping['_temp']) mod = loader.load_module('_temp') # Sanity checks. self.assertEqual(mod.__cached__, compiled) @@ -290,7 +290,7 @@ class SourceLoaderBadBytecodeTest(BadBytecodeTest): - loader = _bootstrap.SourceFileLoader + loader = machinery.SourceFileLoader @source_util.writes_bytecode_files def test_empty_file(self): @@ -414,7 +414,7 @@ class SourcelessLoaderBadBytecodeTest(BadBytecodeTest): - loader = _bootstrap.SourcelessFileLoader + loader = machinery.SourcelessFileLoader def test_empty_file(self): def test(name, mapping, bytecode_path): diff --git a/Lib/importlib/test/source/test_finder.py b/Lib/test/test_importlib/source/test_finder.py rename from Lib/importlib/test/source/test_finder.py rename to Lib/test/test_importlib/source/test_finder.py diff --git a/Lib/importlib/test/source/test_path_hook.py b/Lib/test/test_importlib/source/test_path_hook.py rename from Lib/importlib/test/source/test_path_hook.py rename to Lib/test/test_importlib/source/test_path_hook.py diff --git a/Lib/importlib/test/source/test_source_encoding.py b/Lib/test/test_importlib/source/test_source_encoding.py rename from Lib/importlib/test/source/test_source_encoding.py rename to Lib/test/test_importlib/source/test_source_encoding.py diff --git a/Lib/importlib/test/source/util.py b/Lib/test/test_importlib/source/util.py rename from Lib/importlib/test/source/util.py rename to Lib/test/test_importlib/source/util.py diff --git a/Lib/importlib/test/test_abc.py b/Lib/test/test_importlib/test_abc.py rename from Lib/importlib/test/test_abc.py rename to Lib/test/test_importlib/test_abc.py diff --git a/Lib/importlib/test/test_api.py b/Lib/test/test_importlib/test_api.py rename from Lib/importlib/test/test_api.py rename to Lib/test/test_importlib/test_api.py diff --git a/Lib/importlib/test/test_locks.py b/Lib/test/test_importlib/test_locks.py rename from Lib/importlib/test/test_locks.py rename to Lib/test/test_importlib/test_locks.py diff --git a/Lib/importlib/test/test_util.py b/Lib/test/test_importlib/test_util.py rename from Lib/importlib/test/test_util.py rename to Lib/test/test_importlib/test_util.py diff --git a/Lib/importlib/test/util.py b/Lib/test/test_importlib/util.py rename from Lib/importlib/test/util.py rename to Lib/test/test_importlib/util.py diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -181,6 +181,8 @@ Tests ----- +- Issue #15168: Move importlib.test to test.test_importlib. + - Issue #15091: Reactivate a test on UNIX which was failing thanks to a forgotten importlib.invalidate_caches() call. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 20 20:55:00 2012 From: python-checkins at python.org (brett.cannon) Date: Fri, 20 Jul 2012 20:55:00 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Move_importlib=2Etest=2Ebe?= =?utf-8?q?nchmark_to_Tools/importbench_to_make_it_more?= Message-ID: <3Wf1Vr1VXwzLw5@mail.python.org> http://hg.python.org/cpython/rev/ca08f34e64e2 changeset: 78202:ca08f34e64e2 user: Brett Cannon date: Fri Jul 20 14:54:53 2012 -0400 summary: Move importlib.test.benchmark to Tools/importbench to make it more visible and to place it with other micro-benchmarks (e.g. stringbench). files: Misc/NEWS | 2 ++ Tools/importbench/README | 6 ++++++ Lib/test/test_importlib/benchmark.py | 4 ++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -154,6 +154,8 @@ Tools/Demos ----------- +- Move importlib.test.benchmark to Tools/importbench. + - Issue #12605: The gdb hooks for debugging CPython (within Tools/gdb) have been enhanced to show information on more C frames relevant to CPython within the "py-bt" and "py-bt-full" commands: diff --git a/Tools/importbench/README b/Tools/importbench/README new file mode 100644 --- /dev/null +++ b/Tools/importbench/README @@ -0,0 +1,6 @@ +Importbench is a set of micro-benchmarks for various import scenarios. + +It should not be used as an overall benchmark of import performance, but rather +an easy way to measure impact of possible code changes. For a real-world +benchmark of import, use the normal_startup benchmark from +hg.python.org/benchmarks. diff --git a/Lib/test/test_importlib/benchmark.py b/Tools/importbench/importbench.py rename from Lib/test/test_importlib/benchmark.py rename to Tools/importbench/importbench.py --- a/Lib/test/test_importlib/benchmark.py +++ b/Tools/importbench/importbench.py @@ -4,8 +4,8 @@ thus has no external changes made to import-related attributes in sys. """ -from . import util -from .source import util as source_util +from test.test_importlib import util +from test.test_importlib.source import util as source_util import decimal import imp import importlib -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 20 21:41:03 2012 From: python-checkins at python.org (brett.cannon) Date: Fri, 20 Jul 2012 21:41:03 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_an_import_from_the_imp?= =?utf-8?q?ortlib=2Etest_move=2E?= Message-ID: <3Wf2Wz3BZgzPPC@mail.python.org> http://hg.python.org/cpython/rev/e5c34fe087ef changeset: 78203:e5c34fe087ef user: Brett Cannon date: Fri Jul 20 15:40:57 2012 -0400 summary: Fix an import from the importlib.test move. files: Lib/test/test_import.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -2,7 +2,7 @@ import importlib import builtins import imp -from importlib.test.import_ import util as importlib_util +from test.test_importlib.import_ import util as importlib_util import marshal import os import platform -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 20 21:42:41 2012 From: python-checkins at python.org (brett.cannon) Date: Fri, 20 Jul 2012 21:42:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_another_import_error?= =?utf-8?q?=2E?= Message-ID: <3Wf2Ys2Ht5zPQX@mail.python.org> http://hg.python.org/cpython/rev/e2787e926969 changeset: 78204:e2787e926969 user: Brett Cannon date: Fri Jul 20 15:42:34 2012 -0400 summary: Fix another import error. files: Lib/test/test_namespace_pkgs.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_namespace_pkgs.py b/Lib/test/test_namespace_pkgs.py --- a/Lib/test/test_namespace_pkgs.py +++ b/Lib/test/test_namespace_pkgs.py @@ -3,7 +3,7 @@ import unittest import os -import importlib.test.util +from test.test_importlib import util from test.support import run_unittest # needed tests: @@ -46,7 +46,7 @@ # use default meta_path and path_hooks unless specified otherwise kwargs.setdefault('meta_path', sys.meta_path) kwargs.setdefault('path_hooks', sys.path_hooks) - import_context = importlib.test.util.import_state(**kwargs) + import_context = util.import_state(**kwargs) with import_context, sys_modules_context(): yield -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 20 22:25:33 2012 From: python-checkins at python.org (ned.deily) Date: Fri, 20 Jul 2012 22:25:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315168=3A_Ensure_t?= =?utf-8?q?est=5Fimportlib_subdirectories_are_installed=2E?= Message-ID: <3Wf3WK3KvjzPPh@mail.python.org> http://hg.python.org/cpython/rev/f1f480650a0a changeset: 78205:f1f480650a0a user: Ned Deily date: Fri Jul 20 13:24:58 2012 -0700 summary: Issue #15168: Ensure test_importlib subdirectories are installed. files: Makefile.pre.in | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1008,9 +1008,9 @@ lib2to3/tests/data/fixers/myfixes \ ctypes ctypes/test ctypes/macholib idlelib idlelib/Icons \ distutils distutils/command distutils/tests $(XMLLIBSUBDIRS) \ - importlib importlib/test importlib/test/builtin \ - importlib/test/extension importlib/test/frozen \ - importlib/test/import_ importlib/test/source \ + importlib test/test_importlib test/test_importlib/builtin \ + test/test_importlib/extension test/test_importlib/frozen \ + test/test_importlib/import_ test/test_importlib/source \ turtledemo \ multiprocessing multiprocessing/dummy \ unittest unittest/test unittest/test/testmock \ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 21 00:50:13 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 21 Jul 2012 00:50:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE0NTc5?= =?utf-8?q?=3A_Fix_CVE-2012-2135=3A_vulnerability_in_the_utf-16_decoder_af?= =?utf-8?q?ter?= Message-ID: <3Wf6kF0P6YzPPy@mail.python.org> http://hg.python.org/cpython/rev/034ff986019d changeset: 78206:034ff986019d branch: 3.2 parent: 78196:fb181698775d user: Antoine Pitrou date: Sat Jul 21 00:45:14 2012 +0200 summary: Issue #14579: Fix CVE-2012-2135: vulnerability in the utf-16 decoder after error handling. Patch by Serhiy Storchaka. files: Lib/test/test_codecs.py | 30 ++++++++++++++-- Misc/NEWS | 3 + Objects/unicodeobject.c | 52 +++++++++++----------------- 3 files changed, 50 insertions(+), 35 deletions(-) diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -540,8 +540,19 @@ ) def test_errors(self): - self.assertRaises(UnicodeDecodeError, codecs.utf_16_le_decode, - b"\xff", "strict", True) + tests = [ + (b'\xff', '\ufffd'), + (b'A\x00Z', 'A\ufffd'), + (b'A\x00B\x00C\x00D\x00Z', 'ABCD\ufffd'), + (b'\x00\xd8', '\ufffd'), + (b'\x00\xd8A', '\ufffd'), + (b'\x00\xd8A\x00', '\ufffdA'), + (b'\x00\xdcA\x00', '\ufffdA'), + ] + for raw, expected in tests: + self.assertRaises(UnicodeDecodeError, codecs.utf_16_le_decode, + raw, 'strict', True) + self.assertEqual(raw.decode('utf-16le', 'replace'), expected) def test_nonbmp(self): self.assertEqual("\U00010203".encode(self.encoding), @@ -568,8 +579,19 @@ ) def test_errors(self): - self.assertRaises(UnicodeDecodeError, codecs.utf_16_be_decode, - b"\xff", "strict", True) + tests = [ + (b'\xff', '\ufffd'), + (b'\x00A\xff', 'A\ufffd'), + (b'\x00A\x00B\x00C\x00DZ', 'ABCD\ufffd'), + (b'\xd8\x00', '\ufffd'), + (b'\xd8\x00\xdc', '\ufffd'), + (b'\xd8\x00\x00A', '\ufffdA'), + (b'\xdc\x00\x00A', '\ufffdA'), + ] + for raw, expected in tests: + self.assertRaises(UnicodeDecodeError, codecs.utf_16_be_decode, + raw, 'strict', True) + self.assertEqual(raw.decode('utf-16be', 'replace'), expected) def test_nonbmp(self): self.assertEqual("\U00010203".encode(self.encoding), diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #14579: Fix CVE-2012-2135: vulnerability in the utf-16 decoder after + error handling. Patch by Serhiy Storchaka. + - Issue #15404: Refleak in PyMethodObject repr. - Issue #15394: An issue in PyModule_Create that caused references to diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3425,7 +3425,7 @@ /* Unpack UTF-16 encoded data */ p = unicode->str; q = (unsigned char *)s; - e = q + size - 1; + e = q + size; if (byteorder) bo = *byteorder; @@ -3476,8 +3476,20 @@ #endif aligned_end = (const unsigned char *) ((size_t) e & ~LONG_PTR_MASK); - while (q < e) { + while (1) { Py_UNICODE ch; + if (e - q < 2) { + /* remaining byte at the end? (size should be even) */ + if (q == e || consumed) + break; + errmsg = "truncated data"; + startinpos = ((const char *)q) - starts; + endinpos = ((const char *)e) - starts; + outpos = p - PyUnicode_AS_UNICODE(unicode); + goto utf16Error; + /* The remaining input chars are ignored if the callback + chooses to skip the input */ + } /* First check for possible aligned read of a C 'long'. Unaligned reads are more expensive, better to defer to another iteration. */ if (!((size_t) q & LONG_PTR_MASK)) { @@ -3546,8 +3558,8 @@ } p = _p; q = _q; - if (q >= e) - break; + if (e - q < 2) + continue; } ch = (q[ihi] << 8) | q[ilo]; @@ -3559,10 +3571,10 @@ } /* UTF-16 code pair: */ - if (q > e) { + if (e - q < 2) { errmsg = "unexpected end of data"; startinpos = (((const char *)q) - 2) - starts; - endinpos = ((const char *)e) + 1 - starts; + endinpos = ((const char *)e) - starts; goto utf16Error; } if (0xD800 <= ch && ch <= 0xDBFF) { @@ -3606,31 +3618,9 @@ &outpos, &p)) goto onError; - } - /* remaining byte at the end? (size should be even) */ - if (e == q) { - if (!consumed) { - errmsg = "truncated data"; - startinpos = ((const char *)q) - starts; - endinpos = ((const char *)e) + 1 - starts; - outpos = p - PyUnicode_AS_UNICODE(unicode); - if (unicode_decode_call_errorhandler( - errors, - &errorHandler, - "utf16", errmsg, - &starts, - (const char **)&e, - &startinpos, - &endinpos, - &exc, - (const char **)&q, - &unicode, - &outpos, - &p)) - goto onError; - /* The remaining input chars are ignored if the callback - chooses to skip the input */ - } + /* Update data because unicode_decode_call_errorhandler might have + changed the input object. */ + aligned_end = (const unsigned char *) ((size_t) e & ~LONG_PTR_MASK); } if (byteorder) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 21 00:50:14 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 21 Jul 2012 00:50:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Port_additional_tests_from_=2314579_=28the_issue_is_alre?= =?utf-8?q?ady_fixed=29=2E?= Message-ID: <3Wf6kG5dDgzPQN@mail.python.org> http://hg.python.org/cpython/rev/118fe0ee6921 changeset: 78207:118fe0ee6921 parent: 78205:f1f480650a0a parent: 78206:034ff986019d user: Antoine Pitrou date: Sat Jul 21 00:47:48 2012 +0200 summary: Port additional tests from #14579 (the issue is already fixed). files: Lib/test/test_codecs.py | 30 +++++++++++++++++++++++++--- 1 files changed, 26 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -557,8 +557,19 @@ ) def test_errors(self): - self.assertRaises(UnicodeDecodeError, codecs.utf_16_le_decode, - b"\xff", "strict", True) + tests = [ + (b'\xff', '\ufffd'), + (b'A\x00Z', 'A\ufffd'), + (b'A\x00B\x00C\x00D\x00Z', 'ABCD\ufffd'), + (b'\x00\xd8', '\ufffd'), + (b'\x00\xd8A', '\ufffd'), + (b'\x00\xd8A\x00', '\ufffdA'), + (b'\x00\xdcA\x00', '\ufffdA'), + ] + for raw, expected in tests: + self.assertRaises(UnicodeDecodeError, codecs.utf_16_le_decode, + raw, 'strict', True) + self.assertEqual(raw.decode('utf-16le', 'replace'), expected) def test_nonbmp(self): self.assertEqual("\U00010203".encode(self.encoding), @@ -585,8 +596,19 @@ ) def test_errors(self): - self.assertRaises(UnicodeDecodeError, codecs.utf_16_be_decode, - b"\xff", "strict", True) + tests = [ + (b'\xff', '\ufffd'), + (b'\x00A\xff', 'A\ufffd'), + (b'\x00A\x00B\x00C\x00DZ', 'ABCD\ufffd'), + (b'\xd8\x00', '\ufffd'), + (b'\xd8\x00\xdc', '\ufffd'), + (b'\xd8\x00\x00A', '\ufffdA'), + (b'\xdc\x00\x00A', '\ufffdA'), + ] + for raw, expected in tests: + self.assertRaises(UnicodeDecodeError, codecs.utf_16_be_decode, + raw, 'strict', True) + self.assertEqual(raw.decode('utf-16be', 'replace'), expected) def test_nonbmp(self): self.assertEqual("\U00010203".encode(self.encoding), -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 21 00:54:04 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 21 Jul 2012 00:54:04 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE0NTc5?= =?utf-8?q?=3A_Fix_error_handling_bug_in_the_utf-16_decoder=2E?= Message-ID: <3Wf6ph2H8MzPPr@mail.python.org> http://hg.python.org/cpython/rev/4cadf91aaddd changeset: 78208:4cadf91aaddd branch: 2.7 parent: 78187:204be25f24bd user: Antoine Pitrou date: Sat Jul 21 00:52:06 2012 +0200 summary: Issue #14579: Fix error handling bug in the utf-16 decoder. Patch by Serhiy Storchaka. files: Lib/test/test_codecs.py | 28 ++++++++++++++++++++++++++-- Misc/NEWS | 3 +++ Objects/unicodeobject.c | 2 +- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -495,7 +495,19 @@ ) def test_errors(self): - self.assertRaises(UnicodeDecodeError, codecs.utf_16_le_decode, "\xff", "strict", True) + tests = [ + (b'\xff', u'\ufffd'), + (b'A\x00Z', u'A\ufffd'), + (b'A\x00B\x00C\x00D\x00Z', u'ABCD\ufffd'), + (b'\x00\xd8', u'\ufffd'), + (b'\x00\xd8A', u'\ufffd'), + (b'\x00\xd8A\x00', u'\ufffdA'), + (b'\x00\xdcA\x00', u'\ufffdA'), + ] + for raw, expected in tests: + self.assertRaises(UnicodeDecodeError, codecs.utf_16_le_decode, + raw, 'strict', True) + self.assertEqual(raw.decode('utf-16le', 'replace'), expected) class UTF16BETest(ReadTest): encoding = "utf-16-be" @@ -516,7 +528,19 @@ ) def test_errors(self): - self.assertRaises(UnicodeDecodeError, codecs.utf_16_be_decode, "\xff", "strict", True) + tests = [ + (b'\xff', u'\ufffd'), + (b'\x00A\xff', u'A\ufffd'), + (b'\x00A\x00B\x00C\x00DZ', u'ABCD\ufffd'), + (b'\xd8\x00', u'\ufffd'), + (b'\xd8\x00\xdc', u'\ufffd'), + (b'\xd8\x00\x00A', u'\ufffdA'), + (b'\xdc\x00\x00A', u'\ufffdA'), + ] + for raw, expected in tests: + self.assertRaises(UnicodeDecodeError, codecs.utf_16_be_decode, + raw, 'strict', True) + self.assertEqual(raw.decode('utf-16be', 'replace'), expected) class UTF8Test(ReadTest): encoding = "utf-8" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,6 +9,9 @@ Core and Builtins ----------------- +- Issue #14579: Fix error handling bug in the utf-16 decoder. Patch by + Serhiy Storchaka. + - Issue #15368: An issue that caused bytecode generation to be non-deterministic when using randomized hashing (-R) has been fixed. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -2564,7 +2564,7 @@ } /* UTF-16 code pair: */ - if (q >= e) { + if (e - q < 2) { errmsg = "unexpected end of data"; startinpos = (((const char *)q)-2)-starts; endinpos = ((const char *)e)-starts; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 21 02:13:49 2012 From: python-checkins at python.org (meador.inge) Date: Sat, 21 Jul 2012 02:13:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315409=3A_Replace_?= =?utf-8?q?use_of_deprecated_urllib=2Erequest=2ERequest_methods_in?= Message-ID: <3Wf8Zj1yCjzPPB@mail.python.org> http://hg.python.org/cpython/rev/ea8078365d3b changeset: 78209:ea8078365d3b parent: 78207:118fe0ee6921 user: Meador Inge date: Fri Jul 20 19:12:04 2012 -0500 summary: Issue #15409: Replace use of deprecated urllib.request.Request methods in http.cookijar Patch by Fl?vio Ribeiro. files: Lib/http/cookiejar.py | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/http/cookiejar.py b/Lib/http/cookiejar.py --- a/Lib/http/cookiejar.py +++ b/Lib/http/cookiejar.py @@ -625,7 +625,7 @@ return path def request_port(request): - host = request.get_host() + host = request.host i = host.find(':') if i >= 0: port = host[i+1:] @@ -949,7 +949,7 @@ return True def set_ok_verifiability(self, cookie, request): - if request.is_unverifiable() and is_third_party(request): + if request.unverifiable and is_third_party(request): if cookie.version > 0 and self.strict_rfc2965_unverifiable: _debug(" third-party RFC 2965 cookie during " "unverifiable transaction") @@ -1088,7 +1088,7 @@ return True def return_ok_verifiability(self, cookie, request): - if request.is_unverifiable() and is_third_party(request): + if request.unverifiable and is_third_party(request): if cookie.version > 0 and self.strict_rfc2965_unverifiable: _debug(" third-party RFC 2965 cookie during unverifiable " "transaction") @@ -1100,7 +1100,7 @@ return True def return_ok_secure(self, cookie, request): - if cookie.secure and request.get_type() != "https": + if cookie.secure and request.type != "https": _debug(" secure cookie with non-secure request") return False return True -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 21 02:48:06 2012 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 21 Jul 2012 02:48:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fix_whitespace?= Message-ID: <3Wf9LG3BMFzPQJ@mail.python.org> http://hg.python.org/cpython/rev/15db88f6321d changeset: 78210:15db88f6321d branch: 2.7 parent: 78208:4cadf91aaddd user: Raymond Hettinger date: Fri Jul 20 17:47:59 2012 -0700 summary: Fix whitespace files: Python/peephole.c | 36 +++++++++++++++------------------- 1 files changed, 16 insertions(+), 20 deletions(-) diff --git a/Python/peephole.c b/Python/peephole.c --- a/Python/peephole.c +++ b/Python/peephole.c @@ -347,7 +347,7 @@ codestr = (unsigned char *)memcpy(codestr, PyString_AS_STRING(code), codelen); - /* Verify that RETURN_VALUE terminates the codestring. This allows + /* Verify that RETURN_VALUE terminates the codestring. This allows the various transformation patterns to look ahead several instructions without additional checks to make sure they are not looking beyond the end of the code string. @@ -445,8 +445,8 @@ case BUILD_LIST: j = GETARG(codestr, i); h = i - 3 * j; - if (h >= 0 && - j <= lastlc && + if (h >= 0 && + j <= lastlc && ((opcode == BUILD_TUPLE && ISBASICBLOCK(blocks, h, 3*(j+1))) || (opcode == BUILD_LIST && @@ -490,8 +490,8 @@ case BINARY_AND: case BINARY_XOR: case BINARY_OR: - if (lastlc >= 2 && - ISBASICBLOCK(blocks, i-6, 7) && + if (lastlc >= 2 && + ISBASICBLOCK(blocks, i-6, 7) && fold_binops_on_constants(&codestr[i-6], consts)) { i -= 2; assert(codestr[i] == LOAD_CONST); @@ -500,13 +500,13 @@ break; /* Fold unary ops on constants. - LOAD_CONST c1 UNARY_OP --> LOAD_CONST unary_op(c) */ + LOAD_CONST c1 UNARY_OP --> LOAD_CONST unary_op(c) */ case UNARY_NEGATIVE: case UNARY_CONVERT: case UNARY_INVERT: - if (lastlc >= 1 && - ISBASICBLOCK(blocks, i-3, 4) && - fold_unaryops_on_constants(&codestr[i-3], consts)) { + if (lastlc >= 1 && + ISBASICBLOCK(blocks, i-3, 4) && + fold_unaryops_on_constants(&codestr[i-3], consts)) { i -= 2; assert(codestr[i] == LOAD_CONST); cumlc = 1; @@ -532,8 +532,7 @@ tgt = GETJUMPTGT(codestr, i); j = codestr[tgt]; if (CONDITIONAL_JUMP(j)) { - /* NOTE: all possible jumps here are - absolute! */ + /* NOTE: all possible jumps here are absolute! */ if (JUMPS_ON_TRUE(j) == JUMPS_ON_TRUE(opcode)) { /* The second jump will be taken iff the first is. */ @@ -544,13 +543,10 @@ SETARG(codestr, i, tgttgt); goto reoptimize_current; } else { - /* The second jump is not taken - if the first is (so jump past - it), and all conditional - jumps pop their argument when - they're not taken (so change - the first jump to pop its - argument when it's taken). */ + /* The second jump is not taken if the first is (so + jump past it), and all conditional jumps pop their + argument when they're not taken (so change the + first jump to pop its argument when it's taken). */ if (JUMPS_ON_TRUE(opcode)) codestr[i] = POP_JUMP_IF_TRUE; else @@ -586,8 +582,8 @@ if (opcode == JUMP_FORWARD) /* JMP_ABS can go backwards */ opcode = JUMP_ABSOLUTE; if (!ABSOLUTE_JUMP(opcode)) - tgttgt -= i + 3; /* Calc relative jump addr */ - if (tgttgt < 0) /* No backward relative jumps */ + tgttgt -= i + 3; /* Calc relative jump addr */ + if (tgttgt < 0) /* No backward relative jumps */ continue; codestr[i] = opcode; SETARG(codestr, i, tgttgt); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 21 02:51:29 2012 From: python-checkins at python.org (meador.inge) Date: Sat, 21 Jul 2012 02:51:29 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315410=3A_Fix_the_?= =?utf-8?q?urllib=2Erequest=2ERequest=2Eis=5Funverifiable_deprecation?= Message-ID: <3Wf9Q90Y4TzPPn@mail.python.org> http://hg.python.org/cpython/rev/f39895c55699 changeset: 78211:f39895c55699 parent: 78209:ea8078365d3b user: Meador Inge date: Fri Jul 20 19:50:41 2012 -0500 summary: Issue #15410: Fix the urllib.request.Request.is_unverifiable deprecation documentation. files: Doc/library/urllib.request.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -537,7 +537,7 @@ Return whether the request is unverifiable, as defined by RFC 2965. See the documentation for the :class:`Request` constructor. Deprecated in 3.3, use - :attr:`Request.is_unverifiable`. + :attr:`Request.unverifiable`. .. deprecated:: 3.3 -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat Jul 21 06:01:59 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 21 Jul 2012 06:01:59 +0200 Subject: [Python-checkins] Daily reference leaks (f39895c55699): sum=0 Message-ID: results for f39895c55699 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogwnwvq0', '-x'] From python-checkins at python.org Sat Jul 21 11:23:14 2012 From: python-checkins at python.org (florent.xicluna) Date: Sat, 21 Jul 2012 11:23:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWVzICMxMDAx?= =?utf-8?q?7_and_=2314998=3A_Fix_TypeError_using_pprint_on_dictionaries_wi?= =?utf-8?q?th?= Message-ID: <3WfNmf5P4gzPSq@mail.python.org> http://hg.python.org/cpython/rev/03cda5360dc6 changeset: 78212:03cda5360dc6 branch: 3.2 parent: 78206:034ff986019d user: Florent Xicluna date: Sat Jul 21 11:17:38 2012 +0200 summary: Issues #10017 and #14998: Fix TypeError using pprint on dictionaries with unorderable key. files: Lib/pprint.py | 6 +++++- Lib/test/test_pprint.py | 9 +++++++++ Misc/NEWS | 3 +++ 3 files changed, 17 insertions(+), 1 deletions(-) diff --git a/Lib/pprint.py b/Lib/pprint.py --- a/Lib/pprint.py +++ b/Lib/pprint.py @@ -86,7 +86,11 @@ self.obj = obj def __lt__(self, other): - rv = self.obj.__lt__(other.obj) + try: + rv = self.obj.__lt__(other.obj) + except TypeError: + rv = NotImplemented + if rv is NotImplemented: rv = (str(type(self.obj)), id(self.obj)) < \ (str(type(other.obj)), id(other.obj)) diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py --- a/Lib/test/test_pprint.py +++ b/Lib/test/test_pprint.py @@ -462,6 +462,15 @@ self.assertEqual(clean(pprint.pformat(dict.fromkeys(keys))), '{' + ','.join('%r:None' % k for k in skeys) + '}') + # Issue 10017: TypeError on user-defined types as dict keys. + self.assertEqual(pprint.pformat({Unorderable: 0, 1: 0}), + '{1: 0, ' + repr(Unorderable) +': 0}') + + # Issue 14998: TypeError on tuples with NoneTypes as dict keys. + self.assertEqual(pprint.pformat({(1,): 0, (None,): 0}), + '{(1,): 0, (None,): 0}') + + class DottedPrettyPrinter(pprint.PrettyPrinter): def format(self, object, context, maxlevels, level): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -98,6 +98,9 @@ Library ------- +- Issues #10017 and #14998: Fix TypeError using pprint on dictionaries with + user-defined types as keys or other unorderable keys. + - Issue #14635: telnetlib will use poll() rather than select() when possible to avoid failing due to the select() file descriptor limit. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 21 11:23:16 2012 From: python-checkins at python.org (florent.xicluna) Date: Sat, 21 Jul 2012 11:23:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Issues_=2310017_and_=2314998=3A_Fix_TypeError_using_ppri?= =?utf-8?q?nt_on_dictionaries_with?= Message-ID: <3WfNmh34yzzPTS@mail.python.org> http://hg.python.org/cpython/rev/4d0dcfbdf45b changeset: 78213:4d0dcfbdf45b parent: 78211:f39895c55699 parent: 78212:03cda5360dc6 user: Florent Xicluna date: Sat Jul 21 11:22:33 2012 +0200 summary: Issues #10017 and #14998: Fix TypeError using pprint on dictionaries with unorderable key. files: Lib/pprint.py | 6 +++++- Lib/test/test_pprint.py | 9 +++++++++ Misc/NEWS | 5 ++++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Lib/pprint.py b/Lib/pprint.py --- a/Lib/pprint.py +++ b/Lib/pprint.py @@ -86,7 +86,11 @@ self.obj = obj def __lt__(self, other): - rv = self.obj.__lt__(other.obj) + try: + rv = self.obj.__lt__(other.obj) + except TypeError: + rv = NotImplemented + if rv is NotImplemented: rv = (str(type(self.obj)), id(self.obj)) < \ (str(type(other.obj)), id(other.obj)) diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py --- a/Lib/test/test_pprint.py +++ b/Lib/test/test_pprint.py @@ -466,6 +466,15 @@ self.assertEqual(clean(pprint.pformat(dict.fromkeys(keys))), '{' + ','.join('%r:None' % k for k in skeys) + '}') + # Issue 10017: TypeError on user-defined types as dict keys. + self.assertEqual(pprint.pformat({Unorderable: 0, 1: 0}), + '{1: 0, ' + repr(Unorderable) +': 0}') + + # Issue 14998: TypeError on tuples with NoneTypes as dict keys. + self.assertEqual(pprint.pformat({(1,): 0, (None,): 0}), + '{(1,): 0, (None,): 0}') + + class DottedPrettyPrinter(pprint.PrettyPrinter): def format(self, object, context, maxlevels, level): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -48,10 +48,13 @@ - Issue 15307: Virtual environments now use symlinks with framework builds on Mac OS X, like other POSIX builds. - + Library ------- +- Issues #10017 and #14998: Fix TypeError using pprint on dictionaries with + user-defined types as keys or other unorderable keys. + - Issue #15397: inspect.getmodulename() is now based directly on importlib via a new importlib.machinery.all_suffixes() API. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 21 12:45:19 2012 From: python-checkins at python.org (florent.xicluna) Date: Sat, 21 Jul 2012 12:45:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogRml4IHRlc3RfcHBy?= =?utf-8?q?int_random_dict_ordering=2E?= Message-ID: <3WfQbM0QFbzPTC@mail.python.org> http://hg.python.org/cpython/rev/29642f82bbcc changeset: 78214:29642f82bbcc branch: 3.2 parent: 78212:03cda5360dc6 user: Florent Xicluna date: Sat Jul 21 12:44:20 2012 +0200 summary: Fix test_pprint random dict ordering. files: Lib/test/test_pprint.py | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py --- a/Lib/test/test_pprint.py +++ b/Lib/test/test_pprint.py @@ -467,8 +467,9 @@ '{1: 0, ' + repr(Unorderable) +': 0}') # Issue 14998: TypeError on tuples with NoneTypes as dict keys. - self.assertEqual(pprint.pformat({(1,): 0, (None,): 0}), - '{(1,): 0, (None,): 0}') + keys = [(1,), (None,)] + self.assertEqual(pprint.pformat(dict.fromkeys(keys, 0)), + '{%r: 0, %r: 0}' % tuple(sorted(keys, key=id))) class DottedPrettyPrinter(pprint.PrettyPrinter): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 21 12:45:20 2012 From: python-checkins at python.org (florent.xicluna) Date: Sat, 21 Jul 2012 12:45:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Fix_test=5Fpprint_random_dict_ordering=2E?= Message-ID: <3WfQbN4yHDzPVB@mail.python.org> http://hg.python.org/cpython/rev/79d44f4920d9 changeset: 78215:79d44f4920d9 parent: 78213:4d0dcfbdf45b parent: 78214:29642f82bbcc user: Florent Xicluna date: Sat Jul 21 12:45:02 2012 +0200 summary: Fix test_pprint random dict ordering. files: Lib/test/test_pprint.py | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py --- a/Lib/test/test_pprint.py +++ b/Lib/test/test_pprint.py @@ -471,8 +471,9 @@ '{1: 0, ' + repr(Unorderable) +': 0}') # Issue 14998: TypeError on tuples with NoneTypes as dict keys. - self.assertEqual(pprint.pformat({(1,): 0, (None,): 0}), - '{(1,): 0, (None,): 0}') + keys = [(1,), (None,)] + self.assertEqual(pprint.pformat(dict.fromkeys(keys, 0)), + '{%r: 0, %r: 0}' % tuple(sorted(keys, key=id))) class DottedPrettyPrinter(pprint.PrettyPrinter): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 21 14:44:25 2012 From: python-checkins at python.org (ned.deily) Date: Sat, 21 Jul 2012 14:44:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315184=3A_Ensure_c?= =?utf-8?q?onsistent_results_of_OS_X_configuration?= Message-ID: <3WfTDn3TlVzPTH@mail.python.org> http://hg.python.org/cpython/rev/d76b83803e7e changeset: 78216:d76b83803e7e user: Ned Deily date: Sat Jul 21 05:36:30 2012 -0700 summary: Issue #15184: Ensure consistent results of OS X configuration tailoring for universal builds by factoring out common OS X-specific customizations from sysconfig, distutils.sysconfig, distutils.util, and distutils.unixccompiler into a new module _osx_support that can eventually also be used by packaging. files: Lib/_osx_support.py | 488 +++++++++++++++++++ Lib/distutils/sysconfig.py | 190 +------ Lib/distutils/tests/test_util.py | 9 + Lib/distutils/unixccompiler.py | 70 +-- Lib/distutils/util.py | 92 +--- Lib/sysconfig.py | 154 +----- Lib/test/test__osx_support.py | 267 ++++++++++ Lib/test/test_sysconfig.py | 10 +- Misc/NEWS | 5 + 9 files changed, 818 insertions(+), 467 deletions(-) diff --git a/Lib/_osx_support.py b/Lib/_osx_support.py new file mode 100644 --- /dev/null +++ b/Lib/_osx_support.py @@ -0,0 +1,488 @@ +"""Shared OS X support functions.""" + +import os +import re +import sys + +__all__ = [ + 'compiler_fixup', + 'customize_config_vars', + 'customize_compiler', + 'get_platform_osx', +] + +# configuration variables that may contain universal build flags, +# like "-arch" or "-isdkroot", that may need customization for +# the user environment +_UNIVERSAL_CONFIG_VARS = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS', 'BASECFLAGS', + 'BLDSHARED', 'LDSHARED', 'CC', 'CXX', + 'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS', + 'PY_CORE_CFLAGS') + +# configuration variables that may contain compiler calls +_COMPILER_CONFIG_VARS = ('BLDSHARED', 'LDSHARED', 'CC', 'CXX') + +# prefix added to original configuration variable names +_INITPRE = '_OSX_SUPPORT_INITIAL_' + + +def _find_executable(executable, path=None): + """Tries to find 'executable' in the directories listed in 'path'. + + A string listing directories separated by 'os.pathsep'; defaults to + os.environ['PATH']. Returns the complete filename or None if not found. + """ + if path is None: + path = os.environ['PATH'] + + paths = path.split(os.pathsep) + base, ext = os.path.splitext(executable) + + if (sys.platform == 'win32' or os.name == 'os2') and (ext != '.exe'): + executable = executable + '.exe' + + if not os.path.isfile(executable): + for p in paths: + f = os.path.join(p, executable) + if os.path.isfile(f): + # the file exists, we have a shot at spawn working + return f + return None + else: + return executable + + +def _read_output(commandstring): + """Output from succesful command execution or None""" + # Similar to os.popen(commandstring, "r").read(), + # but without actually using os.popen because that + # function is not usable during python bootstrap. + # tempfile is also not available then. + import contextlib + try: + import tempfile + fp = tempfile.NamedTemporaryFile() + except ImportError: + fp = open("/tmp/_osx_support.%s"%( + os.getpid(),), "w+b") + + with contextlib.closing(fp) as fp: + cmd = "%s 2>/dev/null >'%s'" % (commandstring, fp.name) + return fp.read().decode('utf-8').strip() if not os.system(cmd) else None + + +def _find_build_tool(toolname): + """Find a build tool on current path or using xcrun""" + return (_find_executable(toolname) + or _read_output("/usr/bin/xcrun -find %s" % (toolname,)) + or '' + ) + +_SYSTEM_VERSION = None + +def _get_system_version(): + """Return the OS X system version as a string""" + # Reading this plist is a documented way to get the system + # version (see the documentation for the Gestalt Manager) + # We avoid using platform.mac_ver to avoid possible bootstrap issues during + # the build of Python itself (distutils is used to build standard library + # extensions). + + global _SYSTEM_VERSION + + if _SYSTEM_VERSION is None: + _SYSTEM_VERSION = '' + try: + f = open('/System/Library/CoreServices/SystemVersion.plist') + except IOError: + # We're on a plain darwin box, fall back to the default + # behaviour. + pass + else: + try: + m = re.search(r'ProductUserVisibleVersion\s*' + r'(.*?)', f.read()) + finally: + f.close() + if m is not None: + _SYSTEM_VERSION = '.'.join(m.group(1).split('.')[:2]) + # else: fall back to the default behaviour + + return _SYSTEM_VERSION + +def _remove_original_values(_config_vars): + """Remove original unmodified values for testing""" + # This is needed for higher-level cross-platform tests of get_platform. + for k in list(_config_vars): + if k.startswith(_INITPRE): + del _config_vars[k] + +def _save_modified_value(_config_vars, cv, newvalue): + """Save modified and original unmodified value of configuration var""" + + oldvalue = _config_vars.get(cv, '') + if (oldvalue != newvalue) and (_INITPRE + cv not in _config_vars): + _config_vars[_INITPRE + cv] = oldvalue + _config_vars[cv] = newvalue + +def _supports_universal_builds(): + """Returns True if universal builds are supported on this system""" + # As an approximation, we assume that if we are running on 10.4 or above, + # then we are running with an Xcode environment that supports universal + # builds, in particular -isysroot and -arch arguments to the compiler. This + # is in support of allowing 10.4 universal builds to run on 10.3.x systems. + + osx_version = _get_system_version() + if osx_version: + try: + osx_version = tuple(int(i) for i in osx_version.split('.')) + except ValueError: + osx_version = '' + return bool(osx_version >= (10, 4)) if osx_version else False + + +def _find_appropriate_compiler(_config_vars): + """Find appropriate C compiler for extension module builds""" + + # Issue #13590: + # The OSX location for the compiler varies between OSX + # (or rather Xcode) releases. With older releases (up-to 10.5) + # the compiler is in /usr/bin, with newer releases the compiler + # can only be found inside Xcode.app if the "Command Line Tools" + # are not installed. + # + # Futhermore, the compiler that can be used varies between + # Xcode releases. Upto Xcode 4 it was possible to use 'gcc-4.2' + # as the compiler, after that 'clang' should be used because + # gcc-4.2 is either not present, or a copy of 'llvm-gcc' that + # miscompiles Python. + + # skip checks if the compiler was overriden with a CC env variable + if 'CC' in os.environ: + return _config_vars + + # The CC config var might contain additional arguments. + # Ignore them while searching. + cc = oldcc = _config_vars['CC'].split()[0] + if not _find_executable(cc): + # Compiler is not found on the shell search PATH. + # Now search for clang, first on PATH (if the Command LIne + # Tools have been installed in / or if the user has provided + # another location via CC). If not found, try using xcrun + # to find an uninstalled clang (within a selected Xcode). + + # NOTE: Cannot use subprocess here because of bootstrap + # issues when building Python itself (and os.popen is + # implemented on top of subprocess and is therefore not + # usable as well) + + cc = _find_build_tool('clang') + + elif os.path.basename(cc).startswith('gcc'): + # Compiler is GCC, check if it is LLVM-GCC + data = _read_output("'%s' --version" + % (cc.replace("'", "'\"'\"'"),)) + if 'llvm-gcc' in data: + # Found LLVM-GCC, fall back to clang + cc = _find_build_tool('clang') + + if not cc: + raise SystemError( + "Cannot locate working compiler") + + if cc != oldcc: + # Found a replacement compiler. + # Modify config vars using new compiler, if not already explictly + # overriden by an env variable, preserving additional arguments. + for cv in _COMPILER_CONFIG_VARS: + if cv in _config_vars and cv not in os.environ: + cv_split = _config_vars[cv].split() + cv_split[0] = cc if cv != 'CXX' else cc + '++' + _save_modified_value(_config_vars, cv, ' '.join(cv_split)) + + return _config_vars + + +def _remove_universal_flags(_config_vars): + """Remove all universal build arguments from config vars""" + + for cv in _UNIVERSAL_CONFIG_VARS: + # Do not alter a config var explicitly overriden by env var + if cv in _config_vars and cv not in os.environ: + flags = _config_vars[cv] + flags = re.sub('-arch\s+\w+\s', ' ', flags, re.ASCII) + flags = re.sub('-isysroot [^ \t]*', ' ', flags) + _save_modified_value(_config_vars, cv, flags) + + return _config_vars + + +def _remove_unsupported_archs(_config_vars): + """Remove any unsupported archs from config vars""" + # Different Xcode releases support different sets for '-arch' + # flags. In particular, Xcode 4.x no longer supports the + # PPC architectures. + # + # This code automatically removes '-arch ppc' and '-arch ppc64' + # when these are not supported. That makes it possible to + # build extensions on OSX 10.7 and later with the prebuilt + # 32-bit installer on the python.org website. + + # skip checks if the compiler was overriden with a CC env variable + if 'CC' in os.environ: + return _config_vars + + if re.search('-arch\s+ppc', _config_vars['CFLAGS']) is not None: + # NOTE: Cannot use subprocess here because of bootstrap + # issues when building Python itself + status = os.system("'%s' -arch ppc -x c /dev/null 2>/dev/null"%( + _config_vars['CC'].replace("'", "'\"'\"'"),)) + # The Apple compiler drivers return status 255 if no PPC + if (status >> 8) == 255: + # Compiler doesn't support PPC, remove the related + # '-arch' flags if not explicitly overridden by an + # environment variable + for cv in _UNIVERSAL_CONFIG_VARS: + if cv in _config_vars and cv not in os.environ: + flags = _config_vars[cv] + flags = re.sub('-arch\s+ppc\w*\s', ' ', flags) + _save_modified_value(_config_vars, cv, flags) + + return _config_vars + + +def _override_all_archs(_config_vars): + """Allow override of all archs with ARCHFLAGS env var""" + # NOTE: This name was introduced by Apple in OSX 10.5 and + # is used by several scripting languages distributed with + # that OS release. + if 'ARCHFLAGS' in os.environ: + arch = os.environ['ARCHFLAGS'] + for cv in _UNIVERSAL_CONFIG_VARS: + if cv in _config_vars and '-arch' in _config_vars[cv]: + flags = _config_vars[cv] + flags = re.sub('-arch\s+\w+\s', ' ', flags) + flags = flags + ' ' + arch + _save_modified_value(_config_vars, cv, flags) + + return _config_vars + + +def _check_for_unavailable_sdk(_config_vars): + """Remove references to any SDKs not available""" + # If we're on OSX 10.5 or later and the user tries to + # compile an extension using an SDK that is not present + # on the current machine it is better to not use an SDK + # than to fail. This is particularly important with + # the standalong Command Line Tools alternative to a + # full-blown Xcode install since the CLT packages do not + # provide SDKs. If the SDK is not present, it is assumed + # that the header files and dev libs have been installed + # to /usr and /System/Library by either a standalone CLT + # package or the CLT component within Xcode. + cflags = _config_vars.get('CFLAGS', '') + m = re.search(r'-isysroot\s+(\S+)', cflags) + if m is not None: + sdk = m.group(1) + if not os.path.exists(sdk): + for cv in _UNIVERSAL_CONFIG_VARS: + # Do not alter a config var explicitly overriden by env var + if cv in _config_vars and cv not in os.environ: + flags = _config_vars[cv] + flags = re.sub(r'-isysroot\s+\S+(?:\s|$)', ' ', flags) + _save_modified_value(_config_vars, cv, flags) + + return _config_vars + + +def compiler_fixup(compiler_so, cc_args): + """ + This function will strip '-isysroot PATH' and '-arch ARCH' from the + compile flags if the user has specified one them in extra_compile_flags. + + This is needed because '-arch ARCH' adds another architecture to the + build, without a way to remove an architecture. Furthermore GCC will + barf if multiple '-isysroot' arguments are present. + """ + stripArch = stripSysroot = False + + compiler_so = list(compiler_so) + + if not _supports_universal_builds(): + # OSX before 10.4.0, these don't support -arch and -isysroot at + # all. + stripArch = stripSysroot = True + else: + stripArch = '-arch' in cc_args + stripSysroot = '-isysroot' in cc_args + + if stripArch or 'ARCHFLAGS' in os.environ: + while True: + try: + index = compiler_so.index('-arch') + # Strip this argument and the next one: + del compiler_so[index:index+2] + except ValueError: + break + + if 'ARCHFLAGS' in os.environ and not stripArch: + # User specified different -arch flags in the environ, + # see also distutils.sysconfig + compiler_so = compiler_so + os.environ['ARCHFLAGS'].split() + + if stripSysroot: + while True: + try: + index = compiler_so.index('-isysroot') + # Strip this argument and the next one: + del compiler_so[index:index+2] + except ValueError: + break + + # Check if the SDK that is used during compilation actually exists, + # the universal build requires the usage of a universal SDK and not all + # users have that installed by default. + sysroot = None + if '-isysroot' in cc_args: + idx = cc_args.index('-isysroot') + sysroot = cc_args[idx+1] + elif '-isysroot' in compiler_so: + idx = compiler_so.index('-isysroot') + sysroot = compiler_so[idx+1] + + if sysroot and not os.path.isdir(sysroot): + from distutils import log + log.warn("Compiling with an SDK that doesn't seem to exist: %s", + sysroot) + log.warn("Please check your Xcode installation") + + return compiler_so + + +def customize_config_vars(_config_vars): + """Customize Python build configuration variables. + + Called internally from sysconfig with a mutable mapping + containing name/value pairs parsed from the configured + makefile used to build this interpreter. Returns + the mapping updated as needed to reflect the environment + in which the interpreter is running; in the case of + a Python from a binary installer, the installed + environment may be very different from the build + environment, i.e. different OS levels, different + built tools, different available CPU architectures. + + This customization is performed whenever + distutils.sysconfig.get_config_vars() is first + called. It may be used in environments where no + compilers are present, i.e. when installing pure + Python dists. Customization of compiler paths + and detection of unavailable archs is deferred + until the first extention module build is + requested (in distutils.sysconfig.customize_compiler). + + Currently called from distutils.sysconfig + """ + + if not _supports_universal_builds(): + # On Mac OS X before 10.4, check if -arch and -isysroot + # are in CFLAGS or LDFLAGS and remove them if they are. + # This is needed when building extensions on a 10.3 system + # using a universal build of python. + _remove_universal_flags(_config_vars) + + # Allow user to override all archs with ARCHFLAGS env var + _override_all_archs(_config_vars) + + # Remove references to sdks that are not found + _check_for_unavailable_sdk(_config_vars) + + return _config_vars + + +def customize_compiler(_config_vars): + """Customize compiler path and configuration variables. + + This customization is performed when the first + extension module build is requested + in distutils.sysconfig.customize_compiler). + """ + + # Find a compiler to use for extension module builds + _find_appropriate_compiler(_config_vars) + + # Remove ppc arch flags if not supported here + _remove_unsupported_archs(_config_vars) + + # Allow user to override all archs with ARCHFLAGS env var + _override_all_archs(_config_vars) + + return _config_vars + + +def get_platform_osx(_config_vars, osname, release, machine): + """Filter values for get_platform()""" + # called from get_platform() in sysconfig and distutils.util + # + # For our purposes, we'll assume that the system version from + # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set + # to. This makes the compatibility story a bit more sane because the + # machine is going to compile and link as if it were + # MACOSX_DEPLOYMENT_TARGET. + + macver = _config_vars.get('MACOSX_DEPLOYMENT_TARGET', '') + macrelease = _get_system_version() or macver + macver = macver or macrelease + + if macver: + release = macver + osname = "macosx" + + # Use the original CFLAGS value, if available, so that we + # return the same machine type for the platform string. + # Otherwise, distutils may consider this a cross-compiling + # case and disallow installs. + cflags = _config_vars.get(_INITPRE+'CFLAGS', + _config_vars.get('CFLAGS', '')) + if ((macrelease + '.') >= '10.4.' and + '-arch' in cflags.strip()): + # The universal build will build fat binaries, but not on + # systems before 10.4 + + machine = 'fat' + + archs = re.findall('-arch\s+(\S+)', cflags) + archs = tuple(sorted(set(archs))) + + if len(archs) == 1: + machine = archs[0] + elif archs == ('i386', 'ppc'): + machine = 'fat' + elif archs == ('i386', 'x86_64'): + machine = 'intel' + elif archs == ('i386', 'ppc', 'x86_64'): + machine = 'fat3' + elif archs == ('ppc64', 'x86_64'): + machine = 'fat64' + elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'): + machine = 'universal' + else: + raise ValueError( + "Don't know machine value for archs=%r" % (archs,)) + + elif machine == 'i386': + # On OSX the machine type returned by uname is always the + # 32-bit variant, even if the executable architecture is + # the 64-bit variant + if sys.maxsize >= 2**32: + machine = 'x86_64' + + elif machine in ('PowerPC', 'Power_Macintosh'): + # Pick a sane name for the PPC architecture. + # See 'i386' case + if sys.maxsize >= 2**32: + machine = 'ppc64' + else: + machine = 'ppc' + + return (osname, release, machine) diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -172,6 +172,21 @@ varies across Unices and is stored in Python's Makefile. """ if compiler.compiler_type == "unix": + if sys.platform == "darwin": + # Perform first-time customization of compiler-related + # config vars on OS X now that we know we need a compiler. + # This is primarily to support Pythons from binary + # installers. The kind and paths to build tools on + # the user system may vary significantly from the system + # that Python itself was built on. Also the user OS + # version and build tools may not support the same set + # of CPU architectures for universal builds. + global _config_vars + if not _config_vars.get('CUSTOMIZED_OSX_COMPILER', ''): + import _osx_support + _osx_support.customize_compiler(_config_vars) + _config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True' + (cc, cxx, opt, cflags, ccshared, ldshared, so_ext, ar, ar_flags) = \ get_config_vars('CC', 'CXX', 'OPT', 'CFLAGS', 'CCSHARED', 'LDSHARED', 'SO', 'AR', 'ARFLAGS') @@ -494,35 +509,12 @@ _config_vars = g -def _read_output(commandstring): - """ - Returns os.popen(commandstring, "r").read(), but - without actually using os.popen because that - function is not usable during python bootstrap - """ - # NOTE: tempfile is also not useable during - # bootstrap - import contextlib - try: - import tempfile - fp = tempfile.NamedTemporaryFile() - except ImportError: - fp = open("/tmp/distutils.%s"%( - os.getpid(),), "w+b") - - with contextlib.closing(fp) as fp: - cmd = "%s >'%s'"%(commandstring, fp.name) - os.system(cmd) - data = fp.read() - - return data.decode('utf-8') - def get_config_vars(*args): """With no arguments, return a dictionary of all configuration variables relevant for the current platform. Generally this includes everything needed to build extensions and install both pure modules and extensions. On Unix, this means every variable defined in Python's - installed Makefile; on Windows and Mac OS it's a much smaller set. + installed Makefile; on Windows it's a much smaller set. With arguments, return a list of values that result from looking up each argument in the configuration variable dictionary. @@ -555,153 +547,11 @@ srcdir = os.path.join(base, _config_vars['srcdir']) _config_vars['srcdir'] = os.path.normpath(srcdir) + # OS X platforms require special customization to handle + # multi-architecture, multi-os-version installers if sys.platform == 'darwin': - from distutils.spawn import find_executable - - kernel_version = os.uname()[2] # Kernel version (8.4.3) - major_version = int(kernel_version.split('.')[0]) - - # Issue #13590: - # The OSX location for the compiler varies between OSX - # (or rather Xcode) releases. With older releases (up-to 10.5) - # the compiler is in /usr/bin, with newer releases the compiler - # can only be found inside Xcode.app if the "Command Line Tools" - # are not installed. - # - # Futhermore, the compiler that can be used varies between - # Xcode releases. Upto Xcode 4 it was possible to use 'gcc-4.2' - # as the compiler, after that 'clang' should be used because - # gcc-4.2 is either not present, or a copy of 'llvm-gcc' that - # miscompiles Python. - - # skip checks if the compiler was overriden with a CC env variable - if 'CC' not in os.environ: - cc = oldcc = _config_vars['CC'] - if not find_executable(cc): - # Compiler is not found on the shell search PATH. - # Now search for clang, first on PATH (if the Command LIne - # Tools have been installed in / or if the user has provided - # another location via CC). If not found, try using xcrun - # to find an uninstalled clang (within a selected Xcode). - - # NOTE: Cannot use subprocess here because of bootstrap - # issues when building Python itself (and os.popen is - # implemented on top of subprocess and is therefore not - # usable as well) - - data = (find_executable('clang') or - _read_output( - "/usr/bin/xcrun -find clang 2>/dev/null").strip()) - if not data: - raise DistutilsPlatformError( - "Cannot locate working compiler") - - _config_vars['CC'] = cc = data - _config_vars['CXX'] = cc + '++' - - elif os.path.basename(cc).startswith('gcc'): - # Compiler is GCC, check if it is LLVM-GCC - data = _read_output("'%s' --version 2>/dev/null" - % (cc.replace("'", "'\"'\"'"),)) - if 'llvm-gcc' in data: - # Found LLVM-GCC, fall back to clang - data = (find_executable('clang') or - _read_output( - "/usr/bin/xcrun -find clang 2>/dev/null").strip()) - if find_executable(data): - _config_vars['CC'] = cc = data - _config_vars['CXX'] = cc + '++' - - if (cc != oldcc - and 'LDSHARED' in _config_vars - and 'LDSHARED' not in os.environ): - # modify LDSHARED if we modified CC - ldshared = _config_vars['LDSHARED'] - if ldshared.startswith(oldcc): - _config_vars['LDSHARED'] = cc + ldshared[len(oldcc):] - - if major_version < 8: - # On Mac OS X before 10.4, check if -arch and -isysroot - # are in CFLAGS or LDFLAGS and remove them if they are. - # This is needed when building extensions on a 10.3 system - # using a universal build of python. - for key in ('LDFLAGS', 'BASECFLAGS', 'LDSHARED', - # a number of derived variables. These need to be - # patched up as well. - 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): - flags = _config_vars[key] - flags = re.sub('-arch\s+\w+\s', ' ', flags, re.ASCII) - flags = re.sub('-isysroot [^ \t]*', ' ', flags) - _config_vars[key] = flags - - else: - # Different Xcode releases support different sets for '-arch' - # flags. In particular, Xcode 4.x no longer supports the - # PPC architectures. - # - # This code automatically removes '-arch ppc' and '-arch ppc64' - # when these are not supported. That makes it possible to - # build extensions on OSX 10.7 and later with the prebuilt - # 32-bit installer on the python.org website. - flags = _config_vars['CFLAGS'] - if re.search('-arch\s+ppc', flags) is not None: - # NOTE: Cannot use subprocess here because of bootstrap - # issues when building Python itself - status = os.system("'%s' -arch ppc -x c /dev/null 2>/dev/null"%( - _config_vars['CC'].replace("'", "'\"'\"'"),)) - - if status != 0: - # Compiler doesn't support PPC, remove the related - # '-arch' flags. - for key in ('LDFLAGS', 'BASECFLAGS', - # a number of derived variables. These need to be - # patched up as well. - 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED', 'LDSHARED'): - - flags = _config_vars[key] - flags = re.sub('-arch\s+ppc\w*\s', ' ', flags) - _config_vars[key] = flags - - - # Allow the user to override the architecture flags using - # an environment variable. - # NOTE: This name was introduced by Apple in OSX 10.5 and - # is used by several scripting languages distributed with - # that OS release. - if 'ARCHFLAGS' in os.environ: - arch = os.environ['ARCHFLAGS'] - for key in ('LDFLAGS', 'BASECFLAGS', 'LDSHARED', - # a number of derived variables. These need to be - # patched up as well. - 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): - - flags = _config_vars[key] - flags = re.sub('-arch\s+\w+\s', ' ', flags) - flags = flags + ' ' + arch - _config_vars[key] = flags - - # If we're on OSX 10.5 or later and the user tries to - # compiles an extension using an SDK that is not present - # on the current machine it is better to not use an SDK - # than to fail. - # - # The major usecase for this is users using a Python.org - # binary installer on OSX 10.6: that installer uses - # the 10.4u SDK, but that SDK is not installed by default - # when you install Xcode. - # - m = re.search('-isysroot\s+(\S+)', _config_vars['CFLAGS']) - if m is not None: - sdk = m.group(1) - if not os.path.exists(sdk): - for key in ('LDFLAGS', 'BASECFLAGS', 'LDSHARED', - # a number of derived variables. These need to be - # patched up as well. - 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): - - flags = _config_vars[key] - flags = re.sub('-isysroot\s+\S+(\s|$)', ' ', flags) - _config_vars[key] = flags + import _osx_support + _osx_support.customize_config_vars(_config_vars) if args: vals = [] diff --git a/Lib/distutils/tests/test_util.py b/Lib/distutils/tests/test_util.py --- a/Lib/distutils/tests/test_util.py +++ b/Lib/distutils/tests/test_util.py @@ -13,6 +13,7 @@ from distutils.sysconfig import get_config_vars from distutils import sysconfig from distutils.tests import support +import _osx_support class UtilTestCase(support.EnvironGuard, unittest.TestCase): @@ -92,6 +93,7 @@ ('Darwin Kernel Version 8.11.1: ' 'Wed Oct 10 18:23:28 PDT 2007; ' 'root:xnu-792.25.20~1/RELEASE_I386'), 'i386')) + _osx_support._remove_original_values(get_config_vars()) get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.3' get_config_vars()['CFLAGS'] = ('-fno-strict-aliasing -DNDEBUG -g ' @@ -105,6 +107,7 @@ sys.maxsize = cursize # macbook with fat binaries (fat, universal or fat64) + _osx_support._remove_original_values(get_config_vars()) get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.4' get_config_vars()['CFLAGS'] = ('-arch ppc -arch i386 -isysroot ' '/Developer/SDKs/MacOSX10.4u.sdk ' @@ -113,10 +116,12 @@ self.assertEqual(get_platform(), 'macosx-10.4-fat') + _osx_support._remove_original_values(get_config_vars()) os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.1' self.assertEqual(get_platform(), 'macosx-10.4-fat') + _osx_support._remove_original_values(get_config_vars()) get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch i386 -isysroot ' '/Developer/SDKs/MacOSX10.4u.sdk ' '-fno-strict-aliasing -fno-common ' @@ -124,18 +129,21 @@ self.assertEqual(get_platform(), 'macosx-10.4-intel') + _osx_support._remove_original_values(get_config_vars()) get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch ppc -arch i386 -isysroot ' '/Developer/SDKs/MacOSX10.4u.sdk ' '-fno-strict-aliasing -fno-common ' '-dynamic -DNDEBUG -g -O3') self.assertEqual(get_platform(), 'macosx-10.4-fat3') + _osx_support._remove_original_values(get_config_vars()) get_config_vars()['CFLAGS'] = ('-arch ppc64 -arch x86_64 -arch ppc -arch i386 -isysroot ' '/Developer/SDKs/MacOSX10.4u.sdk ' '-fno-strict-aliasing -fno-common ' '-dynamic -DNDEBUG -g -O3') self.assertEqual(get_platform(), 'macosx-10.4-universal') + _osx_support._remove_original_values(get_config_vars()) get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch ppc64 -isysroot ' '/Developer/SDKs/MacOSX10.4u.sdk ' '-fno-strict-aliasing -fno-common ' @@ -144,6 +152,7 @@ self.assertEqual(get_platform(), 'macosx-10.4-fat64') for arch in ('ppc', 'i386', 'x86_64', 'ppc64'): + _osx_support._remove_original_values(get_config_vars()) get_config_vars()['CFLAGS'] = ('-arch %s -isysroot ' '/Developer/SDKs/MacOSX10.4u.sdk ' '-fno-strict-aliasing -fno-common ' diff --git a/Lib/distutils/unixccompiler.py b/Lib/distutils/unixccompiler.py --- a/Lib/distutils/unixccompiler.py +++ b/Lib/distutils/unixccompiler.py @@ -23,6 +23,9 @@ DistutilsExecError, CompileError, LibError, LinkError from distutils import log +if sys.platform == 'darwin': + import _osx_support + # XXX Things not currently handled: # * optimization/debug/warning flags; we just use whatever's in Python's # Makefile and live with it. Is this adequate? If not, we might @@ -38,68 +41,6 @@ # should just happily stuff them into the preprocessor/compiler/linker # options and carry on. -def _darwin_compiler_fixup(compiler_so, cc_args): - """ - This function will strip '-isysroot PATH' and '-arch ARCH' from the - compile flags if the user has specified one them in extra_compile_flags. - - This is needed because '-arch ARCH' adds another architecture to the - build, without a way to remove an architecture. Furthermore GCC will - barf if multiple '-isysroot' arguments are present. - """ - stripArch = stripSysroot = False - - compiler_so = list(compiler_so) - kernel_version = os.uname()[2] # 8.4.3 - major_version = int(kernel_version.split('.')[0]) - - if major_version < 8: - # OSX before 10.4.0, these don't support -arch and -isysroot at - # all. - stripArch = stripSysroot = True - else: - stripArch = '-arch' in cc_args - stripSysroot = '-isysroot' in cc_args - - if stripArch or 'ARCHFLAGS' in os.environ: - while True: - try: - index = compiler_so.index('-arch') - # Strip this argument and the next one: - del compiler_so[index:index+2] - except ValueError: - break - - if 'ARCHFLAGS' in os.environ and not stripArch: - # User specified different -arch flags in the environ, - # see also distutils.sysconfig - compiler_so = compiler_so + os.environ['ARCHFLAGS'].split() - - if stripSysroot: - try: - index = compiler_so.index('-isysroot') - # Strip this argument and the next one: - del compiler_so[index:index+2] - except ValueError: - pass - - # Check if the SDK that is used during compilation actually exists, - # the universal build requires the usage of a universal SDK and not all - # users have that installed by default. - sysroot = None - if '-isysroot' in cc_args: - idx = cc_args.index('-isysroot') - sysroot = cc_args[idx+1] - elif '-isysroot' in compiler_so: - idx = compiler_so.index('-isysroot') - sysroot = compiler_so[idx+1] - - if sysroot and not os.path.isdir(sysroot): - log.warn("Compiling with an SDK that doesn't seem to exist: %s", - sysroot) - log.warn("Please check your Xcode installation") - - return compiler_so class UnixCCompiler(CCompiler): @@ -168,7 +109,8 @@ def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): compiler_so = self.compiler_so if sys.platform == 'darwin': - compiler_so = _darwin_compiler_fixup(compiler_so, cc_args + extra_postargs) + compiler_so = _osx_support.compiler_fixup(compiler_so, + cc_args + extra_postargs) try: self.spawn(compiler_so + cc_args + [src, '-o', obj] + extra_postargs) @@ -247,7 +189,7 @@ linker[i] = self.compiler_cxx[i] if sys.platform == 'darwin': - linker = _darwin_compiler_fixup(linker, ld_args) + linker = _osx_support.compiler_fixup(linker, ld_args) self.spawn(linker + ld_args) except DistutilsExecError as msg: diff --git a/Lib/distutils/util.py b/Lib/distutils/util.py --- a/Lib/distutils/util.py +++ b/Lib/distutils/util.py @@ -98,94 +98,10 @@ if m: release = m.group() elif osname[:6] == "darwin": - # - # For our purposes, we'll assume that the system version from - # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set - # to. This makes the compatibility story a bit more sane because the - # machine is going to compile and link as if it were - # MACOSX_DEPLOYMENT_TARGET. - from distutils.sysconfig import get_config_vars - cfgvars = get_config_vars() - - macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET') - - if 1: - # Always calculate the release of the running machine, - # needed to determine if we can build fat binaries or not. - - macrelease = macver - # Get the system version. Reading this plist is a documented - # way to get the system version (see the documentation for - # the Gestalt Manager) - try: - f = open('/System/Library/CoreServices/SystemVersion.plist') - except IOError: - # We're on a plain darwin box, fall back to the default - # behaviour. - pass - else: - try: - m = re.search( - r'ProductUserVisibleVersion\s*' + - r'(.*?)', f.read()) - if m is not None: - macrelease = '.'.join(m.group(1).split('.')[:2]) - # else: fall back to the default behaviour - finally: - f.close() - - if not macver: - macver = macrelease - - if macver: - from distutils.sysconfig import get_config_vars - release = macver - osname = "macosx" - - if (macrelease + '.') >= '10.4.' and \ - '-arch' in get_config_vars().get('CFLAGS', '').strip(): - # The universal build will build fat binaries, but not on - # systems before 10.4 - # - # Try to detect 4-way universal builds, those have machine-type - # 'universal' instead of 'fat'. - - machine = 'fat' - cflags = get_config_vars().get('CFLAGS') - - archs = re.findall('-arch\s+(\S+)', cflags) - archs = tuple(sorted(set(archs))) - - if len(archs) == 1: - machine = archs[0] - elif archs == ('i386', 'ppc'): - machine = 'fat' - elif archs == ('i386', 'x86_64'): - machine = 'intel' - elif archs == ('i386', 'ppc', 'x86_64'): - machine = 'fat3' - elif archs == ('ppc64', 'x86_64'): - machine = 'fat64' - elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'): - machine = 'universal' - else: - raise ValueError( - "Don't know machine value for archs=%r"%(archs,)) - - elif machine == 'i386': - # On OSX the machine type returned by uname is always the - # 32-bit variant, even if the executable architecture is - # the 64-bit variant - if sys.maxsize >= 2**32: - machine = 'x86_64' - - elif machine in ('PowerPC', 'Power_Macintosh'): - # Pick a sane name for the PPC architecture. - machine = 'ppc' - - # See 'i386' case - if sys.maxsize >= 2**32: - machine = 'ppc64' + import _osx_support, distutils.sysconfig + osname, release, machine = _osx_support.get_platform_osx( + distutils.sysconfig.get_config_vars(), + osname, release, machine) return "%s-%s-%s" % (osname, release, machine) diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -497,7 +497,7 @@ variables relevant for the current platform. On Unix, this means every variable defined in Python's installed Makefile; - On Windows and Mac OS it's a much smaller set. + On Windows it's a much smaller set. With arguments, return a list of values that result from looking up each argument in the configuration variable dictionary. @@ -556,64 +556,11 @@ srcdir = os.path.join(base, _CONFIG_VARS['srcdir']) _CONFIG_VARS['srcdir'] = os.path.normpath(srcdir) + # OS X platforms require special customization to handle + # multi-architecture, multi-os-version installers if sys.platform == 'darwin': - kernel_version = os.uname().release # Kernel version (8.4.3) - major_version = int(kernel_version.split('.')[0]) - - if major_version < 8: - # On Mac OS X before 10.4, check if -arch and -isysroot - # are in CFLAGS or LDFLAGS and remove them if they are. - # This is needed when building extensions on a 10.3 system - # using a universal build of python. - for key in ('LDFLAGS', 'BASECFLAGS', 'LDSHARED', - # a number of derived variables. These need to be - # patched up as well. - 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): - flags = _CONFIG_VARS[key] - flags = re.sub('-arch\s+\w+\s', ' ', flags) - flags = re.sub('-isysroot [^ \t]*', ' ', flags) - _CONFIG_VARS[key] = flags - else: - # Allow the user to override the architecture flags using - # an environment variable. - # NOTE: This name was introduced by Apple in OSX 10.5 and - # is used by several scripting languages distributed with - # that OS release. - if 'ARCHFLAGS' in os.environ: - arch = os.environ['ARCHFLAGS'] - for key in ('LDFLAGS', 'BASECFLAGS', 'LDSHARED', - # a number of derived variables. These need to be - # patched up as well. - 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): - - flags = _CONFIG_VARS[key] - flags = re.sub('-arch\s+\w+\s', ' ', flags) - flags = flags + ' ' + arch - _CONFIG_VARS[key] = flags - - # If we're on OSX 10.5 or later and the user tries to - # compiles an extension using an SDK that is not present - # on the current machine it is better to not use an SDK - # than to fail. - # - # The major usecase for this is users using a Python.org - # binary installer on OSX 10.6: that installer uses - # the 10.4u SDK, but that SDK is not installed by default - # when you install Xcode. - # - CFLAGS = _CONFIG_VARS.get('CFLAGS', '') - m = re.search('-isysroot\s+(\S+)', CFLAGS) - if m is not None: - sdk = m.group(1) - if not os.path.exists(sdk): - for key in ('LDFLAGS', 'BASECFLAGS', 'LDSHARED', - # a number of derived variables. These need to be - # patched up as well. - 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): - - flags = _CONFIG_VARS[key] - flags = re.sub('-isysroot\s+\S+(\s|$)', ' ', flags) - _CONFIG_VARS[key] = flags + import _osx_support + _osx_support.customize_config_vars(_CONFIG_VARS) if args: vals = [] @@ -673,8 +620,7 @@ return sys.platform if os.name != "posix" or not hasattr(os, 'uname'): - # XXX what about the architecture? NT is Intel or Alpha, - # Mac OS is M68k or PPC, etc. + # XXX what about the architecture? NT is Intel or Alpha return sys.platform # Set for cross builds explicitly @@ -716,90 +662,10 @@ if m: release = m.group() elif osname[:6] == "darwin": - # - # For our purposes, we'll assume that the system version from - # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set - # to. This makes the compatibility story a bit more sane because the - # machine is going to compile and link as if it were - # MACOSX_DEPLOYMENT_TARGET. - cfgvars = get_config_vars() - macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET') - - if True: - # Always calculate the release of the running machine, - # needed to determine if we can build fat binaries or not. - - macrelease = macver - # Get the system version. Reading this plist is a documented - # way to get the system version (see the documentation for - # the Gestalt Manager) - try: - f = open('/System/Library/CoreServices/SystemVersion.plist') - except IOError: - # We're on a plain darwin box, fall back to the default - # behaviour. - pass - else: - try: - m = re.search(r'ProductUserVisibleVersion\s*' - r'(.*?)', f.read()) - finally: - f.close() - if m is not None: - macrelease = '.'.join(m.group(1).split('.')[:2]) - # else: fall back to the default behaviour - - if not macver: - macver = macrelease - - if macver: - release = macver - osname = "macosx" - - if ((macrelease + '.') >= '10.4.' and - '-arch' in get_config_vars().get('CFLAGS', '').strip()): - # The universal build will build fat binaries, but not on - # systems before 10.4 - # - # Try to detect 4-way universal builds, those have machine-type - # 'universal' instead of 'fat'. - - machine = 'fat' - cflags = get_config_vars().get('CFLAGS') - - archs = re.findall('-arch\s+(\S+)', cflags) - archs = tuple(sorted(set(archs))) - - if len(archs) == 1: - machine = archs[0] - elif archs == ('i386', 'ppc'): - machine = 'fat' - elif archs == ('i386', 'x86_64'): - machine = 'intel' - elif archs == ('i386', 'ppc', 'x86_64'): - machine = 'fat3' - elif archs == ('ppc64', 'x86_64'): - machine = 'fat64' - elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'): - machine = 'universal' - else: - raise ValueError( - "Don't know machine value for archs=%r" % (archs,)) - - elif machine == 'i386': - # On OSX the machine type returned by uname is always the - # 32-bit variant, even if the executable architecture is - # the 64-bit variant - if sys.maxsize >= 2**32: - machine = 'x86_64' - - elif machine in ('PowerPC', 'Power_Macintosh'): - # Pick a sane name for the PPC architecture. - # See 'i386' case - if sys.maxsize >= 2**32: - machine = 'ppc64' - else: - machine = 'ppc' + import _osx_support + osname, release, machine = _osx_support.get_platform_osx( + get_config_vars(), + osname, release, machine) return "%s-%s-%s" % (osname, release, machine) diff --git a/Lib/test/test__osx_support.py b/Lib/test/test__osx_support.py new file mode 100644 --- /dev/null +++ b/Lib/test/test__osx_support.py @@ -0,0 +1,267 @@ +""" +Test suite for _osx_support: shared OS X support functions. +""" + +import os +import platform +import shutil +import stat +import sys +import unittest + +import test.support + +import _osx_support + + at unittest.skipUnless(sys.platform.startswith("darwin"), "requires OS X") +class Test_OSXSupport(unittest.TestCase): + + def setUp(self): + self.maxDiff = None + self.prog_name = 'bogus_program_xxxx' + self.temp_path_dir = os.path.abspath(os.getcwd()) + + def add_expected_saved_initial_values(self, config_vars, expected_vars): + # Ensure that the initial values for all modified config vars + # are also saved with modified keys. + expected_vars.update(('_OSX_SUPPORT_INITIAL_'+ k, + config_vars[k]) for k in config_vars + if config_vars[k] != expected_vars[k]) + + def test__find_executable(self): + with test.support.EnvironmentVarGuard() as env: + if env['PATH']: + env['PATH'] = env['PATH'] + ':' + env['PATH'] = env['PATH'] + os.path.abspath(self.temp_path_dir) + test.support.unlink(self.prog_name) + self.assertIsNone(_osx_support._find_executable(self.prog_name)) + self.addCleanup(test.support.unlink, self.prog_name) + with open(self.prog_name, 'w') as f: + f.write("#!/bin/sh\n/bin/echo OK\n") + os.chmod(self.prog_name, stat.S_IRWXU) + self.assertEqual(self.prog_name, + _osx_support._find_executable(self.prog_name)) + + def test__read_output(self): + with test.support.EnvironmentVarGuard() as env: + if env['PATH']: + env['PATH'] = env['PATH'] + ':' + env['PATH'] = env['PATH'] + os.path.abspath(self.temp_path_dir) + test.support.unlink(self.prog_name) + self.addCleanup(test.support.unlink, self.prog_name) + with open(self.prog_name, 'w') as f: + f.write("#!/bin/sh\n/bin/echo ExpectedOutput\n") + os.chmod(self.prog_name, stat.S_IRWXU) + self.assertEqual('ExpectedOutput', + _osx_support._read_output(self.prog_name)) + + def test__find_build_tool(self): + out = _osx_support._find_build_tool('cc') + self.assertTrue(os.path.isfile(out), + 'cc not found - check xcode-select') + + def test__get_system_version(self): + self.assertTrue(platform.mac_ver()[0].startswith( + _osx_support._get_system_version())) + + def test__remove_original_values(self): + config_vars = { + 'CC': 'gcc-test -pthreads', + } + expected_vars = { + 'CC': 'clang -pthreads', + } + cv = 'CC' + newvalue = 'clang -pthreads' + _osx_support._save_modified_value(config_vars, cv, newvalue) + self.assertNotEqual(expected_vars, config_vars) + _osx_support._remove_original_values(config_vars) + self.assertEqual(expected_vars, config_vars) + + def test__save_modified_value(self): + config_vars = { + 'CC': 'gcc-test -pthreads', + } + expected_vars = { + 'CC': 'clang -pthreads', + } + self.add_expected_saved_initial_values(config_vars, expected_vars) + cv = 'CC' + newvalue = 'clang -pthreads' + _osx_support._save_modified_value(config_vars, cv, newvalue) + self.assertEqual(expected_vars, config_vars) + + def test__save_modified_value_unchanged(self): + config_vars = { + 'CC': 'gcc-test -pthreads', + } + expected_vars = config_vars.copy() + cv = 'CC' + newvalue = 'gcc-test -pthreads' + _osx_support._save_modified_value(config_vars, cv, newvalue) + self.assertEqual(expected_vars, config_vars) + + def test__supports_universal_builds(self): + import platform + self.assertEqual(platform.mac_ver()[0].split('.') >= ['10', '4'], + _osx_support._supports_universal_builds()) + + def test__find_appropriate_compiler(self): + compilers = ( + ('gcc-test', 'i686-apple-darwin11-llvm-gcc-4.2'), + ('clang', 'clang version 3.1'), + ) + config_vars = { + 'CC': 'gcc-test -pthreads', + 'CXX': 'cc++-test', + 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch ppc -arch i386 ', + 'LDFLAGS': '-arch ppc -arch i386 -g', + 'CPPFLAGS': '-I. -isysroot /Developer/SDKs/MacOSX10.4u.sdk', + 'BLDSHARED': 'gcc-test -bundle -arch ppc -arch i386 -g', + 'LDSHARED': 'gcc-test -bundle -arch ppc -arch i386 ' + '-isysroot /Developer/SDKs/MacOSX10.4u.sdk -g', + } + expected_vars = { + 'CC': 'clang -pthreads', + 'CXX': 'clang++', + 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch ppc -arch i386 ', + 'LDFLAGS': '-arch ppc -arch i386 -g', + 'CPPFLAGS': '-I. -isysroot /Developer/SDKs/MacOSX10.4u.sdk', + 'BLDSHARED': 'clang -bundle -arch ppc -arch i386 -g', + 'LDSHARED': 'clang -bundle -arch ppc -arch i386 ' + '-isysroot /Developer/SDKs/MacOSX10.4u.sdk -g', + } + self.add_expected_saved_initial_values(config_vars, expected_vars) + + with test.support.EnvironmentVarGuard() as env: + suffix = (':' + env['PATH']) if env['PATH'] else '' + env['PATH'] = os.path.abspath(self.temp_path_dir) + suffix + for c_name, c_output in compilers: + test.support.unlink(c_name) + self.addCleanup(test.support.unlink, c_name) + with open(c_name, 'w') as f: + f.write("#!/bin/sh\n/bin/echo " + c_output) + os.chmod(c_name, stat.S_IRWXU) + self.assertEqual(expected_vars, + _osx_support._find_appropriate_compiler( + config_vars)) + + def test__remove_universal_flags(self): + config_vars = { + 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch ppc -arch i386 ', + 'LDFLAGS': '-arch ppc -arch i386 -g', + 'CPPFLAGS': '-I. -isysroot /Developer/SDKs/MacOSX10.4u.sdk', + 'BLDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 -g', + 'LDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 ' + '-isysroot /Developer/SDKs/MacOSX10.4u.sdk -g', + } + expected_vars = { + 'CFLAGS': '-fno-strict-aliasing -g -O3 ', + 'LDFLAGS': ' -g', + 'CPPFLAGS': '-I. ', + 'BLDSHARED': 'gcc-4.0 -bundle -g', + 'LDSHARED': 'gcc-4.0 -bundle -g', + } + self.add_expected_saved_initial_values(config_vars, expected_vars) + + self.assertEqual(expected_vars, + _osx_support._remove_universal_flags( + config_vars)) + + @unittest.skipUnless(shutil.which('clang'),'test requires clang') + def test__remove_unsupported_archs(self): + config_vars = { + 'CC': 'clang', + 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch ppc -arch i386 ', + 'LDFLAGS': '-arch ppc -arch i386 -g', + 'CPPFLAGS': '-I. -isysroot /Developer/SDKs/MacOSX10.4u.sdk', + 'BLDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 -g', + 'LDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 ' + '-isysroot /Developer/SDKs/MacOSX10.4u.sdk -g', + } + expected_vars = { + 'CC': 'clang', + 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch i386 ', + 'LDFLAGS': ' -arch i386 -g', + 'CPPFLAGS': '-I. -isysroot /Developer/SDKs/MacOSX10.4u.sdk', + 'BLDSHARED': 'gcc-4.0 -bundle -arch i386 -g', + 'LDSHARED': 'gcc-4.0 -bundle -arch i386 ' + '-isysroot /Developer/SDKs/MacOSX10.4u.sdk -g', + } + self.add_expected_saved_initial_values(config_vars, expected_vars) + + self.assertEqual(expected_vars, + _osx_support._remove_unsupported_archs( + config_vars)) + + def test__override_all_archs(self): + with test.support.EnvironmentVarGuard() as env: + env['ARCHFLAGS'] = '-arch x86_64' + config_vars = { + 'CC': 'clang', + 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch ppc -arch i386 ', + 'LDFLAGS': '-arch ppc -arch i386 -g', + 'CPPFLAGS': '-I. -isysroot /Developer/SDKs/MacOSX10.4u.sdk', + 'BLDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 -g', + 'LDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 ' + '-isysroot /Developer/SDKs/MacOSX10.4u.sdk -g', + } + expected_vars = { + 'CC': 'clang', + 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch x86_64', + 'LDFLAGS': ' -g -arch x86_64', + 'CPPFLAGS': '-I. -isysroot /Developer/SDKs/MacOSX10.4u.sdk', + 'BLDSHARED': 'gcc-4.0 -bundle -g -arch x86_64', + 'LDSHARED': 'gcc-4.0 -bundle -isysroot ' + '/Developer/SDKs/MacOSX10.4u.sdk -g -arch x86_64', + } + self.add_expected_saved_initial_values(config_vars, expected_vars) + + self.assertEqual(expected_vars, + _osx_support._override_all_archs( + config_vars)) + + def test__check_for_unavailable_sdk(self): + config_vars = { + 'CC': 'clang', + 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch ppc -arch i386 ' + '-isysroot /Developer/SDKs/MacOSX10.1.sdk', + 'LDFLAGS': '-arch ppc -arch i386 -g', + 'CPPFLAGS': '-I. -isysroot /Developer/SDKs/MacOSX10.1.sdk', + 'BLDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 -g', + 'LDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 ' + '-isysroot /Developer/SDKs/MacOSX10.1.sdk -g', + } + expected_vars = { + 'CC': 'clang', + 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch ppc -arch i386 ' + ' ', + 'LDFLAGS': '-arch ppc -arch i386 -g', + 'CPPFLAGS': '-I. ', + 'BLDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 -g', + 'LDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 ' + ' -g', + } + self.add_expected_saved_initial_values(config_vars, expected_vars) + + self.assertEqual(expected_vars, + _osx_support._check_for_unavailable_sdk( + config_vars)) + + def test_get_platform_osx(self): + # Note, get_platform_osx is currently tested more extensively + # indirectly by test_sysconfig and test_distutils + config_vars = { + 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch ppc -arch i386 ' + '-isysroot /Developer/SDKs/MacOSX10.1.sdk', + 'MACOSX_DEPLOYMENT_TARGET': '10.6', + } + result = _osx_support.get_platform_osx(config_vars, ' ', ' ', ' ') + self.assertEqual(('macosx', '10.6', 'fat'), result) + +def test_main(): + if sys.platform == 'darwin': + test.support.run_unittest(Test_OSXSupport) + +if __name__ == "__main__": + test_main() diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py @@ -13,6 +13,7 @@ get_path, get_path_names, _INSTALL_SCHEMES, _get_default_scheme, _expand_vars, get_scheme_names, get_config_var, _main) +import _osx_support class TestSysConfig(unittest.TestCase): @@ -134,6 +135,7 @@ ('Darwin Kernel Version 8.11.1: ' 'Wed Oct 10 18:23:28 PDT 2007; ' 'root:xnu-792.25.20~1/RELEASE_I386'), 'PowerPC')) + _osx_support._remove_original_values(get_config_vars()) get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.3' get_config_vars()['CFLAGS'] = ('-fno-strict-aliasing -DNDEBUG -g ' @@ -152,7 +154,7 @@ ('Darwin Kernel Version 8.11.1: ' 'Wed Oct 10 18:23:28 PDT 2007; ' 'root:xnu-792.25.20~1/RELEASE_I386'), 'i386')) - get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.3' + _osx_support._remove_original_values(get_config_vars()) get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.3' get_config_vars()['CFLAGS'] = ('-fno-strict-aliasing -DNDEBUG -g ' @@ -167,6 +169,7 @@ sys.maxsize = maxint # macbook with fat binaries (fat, universal or fat64) + _osx_support._remove_original_values(get_config_vars()) get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.4' get_config_vars()['CFLAGS'] = ('-arch ppc -arch i386 -isysroot ' '/Developer/SDKs/MacOSX10.4u.sdk ' @@ -175,6 +178,7 @@ self.assertEqual(get_platform(), 'macosx-10.4-fat') + _osx_support._remove_original_values(get_config_vars()) get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch i386 -isysroot ' '/Developer/SDKs/MacOSX10.4u.sdk ' '-fno-strict-aliasing -fno-common ' @@ -182,18 +186,21 @@ self.assertEqual(get_platform(), 'macosx-10.4-intel') + _osx_support._remove_original_values(get_config_vars()) get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch ppc -arch i386 -isysroot ' '/Developer/SDKs/MacOSX10.4u.sdk ' '-fno-strict-aliasing -fno-common ' '-dynamic -DNDEBUG -g -O3') self.assertEqual(get_platform(), 'macosx-10.4-fat3') + _osx_support._remove_original_values(get_config_vars()) get_config_vars()['CFLAGS'] = ('-arch ppc64 -arch x86_64 -arch ppc -arch i386 -isysroot ' '/Developer/SDKs/MacOSX10.4u.sdk ' '-fno-strict-aliasing -fno-common ' '-dynamic -DNDEBUG -g -O3') self.assertEqual(get_platform(), 'macosx-10.4-universal') + _osx_support._remove_original_values(get_config_vars()) get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch ppc64 -isysroot ' '/Developer/SDKs/MacOSX10.4u.sdk ' '-fno-strict-aliasing -fno-common ' @@ -202,6 +209,7 @@ self.assertEqual(get_platform(), 'macosx-10.4-fat64') for arch in ('ppc', 'i386', 'x86_64', 'ppc64'): + _osx_support._remove_original_values(get_config_vars()) get_config_vars()['CFLAGS'] = ('-arch %s -isysroot ' '/Developer/SDKs/MacOSX10.4u.sdk ' '-fno-strict-aliasing -fno-common ' diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -137,6 +137,11 @@ - Issue 10924: Fixed mksalt() to use a RNG that is suitable for cryptographic purpose. +- Issue #15184: Ensure consistent results of OS X configuration + tailoring for universal builds by factoring out common OS X-specific + customizations from sysconfig, distutils.sysconfig, distutils.util, + and distutils.unixccompiler into a new module _osx_support. + C API ----- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 21 15:55:04 2012 From: python-checkins at python.org (brett.cannon) Date: Sat, 21 Jul 2012 15:55:04 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Remove_a_relative_import_t?= =?utf-8?q?hat_escaped_test=2Etest=5Fimportlib=2E?= Message-ID: <3WfVpJ5XgPzNQx@mail.python.org> http://hg.python.org/cpython/rev/ec6a6500833d changeset: 78217:ec6a6500833d user: Brett Cannon date: Sat Jul 21 09:54:58 2012 -0400 summary: Remove a relative import that escaped test.test_importlib. files: Lib/test/test_importlib/__init__.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_importlib/__init__.py b/Lib/test/test_importlib/__init__.py --- a/Lib/test/test_importlib/__init__.py +++ b/Lib/test/test_importlib/__init__.py @@ -1,6 +1,6 @@ import os import sys -from .. import support +from test import support import unittest def test_suite(package=__package__, directory=os.path.dirname(__file__)): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 21 16:48:36 2012 From: python-checkins at python.org (georg.brandl) Date: Sat, 21 Jul 2012 16:48:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fix_typo_intro?= =?utf-8?q?duced_in_79d54fba49b3=2E?= Message-ID: <3WfX046H9NzPHW@mail.python.org> http://hg.python.org/cpython/rev/b14d38f00891 changeset: 78218:b14d38f00891 branch: 2.7 parent: 78210:15db88f6321d user: Georg Brandl date: Sat Jul 21 16:48:16 2012 +0200 summary: Fix typo introduced in 79d54fba49b3. files: Misc/NEWS | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1,4 +1,4 @@ -,Python News +Python News +++++++++++ What's New in Python 2.7.4 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 21 18:38:17 2012 From: python-checkins at python.org (ned.deily) Date: Sat, 21 Jul 2012 18:38:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315184=3A_Ensure_c?= =?utf-8?q?onfiguration-related_environment_variables?= Message-ID: <3WfZQd07GWzPPk@mail.python.org> http://hg.python.org/cpython/rev/295b715b6875 changeset: 78219:295b715b6875 parent: 78217:ec6a6500833d user: Ned Deily date: Sat Jul 21 09:29:54 2012 -0700 summary: Issue #15184: Ensure configuration-related environment variables are unset during test execution. files: Lib/test/test__osx_support.py | 122 +++++++++++---------- 1 files changed, 63 insertions(+), 59 deletions(-) diff --git a/Lib/test/test__osx_support.py b/Lib/test/test__osx_support.py --- a/Lib/test/test__osx_support.py +++ b/Lib/test/test__osx_support.py @@ -20,6 +20,14 @@ self.maxDiff = None self.prog_name = 'bogus_program_xxxx' self.temp_path_dir = os.path.abspath(os.getcwd()) + self.env = test.support.EnvironmentVarGuard() + self.addCleanup(self.env.__exit__) + for cv in ('CFLAGS', 'LDFLAGS', 'CPPFLAGS', + 'BASECFLAGS', 'BLDSHARED', 'LDSHARED', 'CC', + 'CXX', 'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS', + 'PY_CORE_CFLAGS'): + if cv in self.env: + self.env.unset(cv) def add_expected_saved_initial_values(self, config_vars, expected_vars): # Ensure that the initial values for all modified config vars @@ -29,31 +37,29 @@ if config_vars[k] != expected_vars[k]) def test__find_executable(self): - with test.support.EnvironmentVarGuard() as env: - if env['PATH']: - env['PATH'] = env['PATH'] + ':' - env['PATH'] = env['PATH'] + os.path.abspath(self.temp_path_dir) - test.support.unlink(self.prog_name) - self.assertIsNone(_osx_support._find_executable(self.prog_name)) - self.addCleanup(test.support.unlink, self.prog_name) - with open(self.prog_name, 'w') as f: - f.write("#!/bin/sh\n/bin/echo OK\n") - os.chmod(self.prog_name, stat.S_IRWXU) - self.assertEqual(self.prog_name, - _osx_support._find_executable(self.prog_name)) + if self.env['PATH']: + self.env['PATH'] = self.env['PATH'] + ':' + self.env['PATH'] = self.env['PATH'] + os.path.abspath(self.temp_path_dir) + test.support.unlink(self.prog_name) + self.assertIsNone(_osx_support._find_executable(self.prog_name)) + self.addCleanup(test.support.unlink, self.prog_name) + with open(self.prog_name, 'w') as f: + f.write("#!/bin/sh\n/bin/echo OK\n") + os.chmod(self.prog_name, stat.S_IRWXU) + self.assertEqual(self.prog_name, + _osx_support._find_executable(self.prog_name)) def test__read_output(self): - with test.support.EnvironmentVarGuard() as env: - if env['PATH']: - env['PATH'] = env['PATH'] + ':' - env['PATH'] = env['PATH'] + os.path.abspath(self.temp_path_dir) - test.support.unlink(self.prog_name) - self.addCleanup(test.support.unlink, self.prog_name) - with open(self.prog_name, 'w') as f: - f.write("#!/bin/sh\n/bin/echo ExpectedOutput\n") - os.chmod(self.prog_name, stat.S_IRWXU) - self.assertEqual('ExpectedOutput', - _osx_support._read_output(self.prog_name)) + if self.env['PATH']: + self.env['PATH'] = self.env['PATH'] + ':' + self.env['PATH'] = self.env['PATH'] + os.path.abspath(self.temp_path_dir) + test.support.unlink(self.prog_name) + self.addCleanup(test.support.unlink, self.prog_name) + with open(self.prog_name, 'w') as f: + f.write("#!/bin/sh\n/bin/echo ExpectedOutput\n") + os.chmod(self.prog_name, stat.S_IRWXU) + self.assertEqual('ExpectedOutput', + _osx_support._read_output(self.prog_name)) def test__find_build_tool(self): out = _osx_support._find_build_tool('cc') @@ -133,18 +139,17 @@ } self.add_expected_saved_initial_values(config_vars, expected_vars) - with test.support.EnvironmentVarGuard() as env: - suffix = (':' + env['PATH']) if env['PATH'] else '' - env['PATH'] = os.path.abspath(self.temp_path_dir) + suffix - for c_name, c_output in compilers: - test.support.unlink(c_name) - self.addCleanup(test.support.unlink, c_name) - with open(c_name, 'w') as f: - f.write("#!/bin/sh\n/bin/echo " + c_output) - os.chmod(c_name, stat.S_IRWXU) - self.assertEqual(expected_vars, - _osx_support._find_appropriate_compiler( - config_vars)) + suffix = (':' + self.env['PATH']) if self.env['PATH'] else '' + self.env['PATH'] = os.path.abspath(self.temp_path_dir) + suffix + for c_name, c_output in compilers: + test.support.unlink(c_name) + self.addCleanup(test.support.unlink, c_name) + with open(c_name, 'w') as f: + f.write("#!/bin/sh\n/bin/echo " + c_output) + os.chmod(c_name, stat.S_IRWXU) + self.assertEqual(expected_vars, + _osx_support._find_appropriate_compiler( + config_vars)) def test__remove_universal_flags(self): config_vars = { @@ -195,31 +200,30 @@ config_vars)) def test__override_all_archs(self): - with test.support.EnvironmentVarGuard() as env: - env['ARCHFLAGS'] = '-arch x86_64' - config_vars = { - 'CC': 'clang', - 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch ppc -arch i386 ', - 'LDFLAGS': '-arch ppc -arch i386 -g', - 'CPPFLAGS': '-I. -isysroot /Developer/SDKs/MacOSX10.4u.sdk', - 'BLDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 -g', - 'LDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 ' - '-isysroot /Developer/SDKs/MacOSX10.4u.sdk -g', - } - expected_vars = { - 'CC': 'clang', - 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch x86_64', - 'LDFLAGS': ' -g -arch x86_64', - 'CPPFLAGS': '-I. -isysroot /Developer/SDKs/MacOSX10.4u.sdk', - 'BLDSHARED': 'gcc-4.0 -bundle -g -arch x86_64', - 'LDSHARED': 'gcc-4.0 -bundle -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk -g -arch x86_64', - } - self.add_expected_saved_initial_values(config_vars, expected_vars) + self.env['ARCHFLAGS'] = '-arch x86_64' + config_vars = { + 'CC': 'clang', + 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch ppc -arch i386 ', + 'LDFLAGS': '-arch ppc -arch i386 -g', + 'CPPFLAGS': '-I. -isysroot /Developer/SDKs/MacOSX10.4u.sdk', + 'BLDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 -g', + 'LDSHARED': 'gcc-4.0 -bundle -arch ppc -arch i386 ' + '-isysroot /Developer/SDKs/MacOSX10.4u.sdk -g', + } + expected_vars = { + 'CC': 'clang', + 'CFLAGS': '-fno-strict-aliasing -g -O3 -arch x86_64', + 'LDFLAGS': ' -g -arch x86_64', + 'CPPFLAGS': '-I. -isysroot /Developer/SDKs/MacOSX10.4u.sdk', + 'BLDSHARED': 'gcc-4.0 -bundle -g -arch x86_64', + 'LDSHARED': 'gcc-4.0 -bundle -isysroot ' + '/Developer/SDKs/MacOSX10.4u.sdk -g -arch x86_64', + } + self.add_expected_saved_initial_values(config_vars, expected_vars) - self.assertEqual(expected_vars, - _osx_support._override_all_archs( - config_vars)) + self.assertEqual(expected_vars, + _osx_support._override_all_archs( + config_vars)) def test__check_for_unavailable_sdk(self): config_vars = { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 21 19:33:15 2012 From: python-checkins at python.org (eli.bendersky) Date: Sat, 21 Jul 2012 19:33:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_Raise_ImportEr?= =?utf-8?q?ror_if_pyexpat=27s_version_is_incompatible?= Message-ID: <3Wfbf33wFjzPVN@mail.python.org> http://hg.python.org/cpython/rev/c8534d55c5e6 changeset: 78220:c8534d55c5e6 branch: 3.2 parent: 78214:29642f82bbcc user: Eli Bendersky date: Sat Jul 21 20:28:46 2012 +0300 summary: Raise ImportError if pyexpat's version is incompatible files: Modules/_elementtree.c | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -3114,11 +3114,14 @@ expat_capi->size < sizeof(struct PyExpat_CAPI) || expat_capi->MAJOR_VERSION != XML_MAJOR_VERSION || expat_capi->MINOR_VERSION != XML_MINOR_VERSION || - expat_capi->MICRO_VERSION != XML_MICRO_VERSION) - expat_capi = NULL; + expat_capi->MICRO_VERSION != XML_MICRO_VERSION) { + PyErr_SetString(PyExc_ImportError, + "pyexpat version is incompatible"); + return NULL; + } + } else { + return NULL; } - if (!expat_capi) - return NULL; #endif elementtree_parseerror_obj = PyErr_NewException( -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 21 19:33:17 2012 From: python-checkins at python.org (eli.bendersky) Date: Sat, 21 Jul 2012 19:33:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Raise_ImportError_if_pyexpat=27s_version_is_incompatible?= Message-ID: <3Wfbf52NYZzPVc@mail.python.org> http://hg.python.org/cpython/rev/4b232f6d2ea3 changeset: 78221:4b232f6d2ea3 parent: 78219:295b715b6875 parent: 78220:c8534d55c5e6 user: Eli Bendersky date: Sat Jul 21 20:32:39 2012 +0300 summary: Raise ImportError if pyexpat's version is incompatible files: Modules/_elementtree.c | 8 +++++--- 1 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -3511,11 +3511,13 @@ expat_capi->MAJOR_VERSION != XML_MAJOR_VERSION || expat_capi->MINOR_VERSION != XML_MINOR_VERSION || expat_capi->MICRO_VERSION != XML_MICRO_VERSION) { - expat_capi = NULL; + PyErr_SetString(PyExc_ImportError, + "pyexpat version is incompatible"); + return NULL; } + } else { + return NULL; } - if (!expat_capi) - return NULL; elementtree_parseerror_obj = PyErr_NewException( "xml.etree.ElementTree.ParseError", PyExc_SyntaxError, NULL -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 21 19:52:02 2012 From: python-checkins at python.org (ned.deily) Date: Sat, 21 Jul 2012 19:52:02 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315188=3A_Modify_t?= =?utf-8?q?he_OS_X_build=5Finstaller_script_to_remove_temporary?= Message-ID: <3Wfc3k5HGfzPVP@mail.python.org> http://hg.python.org/cpython/rev/cd883160ad97 changeset: 78222:cd883160ad97 user: Ned Deily date: Sat Jul 21 10:48:09 2012 -0700 summary: Issue #15188: Modify the OS X build_installer script to remove temporary build paths from configuration variables cached in _sysconfigdata.py, as is already done for the installed Makefile. This avoids a distuils test case failure in test_ldshared_value. files: Mac/BuildScript/build-installer.py | 31 +++++++++++------ 1 files changed, 19 insertions(+), 12 deletions(-) diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -900,19 +900,26 @@ # We added some directories to the search path during the configure # phase. Remove those because those directories won't be there on - # the end-users system. - path =os.path.join(rootDir, 'Library', 'Frameworks', 'Python.framework', - 'Versions', version, 'lib', 'python%s'%(version,), - 'config' + config_suffix, 'Makefile') - fp = open(path, 'r') - data = fp.read() - fp.close() + # the end-users system. Also remove the directories from _sysconfigdata.py + # (added in 3.3) if it exists. - data = data.replace('-L%s/libraries/usr/local/lib'%(WORKDIR,), '') - data = data.replace('-I%s/libraries/usr/local/include'%(WORKDIR,), '') - fp = open(path, 'w') - fp.write(data) - fp.close() + path_to_lib = os.path.join(rootDir, 'Library', 'Frameworks', + 'Python.framework', 'Versions', + version, 'lib', 'python%s'%(version,)) + paths = [os.path.join(path_to_lib, 'config' + config_suffix, 'Makefile'), + os.path.join(path_to_lib, '_sysconfigdata.py')] + for path in paths: + if not os.path.exists(path): + continue + fp = open(path, 'r') + data = fp.read() + fp.close() + + data = data.replace('-L%s/libraries/usr/local/lib'%(WORKDIR,), '') + data = data.replace('-I%s/libraries/usr/local/include'%(WORKDIR,), '') + fp = open(path, 'w') + fp.write(data) + fp.close() # Add symlinks in /usr/local/bin, using relative links usr_local_bin = os.path.join(rootDir, 'usr', 'local', 'bin') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 21 20:38:35 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 21 Jul 2012 20:38:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogIzE1MzQyOiBBZGQg?= =?utf-8?q?clarifying_sentence_to_posixpath=2Ejoin_docstring=2E?= Message-ID: <3Wfd5R5hRmzPQH@mail.python.org> http://hg.python.org/cpython/rev/61d0e3526a51 changeset: 78223:61d0e3526a51 branch: 3.2 parent: 78220:c8534d55c5e6 user: R David Murray date: Sat Jul 21 14:33:56 2012 -0400 summary: #15342: Add clarifying sentence to posixpath.join docstring. This sentence appears as a clarifying note in the HTML docs, and seems worth having in the docstring since it covers a very common use case that isn't otherwise obvious. Thanks to Yongzhi Pan for the suggestion. files: Lib/posixpath.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/posixpath.py b/Lib/posixpath.py --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -71,7 +71,8 @@ def join(a, *p): """Join two or more pathname components, inserting '/' as needed. If any component is an absolute path, all previous path components - will be discarded.""" + will be discarded. An empty last part will result in a path that + ends with a separator.""" sep = _get_sep(a) path = a try: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 21 20:38:37 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 21 Jul 2012 20:38:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Merge_=2315342=3A_Add_clarifying_sentence_to_posixpath?= =?utf-8?q?=2Ejoin_docstring=2E?= Message-ID: <3Wfd5T1kvgzPQj@mail.python.org> http://hg.python.org/cpython/rev/30d4d1528b58 changeset: 78224:30d4d1528b58 parent: 78222:cd883160ad97 parent: 78223:61d0e3526a51 user: R David Murray date: Sat Jul 21 14:34:51 2012 -0400 summary: Merge #15342: Add clarifying sentence to posixpath.join docstring. This sentence appears as a clarifying note in the HTML docs, and seems worth having in the docstring since it covers a very common use case that isn't otherwise obvious. Thanks to Yongzhi Pan for the suggestion. files: Lib/posixpath.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/posixpath.py b/Lib/posixpath.py --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -71,7 +71,8 @@ def join(a, *p): """Join two or more pathname components, inserting '/' as needed. If any component is an absolute path, all previous path components - will be discarded.""" + will be discarded. An empty last part will result in a path that + ends with a separator.""" sep = _get_sep(a) path = a try: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 21 20:38:38 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 21 Jul 2012 20:38:38 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE1MzQyOiBBZGQg?= =?utf-8?q?clarifying_sentence_to_posixpath=2Ejoin_docstring=2E?= Message-ID: <3Wfd5V5mZDzPR4@mail.python.org> http://hg.python.org/cpython/rev/f3cc7626a621 changeset: 78225:f3cc7626a621 branch: 2.7 parent: 78218:b14d38f00891 user: R David Murray date: Sat Jul 21 14:37:29 2012 -0400 summary: #15342: Add clarifying sentence to posixpath.join docstring. This sentence appears as a clarifying note in the HTML docs, and seems worth having in the docstring since it covers a very common use case that isn't otherwise obvious. Thanks to Yongzhi Pan for the suggestion. files: Lib/posixpath.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/posixpath.py b/Lib/posixpath.py --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -68,7 +68,8 @@ def join(a, *p): """Join two or more pathname components, inserting '/' as needed. If any component is an absolute path, all previous path components - will be discarded.""" + will be discarded. An empty last part will result in a path that + ends with a separator.""" path = a for b in p: if b.startswith('/'): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 21 23:07:04 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 21 Jul 2012 23:07:04 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogIzE0MzkxOiBjbGFy?= =?utf-8?q?ify_docstring_discussion_of_Action=27s_=27type=27_argument=27s_?= =?utf-8?q?value=2E?= Message-ID: <3WfhNm6WTBzPQm@mail.python.org> http://hg.python.org/cpython/rev/e7f205ce080e changeset: 78226:e7f205ce080e branch: 3.2 parent: 78223:61d0e3526a51 user: R David Murray date: Sat Jul 21 17:04:25 2012 -0400 summary: #14391: clarify docstring discussion of Action's 'type' argument's value. files: Lib/argparse.py | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -736,10 +736,10 @@ - default -- The value to be produced if the option is not specified. - - type -- The type which the command-line arguments should be converted - to, should be one of 'string', 'int', 'float', 'complex' or a - callable object that accepts a single string argument. If None, - 'string' is assumed. + - type -- A callable that accepts a single string argument, and + returns the converted value. The standard Python types str, int, + float, and complex are useful examples of such callables. If None, + str is used. - choices -- A container of values that should be allowed. If not None, after a command-line argument has been converted to the appropriate -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 21 23:07:06 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 21 Jul 2012 23:07:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Merge_=2314391=3A_clarify_docstring_discussion_of_Action?= =?utf-8?b?J3MgJ3R5cGUnIGFyZ3VtZW50J3MgdmFsdWUu?= Message-ID: <3WfhNp4VcBzPSn@mail.python.org> http://hg.python.org/cpython/rev/3d1ea33611c1 changeset: 78227:3d1ea33611c1 parent: 78224:30d4d1528b58 parent: 78226:e7f205ce080e user: R David Murray date: Sat Jul 21 17:05:24 2012 -0400 summary: Merge #14391: clarify docstring discussion of Action's 'type' argument's value. files: Lib/argparse.py | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -761,10 +761,10 @@ - default -- The value to be produced if the option is not specified. - - type -- The type which the command-line arguments should be converted - to, should be one of 'string', 'int', 'float', 'complex' or a - callable object that accepts a single string argument. If None, - 'string' is assumed. + - type -- A callable that accepts a single string argument, and + returns the converted value. The standard Python types str, int, + float, and complex are useful examples of such callables. If None, + str is used. - choices -- A container of values that should be allowed. If not None, after a command-line argument has been converted to the appropriate -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 21 23:07:08 2012 From: python-checkins at python.org (r.david.murray) Date: Sat, 21 Jul 2012 23:07:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE0MzkxOiBjbGFy?= =?utf-8?q?ify_docstring_discussion_of_Action=27s_=27type=27_argument=27s_?= =?utf-8?q?value=2E?= Message-ID: <3WfhNr0LV6zPSf@mail.python.org> http://hg.python.org/cpython/rev/905d9bdae970 changeset: 78228:905d9bdae970 branch: 2.7 parent: 78225:f3cc7626a621 user: R David Murray date: Sat Jul 21 17:06:28 2012 -0400 summary: #14391: clarify docstring discussion of Action's 'type' argument's value. files: Lib/argparse.py | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -740,10 +740,10 @@ - default -- The value to be produced if the option is not specified. - - type -- The type which the command-line arguments should be converted - to, should be one of 'string', 'int', 'float', 'complex' or a - callable object that accepts a single string argument. If None, - 'string' is assumed. + - type -- A callable that accepts a single string argument, and + returns the converted value. The standard Python types str, int, + float, and complex are useful examples of such callables. If None, + str is used. - choices -- A container of values that should be allowed. If not None, after a command-line argument has been converted to the appropriate -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 22 04:35:29 2012 From: python-checkins at python.org (r.david.murray) Date: Sun, 22 Jul 2012 04:35:29 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogIzEyMzUzOiBhcmdw?= =?utf-8?q?arse_now_correctly_handles_null_argument_values=2E?= Message-ID: <3Wfqgj5JZ3zPTx@mail.python.org> http://hg.python.org/cpython/rev/ac53876d1cc8 changeset: 78229:ac53876d1cc8 branch: 3.2 parent: 78226:e7f205ce080e user: R David Murray date: Sat Jul 21 22:20:11 2012 -0400 summary: #12353: argparse now correctly handles null argument values. Patch by Torsten Landschoff. files: Lib/argparse.py | 2 +- Lib/test/test_argparse.py | 1 + Misc/NEWS | 2 ++ 3 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1976,7 +1976,7 @@ for arg_string in arg_strings: # for regular arguments, just add them back into the list - if arg_string[0] not in self.fromfile_prefix_chars: + if not arg_string or arg_string[0] not in self.fromfile_prefix_chars: new_arg_strings.append(arg_string) # replace arguments referencing files with the file content diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -1371,6 +1371,7 @@ ('X @hello', NS(a=None, x='X', y=['hello world!'])), ('-a B @recursive Y Z', NS(a='A', x='hello world!', y=['Y', 'Z'])), ('X @recursive Z -a B', NS(a='B', x='X', y=['hello world!', 'Z'])), + (["-a", "", "X", "Y"], NS(a='', x='X', y=['Y'])), ] diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -98,6 +98,8 @@ Library ------- +- Issue #12353: argparse now correctly handles null argument values. + - Issues #10017 and #14998: Fix TypeError using pprint on dictionaries with user-defined types as keys or other unorderable keys. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 22 04:35:32 2012 From: python-checkins at python.org (r.david.murray) Date: Sun, 22 Jul 2012 04:35:32 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Merge_=2312353=3A_argparse_now_correctly_handles_null_ar?= =?utf-8?q?gument_values=2E?= Message-ID: <3Wfqgm0cf8zPX9@mail.python.org> http://hg.python.org/cpython/rev/c4ad8a6eb0df changeset: 78230:c4ad8a6eb0df parent: 78227:3d1ea33611c1 parent: 78229:ac53876d1cc8 user: R David Murray date: Sat Jul 21 22:28:08 2012 -0400 summary: Merge #12353: argparse now correctly handles null argument values. Patch by Torsten Landschoff. files: Lib/argparse.py | 2 +- Lib/test/test_argparse.py | 1 + Misc/NEWS | 2 ++ 3 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1979,7 +1979,7 @@ for arg_string in arg_strings: # for regular arguments, just add them back into the list - if arg_string[0] not in self.fromfile_prefix_chars: + if not arg_string or arg_string[0] not in self.fromfile_prefix_chars: new_arg_strings.append(arg_string) # replace arguments referencing files with the file content diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -1372,6 +1372,7 @@ ('X @hello', NS(a=None, x='X', y=['hello world!'])), ('-a B @recursive Y Z', NS(a='A', x='hello world!', y=['Y', 'Z'])), ('X @recursive Z -a B', NS(a='B', x='X', y=['hello world!', 'Z'])), + (["-a", "", "X", "Y"], NS(a='', x='X', y=['Y'])), ] diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -52,6 +52,8 @@ Library ------- +- Issue #12353: argparse now correctly handles null argument values. + - Issues #10017 and #14998: Fix TypeError using pprint on dictionaries with user-defined types as keys or other unorderable keys. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 22 04:35:33 2012 From: python-checkins at python.org (r.david.murray) Date: Sun, 22 Jul 2012 04:35:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzEyMzUzOiBhcmdw?= =?utf-8?q?arse_now_correctly_handles_null_argument_values=2E?= Message-ID: <3Wfqgn3k6fzPWK@mail.python.org> http://hg.python.org/cpython/rev/c9806f0aaefb changeset: 78231:c9806f0aaefb branch: 2.7 parent: 78228:905d9bdae970 user: R David Murray date: Sat Jul 21 22:35:00 2012 -0400 summary: #12353: argparse now correctly handles null argument values. Patch by Torsten Landschoff. files: Lib/argparse.py | 2 +- Lib/test/test_argparse.py | 1 + Misc/NEWS | 2 ++ 3 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1967,7 +1967,7 @@ for arg_string in arg_strings: # for regular arguments, just add them back into the list - if arg_string[0] not in self.fromfile_prefix_chars: + if not arg_string or arg_string[0] not in self.fromfile_prefix_chars: new_arg_strings.append(arg_string) # replace arguments referencing files with the file content diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -1374,6 +1374,7 @@ ('X @hello', NS(a=None, x='X', y=['hello world!'])), ('-a B @recursive Y Z', NS(a='A', x='hello world!', y=['Y', 'Z'])), ('X @recursive Z -a B', NS(a='B', x='X', y=['hello world!', 'Z'])), + (["-a", "", "X", "Y"], NS(a='', x='X', y=['Y'])), ] diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -90,6 +90,8 @@ Library ------- +- Issue #12353: argparse now correctly handles null argument values. + - Issue #6493: An issue in ctypes on Windows that caused structure bitfields of type ctypes.c_uint32 and width 32 to incorrectly be set has been fixed. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 22 04:58:04 2012 From: python-checkins at python.org (r.david.murray) Date: Sun, 22 Jul 2012 04:58:04 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogIzEzOTIyOiBhcmdw?= =?utf-8?q?arse_no_longer_incorrectly_strips_=27--=27_after_the_first_one?= =?utf-8?q?=2E?= Message-ID: <3Wfr9m1kHszPX2@mail.python.org> http://hg.python.org/cpython/rev/18b114be013e changeset: 78232:18b114be013e branch: 3.2 parent: 78229:ac53876d1cc8 user: R David Murray date: Sat Jul 21 22:48:35 2012 -0400 summary: #13922: argparse no longer incorrectly strips '--' after the first one. Patch by Jeff Knupp. files: Lib/argparse.py | 7 +++- Lib/test/test_argparse.py | 38 ++++++++++++++++++-------- Misc/ACKS | 1 + Misc/NEWS | 3 ++ 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -2186,9 +2186,12 @@ # Value conversion methods # ======================== def _get_values(self, action, arg_strings): - # for everything but PARSER args, strip out '--' + # for everything but PARSER, REMAINDER args, strip out first '--' if action.nargs not in [PARSER, REMAINDER]: - arg_strings = [s for s in arg_strings if s != '--'] + try: + arg_strings.remove('--') + except ValueError: + pass # optional argument produces a default when not present if not arg_strings and action.nargs == OPTIONAL: diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -1761,6 +1761,14 @@ parser2.add_argument('-y', choices='123', help='y help') parser2.add_argument('z', type=complex, nargs='*', help='z help') + # add third sub-parser + parser3_kwargs = dict(description='3 description') + if subparser_help: + parser3_kwargs['help'] = '3 help' + parser3 = subparsers.add_parser('3', **parser3_kwargs) + parser3.add_argument('t', type=int, help='t help') + parser3.add_argument('u', nargs='...', help='u help') + # return the main parser return parser @@ -1790,6 +1798,10 @@ self.parser.parse_args('--foo 0.125 1 c'.split()), NS(foo=True, bar=0.125, w=None, x='c'), ) + self.assertEqual( + self.parser.parse_args('-1.5 3 11 -- a --foo 7 -- b'.split()), + NS(foo=False, bar=-1.5, t=11, u=['a', '--foo', '7', '--', 'b']), + ) def test_parse_known_args(self): self.assertEqual( @@ -1824,15 +1836,15 @@ def test_help(self): self.assertEqual(self.parser.format_usage(), - 'usage: PROG [-h] [--foo] bar {1,2} ...\n') + 'usage: PROG [-h] [--foo] bar {1,2,3} ...\n') self.assertEqual(self.parser.format_help(), textwrap.dedent('''\ - usage: PROG [-h] [--foo] bar {1,2} ... + usage: PROG [-h] [--foo] bar {1,2,3} ... main description positional arguments: bar bar help - {1,2} command help + {1,2,3} command help optional arguments: -h, --help show this help message and exit @@ -1843,15 +1855,15 @@ # Make sure - is still used for help if it is a non-first prefix char parser = self._get_parser(prefix_chars='+:-') self.assertEqual(parser.format_usage(), - 'usage: PROG [-h] [++foo] bar {1,2} ...\n') + 'usage: PROG [-h] [++foo] bar {1,2,3} ...\n') self.assertEqual(parser.format_help(), textwrap.dedent('''\ - usage: PROG [-h] [++foo] bar {1,2} ... + usage: PROG [-h] [++foo] bar {1,2,3} ... main description positional arguments: bar bar help - {1,2} command help + {1,2,3} command help optional arguments: -h, --help show this help message and exit @@ -1862,15 +1874,15 @@ def test_help_alternate_prefix_chars(self): parser = self._get_parser(prefix_chars='+:/') self.assertEqual(parser.format_usage(), - 'usage: PROG [+h] [++foo] bar {1,2} ...\n') + 'usage: PROG [+h] [++foo] bar {1,2,3} ...\n') self.assertEqual(parser.format_help(), textwrap.dedent('''\ - usage: PROG [+h] [++foo] bar {1,2} ... + usage: PROG [+h] [++foo] bar {1,2,3} ... main description positional arguments: bar bar help - {1,2} command help + {1,2,3} command help optional arguments: +h, ++help show this help message and exit @@ -1879,18 +1891,19 @@ def test_parser_command_help(self): self.assertEqual(self.command_help_parser.format_usage(), - 'usage: PROG [-h] [--foo] bar {1,2} ...\n') + 'usage: PROG [-h] [--foo] bar {1,2,3} ...\n') self.assertEqual(self.command_help_parser.format_help(), textwrap.dedent('''\ - usage: PROG [-h] [--foo] bar {1,2} ... + usage: PROG [-h] [--foo] bar {1,2,3} ... main description positional arguments: bar bar help - {1,2} command help + {1,2,3} command help 1 1 help 2 2 help + 3 3 help optional arguments: -h, --help show this help message and exit @@ -2001,6 +2014,7 @@ 1 (1alias1, 1alias2) 1 help 2 2 help + 3 3 help """)) # ============ diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -511,6 +511,7 @@ Kim Knapp Lenny Kneler Pat Knight +Jeff Knupp Greg Kochanski Damon Kohler Marko Kohtala diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -98,6 +98,9 @@ Library ------- +- Issue #13922: argparse no longer incorrectly strips '--'s that appear + after the first one. + - Issue #12353: argparse now correctly handles null argument values. - Issues #10017 and #14998: Fix TypeError using pprint on dictionaries with -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 22 04:58:06 2012 From: python-checkins at python.org (r.david.murray) Date: Sun, 22 Jul 2012 04:58:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzEzOTIyOiBhcmdw?= =?utf-8?q?arse_no_longer_incorrectly_strips_=27--=27_after_the_first_one?= =?utf-8?q?=2E?= Message-ID: <3Wfr9p23bmzPXY@mail.python.org> http://hg.python.org/cpython/rev/bd2c167dfabc changeset: 78233:bd2c167dfabc branch: 2.7 parent: 78231:c9806f0aaefb user: R David Murray date: Sat Jul 21 22:54:34 2012 -0400 summary: #13922: argparse no longer incorrectly strips '--' after the first one. Patch by Jeff Knupp. files: Lib/argparse.py | 7 +++- Lib/test/test_argparse.py | 37 ++++++++++++++++++-------- Misc/ACKS | 1 + Misc/NEWS | 3 ++ 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -2174,9 +2174,12 @@ # Value conversion methods # ======================== def _get_values(self, action, arg_strings): - # for everything but PARSER args, strip out '--' + # for everything but PARSER, REMAINDER args, strip out first '--' if action.nargs not in [PARSER, REMAINDER]: - arg_strings = [s for s in arg_strings if s != '--'] + try: + arg_strings.remove('--') + except ValueError: + pass # optional argument produces a default when not present if not arg_strings and action.nargs == OPTIONAL: diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -1764,6 +1764,14 @@ parser2.add_argument('-y', choices='123', help='y help') parser2.add_argument('z', type=complex, nargs='*', help='z help') + # add third sub-parser + parser3_kwargs = dict(description='3 description') + if subparser_help: + parser3_kwargs['help'] = '3 help' + parser3 = subparsers.add_parser('3', **parser3_kwargs) + parser3.add_argument('t', type=int, help='t help') + parser3.add_argument('u', nargs='...', help='u help') + # return the main parser return parser @@ -1793,6 +1801,10 @@ self.parser.parse_args('--foo 0.125 1 c'.split()), NS(foo=True, bar=0.125, w=None, x='c'), ) + self.assertEqual( + self.parser.parse_args('-1.5 3 11 -- a --foo 7 -- b'.split()), + NS(foo=False, bar=-1.5, t=11, u=['a', '--foo', '7', '--', 'b']), + ) def test_parse_known_args(self): self.assertEqual( @@ -1827,15 +1839,15 @@ def test_help(self): self.assertEqual(self.parser.format_usage(), - 'usage: PROG [-h] [--foo] bar {1,2} ...\n') + 'usage: PROG [-h] [--foo] bar {1,2,3} ...\n') self.assertEqual(self.parser.format_help(), textwrap.dedent('''\ - usage: PROG [-h] [--foo] bar {1,2} ... + usage: PROG [-h] [--foo] bar {1,2,3} ... main description positional arguments: bar bar help - {1,2} command help + {1,2,3} command help optional arguments: -h, --help show this help message and exit @@ -1846,15 +1858,15 @@ # Make sure - is still used for help if it is a non-first prefix char parser = self._get_parser(prefix_chars='+:-') self.assertEqual(parser.format_usage(), - 'usage: PROG [-h] [++foo] bar {1,2} ...\n') + 'usage: PROG [-h] [++foo] bar {1,2,3} ...\n') self.assertEqual(parser.format_help(), textwrap.dedent('''\ - usage: PROG [-h] [++foo] bar {1,2} ... + usage: PROG [-h] [++foo] bar {1,2,3} ... main description positional arguments: bar bar help - {1,2} command help + {1,2,3} command help optional arguments: -h, --help show this help message and exit @@ -1865,15 +1877,15 @@ def test_help_alternate_prefix_chars(self): parser = self._get_parser(prefix_chars='+:/') self.assertEqual(parser.format_usage(), - 'usage: PROG [+h] [++foo] bar {1,2} ...\n') + 'usage: PROG [+h] [++foo] bar {1,2,3} ...\n') self.assertEqual(parser.format_help(), textwrap.dedent('''\ - usage: PROG [+h] [++foo] bar {1,2} ... + usage: PROG [+h] [++foo] bar {1,2,3} ... main description positional arguments: bar bar help - {1,2} command help + {1,2,3} command help optional arguments: +h, ++help show this help message and exit @@ -1882,18 +1894,19 @@ def test_parser_command_help(self): self.assertEqual(self.command_help_parser.format_usage(), - 'usage: PROG [-h] [--foo] bar {1,2} ...\n') + 'usage: PROG [-h] [--foo] bar {1,2,3} ...\n') self.assertEqual(self.command_help_parser.format_help(), textwrap.dedent('''\ - usage: PROG [-h] [--foo] bar {1,2} ... + usage: PROG [-h] [--foo] bar {1,2,3} ... main description positional arguments: bar bar help - {1,2} command help + {1,2,3} command help 1 1 help 2 2 help + 3 3 help optional arguments: -h, --help show this help message and exit diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -462,6 +462,7 @@ Kim Knapp Lenny Kneler Pat Knight +Jeff Knupp Greg Kochanski Damon Kohler Marko Kohtala diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -90,6 +90,9 @@ Library ------- +- Issue #13922: argparse no longer incorrectly strips '--'s that appear + after the first one. + - Issue #12353: argparse now correctly handles null argument values. - Issue #6493: An issue in ctypes on Windows that caused structure bitfields -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 22 04:58:07 2012 From: python-checkins at python.org (r.david.murray) Date: Sun, 22 Jul 2012 04:58:07 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Merge_=2313922=3A_argparse_no_longer_incorrectly_strips_?= =?utf-8?q?=27--=27_after_the_first_one=2E?= Message-ID: <3Wfr9q74tszPXZ@mail.python.org> http://hg.python.org/cpython/rev/a636f365d815 changeset: 78234:a636f365d815 parent: 78230:c4ad8a6eb0df parent: 78232:18b114be013e user: R David Murray date: Sat Jul 21 22:56:49 2012 -0400 summary: Merge #13922: argparse no longer incorrectly strips '--' after the first one. Patch by Jeff Knupp. files: Lib/argparse.py | 7 +++- Lib/test/test_argparse.py | 38 ++++++++++++++++++-------- Misc/NEWS | 3 ++ 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -2189,9 +2189,12 @@ # Value conversion methods # ======================== def _get_values(self, action, arg_strings): - # for everything but PARSER args, strip out '--' + # for everything but PARSER, REMAINDER args, strip out first '--' if action.nargs not in [PARSER, REMAINDER]: - arg_strings = [s for s in arg_strings if s != '--'] + try: + arg_strings.remove('--') + except ValueError: + pass # optional argument produces a default when not present if not arg_strings and action.nargs == OPTIONAL: diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -1762,6 +1762,14 @@ parser2.add_argument('-y', choices='123', help='y help') parser2.add_argument('z', type=complex, nargs='*', help='z help') + # add third sub-parser + parser3_kwargs = dict(description='3 description') + if subparser_help: + parser3_kwargs['help'] = '3 help' + parser3 = subparsers.add_parser('3', **parser3_kwargs) + parser3.add_argument('t', type=int, help='t help') + parser3.add_argument('u', nargs='...', help='u help') + # return the main parser return parser @@ -1791,6 +1799,10 @@ self.parser.parse_args('--foo 0.125 1 c'.split()), NS(foo=True, bar=0.125, w=None, x='c'), ) + self.assertEqual( + self.parser.parse_args('-1.5 3 11 -- a --foo 7 -- b'.split()), + NS(foo=False, bar=-1.5, t=11, u=['a', '--foo', '7', '--', 'b']), + ) def test_parse_known_args(self): self.assertEqual( @@ -1825,15 +1837,15 @@ def test_help(self): self.assertEqual(self.parser.format_usage(), - 'usage: PROG [-h] [--foo] bar {1,2} ...\n') + 'usage: PROG [-h] [--foo] bar {1,2,3} ...\n') self.assertEqual(self.parser.format_help(), textwrap.dedent('''\ - usage: PROG [-h] [--foo] bar {1,2} ... + usage: PROG [-h] [--foo] bar {1,2,3} ... main description positional arguments: bar bar help - {1,2} command help + {1,2,3} command help optional arguments: -h, --help show this help message and exit @@ -1844,15 +1856,15 @@ # Make sure - is still used for help if it is a non-first prefix char parser = self._get_parser(prefix_chars='+:-') self.assertEqual(parser.format_usage(), - 'usage: PROG [-h] [++foo] bar {1,2} ...\n') + 'usage: PROG [-h] [++foo] bar {1,2,3} ...\n') self.assertEqual(parser.format_help(), textwrap.dedent('''\ - usage: PROG [-h] [++foo] bar {1,2} ... + usage: PROG [-h] [++foo] bar {1,2,3} ... main description positional arguments: bar bar help - {1,2} command help + {1,2,3} command help optional arguments: -h, --help show this help message and exit @@ -1863,15 +1875,15 @@ def test_help_alternate_prefix_chars(self): parser = self._get_parser(prefix_chars='+:/') self.assertEqual(parser.format_usage(), - 'usage: PROG [+h] [++foo] bar {1,2} ...\n') + 'usage: PROG [+h] [++foo] bar {1,2,3} ...\n') self.assertEqual(parser.format_help(), textwrap.dedent('''\ - usage: PROG [+h] [++foo] bar {1,2} ... + usage: PROG [+h] [++foo] bar {1,2,3} ... main description positional arguments: bar bar help - {1,2} command help + {1,2,3} command help optional arguments: +h, ++help show this help message and exit @@ -1880,18 +1892,19 @@ def test_parser_command_help(self): self.assertEqual(self.command_help_parser.format_usage(), - 'usage: PROG [-h] [--foo] bar {1,2} ...\n') + 'usage: PROG [-h] [--foo] bar {1,2,3} ...\n') self.assertEqual(self.command_help_parser.format_help(), textwrap.dedent('''\ - usage: PROG [-h] [--foo] bar {1,2} ... + usage: PROG [-h] [--foo] bar {1,2,3} ... main description positional arguments: bar bar help - {1,2} command help + {1,2,3} command help 1 1 help 2 2 help + 3 3 help optional arguments: -h, --help show this help message and exit @@ -2002,6 +2015,7 @@ 1 (1alias1, 1alias2) 1 help 2 2 help + 3 3 help """)) # ============ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -52,6 +52,9 @@ Library ------- +- Issue #13922: argparse no longer incorrectly strips '--'s that appear + after the first one. + - Issue #12353: argparse now correctly handles null argument values. - Issues #10017 and #14998: Fix TypeError using pprint on dictionaries with -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sun Jul 22 06:02:57 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 22 Jul 2012 06:02:57 +0200 Subject: [Python-checkins] Daily reference leaks (3d1ea33611c1): sum=2 Message-ID: results for 3d1ea33611c1 on branch "default" -------------------------------------------- test_dbm leaked [0, 2, 0] references, sum=2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogwanHLE', '-x'] From python-checkins at python.org Sun Jul 22 06:23:18 2012 From: python-checkins at python.org (gregory.p.smith) Date: Sun, 22 Jul 2012 06:23:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_Consistently_r?= =?utf-8?q?aise_a_TypeError_when_a_non_str_is_passed_to_hashlib=2Enew?= Message-ID: <3Wft465h52zPVy@mail.python.org> http://hg.python.org/cpython/rev/c97cfe04880f changeset: 78235:c97cfe04880f branch: 3.2 parent: 78232:18b114be013e user: Gregory P. Smith date: Sat Jul 21 21:19:53 2012 -0700 summary: Consistently raise a TypeError when a non str is passed to hashlib.new regardless of which of the two implementations of new is used. files: Lib/hashlib.py | 2 +- Lib/test/test_hashlib.py | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Lib/hashlib.py b/Lib/hashlib.py --- a/Lib/hashlib.py +++ b/Lib/hashlib.py @@ -88,7 +88,7 @@ except ImportError: pass # no extension module, this hash is unsupported. - raise ValueError('unsupported hash type %s' % name) + raise ValueError('unsupported hash type ' + name) def __get_openssl_constructor(name): diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -111,12 +111,8 @@ issubset(hashlib.algorithms_available)) def test_unknown_hash(self): - try: - hashlib.new('spam spam spam spam spam') - except ValueError: - pass - else: - self.assertTrue(0 == "hashlib didn't reject bogus hash name") + self.assertRaises(ValueError, hashlib.new, 'spam spam spam spam spam') + self.assertRaises(TypeError, hashlib.new, 1) def test_get_builtin_constructor(self): get_builtin_constructor = hashlib.__dict__[ @@ -135,6 +131,7 @@ sys.modules['_md5'] = _md5 else: del sys.modules['_md5'] + self.assertRaises(TypeError, get_builtin_constructor, 3) def test_hexdigest(self): for name in self.supported_hash_names: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 22 06:23:21 2012 From: python-checkins at python.org (gregory.p.smith) Date: Sun, 22 Jul 2012 06:23:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Consistently_raise_a_TypeError_when_a_non_str_is_passed_?= =?utf-8?q?to_hashlib=2Enew?= Message-ID: <3Wft493MhFzPWH@mail.python.org> http://hg.python.org/cpython/rev/e683084c8bb9 changeset: 78236:e683084c8bb9 parent: 78234:a636f365d815 parent: 78235:c97cfe04880f user: Gregory P. Smith date: Sat Jul 21 21:20:44 2012 -0700 summary: Consistently raise a TypeError when a non str is passed to hashlib.new regardless of which of the two implementations of new is used. files: Lib/hashlib.py | 2 +- Lib/test/test_hashlib.py | 1 + 2 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/hashlib.py b/Lib/hashlib.py --- a/Lib/hashlib.py +++ b/Lib/hashlib.py @@ -88,7 +88,7 @@ except ImportError: pass # no extension module, this hash is unsupported. - raise ValueError('unsupported hash type %s' % name) + raise ValueError('unsupported hash type ' + name) def __get_openssl_constructor(name): diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -133,6 +133,7 @@ sys.modules['_md5'] = _md5 else: del sys.modules['_md5'] + self.assertRaises(TypeError, get_builtin_constructor, 3) def test_hexdigest(self): for name in self.supported_hash_names: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 22 06:23:25 2012 From: python-checkins at python.org (gregory.p.smith) Date: Sun, 22 Jul 2012 06:23:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Consistently_r?= =?utf-8?q?aise_a_TypeError_when_a_non_str_is_passed_to_hashlib=2Enew?= Message-ID: <3Wft4F1z5LzPWc@mail.python.org> http://hg.python.org/cpython/rev/21691763ab3b changeset: 78237:21691763ab3b branch: 2.7 parent: 78139:cd2d4fe57c0e user: Gregory P. Smith date: Sat Jul 21 21:22:16 2012 -0700 summary: Consistently raise a TypeError when a non str is passed to hashlib.new regardless of which of the two implementations of new is used. files: Lib/hashlib.py | 2 +- Lib/test/test_hashlib.py | 1 + 2 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/hashlib.py b/Lib/hashlib.py --- a/Lib/hashlib.py +++ b/Lib/hashlib.py @@ -88,7 +88,7 @@ except ImportError: pass # no extension module, this hash is unsupported. - raise ValueError('unsupported hash type %s' % name) + raise ValueError('unsupported hash type ' + name) def __get_openssl_constructor(name): diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -128,6 +128,7 @@ sys.modules['_md5'] = _md5 else: del sys.modules['_md5'] + self.assertRaises(TypeError, get_builtin_constructor, 3) def test_hexdigest(self): for name in self.supported_hash_names: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 22 06:23:27 2012 From: python-checkins at python.org (gregory.p.smith) Date: Sun, 22 Jul 2012 06:23:27 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMi43IC0+IDIuNyk6?= =?utf-8?q?_merge_heads?= Message-ID: <3Wft4H0nYKzPXF@mail.python.org> http://hg.python.org/cpython/rev/5fb1057bd490 changeset: 78238:5fb1057bd490 branch: 2.7 parent: 78237:21691763ab3b parent: 78233:bd2c167dfabc user: Gregory P. Smith date: Sat Jul 21 21:23:00 2012 -0700 summary: merge heads files: Doc/library/functions.rst | 11 +--- Doc/library/logging.rst | 3 + Doc/library/subprocess.rst | 2 +- Lib/argparse.py | 17 +++-- Lib/ctypes/test/test_bitfields.py | 20 +++++++ Lib/posixpath.py | 3 +- Lib/test/test_argparse.py | 38 +++++++++---- Lib/test/test_codecs.py | 28 +++++++++- Misc/ACKS | 1 + Misc/NEWS | 14 +++++ Modules/_ctypes/cfield.c | 51 ++++++++---------- Objects/unicodeobject.c | 2 +- Python/bltinmodule.c | 8 ++- Python/compile.c | 24 ++++++++- Python/peephole.c | 36 +++++------- 15 files changed, 173 insertions(+), 85 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1558,7 +1558,7 @@ .. note:: This is an advanced function that is not needed in everyday Python - programming. + programming, unlike :func:`importlib.import_module`. This function is invoked by the :keyword:`import` statement. It can be replaced (by importing the :mod:`__builtin__` module and assigning to @@ -1609,15 +1609,8 @@ names. If you simply want to import a module (potentially within a package) by name, - you can call :func:`__import__` and then look it up in :data:`sys.modules`:: + use :func:`importlib.import_module`. - >>> import sys - >>> name = 'foo.bar.baz' - >>> __import__(name) - - >>> baz = sys.modules[name] - >>> baz - .. versionchanged:: 2.5 The level parameter was added. diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -629,6 +629,9 @@ .. versionchanged:: 2.5 *funcName* was added. +.. versionchanged:: 2.6 + *processName* was added. + .. _logger-adapter: LoggerAdapter Objects diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -289,7 +289,7 @@ Popen(['/bin/sh', '-c', args[0], args[1], ...]) - On Windows: the :class:`Popen` class uses CreateProcess() to execute the child + On Windows: the :class:`Popen` class uses CreateProcess() to execute the child program, which operates on strings. If *args* is a sequence, it will be converted to a string in a manner described in :ref:`converting-argument-sequence`. diff --git a/Lib/argparse.py b/Lib/argparse.py --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -740,10 +740,10 @@ - default -- The value to be produced if the option is not specified. - - type -- The type which the command-line arguments should be converted - to, should be one of 'string', 'int', 'float', 'complex' or a - callable object that accepts a single string argument. If None, - 'string' is assumed. + - type -- A callable that accepts a single string argument, and + returns the converted value. The standard Python types str, int, + float, and complex are useful examples of such callables. If None, + str is used. - choices -- A container of values that should be allowed. If not None, after a command-line argument has been converted to the appropriate @@ -1967,7 +1967,7 @@ for arg_string in arg_strings: # for regular arguments, just add them back into the list - if arg_string[0] not in self.fromfile_prefix_chars: + if not arg_string or arg_string[0] not in self.fromfile_prefix_chars: new_arg_strings.append(arg_string) # replace arguments referencing files with the file content @@ -2174,9 +2174,12 @@ # Value conversion methods # ======================== def _get_values(self, action, arg_strings): - # for everything but PARSER args, strip out '--' + # for everything but PARSER, REMAINDER args, strip out first '--' if action.nargs not in [PARSER, REMAINDER]: - arg_strings = [s for s in arg_strings if s != '--'] + try: + arg_strings.remove('--') + except ValueError: + pass # optional argument produces a default when not present if not arg_strings and action.nargs == OPTIONAL: diff --git a/Lib/ctypes/test/test_bitfields.py b/Lib/ctypes/test/test_bitfields.py --- a/Lib/ctypes/test/test_bitfields.py +++ b/Lib/ctypes/test/test_bitfields.py @@ -240,5 +240,25 @@ _anonymous_ = ["_"] _fields_ = [("_", X)] + @unittest.skipUnless(hasattr(ctypes, "c_uint32"), "c_int32 is required") + def test_uint32(self): + class X(Structure): + _fields_ = [("a", c_uint32, 32)] + x = X() + x.a = 10 + self.assertEquals(x.a, 10) + x.a = 0xFDCBA987 + self.assertEquals(x.a, 0xFDCBA987) + + @unittest.skipUnless(hasattr(ctypes, "c_uint64"), "c_int64 is required") + def test_uint64(self): + class X(Structure): + _fields_ = [("a", c_uint64, 64)] + x = X() + x.a = 10 + self.assertEquals(x.a, 10) + x.a = 0xFEDCBA9876543211 + self.assertEquals(x.a, 0xFEDCBA9876543211) + if __name__ == "__main__": unittest.main() diff --git a/Lib/posixpath.py b/Lib/posixpath.py --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -68,7 +68,8 @@ def join(a, *p): """Join two or more pathname components, inserting '/' as needed. If any component is an absolute path, all previous path components - will be discarded.""" + will be discarded. An empty last part will result in a path that + ends with a separator.""" path = a for b in p: if b.startswith('/'): diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -1374,6 +1374,7 @@ ('X @hello', NS(a=None, x='X', y=['hello world!'])), ('-a B @recursive Y Z', NS(a='A', x='hello world!', y=['Y', 'Z'])), ('X @recursive Z -a B', NS(a='B', x='X', y=['hello world!', 'Z'])), + (["-a", "", "X", "Y"], NS(a='', x='X', y=['Y'])), ] @@ -1763,6 +1764,14 @@ parser2.add_argument('-y', choices='123', help='y help') parser2.add_argument('z', type=complex, nargs='*', help='z help') + # add third sub-parser + parser3_kwargs = dict(description='3 description') + if subparser_help: + parser3_kwargs['help'] = '3 help' + parser3 = subparsers.add_parser('3', **parser3_kwargs) + parser3.add_argument('t', type=int, help='t help') + parser3.add_argument('u', nargs='...', help='u help') + # return the main parser return parser @@ -1792,6 +1801,10 @@ self.parser.parse_args('--foo 0.125 1 c'.split()), NS(foo=True, bar=0.125, w=None, x='c'), ) + self.assertEqual( + self.parser.parse_args('-1.5 3 11 -- a --foo 7 -- b'.split()), + NS(foo=False, bar=-1.5, t=11, u=['a', '--foo', '7', '--', 'b']), + ) def test_parse_known_args(self): self.assertEqual( @@ -1826,15 +1839,15 @@ def test_help(self): self.assertEqual(self.parser.format_usage(), - 'usage: PROG [-h] [--foo] bar {1,2} ...\n') + 'usage: PROG [-h] [--foo] bar {1,2,3} ...\n') self.assertEqual(self.parser.format_help(), textwrap.dedent('''\ - usage: PROG [-h] [--foo] bar {1,2} ... + usage: PROG [-h] [--foo] bar {1,2,3} ... main description positional arguments: bar bar help - {1,2} command help + {1,2,3} command help optional arguments: -h, --help show this help message and exit @@ -1845,15 +1858,15 @@ # Make sure - is still used for help if it is a non-first prefix char parser = self._get_parser(prefix_chars='+:-') self.assertEqual(parser.format_usage(), - 'usage: PROG [-h] [++foo] bar {1,2} ...\n') + 'usage: PROG [-h] [++foo] bar {1,2,3} ...\n') self.assertEqual(parser.format_help(), textwrap.dedent('''\ - usage: PROG [-h] [++foo] bar {1,2} ... + usage: PROG [-h] [++foo] bar {1,2,3} ... main description positional arguments: bar bar help - {1,2} command help + {1,2,3} command help optional arguments: -h, --help show this help message and exit @@ -1864,15 +1877,15 @@ def test_help_alternate_prefix_chars(self): parser = self._get_parser(prefix_chars='+:/') self.assertEqual(parser.format_usage(), - 'usage: PROG [+h] [++foo] bar {1,2} ...\n') + 'usage: PROG [+h] [++foo] bar {1,2,3} ...\n') self.assertEqual(parser.format_help(), textwrap.dedent('''\ - usage: PROG [+h] [++foo] bar {1,2} ... + usage: PROG [+h] [++foo] bar {1,2,3} ... main description positional arguments: bar bar help - {1,2} command help + {1,2,3} command help optional arguments: +h, ++help show this help message and exit @@ -1881,18 +1894,19 @@ def test_parser_command_help(self): self.assertEqual(self.command_help_parser.format_usage(), - 'usage: PROG [-h] [--foo] bar {1,2} ...\n') + 'usage: PROG [-h] [--foo] bar {1,2,3} ...\n') self.assertEqual(self.command_help_parser.format_help(), textwrap.dedent('''\ - usage: PROG [-h] [--foo] bar {1,2} ... + usage: PROG [-h] [--foo] bar {1,2,3} ... main description positional arguments: bar bar help - {1,2} command help + {1,2,3} command help 1 1 help 2 2 help + 3 3 help optional arguments: -h, --help show this help message and exit diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -495,7 +495,19 @@ ) def test_errors(self): - self.assertRaises(UnicodeDecodeError, codecs.utf_16_le_decode, "\xff", "strict", True) + tests = [ + (b'\xff', u'\ufffd'), + (b'A\x00Z', u'A\ufffd'), + (b'A\x00B\x00C\x00D\x00Z', u'ABCD\ufffd'), + (b'\x00\xd8', u'\ufffd'), + (b'\x00\xd8A', u'\ufffd'), + (b'\x00\xd8A\x00', u'\ufffdA'), + (b'\x00\xdcA\x00', u'\ufffdA'), + ] + for raw, expected in tests: + self.assertRaises(UnicodeDecodeError, codecs.utf_16_le_decode, + raw, 'strict', True) + self.assertEqual(raw.decode('utf-16le', 'replace'), expected) class UTF16BETest(ReadTest): encoding = "utf-16-be" @@ -516,7 +528,19 @@ ) def test_errors(self): - self.assertRaises(UnicodeDecodeError, codecs.utf_16_be_decode, "\xff", "strict", True) + tests = [ + (b'\xff', u'\ufffd'), + (b'\x00A\xff', u'A\ufffd'), + (b'\x00A\x00B\x00C\x00DZ', u'ABCD\ufffd'), + (b'\xd8\x00', u'\ufffd'), + (b'\xd8\x00\xdc', u'\ufffd'), + (b'\xd8\x00\x00A', u'\ufffdA'), + (b'\xdc\x00\x00A', u'\ufffdA'), + ] + for raw, expected in tests: + self.assertRaises(UnicodeDecodeError, codecs.utf_16_be_decode, + raw, 'strict', True) + self.assertEqual(raw.decode('utf-16be', 'replace'), expected) class UTF8Test(ReadTest): encoding = "utf-8" diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -462,6 +462,7 @@ Kim Knapp Lenny Kneler Pat Knight +Jeff Knupp Greg Kochanski Damon Kohler Marko Kohtala diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,6 +9,12 @@ Core and Builtins ----------------- +- Issue #14579: Fix error handling bug in the utf-16 decoder. Patch by + Serhiy Storchaka. + +- Issue #15368: An issue that caused bytecode generation to be + non-deterministic when using randomized hashing (-R) has been fixed. + - Issue #15033: Fix the exit status bug when modules invoked using -m swith, return the proper failure return value (1). Patch contributed by Jeff Knupp. @@ -84,6 +90,14 @@ Library ------- +- Issue #13922: argparse no longer incorrectly strips '--'s that appear + after the first one. + +- Issue #12353: argparse now correctly handles null argument values. + +- Issue #6493: An issue in ctypes on Windows that caused structure bitfields + of type ctypes.c_uint32 and width 32 to incorrectly be set has been fixed. + - Issue #14635: telnetlib will use poll() rather than select() when possible to avoid failing due to the select() file descriptor limit. diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -431,12 +431,8 @@ #define LOW_BIT(x) ((x) & 0xFFFF) #define NUM_BITS(x) ((x) >> 16) -/* This seems nore a compiler issue than a Windows/non-Windows one */ -#ifdef MS_WIN32 -# define BIT_MASK(size) ((1 << NUM_BITS(size))-1) -#else -# define BIT_MASK(size) ((1LL << NUM_BITS(size))-1) -#endif +/* Doesn't work if NUM_BITS(size) == 0, but it never happens in SET() call. */ +#define BIT_MASK(type, size) (((((type)1 << (NUM_BITS(size) - 1)) - 1) << 1) + 1) /* This macro CHANGES the first parameter IN PLACE. For proper sign handling, we must first shift left, then right. @@ -448,10 +444,10 @@ } /* This macro RETURNS the first parameter with the bit field CHANGED. */ -#define SET(x, v, size) \ +#define SET(type, x, v, size) \ (NUM_BITS(size) ? \ - ( ( x & ~(BIT_MASK(size) << LOW_BIT(size)) ) | ( (v & BIT_MASK(size)) << LOW_BIT(size) ) ) \ - : v) + ( ( (type)x & ~(BIT_MASK(type, size) << LOW_BIT(size)) ) | ( ((type)v & BIT_MASK(type, size)) << LOW_BIT(size) ) ) \ + : (type)v) /* byte swapping macros */ #define SWAP_2(v) \ @@ -523,7 +519,7 @@ long val; if (get_long(value, &val) < 0) return NULL; - *(signed char *)ptr = (signed char)SET(*(signed char *)ptr, (signed char)val, size); + *(signed char *)ptr = SET(signed char, *(signed char *)ptr, val, size); _RET(value); } @@ -542,8 +538,7 @@ unsigned long val; if (get_ulong(value, &val) < 0) return NULL; - *(unsigned char *)ptr = (unsigned char)SET(*(unsigned char*)ptr, - (unsigned short)val, size); + *(unsigned char *)ptr = SET(unsigned char, *(unsigned char*)ptr, val, size); _RET(value); } @@ -564,7 +559,7 @@ if (get_long(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, (short)val, size); + x = SET(short, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -579,7 +574,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_2(field); - field = SET(field, (short)val, size); + field = SET(short, field, val, size); field = SWAP_2(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -612,7 +607,7 @@ if (get_ulong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, (unsigned short)val, size); + x = SET(unsigned short, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -626,7 +621,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_2(field); - field = SET(field, (unsigned short)val, size); + field = SET(unsigned short, field, val, size); field = SWAP_2(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -660,7 +655,7 @@ if (get_long(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, (int)val, size); + x = SET(int, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -674,7 +669,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_INT(field); - field = SET(field, (int)val, size); + field = SET(int, field, val, size); field = SWAP_INT(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -761,7 +756,7 @@ if (get_ulong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, (unsigned int)val, size); + x = SET(unsigned int, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -774,7 +769,7 @@ if (get_ulong(value, &val) < 0) return NULL; memcpy(&field, ptr, sizeof(field)); - field = (unsigned int)SET(field, (unsigned int)val, size); + field = SET(unsigned int, field, (unsigned int)val, size); field = SWAP_INT(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -808,7 +803,7 @@ if (get_long(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, val, size); + x = SET(long, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -822,7 +817,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_LONG(field); - field = (long)SET(field, val, size); + field = SET(long, field, val, size); field = SWAP_LONG(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -856,7 +851,7 @@ if (get_ulong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, val, size); + x = SET(unsigned long, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -870,7 +865,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_LONG(field); - field = (unsigned long)SET(field, val, size); + field = SET(unsigned long, field, val, size); field = SWAP_LONG(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -905,7 +900,7 @@ if (get_longlong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, val, size); + x = SET(PY_LONG_LONG, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -919,7 +914,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_8(field); - field = (PY_LONG_LONG)SET(field, val, size); + field = SET(PY_LONG_LONG, field, val, size); field = SWAP_8(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -952,7 +947,7 @@ if (get_ulonglong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, val, size); + x = SET(PY_LONG_LONG, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -966,7 +961,7 @@ return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_8(field); - field = (unsigned PY_LONG_LONG)SET(field, val, size); + field = SET(unsigned PY_LONG_LONG, field, val, size); field = SWAP_8(field); memcpy(ptr, &field, sizeof(field)); _RET(value); diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -2564,7 +2564,7 @@ } /* UTF-16 code pair: */ - if (q >= e) { + if (e - q < 2) { errmsg = "unexpected end of data"; startinpos = (((const char *)q)-2)-starts; endinpos = ((const char *)e)-starts; diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -53,8 +53,12 @@ PyDoc_STRVAR(import_doc, "__import__(name, globals={}, locals={}, fromlist=[], level=-1) -> module\n\ \n\ -Import a module. The globals are only used to determine the context;\n\ -they are not modified. The locals are currently unused. The fromlist\n\ +Import a module. Because this function is meant for use by the Python\n\ +interpreter and not for general use it is better to use\n\ +importlib.import_module() to programmatically import a module.\n\ +\n\ +The globals argument is only used to determine the context;\n\ +they are not modified. The locals argument is unused. The fromlist\n\ should be a list of names to emulate ``from name import ...'', or an\n\ empty list to emulate ``import name''.\n\ When importing a module from a package, note that __import__('A.B', ...)\n\ diff --git a/Python/compile.c b/Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -359,14 +359,31 @@ static PyObject * dictbytype(PyObject *src, int scope_type, int flag, int offset) { - Py_ssize_t pos = 0, i = offset, scope; + Py_ssize_t i = offset, scope, num_keys, key_i; PyObject *k, *v, *dest = PyDict_New(); + PyObject *sorted_keys; assert(offset >= 0); if (dest == NULL) return NULL; - while (PyDict_Next(src, &pos, &k, &v)) { + /* Sort the keys so that we have a deterministic order on the indexes + saved in the returned dictionary. These indexes are used as indexes + into the free and cell var storage. Therefore if they aren't + deterministic, then the generated bytecode is not deterministic. + */ + sorted_keys = PyDict_Keys(src); + if (sorted_keys == NULL) + return NULL; + if (PyList_Sort(sorted_keys) != 0) { + Py_DECREF(sorted_keys); + return NULL; + } + num_keys = PyList_GET_SIZE(sorted_keys); + + for (key_i = 0; key_i < num_keys; key_i++) { + k = PyList_GET_ITEM(sorted_keys, key_i); + v = PyDict_GetItem(src, k); /* XXX this should probably be a macro in symtable.h */ assert(PyInt_Check(v)); scope = (PyInt_AS_LONG(v) >> SCOPE_OFF) & SCOPE_MASK; @@ -374,12 +391,14 @@ if (scope == scope_type || PyInt_AS_LONG(v) & flag) { PyObject *tuple, *item = PyInt_FromLong(i); if (item == NULL) { + Py_DECREF(sorted_keys); Py_DECREF(dest); return NULL; } i++; tuple = PyTuple_Pack(2, k, k->ob_type); if (!tuple || PyDict_SetItem(dest, tuple, item) < 0) { + Py_DECREF(sorted_keys); Py_DECREF(item); Py_DECREF(dest); Py_XDECREF(tuple); @@ -389,6 +408,7 @@ Py_DECREF(tuple); } } + Py_DECREF(sorted_keys); return dest; } diff --git a/Python/peephole.c b/Python/peephole.c --- a/Python/peephole.c +++ b/Python/peephole.c @@ -347,7 +347,7 @@ codestr = (unsigned char *)memcpy(codestr, PyString_AS_STRING(code), codelen); - /* Verify that RETURN_VALUE terminates the codestring. This allows + /* Verify that RETURN_VALUE terminates the codestring. This allows the various transformation patterns to look ahead several instructions without additional checks to make sure they are not looking beyond the end of the code string. @@ -445,8 +445,8 @@ case BUILD_LIST: j = GETARG(codestr, i); h = i - 3 * j; - if (h >= 0 && - j <= lastlc && + if (h >= 0 && + j <= lastlc && ((opcode == BUILD_TUPLE && ISBASICBLOCK(blocks, h, 3*(j+1))) || (opcode == BUILD_LIST && @@ -490,8 +490,8 @@ case BINARY_AND: case BINARY_XOR: case BINARY_OR: - if (lastlc >= 2 && - ISBASICBLOCK(blocks, i-6, 7) && + if (lastlc >= 2 && + ISBASICBLOCK(blocks, i-6, 7) && fold_binops_on_constants(&codestr[i-6], consts)) { i -= 2; assert(codestr[i] == LOAD_CONST); @@ -500,13 +500,13 @@ break; /* Fold unary ops on constants. - LOAD_CONST c1 UNARY_OP --> LOAD_CONST unary_op(c) */ + LOAD_CONST c1 UNARY_OP --> LOAD_CONST unary_op(c) */ case UNARY_NEGATIVE: case UNARY_CONVERT: case UNARY_INVERT: - if (lastlc >= 1 && - ISBASICBLOCK(blocks, i-3, 4) && - fold_unaryops_on_constants(&codestr[i-3], consts)) { + if (lastlc >= 1 && + ISBASICBLOCK(blocks, i-3, 4) && + fold_unaryops_on_constants(&codestr[i-3], consts)) { i -= 2; assert(codestr[i] == LOAD_CONST); cumlc = 1; @@ -532,8 +532,7 @@ tgt = GETJUMPTGT(codestr, i); j = codestr[tgt]; if (CONDITIONAL_JUMP(j)) { - /* NOTE: all possible jumps here are - absolute! */ + /* NOTE: all possible jumps here are absolute! */ if (JUMPS_ON_TRUE(j) == JUMPS_ON_TRUE(opcode)) { /* The second jump will be taken iff the first is. */ @@ -544,13 +543,10 @@ SETARG(codestr, i, tgttgt); goto reoptimize_current; } else { - /* The second jump is not taken - if the first is (so jump past - it), and all conditional - jumps pop their argument when - they're not taken (so change - the first jump to pop its - argument when it's taken). */ + /* The second jump is not taken if the first is (so + jump past it), and all conditional jumps pop their + argument when they're not taken (so change the + first jump to pop its argument when it's taken). */ if (JUMPS_ON_TRUE(opcode)) codestr[i] = POP_JUMP_IF_TRUE; else @@ -586,8 +582,8 @@ if (opcode == JUMP_FORWARD) /* JMP_ABS can go backwards */ opcode = JUMP_ABSOLUTE; if (!ABSOLUTE_JUMP(opcode)) - tgttgt -= i + 3; /* Calc relative jump addr */ - if (tgttgt < 0) /* No backward relative jumps */ + tgttgt -= i + 3; /* Calc relative jump addr */ + if (tgttgt < 0) /* No backward relative jumps */ continue; codestr[i] = opcode; SETARG(codestr, i, tgttgt); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 22 07:36:21 2012 From: python-checkins at python.org (ned.deily) Date: Sun, 22 Jul 2012 07:36:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315184=3A_Fix_test?= =?utf-8?q?=5F=5Fremove=5Funsupported=5Farchs_failures_on_10=2E6?= Message-ID: <3WfvhP5LbHzPWK@mail.python.org> http://hg.python.org/cpython/rev/31349bc40214 changeset: 78239:31349bc40214 parent: 78236:e683084c8bb9 user: Ned Deily date: Sat Jul 21 22:35:16 2012 -0700 summary: Issue #15184: Fix test__remove_unsupported_archs failures on 10.6 by removing unwarranted assumptions that clang compiler chain cannot handle ppc (the driver passes off ppc compiles to gcc). Mock the behavior instead. files: Lib/test/test__osx_support.py | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-) diff --git a/Lib/test/test__osx_support.py b/Lib/test/test__osx_support.py --- a/Lib/test/test__osx_support.py +++ b/Lib/test/test__osx_support.py @@ -173,7 +173,6 @@ _osx_support._remove_universal_flags( config_vars)) - @unittest.skipUnless(shutil.which('clang'),'test requires clang') def test__remove_unsupported_archs(self): config_vars = { 'CC': 'clang', @@ -195,6 +194,15 @@ } self.add_expected_saved_initial_values(config_vars, expected_vars) + suffix = (':' + self.env['PATH']) if self.env['PATH'] else '' + self.env['PATH'] = os.path.abspath(self.temp_path_dir) + suffix + c_name = 'clang' + test.support.unlink(c_name) + self.addCleanup(test.support.unlink, c_name) + # exit status 255 means no PPC support in this compiler chain + with open(c_name, 'w') as f: + f.write("#!/bin/sh\nexit 255") + os.chmod(c_name, stat.S_IRWXU) self.assertEqual(expected_vars, _osx_support._remove_unsupported_archs( config_vars)) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 22 09:47:20 2012 From: python-checkins at python.org (ned.deily) Date: Sun, 22 Jul 2012 09:47:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315188=3A_Prevent_?= =?utf-8?q?test=5Fldshared=5Fvalue_failure_due_to_slightly?= Message-ID: <3WfybX5d4CzPWc@mail.python.org> http://hg.python.org/cpython/rev/f4470babf79b changeset: 78240:f4470babf79b user: Ned Deily date: Sun Jul 22 00:46:46 2012 -0700 summary: Issue #15188: Prevent test_ldshared_value failure due to slightly different parsing of the Makefile by distutils.sysconfig and sysconfig in the case when an intermediate config vars, used to construct PY_CFLAGS or PY_LDFLAGS, has a trailing space character. In this case, the OS X installer build script was leaving a trailing space in the OPT and LDFLAGS config vars. The space is not significant and it's not worth toying with the Makefile parsing. files: Mac/BuildScript/build-installer.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -915,8 +915,8 @@ data = fp.read() fp.close() - data = data.replace('-L%s/libraries/usr/local/lib'%(WORKDIR,), '') - data = data.replace('-I%s/libraries/usr/local/include'%(WORKDIR,), '') + data = data.replace(' -L%s/libraries/usr/local/lib'%(WORKDIR,), '') + data = data.replace(' -I%s/libraries/usr/local/include'%(WORKDIR,), '') fp = open(path, 'w') fp.write(data) fp.close() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 22 12:00:03 2012 From: python-checkins at python.org (ned.deily) Date: Sun, 22 Jul 2012 12:00:03 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315184=3A_Some_con?= =?utf-8?q?fig_variables_in_test=5Fsysconfig=5Fmodule?= Message-ID: <3Wg1Xg5D95zPYL@mail.python.org> http://hg.python.org/cpython/rev/c286d50ecd19 changeset: 78241:c286d50ecd19 user: Ned Deily date: Sun Jul 22 02:56:36 2012 -0700 summary: Issue #15184: Some config variables in test_sysconfig_module may differ between sysconfig and distutils.sysconfig due to compiler customizations on OS X. For now, move those vars into a separate test and skip if the customization has taken place in distutils. The long-term solution is to eliminate having two sysconfig modules. files: Lib/distutils/tests/test_sysconfig.py | 22 ++++++++++++++- 1 files changed, 21 insertions(+), 1 deletions(-) diff --git a/Lib/distutils/tests/test_sysconfig.py b/Lib/distutils/tests/test_sysconfig.py --- a/Lib/distutils/tests/test_sysconfig.py +++ b/Lib/distutils/tests/test_sysconfig.py @@ -102,7 +102,27 @@ import sysconfig as global_sysconfig self.assertEqual(global_sysconfig.get_config_var('CFLAGS'), sysconfig.get_config_var('CFLAGS')) self.assertEqual(global_sysconfig.get_config_var('LDFLAGS'), sysconfig.get_config_var('LDFLAGS')) - self.assertEqual(global_sysconfig.get_config_var('LDSHARED'),sysconfig.get_config_var('LDSHARED')) + + @unittest.skipIf(sysconfig.get_config_var('CUSTOMIZED_OSX_COMPILER'),'compiler flags customized') + def test_sysconfig_compiler_vars(self): + # On OS X, binary installers support extension module building on + # various levels of the operating system with differing Xcode + # configurations. This requires customization of some of the + # compiler configuration directives to suit the environment on + # the installed machine. Some of these customizations may require + # running external programs and, so, are deferred until needed by + # the first extension module build. With Python 3.3, only + # the Distutils version of sysconfig is used for extension module + # builds, which happens earlier in the Distutils tests. This may + # cause the following tests to fail since no tests have caused + # the global version of sysconfig to call the customization yet. + # The solution for now is to simply skip this test in this case. + # The longer-term solution is to only have one version of sysconfig. + + import sysconfig as global_sysconfig + if sysconfig.get_config_var('CUSTOMIZED_OSX_COMPILER'): + return + self.assertEqual(global_sysconfig.get_config_var('LDSHARED'), sysconfig.get_config_var('LDSHARED')) self.assertEqual(global_sysconfig.get_config_var('CC'), sysconfig.get_config_var('CC')) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 22 12:57:22 2012 From: python-checkins at python.org (andrew.svetlov) Date: Sun, 22 Jul 2012 12:57:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_=2315094=3A_fix_incorrectl?= =?utf-8?q?y_placed_=23endif_in_=5Ftkinter=2Ec=2E?= Message-ID: <3Wg2pp5cSzzPXp@mail.python.org> http://hg.python.org/cpython/rev/657673a37dd3 changeset: 78242:657673a37dd3 user: Andrew Svetlov date: Sun Jul 22 13:56:54 2012 +0300 summary: #15094: fix incorrectly placed #endif in _tkinter.c. Patch by Serhiy Storchaka. files: Misc/NEWS | 3 +++ Modules/_tkinter.c | 2 +- 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -52,6 +52,9 @@ Library ------- +- Issue #15094: Incorrectly placed #endif in _tkinter.c. + Patch by Serhiy Storchaka. + - Issue #13922: argparse no longer incorrectly strips '--'s that appear after the first one. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -996,8 +996,8 @@ ch); ckfree(FREECAST outbuf); return NULL; + } #endif - } outbuf[i] = ch; } result = Tcl_NewUnicodeObj(outbuf, size); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 23 02:44:07 2012 From: python-checkins at python.org (r.david.murray) Date: Mon, 23 Jul 2012 02:44:07 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogIzE1NDI5OiBGaXgg?= =?utf-8?q?invalid_mention_of_types=2ENoneType_from_None_docs=2E?= Message-ID: <3WgP8l0FNtzPQ2@mail.python.org> http://hg.python.org/cpython/rev/84b577567fab changeset: 78243:84b577567fab branch: 3.2 parent: 78235:c97cfe04880f user: R David Murray date: Sun Jul 22 20:43:13 2012 -0400 summary: #15429: Fix invalid mention of types.NoneType from None docs. files: Doc/library/constants.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/constants.rst b/Doc/library/constants.rst --- a/Doc/library/constants.rst +++ b/Doc/library/constants.rst @@ -19,7 +19,7 @@ .. data:: None - The sole value of :attr:`types.NoneType`. ``None`` is frequently used to + The sole value of the type ``NoneType``. ``None`` is frequently used to represent the absence of a value, as when default arguments are not passed to a function. Assignments to ``None`` are illegal and raise a :exc:`SyntaxError`. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 23 02:44:08 2012 From: python-checkins at python.org (r.david.murray) Date: Mon, 23 Jul 2012 02:44:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Merge_=2315429=3A_Fix_invalid_mention_of_types=2ENoneTyp?= =?utf-8?q?e_from_None_docs=2E?= Message-ID: <3WgP8m61QpzPY2@mail.python.org> http://hg.python.org/cpython/rev/c43d73277756 changeset: 78244:c43d73277756 parent: 78242:657673a37dd3 parent: 78243:84b577567fab user: R David Murray date: Sun Jul 22 20:43:42 2012 -0400 summary: Merge #15429: Fix invalid mention of types.NoneType from None docs. files: Doc/library/constants.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/constants.rst b/Doc/library/constants.rst --- a/Doc/library/constants.rst +++ b/Doc/library/constants.rst @@ -19,7 +19,7 @@ .. data:: None - The sole value of :attr:`types.NoneType`. ``None`` is frequently used to + The sole value of the type ``NoneType``. ``None`` is frequently used to represent the absence of a value, as when default arguments are not passed to a function. Assignments to ``None`` are illegal and raise a :exc:`SyntaxError`. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 23 03:55:35 2012 From: python-checkins at python.org (r.david.murray) Date: Mon, 23 Jul 2012 03:55:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogIzE1MjMyOiBjb3Jy?= =?utf-8?q?ectly_mangle_From_lines_in_MIME_preamble_and_epilogue?= Message-ID: <3WgQlC0cGxzPFy@mail.python.org> http://hg.python.org/cpython/rev/b97f65f2298d changeset: 78245:b97f65f2298d branch: 3.2 parent: 78243:84b577567fab user: R David Murray date: Sun Jul 22 21:47:53 2012 -0400 summary: #15232: correctly mangle From lines in MIME preamble and epilogue files: Lib/email/generator.py | 12 ++++++++++-- Lib/email/test/test_email.py | 22 ++++++++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/Lib/email/generator.py b/Lib/email/generator.py --- a/Lib/email/generator.py +++ b/Lib/email/generator.py @@ -233,7 +233,11 @@ msg.set_boundary(boundary) # If there's a preamble, write it out, with a trailing CRLF if msg.preamble is not None: - self.write(msg.preamble + self._NL) + if self._mangle_from_: + preamble = fcre.sub('>From ', msg.preamble) + else: + preamble = msg.preamble + self.write(preamble + self._NL) # dash-boundary transport-padding CRLF self.write('--' + boundary + self._NL) # body-part @@ -251,7 +255,11 @@ self.write(self._NL + '--' + boundary + '--') if msg.epilogue is not None: self.write(self._NL) - self.write(msg.epilogue) + if self._mangle_from_: + epilogue = fcre.sub('>From ', msg.epilogue) + else: + epilogue = msg.epilogue + self.write(epilogue) def _handle_multipart_signed(self, msg): # The contents of signed parts has to stay unmodified in order to keep diff --git a/Lib/email/test/test_email.py b/Lib/email/test/test_email.py --- a/Lib/email/test/test_email.py +++ b/Lib/email/test/test_email.py @@ -1275,6 +1275,28 @@ Blah blah blah """) + def test_mangle_from_in_preamble_and_epilog(self): + s = StringIO() + g = Generator(s, mangle_from_=True) + msg = email.message_from_string(textwrap.dedent("""\ + From: foo at bar.com + Mime-Version: 1.0 + Content-Type: multipart/mixed; boundary=XXX + + From somewhere unknown + + --XXX + Content-Type: text/plain + + foo + + --XXX-- + + From somewhere unknowable + """)) + g.flatten(msg) + self.assertEqual(len([1 for x in s.getvalue().split('\n') + if x.startswith('>From ')]), 2) # Test the basic MIMEAudio class diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -98,6 +98,9 @@ Library ------- +- Issue #15232: when mangle_from is True, email.Generator now correctly mangles + lines that start with 'From' that occur in a MIME preamble or epilogue. + - Issue #13922: argparse no longer incorrectly strips '--'s that appear after the first one. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 23 03:55:36 2012 From: python-checkins at python.org (r.david.murray) Date: Mon, 23 Jul 2012 03:55:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Merge_=2315232=3A_correctly_mangle_From_lines_in_MIME_pr?= =?utf-8?q?eamble_and_epilogue?= Message-ID: <3WgQlD5GcszPGf@mail.python.org> http://hg.python.org/cpython/rev/80b81658455b changeset: 78246:80b81658455b parent: 78244:c43d73277756 parent: 78245:b97f65f2298d user: R David Murray date: Sun Jul 22 21:53:54 2012 -0400 summary: Merge #15232: correctly mangle From lines in MIME preamble and epilogue files: Lib/email/generator.py | 12 ++++++++- Lib/test/test_email/test_email.py | 22 +++++++++++++++++++ Misc/NEWS | 3 ++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/Lib/email/generator.py b/Lib/email/generator.py --- a/Lib/email/generator.py +++ b/Lib/email/generator.py @@ -252,7 +252,11 @@ msg.set_boundary(boundary) # If there's a preamble, write it out, with a trailing CRLF if msg.preamble is not None: - self.write(msg.preamble + self._NL) + if self._mangle_from_: + preamble = fcre.sub('>From ', msg.preamble) + else: + preamble = msg.preamble + self.write(preamble + self._NL) # dash-boundary transport-padding CRLF self.write('--' + boundary + self._NL) # body-part @@ -270,7 +274,11 @@ self.write(self._NL + '--' + boundary + '--') if msg.epilogue is not None: self.write(self._NL) - self.write(msg.epilogue) + if self._mangle_from_: + epilogue = fcre.sub('>From ', msg.epilogue) + else: + epilogue = msg.epilogue + self.write(epilogue) def _handle_multipart_signed(self, msg): # The contents of signed parts has to stay unmodified in order to keep diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -1283,6 +1283,28 @@ Blah blah blah """) + def test_mangle_from_in_preamble_and_epilog(self): + s = StringIO() + g = Generator(s, mangle_from_=True) + msg = email.message_from_string(textwrap.dedent("""\ + From: foo at bar.com + Mime-Version: 1.0 + Content-Type: multipart/mixed; boundary=XXX + + From somewhere unknown + + --XXX + Content-Type: text/plain + + foo + + --XXX-- + + From somewhere unknowable + """)) + g.flatten(msg) + self.assertEqual(len([1 for x in s.getvalue().split('\n') + if x.startswith('>From ')]), 2) # Test the basic MIMEAudio class diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -52,6 +52,9 @@ Library ------- +- Issue #15232: when mangle_from is True, email.Generator now correctly mangles + lines that start with 'From' that occur in a MIME preamble or epilogue. + - Issue #15094: Incorrectly placed #endif in _tkinter.c. Patch by Serhiy Storchaka. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 23 03:55:38 2012 From: python-checkins at python.org (r.david.murray) Date: Mon, 23 Jul 2012 03:55:38 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE1MjMyOiBjb3Jy?= =?utf-8?q?ectly_mangle_From_lines_in_MIME_preamble_and_epilogue?= Message-ID: <3WgQlG2YLqzPQX@mail.python.org> http://hg.python.org/cpython/rev/9f500171c592 changeset: 78247:9f500171c592 branch: 2.7 parent: 78238:5fb1057bd490 user: R David Murray date: Sun Jul 22 21:55:12 2012 -0400 summary: #15232: correctly mangle From lines in MIME preamble and epilogue files: Lib/email/generator.py | 12 ++++++++++-- Lib/email/test/test_email.py | 23 +++++++++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/Lib/email/generator.py b/Lib/email/generator.py --- a/Lib/email/generator.py +++ b/Lib/email/generator.py @@ -212,7 +212,11 @@ msg.set_boundary(boundary) # If there's a preamble, write it out, with a trailing CRLF if msg.preamble is not None: - print >> self._fp, msg.preamble + if self._mangle_from_: + preamble = fcre.sub('>From ', msg.preamble) + else: + preamble = msg.preamble + print >> self._fp, preamble # dash-boundary transport-padding CRLF print >> self._fp, '--' + boundary # body-part @@ -230,7 +234,11 @@ self._fp.write('\n--' + boundary + '--') if msg.epilogue is not None: print >> self._fp - self._fp.write(msg.epilogue) + if self._mangle_from_: + epilogue = fcre.sub('>From ', msg.epilogue) + else: + epilogue = msg.epilogue + self._fp.write(epilogue) def _handle_multipart_signed(self, msg): # The contents of signed parts has to stay unmodified in order to keep diff --git a/Lib/email/test/test_email.py b/Lib/email/test/test_email.py --- a/Lib/email/test/test_email.py +++ b/Lib/email/test/test_email.py @@ -9,6 +9,7 @@ import difflib import unittest import warnings +import textwrap from cStringIO import StringIO import email @@ -948,6 +949,28 @@ Blah blah blah """) + def test_mangle_from_in_preamble_and_epilog(self): + s = StringIO() + g = Generator(s, mangle_from_=True) + msg = email.message_from_string(textwrap.dedent("""\ + From: foo at bar.com + Mime-Version: 1.0 + Content-Type: multipart/mixed; boundary=XXX + + From somewhere unknown + + --XXX + Content-Type: text/plain + + foo + + --XXX-- + + From somewhere unknowable + """)) + g.flatten(msg) + self.assertEqual(len([1 for x in s.getvalue().split('\n') + if x.startswith('>From ')]), 2) # Test the basic MIMEAudio class diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -90,6 +90,9 @@ Library ------- +- Issue #15232: when mangle_from is True, email.Generator now correctly mangles + lines that start with 'From' that occur in a MIME preamble or epilog. + - Issue #13922: argparse no longer incorrectly strips '--'s that appear after the first one. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 23 04:33:38 2012 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 23 Jul 2012 04:33:38 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogLSBJc3N1ZSAjMTUy?= =?utf-8?q?50=3A_Document_that_filecmp=2Edircmp_compares_files_shallowly?= =?utf-8?q?=2E_Patch?= Message-ID: <3WgRb66Qh1zPCm@mail.python.org> http://hg.python.org/cpython/rev/f6ce142c2fce changeset: 78248:f6ce142c2fce branch: 3.2 parent: 78243:84b577567fab user: Senthil Kumaran date: Sun Jul 22 19:12:58 2012 -0700 summary: - Issue #15250: Document that filecmp.dircmp compares files shallowly. Patch contributed by Chris Jerdonek. files: Doc/library/filecmp.rst | 11 ++++++++--- Misc/NEWS | 3 +++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Doc/library/filecmp.rst b/Doc/library/filecmp.rst --- a/Doc/library/filecmp.rst +++ b/Doc/library/filecmp.rst @@ -75,6 +75,9 @@ 'tags']``. *hide* is a list of names to hide, and defaults to ``[os.curdir, os.pardir]``. + The :class:`dircmp` class compares files by doing *shallow* comparisons + as described for :func:`filecmp.cmp`. + The :class:`dircmp` class provides the following methods: @@ -94,7 +97,7 @@ Print a comparison between *a* and *b* and common subdirectories (recursively). - The :class:`dircmp` offers a number of interesting attributes that may be + The :class:`dircmp` class offers a number of interesting attributes that may be used to get various bits of information about the directory trees being compared. @@ -146,12 +149,14 @@ .. attribute:: same_files - Files which are identical in both *a* and *b*. + Files which are identical in both *a* and *b*, using the class's + file comparison operator. .. attribute:: diff_files - Files which are in both *a* and *b*, whose contents differ. + Files which are in both *a* and *b*, whose contents differ according + to the class's file comparison operator. .. attribute:: funny_files diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -424,6 +424,9 @@ - Issue #14034: added the argparse tutorial. +- Issue #15250: Document that filecmp.dircmp compares files shallowly. Patch + contributed by Chris Jerdonek. + Tools/Demos ----------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 23 04:33:40 2012 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 23 Jul 2012 04:33:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_-_Issue_=2315250=3A_Document_that_filecmp=2Edircmp_compa?= =?utf-8?q?res_files_shallowly=2E_Patch?= Message-ID: <3WgRb84mh6zPMW@mail.python.org> http://hg.python.org/cpython/rev/d2a49ee77b6f changeset: 78249:d2a49ee77b6f parent: 78244:c43d73277756 parent: 78248:f6ce142c2fce user: Senthil Kumaran date: Sun Jul 22 19:31:36 2012 -0700 summary: - Issue #15250: Document that filecmp.dircmp compares files shallowly. Patch contributed by Chris Jerdonek. files: Doc/library/filecmp.rst | 11 ++++++++--- Misc/NEWS | 3 +++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Doc/library/filecmp.rst b/Doc/library/filecmp.rst --- a/Doc/library/filecmp.rst +++ b/Doc/library/filecmp.rst @@ -75,6 +75,9 @@ 'tags']``. *hide* is a list of names to hide, and defaults to ``[os.curdir, os.pardir]``. + The :class:`dircmp` class compares files by doing *shallow* comparisons + as described for :func:`filecmp.cmp`. + The :class:`dircmp` class provides the following methods: @@ -94,7 +97,7 @@ Print a comparison between *a* and *b* and common subdirectories (recursively). - The :class:`dircmp` offers a number of interesting attributes that may be + The :class:`dircmp` class offers a number of interesting attributes that may be used to get various bits of information about the directory trees being compared. @@ -146,12 +149,14 @@ .. attribute:: same_files - Files which are identical in both *a* and *b*. + Files which are identical in both *a* and *b*, using the class's + file comparison operator. .. attribute:: diff_files - Files which are in both *a* and *b*, whose contents differ. + Files which are in both *a* and *b*, whose contents differ according + to the class's file comparison operator. .. attribute:: funny_files diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -196,6 +196,9 @@ - Issue #13557: Clarify effect of giving two different namespaces to exec or execfile(). +- Issue #15250: Document that filecmp.dircmp compares files shallowly. Patch + contributed by Chris Jerdonek. + Tests ----- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 23 04:33:42 2012 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 23 Jul 2012 04:33:42 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgaGVhZHMu?= Message-ID: <3WgRbB2PdfzPNL@mail.python.org> http://hg.python.org/cpython/rev/2429e760b0bd changeset: 78250:2429e760b0bd parent: 78249:d2a49ee77b6f parent: 78246:80b81658455b user: Senthil Kumaran date: Sun Jul 22 19:32:17 2012 -0700 summary: merge heads. files: Lib/email/generator.py | 12 ++++++++- Lib/test/test_email/test_email.py | 22 +++++++++++++++++++ Misc/NEWS | 3 ++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/Lib/email/generator.py b/Lib/email/generator.py --- a/Lib/email/generator.py +++ b/Lib/email/generator.py @@ -252,7 +252,11 @@ msg.set_boundary(boundary) # If there's a preamble, write it out, with a trailing CRLF if msg.preamble is not None: - self.write(msg.preamble + self._NL) + if self._mangle_from_: + preamble = fcre.sub('>From ', msg.preamble) + else: + preamble = msg.preamble + self.write(preamble + self._NL) # dash-boundary transport-padding CRLF self.write('--' + boundary + self._NL) # body-part @@ -270,7 +274,11 @@ self.write(self._NL + '--' + boundary + '--') if msg.epilogue is not None: self.write(self._NL) - self.write(msg.epilogue) + if self._mangle_from_: + epilogue = fcre.sub('>From ', msg.epilogue) + else: + epilogue = msg.epilogue + self.write(epilogue) def _handle_multipart_signed(self, msg): # The contents of signed parts has to stay unmodified in order to keep diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -1283,6 +1283,28 @@ Blah blah blah """) + def test_mangle_from_in_preamble_and_epilog(self): + s = StringIO() + g = Generator(s, mangle_from_=True) + msg = email.message_from_string(textwrap.dedent("""\ + From: foo at bar.com + Mime-Version: 1.0 + Content-Type: multipart/mixed; boundary=XXX + + From somewhere unknown + + --XXX + Content-Type: text/plain + + foo + + --XXX-- + + From somewhere unknowable + """)) + g.flatten(msg) + self.assertEqual(len([1 for x in s.getvalue().split('\n') + if x.startswith('>From ')]), 2) # Test the basic MIMEAudio class diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -52,6 +52,9 @@ Library ------- +- Issue #15232: when mangle_from is True, email.Generator now correctly mangles + lines that start with 'From' that occur in a MIME preamble or epilogue. + - Issue #15094: Incorrectly placed #endif in _tkinter.c. Patch by Serhiy Storchaka. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 23 04:33:43 2012 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 23 Jul 2012 04:33:43 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4yIC0+IDMuMik6?= =?utf-8?q?_merge_heads=2E?= Message-ID: <3WgRbC6mBGzPNZ@mail.python.org> http://hg.python.org/cpython/rev/af2e044609ca changeset: 78251:af2e044609ca branch: 3.2 parent: 78248:f6ce142c2fce parent: 78245:b97f65f2298d user: Senthil Kumaran date: Sun Jul 22 19:32:44 2012 -0700 summary: merge heads. files: Lib/email/generator.py | 12 ++++++++++-- Lib/email/test/test_email.py | 22 ++++++++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/Lib/email/generator.py b/Lib/email/generator.py --- a/Lib/email/generator.py +++ b/Lib/email/generator.py @@ -233,7 +233,11 @@ msg.set_boundary(boundary) # If there's a preamble, write it out, with a trailing CRLF if msg.preamble is not None: - self.write(msg.preamble + self._NL) + if self._mangle_from_: + preamble = fcre.sub('>From ', msg.preamble) + else: + preamble = msg.preamble + self.write(preamble + self._NL) # dash-boundary transport-padding CRLF self.write('--' + boundary + self._NL) # body-part @@ -251,7 +255,11 @@ self.write(self._NL + '--' + boundary + '--') if msg.epilogue is not None: self.write(self._NL) - self.write(msg.epilogue) + if self._mangle_from_: + epilogue = fcre.sub('>From ', msg.epilogue) + else: + epilogue = msg.epilogue + self.write(epilogue) def _handle_multipart_signed(self, msg): # The contents of signed parts has to stay unmodified in order to keep diff --git a/Lib/email/test/test_email.py b/Lib/email/test/test_email.py --- a/Lib/email/test/test_email.py +++ b/Lib/email/test/test_email.py @@ -1275,6 +1275,28 @@ Blah blah blah """) + def test_mangle_from_in_preamble_and_epilog(self): + s = StringIO() + g = Generator(s, mangle_from_=True) + msg = email.message_from_string(textwrap.dedent("""\ + From: foo at bar.com + Mime-Version: 1.0 + Content-Type: multipart/mixed; boundary=XXX + + From somewhere unknown + + --XXX + Content-Type: text/plain + + foo + + --XXX-- + + From somewhere unknowable + """)) + g.flatten(msg) + self.assertEqual(len([1 for x in s.getvalue().split('\n') + if x.startswith('>From ')]), 2) # Test the basic MIMEAudio class diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -98,6 +98,9 @@ Library ------- +- Issue #15232: when mangle_from is True, email.Generator now correctly mangles + lines that start with 'From' that occur in a MIME preamble or epilogue. + - Issue #13922: argparse no longer incorrectly strips '--'s that appear after the first one. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 23 04:36:58 2012 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 23 Jul 2012 04:36:58 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE1MjUw?= =?utf-8?q?=3A_Document_that_filecmp=2Edircmp_compares_files_shallowly=2E_?= =?utf-8?q?Patch?= Message-ID: <3WgRfy3mRFzPLZ@mail.python.org> http://hg.python.org/cpython/rev/3921d3c71e64 changeset: 78252:3921d3c71e64 branch: 2.7 parent: 78247:9f500171c592 user: Senthil Kumaran date: Sun Jul 22 19:36:03 2012 -0700 summary: Issue #15250: Document that filecmp.dircmp compares files shallowly. Patch contributed by Chris Jerdonek. files: Doc/library/filecmp.rst | 11 ++++++++--- Misc/NEWS | 4 ++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Doc/library/filecmp.rst b/Doc/library/filecmp.rst --- a/Doc/library/filecmp.rst +++ b/Doc/library/filecmp.rst @@ -75,6 +75,9 @@ 'tags']``. *hide* is a list of names to hide, and defaults to ``[os.curdir, os.pardir]``. + The :class:`dircmp` class compares files by doing *shallow* comparisons + as described for :func:`filecmp.cmp`. + The :class:`dircmp` class provides the following methods: @@ -94,7 +97,7 @@ Print a comparison between *a* and *b* and common subdirectories (recursively). - The :class:`dircmp` offers a number of interesting attributes that may be + The :class:`dircmp` class offers a number of interesting attributes that may be used to get various bits of information about the directory trees being compared. @@ -146,12 +149,14 @@ .. attribute:: same_files - Files which are identical in both *a* and *b*. + Files which are identical in both *a* and *b*, using the class's + file comparison operator. .. attribute:: diff_files - Files which are in both *a* and *b*, whose contents differ. + Files which are in both *a* and *b*, whose contents differ according + to the class's file comparison operator. .. attribute:: funny_files diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -304,12 +304,16 @@ - Issue #14437: Fix building the _io module under Cygwin. Documentation +------------- - Issue #13557: Clarify effect of giving two different namespaces to exec or execfile(). - Issue #14034: added the argparse tutorial. +- Issue #15250: Document that filecmp.dircmp compares files shallowly. Patch + contributed by Chris Jerdonek. + What's New in Python 2.7.3 release candidate 2? =============================================== -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Mon Jul 23 06:02:22 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 23 Jul 2012 06:02:22 +0200 Subject: [Python-checkins] Daily reference leaks (c43d73277756): sum=0 Message-ID: results for c43d73277756 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogge2WV5', '-x'] From python-checkins at python.org Mon Jul 23 07:24:40 2012 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 23 Jul 2012 07:24:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Simplify_the_LaTeX_section?= =?utf-8?q?_=28only_three_escapes_are_needed_for_alltt=29?= Message-ID: <3WgWNS2Nt5zPDD@mail.python.org> http://hg.python.org/cpython/rev/b127046831e2 changeset: 78253:b127046831e2 parent: 78250:2429e760b0bd user: Raymond Hettinger date: Mon Jul 23 00:24:24 2012 -0500 summary: Simplify the LaTeX section (only three escapes are needed for alltt) files: Tools/scripts/highlight.py | 17 ++++++----------- 1 files changed, 6 insertions(+), 11 deletions(-) diff --git a/Tools/scripts/highlight.py b/Tools/scripts/highlight.py --- a/Tools/scripts/highlight.py +++ b/Tools/scripts/highlight.py @@ -57,7 +57,7 @@ if kind: text, written = combine_range(lines, written, (srow, scol)) yield '', text - text, written = combine_range(lines, written, (erow, ecol)) + text, written = tok_str, (erow, ecol) yield kind, text line_upto_token, written = combine_range(lines, written, (erow, ecol)) yield '', line_upto_token @@ -172,15 +172,10 @@ \end{document} ''' -def latex_escape(s): - 'Replace LaTeX special characters with their escaped equivalents' - # http://en.wikibooks.org/wiki/LaTeX/Basics#Special_Characters - xlat = { - '#': r'\#', '$': r'\$', '%': r'\%', '^': r'\textasciicircum{}', - '&': r'\&', '_': r'\_', '{': r'\{', '}': r'\}', '~': r'\~{}', - '\\': r'\textbackslash{}', - } - return re.sub(r'[\\#$%^&_{}~]', lambda mo: xlat[mo.group()], s) +def alltt_escape(s): + 'Replace backslash and braces with their escaped equivalents' + xlat = {'{': r'\{', '}': r'\}', '\\': r'\textbackslash{}'} + return re.sub(r'[\\{}]', lambda mo: xlat[mo.group()], s) def latex_highlight(classified_text, title = 'python', commands = default_latex_commands, @@ -191,7 +186,7 @@ for kind, text in classified_text: if kind: result.append(r'\py%s{' % kind) - result.append(latex_escape(text)) + result.append(alltt_escape(text)) if kind: result.append('}') return default_latex_document % dict(title=title, macros=macros, body=''.join(result)) -- Repository URL: http://hg.python.org/cpython From meadori at gmail.com Mon Jul 23 07:34:02 2012 From: meadori at gmail.com (Meador Inge) Date: Mon, 23 Jul 2012 00:34:02 -0500 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge #15232: correctly mangle From lines in MIME preamble and epilogue In-Reply-To: <3WgQlD5GcszPGf@mail.python.org> References: <3WgQlD5GcszPGf@mail.python.org> Message-ID: On Sun, Jul 22, 2012 at 8:55 PM, r.david.murray wrote: > http://hg.python.org/cpython/rev/80b81658455b > changeset: 78246:80b81658455b > parent: 78244:c43d73277756 > parent: 78245:b97f65f2298d > user: R David Murray > date: Sun Jul 22 21:53:54 2012 -0400 > summary: > Merge #15232: correctly mangle From lines in MIME preamble and epilogue > > files: > Lib/email/generator.py | 12 ++++++++- > Lib/test/test_email/test_email.py | 22 +++++++++++++++++++ > Misc/NEWS | 3 ++ > 3 files changed, 35 insertions(+), 2 deletions(-) I'm not quite sure what happened, but something seems to have gone wrong with this merge. After doing the following while on the "default" branch: $ hg merge 3.2 I see: $ hg st M Lib/email/generator.py M Lib/test/test_email/test_email.py M Misc/NEWS and a bunch of conflicts in 'Misc/NEWS'. > > diff --git a/Lib/email/generator.py b/Lib/email/generator.py > --- a/Lib/email/generator.py > +++ b/Lib/email/generator.py > @@ -252,7 +252,11 @@ > msg.set_boundary(boundary) > # If there's a preamble, write it out, with a trailing CRLF > if msg.preamble is not None: > - self.write(msg.preamble + self._NL) > + if self._mangle_from_: > + preamble = fcre.sub('>From ', msg.preamble) > + else: > + preamble = msg.preamble > + self.write(preamble + self._NL) > # dash-boundary transport-padding CRLF > self.write('--' + boundary + self._NL) > # body-part > @@ -270,7 +274,11 @@ > self.write(self._NL + '--' + boundary + '--') > if msg.epilogue is not None: > self.write(self._NL) > - self.write(msg.epilogue) > + if self._mangle_from_: > + epilogue = fcre.sub('>From ', msg.epilogue) > + else: > + epilogue = msg.epilogue > + self.write(epilogue) > > def _handle_multipart_signed(self, msg): > # The contents of signed parts has to stay unmodified in order to keep > diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py > --- a/Lib/test/test_email/test_email.py > +++ b/Lib/test/test_email/test_email.py > @@ -1283,6 +1283,28 @@ > Blah blah blah > """) > > + def test_mangle_from_in_preamble_and_epilog(self): > + s = StringIO() > + g = Generator(s, mangle_from_=True) > + msg = email.message_from_string(textwrap.dedent("""\ > + From: foo at bar.com > + Mime-Version: 1.0 > + Content-Type: multipart/mixed; boundary=XXX > + > + From somewhere unknown > + > + --XXX > + Content-Type: text/plain > + > + foo > + > + --XXX-- > + > + From somewhere unknowable > + """)) > + g.flatten(msg) > + self.assertEqual(len([1 for x in s.getvalue().split('\n') > + if x.startswith('>From ')]), 2) > > > # Test the basic MIMEAudio class > diff --git a/Misc/NEWS b/Misc/NEWS > --- a/Misc/NEWS > +++ b/Misc/NEWS > @@ -52,6 +52,9 @@ > Library > ------- > > +- Issue #15232: when mangle_from is True, email.Generator now correctly mangles > + lines that start with 'From' that occur in a MIME preamble or epilogue. > + > - Issue #15094: Incorrectly placed #endif in _tkinter.c. > Patch by Serhiy Storchaka. > > > -- > Repository URL: http://hg.python.org/cpython > > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > http://mail.python.org/mailman/listinfo/python-checkins > -- # Meador From python-checkins at python.org Mon Jul 23 16:17:21 2012 From: python-checkins at python.org (meador.inge) Date: Mon, 23 Jul 2012 16:17:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Putting_the_3=2E2_-=3E_default_merge_info_in_a_happy_pla?= =?utf-8?b?Y2Uu?= Message-ID: <3WglC55d7hzPPD@mail.python.org> http://hg.python.org/cpython/rev/db0973994844 changeset: 78254:db0973994844 parent: 78253:b127046831e2 parent: 78251:af2e044609ca user: Meador Inge date: Mon Jul 23 09:16:53 2012 -0500 summary: Putting the 3.2 -> default merge info in a happy place. files: -- Repository URL: http://hg.python.org/cpython From meadori at gmail.com Mon Jul 23 16:17:33 2012 From: meadori at gmail.com (Meador Inge) Date: Mon, 23 Jul 2012 09:17:33 -0500 Subject: [Python-checkins] cpython (merge 3.2 -> default): Merge #15232: correctly mangle From lines in MIME preamble and epilogue In-Reply-To: References: <3WgQlD5GcszPGf@mail.python.org> Message-ID: On Mon, Jul 23, 2012 at 12:34 AM, Meador Inge wrote: > On Sun, Jul 22, 2012 at 8:55 PM, r.david.murray > wrote: > >> http://hg.python.org/cpython/rev/80b81658455b >> changeset: 78246:80b81658455b >> parent: 78244:c43d73277756 >> parent: 78245:b97f65f2298d >> user: R David Murray >> date: Sun Jul 22 21:53:54 2012 -0400 >> summary: >> Merge #15232: correctly mangle From lines in MIME preamble and epilogue >> >> files: >> Lib/email/generator.py | 12 ++++++++- >> Lib/test/test_email/test_email.py | 22 +++++++++++++++++++ >> Misc/NEWS | 3 ++ >> 3 files changed, 35 insertions(+), 2 deletions(-) > > I'm not quite sure what happened, but something seems to have gone wrong > with this merge. After doing the following while on the "default" branch: > > $ hg merge 3.2 > > I see: > > $ hg st > M Lib/email/generator.py > M Lib/test/test_email/test_email.py > M Misc/NEWS > > and a bunch of conflicts in 'Misc/NEWS'. Hmmm, actually it looks like this head merge that Senthil performed: http://hg.python.org/cpython/rev/af2e044609ca. Anyway, I resolved the conflicts. -- Meador From python-checkins at python.org Mon Jul 23 17:25:46 2012 From: python-checkins at python.org (meador.inge) Date: Mon, 23 Jul 2012 17:25:46 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE1NDAy?= =?utf-8?q?=3A_Add_a_=5F=5Fsizeof=5F=5F_method_to_struct=2EStruct=2E?= Message-ID: <3Wgmk243zMzPN8@mail.python.org> http://hg.python.org/cpython/rev/dbe7f39ff341 changeset: 78255:dbe7f39ff341 branch: 2.7 parent: 78252:3921d3c71e64 user: Meador Inge date: Mon Jul 23 09:27:00 2012 -0500 summary: Issue #15402: Add a __sizeof__ method to struct.Struct. Initial patch by Serhiy Storchaka. files: Lib/test/test_struct.py | 10 ++++++++++ Misc/NEWS | 4 ++++ Modules/_struct.c | 17 +++++++++++++++++ 3 files changed, 31 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -544,6 +544,16 @@ hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2) self.assertRaises(struct.error, struct.calcsize, hugecount2) + def test_sizeof(self): + self.assertGreater(sys.getsizeof(struct.Struct('BHILfdspP')), + sys.getsizeof(struct.Struct('B'))) + self.assertGreaterEqual(sys.getsizeof(struct.Struct('123B')), + sys.getsizeof(struct.Struct('B'))) + self.assertGreaterEqual(sys.getsizeof(struct.Struct('B' * 123)), + sys.getsizeof(struct.Struct('123B'))) + self.assertGreaterEqual(sys.getsizeof(struct.Struct('123xB')), + sys.getsizeof(struct.Struct('B'))) + def test_main(): run_unittest(StructTest) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -90,6 +90,10 @@ Library ------- +- Issue #15402: An issue in the struct module that caused sys.getsizeof to + return incorrect results for struct.Struct instances has been fixed. + Initial patch by Serhiy Storchaka. + - Issue #15232: when mangle_from is True, email.Generator now correctly mangles lines that start with 'From' that occur in a MIME preamble or epilog. diff --git a/Modules/_struct.c b/Modules/_struct.c --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -1693,6 +1693,22 @@ return PyInt_FromSsize_t(self->s_size); } +PyDoc_STRVAR(s_sizeof__doc__, +"S.__sizeof__() -> size of S in memory, in bytes"); + +static PyObject * +s_sizeof(PyStructObject *self) +{ + Py_ssize_t size; + formatcode *code; + + size = sizeof(PyStructObject) + sizeof(formatcode); + for (code = self->s_codes; code->fmtdef != NULL; code++) { + size += sizeof(formatcode); + } + return PyLong_FromSsize_t(size); +} + /* List of functions */ static struct PyMethodDef s_methods[] = { @@ -1701,6 +1717,7 @@ {"unpack", s_unpack, METH_O, s_unpack__doc__}, {"unpack_from", (PyCFunction)s_unpack_from, METH_VARARGS|METH_KEYWORDS, s_unpack_from__doc__}, + {"__sizeof__", (PyCFunction)s_sizeof, METH_NOARGS, s_sizeof__doc__}, {NULL, NULL} /* sentinel */ }; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 23 17:25:48 2012 From: python-checkins at python.org (meador.inge) Date: Mon, 23 Jul 2012 17:25:48 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE1NDAy?= =?utf-8?q?=3A_Add_a_=5F=5Fsizeof=5F=5F_method_to_struct=2EStruct=2E?= Message-ID: <3Wgmk428x7zPPT@mail.python.org> http://hg.python.org/cpython/rev/3e7b517e1b68 changeset: 78256:3e7b517e1b68 branch: 3.2 parent: 78251:af2e044609ca user: Meador Inge date: Mon Jul 23 10:01:29 2012 -0500 summary: Issue #15402: Add a __sizeof__ method to struct.Struct. Initial patch by Serhiy Storchaka. files: Lib/test/test_struct.py | 10 ++++++++++ Misc/NEWS | 4 ++++ Modules/_struct.c | 17 +++++++++++++++++ 3 files changed, 31 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -556,6 +556,16 @@ s = struct.Struct('i') s.__init__('ii') + def test_sizeof(self): + self.assertGreater(sys.getsizeof(struct.Struct('BHILfdspP')), + sys.getsizeof(struct.Struct('B'))) + self.assertGreaterEqual(sys.getsizeof(struct.Struct('123B')), + sys.getsizeof(struct.Struct('B'))) + self.assertGreaterEqual(sys.getsizeof(struct.Struct('B' * 123)), + sys.getsizeof(struct.Struct('123B'))) + self.assertGreaterEqual(sys.getsizeof(struct.Struct('123xB')), + sys.getsizeof(struct.Struct('B'))) + def test_main(): run_unittest(StructTest) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -98,6 +98,10 @@ Library ------- +- Issue #15402: An issue in the struct module that caused sys.getsizeof to + return incorrect results for struct.Struct instances has been fixed. + Initial patch by Serhiy Storchaka. + - Issue #15232: when mangle_from is True, email.Generator now correctly mangles lines that start with 'From' that occur in a MIME preamble or epilogue. diff --git a/Modules/_struct.c b/Modules/_struct.c --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -1665,6 +1665,22 @@ return PyLong_FromSsize_t(self->s_size); } +PyDoc_STRVAR(s_sizeof__doc__, +"S.__sizeof__() -> size of S in memory, in bytes"); + +static PyObject * +s_sizeof(PyStructObject *self) +{ + Py_ssize_t size; + formatcode *code; + + size = sizeof(PyStructObject) + sizeof(formatcode); + for (code = self->s_codes; code->fmtdef != NULL; code++) { + size += sizeof(formatcode); + } + return PyLong_FromSsize_t(size); +} + /* List of functions */ static struct PyMethodDef s_methods[] = { @@ -1673,6 +1689,7 @@ {"unpack", s_unpack, METH_O, s_unpack__doc__}, {"unpack_from", (PyCFunction)s_unpack_from, METH_VARARGS|METH_KEYWORDS, s_unpack_from__doc__}, + {"__sizeof__", (PyCFunction)s_sizeof, METH_NOARGS, s_sizeof__doc__}, {NULL, NULL} /* sentinel */ }; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 23 17:25:49 2012 From: python-checkins at python.org (meador.inge) Date: Mon, 23 Jul 2012 17:25:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2315402=3A_Add_a_=5F=5Fsizeof=5F=5F_method_to_str?= =?utf-8?q?uct=2EStruct=2E?= Message-ID: <3Wgmk56WLyzPPK@mail.python.org> http://hg.python.org/cpython/rev/03063e718f5f changeset: 78257:03063e718f5f parent: 78254:db0973994844 parent: 78256:3e7b517e1b68 user: Meador Inge date: Mon Jul 23 10:22:36 2012 -0500 summary: Issue #15402: Add a __sizeof__ method to struct.Struct. Initial patch by Serhiy Storchaka. files: Lib/test/test_struct.py | 10 ++++++++++ Misc/NEWS | 4 ++++ Modules/_struct.c | 17 +++++++++++++++++ 3 files changed, 31 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -572,6 +572,16 @@ s = struct.Struct('i') s.__init__('ii') + def test_sizeof(self): + self.assertGreater(sys.getsizeof(struct.Struct('BHILfdspP')), + sys.getsizeof(struct.Struct('B'))) + self.assertGreaterEqual(sys.getsizeof(struct.Struct('123B')), + sys.getsizeof(struct.Struct('B'))) + self.assertGreaterEqual(sys.getsizeof(struct.Struct('B' * 123)), + sys.getsizeof(struct.Struct('123B'))) + self.assertGreaterEqual(sys.getsizeof(struct.Struct('123xB')), + sys.getsizeof(struct.Struct('B'))) + def test_main(): run_unittest(StructTest) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -52,6 +52,10 @@ Library ------- +- Issue #15402: An issue in the struct module that caused sys.getsizeof to + return incorrect results for struct.Struct instances has been fixed. + Initial patch by Serhiy Storchaka. + - Issue #15232: when mangle_from is True, email.Generator now correctly mangles lines that start with 'From' that occur in a MIME preamble or epilogue. diff --git a/Modules/_struct.c b/Modules/_struct.c --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -1752,6 +1752,22 @@ return PyLong_FromSsize_t(self->s_size); } +PyDoc_STRVAR(s_sizeof__doc__, +"S.__sizeof__() -> size of S in memory, in bytes"); + +static PyObject * +s_sizeof(PyStructObject *self) +{ + Py_ssize_t size; + formatcode *code; + + size = sizeof(PyStructObject) + sizeof(formatcode); + for (code = self->s_codes; code->fmtdef != NULL; code++) { + size += sizeof(formatcode); + } + return PyLong_FromSsize_t(size); +} + /* List of functions */ static struct PyMethodDef s_methods[] = { @@ -1760,6 +1776,7 @@ {"unpack", s_unpack, METH_O, s_unpack__doc__}, {"unpack_from", (PyCFunction)s_unpack_from, METH_VARARGS|METH_KEYWORDS, s_unpack_from__doc__}, + {"__sizeof__", (PyCFunction)s_sizeof, METH_NOARGS, s_sizeof__doc__}, {NULL, NULL} /* sentinel */ }; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 23 18:17:22 2012 From: python-checkins at python.org (jesus.cea) Date: Mon, 23 Jul 2012 18:17:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Better_test_fo?= =?utf-8?q?r_Issue_=2315402=3A_Add_a_=5F=5Fsizeof=5F=5F_method_to_struct?= =?utf-8?q?=2EStruct?= Message-ID: <3WgnsZ0RjVzPR1@mail.python.org> http://hg.python.org/cpython/rev/b1d85a44f149 changeset: 78258:b1d85a44f149 branch: 2.7 parent: 78255:dbe7f39ff341 user: Jesus Cea date: Mon Jul 23 18:14:45 2012 +0200 summary: Better test for Issue #15402: Add a __sizeof__ method to struct.Struct files: Doc/ACKS.txt | 1 + Lib/test/test_struct.py | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Doc/ACKS.txt b/Doc/ACKS.txt --- a/Doc/ACKS.txt +++ b/Doc/ACKS.txt @@ -197,6 +197,7 @@ * Anthony Starks * Greg Stein * Peter Stoehr + * Serhiy Storchaka * Mark Summerfield * Reuben Sumner * Kalle Svensson diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -547,12 +547,12 @@ def test_sizeof(self): self.assertGreater(sys.getsizeof(struct.Struct('BHILfdspP')), sys.getsizeof(struct.Struct('B'))) - self.assertGreaterEqual(sys.getsizeof(struct.Struct('123B')), + self.assertGreater(sys.getsizeof(struct.Struct('123B')), sys.getsizeof(struct.Struct('B'))) - self.assertGreaterEqual(sys.getsizeof(struct.Struct('B' * 123)), + self.assertGreater(sys.getsizeof(struct.Struct('B' * 1234)), sys.getsizeof(struct.Struct('123B'))) - self.assertGreaterEqual(sys.getsizeof(struct.Struct('123xB')), - sys.getsizeof(struct.Struct('B'))) + self.assertGreater(sys.getsizeof(struct.Struct('1234B')), + sys.getsizeof(struct.Struct('123B'))) def test_main(): run_unittest(StructTest) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 23 18:17:23 2012 From: python-checkins at python.org (jesus.cea) Date: Mon, 23 Jul 2012 18:17:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_Better_test_fo?= =?utf-8?q?r_Issue_=2315402=3A_Add_a_=5F=5Fsizeof=5F=5F_method_to_struct?= =?utf-8?q?=2EStruct?= Message-ID: <3Wgnsb4tzXzPRQ@mail.python.org> http://hg.python.org/cpython/rev/1911e192af0d changeset: 78259:1911e192af0d branch: 3.2 parent: 78256:3e7b517e1b68 user: Jesus Cea date: Mon Jul 23 18:15:33 2012 +0200 summary: Better test for Issue #15402: Add a __sizeof__ method to struct.Struct files: Doc/ACKS.txt | 1 + Lib/test/test_struct.py | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Doc/ACKS.txt b/Doc/ACKS.txt --- a/Doc/ACKS.txt +++ b/Doc/ACKS.txt @@ -204,6 +204,7 @@ * Anthony Starks * Greg Stein * Peter Stoehr + * Serhiy Storchaka * Mark Summerfield * Reuben Sumner * Kalle Svensson diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -559,12 +559,12 @@ def test_sizeof(self): self.assertGreater(sys.getsizeof(struct.Struct('BHILfdspP')), sys.getsizeof(struct.Struct('B'))) - self.assertGreaterEqual(sys.getsizeof(struct.Struct('123B')), + self.assertGreater(sys.getsizeof(struct.Struct('123B')), sys.getsizeof(struct.Struct('B'))) - self.assertGreaterEqual(sys.getsizeof(struct.Struct('B' * 123)), + self.assertGreater(sys.getsizeof(struct.Struct('B' * 1234)), sys.getsizeof(struct.Struct('123B'))) - self.assertGreaterEqual(sys.getsizeof(struct.Struct('123xB')), - sys.getsizeof(struct.Struct('B'))) + self.assertGreater(sys.getsizeof(struct.Struct('1234B')), + sys.getsizeof(struct.Struct('123B'))) def test_main(): run_unittest(StructTest) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 23 18:17:25 2012 From: python-checkins at python.org (jesus.cea) Date: Mon, 23 Jul 2012 18:17:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_MERGE=3A_Better_test_for_Issue_=2315402=3A_Add_a_=5F=5Fs?= =?utf-8?q?izeof=5F=5F_method_to_struct=2EStruct?= Message-ID: <3Wgnsd0h5RzNS2@mail.python.org> http://hg.python.org/cpython/rev/b9a3ed1b14b9 changeset: 78260:b9a3ed1b14b9 parent: 78257:03063e718f5f parent: 78259:1911e192af0d user: Jesus Cea date: Mon Jul 23 18:16:18 2012 +0200 summary: MERGE: Better test for Issue #15402: Add a __sizeof__ method to struct.Struct files: Doc/ACKS.txt | 1 + Lib/test/test_struct.py | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Doc/ACKS.txt b/Doc/ACKS.txt --- a/Doc/ACKS.txt +++ b/Doc/ACKS.txt @@ -205,6 +205,7 @@ * Anthony Starks * Greg Stein * Peter Stoehr + * Serhiy Storchaka * Mark Summerfield * Reuben Sumner * Kalle Svensson diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -575,12 +575,12 @@ def test_sizeof(self): self.assertGreater(sys.getsizeof(struct.Struct('BHILfdspP')), sys.getsizeof(struct.Struct('B'))) - self.assertGreaterEqual(sys.getsizeof(struct.Struct('123B')), + self.assertGreater(sys.getsizeof(struct.Struct('123B')), sys.getsizeof(struct.Struct('B'))) - self.assertGreaterEqual(sys.getsizeof(struct.Struct('B' * 123)), + self.assertGreater(sys.getsizeof(struct.Struct('B' * 1234)), sys.getsizeof(struct.Struct('123B'))) - self.assertGreaterEqual(sys.getsizeof(struct.Struct('123xB')), - sys.getsizeof(struct.Struct('B'))) + self.assertGreater(sys.getsizeof(struct.Struct('1234B')), + sys.getsizeof(struct.Struct('123B'))) def test_main(): run_unittest(StructTest) -- Repository URL: http://hg.python.org/cpython From meadori at gmail.com Mon Jul 23 18:27:44 2012 From: meadori at gmail.com (Meador Inge) Date: Mon, 23 Jul 2012 11:27:44 -0500 Subject: [Python-checkins] cpython (merge 3.2 -> default): MERGE: Better test for Issue #15402: Add a __sizeof__ method to struct.Struct In-Reply-To: <3Wgnsd0h5RzNS2@mail.python.org> References: <3Wgnsd0h5RzNS2@mail.python.org> Message-ID: On Mon, Jul 23, 2012 at 11:17 AM, jesus.cea wrote: > http://hg.python.org/cpython/rev/b9a3ed1b14b9 > changeset: 78260:b9a3ed1b14b9 > parent: 78257:03063e718f5f > parent: 78259:1911e192af0d > user: Jesus Cea > date: Mon Jul 23 18:16:18 2012 +0200 > summary: > MERGE: Better test for Issue #15402: Add a __sizeof__ method to struct.Struct > > files: > Doc/ACKS.txt | 1 + > Lib/test/test_struct.py | 8 ++++---- > 2 files changed, 5 insertions(+), 4 deletions(-) Jes?s, Doc/ACKS.txt is *only* for acknowledging documentation contributions. Serhiy is already in Misc/ACKS. No need to add him to Doc/ACKS.txt. As for the tests, I intentionally kept them the way that Serhiy contributed them -- using >= instead of >. I kept them this way because we also discussed in issue14596 the prospect of optimizing the way repeat counts are handled. These tests would start failing if (when) that optimization happens. So, neither of these changes are really necessary. Although, it wouldn't hurt to have *additional* tests using the > relation. > > diff --git a/Doc/ACKS.txt b/Doc/ACKS.txt > --- a/Doc/ACKS.txt > +++ b/Doc/ACKS.txt > @@ -205,6 +205,7 @@ > * Anthony Starks > * Greg Stein > * Peter Stoehr > + * Serhiy Storchaka > * Mark Summerfield > * Reuben Sumner > * Kalle Svensson > diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py > --- a/Lib/test/test_struct.py > +++ b/Lib/test/test_struct.py > @@ -575,12 +575,12 @@ > def test_sizeof(self): > self.assertGreater(sys.getsizeof(struct.Struct('BHILfdspP')), > sys.getsizeof(struct.Struct('B'))) > - self.assertGreaterEqual(sys.getsizeof(struct.Struct('123B')), > + self.assertGreater(sys.getsizeof(struct.Struct('123B')), > sys.getsizeof(struct.Struct('B'))) > - self.assertGreaterEqual(sys.getsizeof(struct.Struct('B' * 123)), > + self.assertGreater(sys.getsizeof(struct.Struct('B' * 1234)), > sys.getsizeof(struct.Struct('123B'))) > - self.assertGreaterEqual(sys.getsizeof(struct.Struct('123xB')), > - sys.getsizeof(struct.Struct('B'))) > + self.assertGreater(sys.getsizeof(struct.Struct('1234B')), > + sys.getsizeof(struct.Struct('123B'))) > > def test_main(): > run_unittest(StructTest) > > -- > Repository URL: http://hg.python.org/cpython > > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > http://mail.python.org/mailman/listinfo/python-checkins > -- # Meador From python-checkins at python.org Mon Jul 23 18:45:07 2012 From: python-checkins at python.org (jesus.cea) Date: Mon, 23 Jul 2012 18:45:07 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Rollback_an_in?= =?utf-8?q?correct_Doc/ACKS=2Etxt_entry?= Message-ID: <3WgpTb0GkHzMcx@mail.python.org> http://hg.python.org/cpython/rev/d56306b78b64 changeset: 78261:d56306b78b64 branch: 2.7 parent: 78258:b1d85a44f149 user: Jesus Cea date: Mon Jul 23 18:39:51 2012 +0200 summary: Rollback an incorrect Doc/ACKS.txt entry files: Doc/ACKS.txt | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Doc/ACKS.txt b/Doc/ACKS.txt --- a/Doc/ACKS.txt +++ b/Doc/ACKS.txt @@ -197,7 +197,6 @@ * Anthony Starks * Greg Stein * Peter Stoehr - * Serhiy Storchaka * Mark Summerfield * Reuben Sumner * Kalle Svensson -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 23 18:45:08 2012 From: python-checkins at python.org (jesus.cea) Date: Mon, 23 Jul 2012 18:45:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_Rollback_an_in?= =?utf-8?q?correct_Doc/ACKS=2Etxt_entry?= Message-ID: <3WgpTc5F1fzPHj@mail.python.org> http://hg.python.org/cpython/rev/52032b13243e changeset: 78262:52032b13243e branch: 3.2 parent: 78259:1911e192af0d user: Jesus Cea date: Mon Jul 23 18:42:37 2012 +0200 summary: Rollback an incorrect Doc/ACKS.txt entry files: Doc/ACKS.txt | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Doc/ACKS.txt b/Doc/ACKS.txt --- a/Doc/ACKS.txt +++ b/Doc/ACKS.txt @@ -204,7 +204,6 @@ * Anthony Starks * Greg Stein * Peter Stoehr - * Serhiy Storchaka * Mark Summerfield * Reuben Sumner * Kalle Svensson -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 23 18:45:10 2012 From: python-checkins at python.org (jesus.cea) Date: Mon, 23 Jul 2012 18:45:10 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_MERGE=3A_Rollback_an_incorrect_Doc/ACKS=2Etxt_entry?= Message-ID: <3WgpTf0x1PzPNH@mail.python.org> http://hg.python.org/cpython/rev/00db71b3c5bd changeset: 78263:00db71b3c5bd parent: 78260:b9a3ed1b14b9 parent: 78262:52032b13243e user: Jesus Cea date: Mon Jul 23 18:43:18 2012 +0200 summary: MERGE: Rollback an incorrect Doc/ACKS.txt entry files: Doc/ACKS.txt | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Doc/ACKS.txt b/Doc/ACKS.txt --- a/Doc/ACKS.txt +++ b/Doc/ACKS.txt @@ -205,7 +205,6 @@ * Anthony Starks * Greg Stein * Peter Stoehr - * Serhiy Storchaka * Mark Summerfield * Reuben Sumner * Kalle Svensson -- Repository URL: http://hg.python.org/cpython From jcea at jcea.es Mon Jul 23 18:38:30 2012 From: jcea at jcea.es (Jesus Cea) Date: Mon, 23 Jul 2012 18:38:30 +0200 Subject: [Python-checkins] cpython (merge 3.2 -> default): MERGE: Better test for Issue #15402: Add a __sizeof__ method to struct.Struct In-Reply-To: References: <3Wgnsd0h5RzNS2@mail.python.org> Message-ID: <500D7E06.4020606@jcea.es> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 23/07/12 18:27, Meador Inge wrote: > Doc/ACKS.txt is *only* for acknowledging documentation > contributions. Serhiy is already in Misc/ACKS. No need to add him > to Doc/ACKS.txt. Oh, I missed that. Thanks for the head up. > As for the tests, I intentionally kept them the way that Serhiy > contributed them -- using >= instead of >. I kept them this way > because we also discussed in issue14596 the prospect of optimizing > the way repeat counts are handled. These tests would start failing > if (when) that optimization happens. The problem is that if we do ">=", then an unpatched python interpreter could pass the test too. So we are not actually testing the feature. If the repeat counters are going to be optimized, the obvious step would be to upgrade the test to do something like "BHHIL" instead of "123B". I would wait until this feature is implemented to update the test. What do you think?. > > So, neither of these changes are really necessary. Although, it > wouldn't hurt to have *additional* tests using the > relation. > >> >> diff --git a/Doc/ACKS.txt b/Doc/ACKS.txt --- a/Doc/ACKS.txt +++ >> b/Doc/ACKS.txt @@ -205,6 +205,7 @@ * Anthony Starks * Greg Stein >> * Peter Stoehr + * Serhiy Storchaka * Mark Summerfield * Reuben >> Sumner * Kalle Svensson diff --git a/Lib/test/test_struct.py >> b/Lib/test/test_struct.py --- a/Lib/test/test_struct.py +++ >> b/Lib/test/test_struct.py @@ -575,12 +575,12 @@ def >> test_sizeof(self): >> self.assertGreater(sys.getsizeof(struct.Struct('BHILfdspP')), >> sys.getsizeof(struct.Struct('B'))) - >> self.assertGreaterEqual(sys.getsizeof(struct.Struct('123B')), + >> self.assertGreater(sys.getsizeof(struct.Struct('123B')), >> sys.getsizeof(struct.Struct('B'))) - >> self.assertGreaterEqual(sys.getsizeof(struct.Struct('B' * 123)), >> + self.assertGreater(sys.getsizeof(struct.Struct('B' * >> 1234)), sys.getsizeof(struct.Struct('123B'))) - >> self.assertGreaterEqual(sys.getsizeof(struct.Struct('123xB')), - >> sys.getsizeof(struct.Struct('B'))) + >> self.assertGreater(sys.getsizeof(struct.Struct('1234B')), + >> sys.getsizeof(struct.Struct('123B'))) >> >> def test_main(): run_unittest(StructTest) >> >> -- Repository URL: http://hg.python.org/cpython >> >> _______________________________________________ Python-checkins >> mailing list Python-checkins at python.org >> http://mail.python.org/mailman/listinfo/python-checkins >> > > > - -- Jesus Cea Avion _/_/ _/_/_/ _/_/_/ jcea at jcea.es - http://www.jcea.es/ _/_/ _/_/ _/_/ _/_/ _/_/ jabber / xmpp:jcea at jabber.org _/_/ _/_/ _/_/_/_/_/ . _/_/ _/_/ _/_/ _/_/ _/_/ "Things are not so easy" _/_/ _/_/ _/_/ _/_/ _/_/ _/_/ "My name is Dump, Core Dump" _/_/_/ _/_/_/ _/_/ _/_/ "El amor es poner tu felicidad en la felicidad de otro" - Leibniz -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iQCVAwUBUA1+Bplgi5GaxT1NAQJtSAQAkv5DyoQ1N1YdOH2QLHnFbOsvp/1aG0Vy hHMlD6cu/L7Ub+gyWWo65v9Dp4sLahV+CYem1wL4Fzd2QyBNQdg+BNou9eqoDzGF IJbY2HALwOwz1vgeBiamFOSvpyWya/hzXR9I7rkBqXdR9c2Njdl/ioZQNKETO05k TRfd/BQas4k= =TKFO -----END PGP SIGNATURE----- From meadori at gmail.com Mon Jul 23 20:19:51 2012 From: meadori at gmail.com (Meador Inge) Date: Mon, 23 Jul 2012 13:19:51 -0500 Subject: [Python-checkins] cpython (merge 3.2 -> default): MERGE: Better test for Issue #15402: Add a __sizeof__ method to struct.Struct In-Reply-To: <500D7E06.4020606@jcea.es> References: <3Wgnsd0h5RzNS2@mail.python.org> <500D7E06.4020606@jcea.es> Message-ID: On Mon, Jul 23, 2012 at 11:38 AM, Jesus Cea wrote: >> As for the tests, I intentionally kept them the way that Serhiy >> contributed them -- using >= instead of >. I kept them this way >> because we also discussed in issue14596 the prospect of optimizing >> the way repeat counts are handled. These tests would start failing >> if (when) that optimization happens. > > The problem is that if we do ">=", then an unpatched python > interpreter could pass the test too. So we are not actually testing > the feature. We are testing the feature because the first test looks like: self.assertGreater(sys.getsizeof(struct.Struct('BHILfdspP')), sys.getsizeof(struct.Struct('B'))) The way things were written 'sys.getsizeof' would returns the same answer regardless of the format string. The remaining tests looked like: self.assertGreaterEqual(sys.getsizeof(struct.Struct('123B')), sys.getsizeof(struct.Struct('B'))) self.assertGreaterEqual(sys.getsizeof(struct.Struct('B' * 123)), sys.getsizeof(struct.Struct('123B'))) self.assertGreaterEqual(sys.getsizeof(struct.Struct('123xB')), sys.getsizeof(struct.Struct('B'))) and while they didn't fail without the patch I felt they were still useful in documenting that there is nothing that guarantees 'sizeof("123B") > sizeof("B")' 'sizeof("B" * 123) > sizeof("123B")', or 'sizeof("123xB") > sizeof("B")'. > If the repeat counters are going to be optimized, the obvious step > would be to upgrade the test to do something like "BHHIL" instead of > "123B". I would wait until this feature is implemented to update the test. That is what the first test basically already does :-) > What do you think?. It isn't that big of a deal. We can just leave the tests as you changed them. In the future it would probably be better to hash this stuff out in the tracker. The patch was out for review for several days ... Thanks, -- Meador From storchaka at gmail.com Mon Jul 23 20:59:40 2012 From: storchaka at gmail.com (Serhiy Storchaka) Date: Mon, 23 Jul 2012 21:59:40 +0300 Subject: [Python-checkins] cpython (merge 3.2 -> default): MERGE: Better test for Issue #15402: Add a __sizeof__ method to struct.Struct In-Reply-To: References: <3Wgnsd0h5RzNS2@mail.python.org> <500D7E06.4020606@jcea.es> Message-ID: On 23.07.12 21:19, Meador Inge wrote: > The patch was out for review for several days ... Actually for several months (in issue14596). From python-checkins at python.org Mon Jul 23 23:23:18 2012 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 23 Jul 2012 23:23:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?benchmarks=3A_Add_a_pathlib_benchmark?= =?utf-8?q?_=28see_speed_ML=29?= Message-ID: <3WgwfZ4FcwzPRQ@mail.python.org> http://hg.python.org/benchmarks/rev/72516165f6ed changeset: 158:72516165f6ed user: Antoine Pitrou date: Mon Jul 23 23:21:12 2012 +0200 summary: Add a pathlib benchmark (see speed ML) files: lib/pathlib/LICENSE.txt | 19 + lib/pathlib/MANIFEST.in | 3 + lib/pathlib/README.txt | 104 + lib/pathlib/VERSION.txt | 1 + lib/pathlib/docs/Makefile | 153 ++ lib/pathlib/docs/conf.py | 245 +++ lib/pathlib/docs/index.rst | 803 +++++++++++++ lib/pathlib/docs/make.bat | 190 +++ lib/pathlib/pathlib.py | 1265 ++++++++++++++++++++ lib/pathlib/setup.py | 28 + lib/pathlib/test_pathlib.py | 1417 +++++++++++++++++++++++ perf.py | 14 +- performance/bm_pathlib.py | 83 + performance/compat.py | 2 + 14 files changed, 4326 insertions(+), 1 deletions(-) diff --git a/lib/pathlib/LICENSE.txt b/lib/pathlib/LICENSE.txt new file mode 100644 --- /dev/null +++ b/lib/pathlib/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2012 Antoine Pitrou + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lib/pathlib/MANIFEST.in b/lib/pathlib/MANIFEST.in new file mode 100644 --- /dev/null +++ b/lib/pathlib/MANIFEST.in @@ -0,0 +1,3 @@ +include *.py *.txt *.rst +recursive-include docs *.rst *.py make.bat Makefile + diff --git a/lib/pathlib/README.txt b/lib/pathlib/README.txt new file mode 100644 --- /dev/null +++ b/lib/pathlib/README.txt @@ -0,0 +1,104 @@ +pathlib offers a set of classes to handle filesystem paths. It offers the +following advantages over using string objects: + +* No more cumbersome use of os and os.path functions. Everything can be + done easily through operators, attribute accesses, and method calls. + +* Embodies the semantics of different path types. For example, comparing + Windows paths ignores casing. + +* Well-defined semantics, eliminating any warts or ambiguities (forward vs. + backward slashes, etc.). + +Requirements +------------ + +Python 3.2 or later is recommended, but pathlib is also usable with Python 2.7. + +Install +------- + +``easy_install pathlib`` or ``pip install pathlib`` should do the trick. + +Examples +-------- + +Importing the module classes:: + + >>> from pathlib import * + +Listing Python source files in a directory:: + + >>> p = Path('.') + >>> [x for x in p if x.ext == '.py'] + [PosixPath('test_pathlib.py'), PosixPath('setup.py'), + PosixPath('pathlib.py')] + +Listing subdirectories:: + + >>> [x for x in p if x.is_dir()] + [PosixPath('.hg'), PosixPath('docs'), PosixPath('dist'), + PosixPath('__pycache__'), PosixPath('build')] + +Navigating inside a directory tree:: + + >>> p = Path('/etc') + >>> q = p['init.d/reboot'] + >>> q + PosixPath('/etc/init.d/reboot') + >>> q.resolve() + PosixPath('/etc/rc.d/init.d/halt') + +Querying path properties:: + + >>> q.exists() + True + >>> q.is_dir() + False + >>> q.st_mode + 33261 + +Opening a file:: + + >>> with q.open() as f: f.readline() + ... + '#!/bin/bash\n' + + +Documentation +------------- + +The full documentation can be read at `Read the Docs +`_. + + +Contributing +------------ + +The issue tracker and repository are hosted by `BitBucket +`_. + + +History +------- + +Version 0.7 +^^^^^^^^^^^ + +- Fix openat() support after the API refactoring in Python 3.3 beta1. +- Add a *target_is_directory* argument to Path.symlink_to() + +Version 0.6 +^^^^^^^^^^^ + +- Add Path.is_file() and Path.is_symlink() +- Add Path.glob() and Path.rglob() +- Add PurePath.match() + +Version 0.5 +^^^^^^^^^^^ + +- Add Path.mkdir(). +- Add Python 2.7 compatibility by Michele Lacchia. +- Make parent() raise ValueError when the level is greater than the path + length. diff --git a/lib/pathlib/VERSION.txt b/lib/pathlib/VERSION.txt new file mode 100644 --- /dev/null +++ b/lib/pathlib/VERSION.txt @@ -0,0 +1,1 @@ +0.6 diff --git a/lib/pathlib/docs/Makefile b/lib/pathlib/docs/Makefile new file mode 100644 --- /dev/null +++ b/lib/pathlib/docs/Makefile @@ -0,0 +1,153 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/pathlib.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/pathlib.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/pathlib" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/pathlib" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff --git a/lib/pathlib/docs/conf.py b/lib/pathlib/docs/conf.py new file mode 100644 --- /dev/null +++ b/lib/pathlib/docs/conf.py @@ -0,0 +1,245 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# pathlib documentation build configuration file, created by +# sphinx-quickstart on Sun Jan 29 23:31:18 2012. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'pathlib' +copyright = '2012, Antoine Pitrou' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = open(os.path.join( + os.path.dirname(os.path.dirname(__file__)), + 'VERSION.txt')).read().strip() +# The full version, including alpha/beta/rc tags. +release = version + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'pathlibdoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'pathlib.tex', 'pathlib Documentation', + 'Antoine Pitrou', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'pathlib', 'pathlib Documentation', + ['Antoine Pitrou'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'pathlib', 'pathlib Documentation', + 'Antoine Pitrou', 'pathlib', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' diff --git a/lib/pathlib/docs/index.rst b/lib/pathlib/docs/index.rst new file mode 100644 --- /dev/null +++ b/lib/pathlib/docs/index.rst @@ -0,0 +1,803 @@ + +pathlib +======= + +.. module:: pathlib + :synopsis: Object-oriented filesystem paths + +.. moduleauthor:: Antoine Pitrou + +.. toctree:: + :maxdepth: 2 + + +Manipulating filesystem paths as string objects can quickly become cumbersome: +multiple calls to :func:`os.path.join` or :func:`os.path.dirname`, etc. +This module offers a set of classes featuring all the common operations on +paths in an easy, object-oriented way. + +This module is best used with Python 3.2 or later, but it is also compatible +with Python 2.7. If using it with Python 3.3, you also have access to +optional ``openat``-based filesystem operations. + + +Download +-------- + +Releases are available on PyPI: http://pypi.python.org/pypi/pathlib/ + +The development repository and issue tracker can be found at BitBucket: +https://bitbucket.org/pitrou/pathlib/ + + +Basic use +--------- + +Importing the module classes:: + + >>> from pathlib import * + +Listing Python source files in the current directory:: + + >>> p = Path('.') + >>> [x for x in p if x.ext == '.py'] + [PosixPath('test_pathlib.py'), PosixPath('setup.py'), + PosixPath('pathlib.py')] + +Listing subdirectories:: + + >>> [x for x in p if x.is_dir()] + [PosixPath('.hg'), PosixPath('docs'), PosixPath('dist'), + PosixPath('__pycache__'), PosixPath('build')] + +Navigating inside a directory tree:: + + >>> p = Path('/etc') + >>> q = p['init.d/reboot'] + >>> q + PosixPath('/etc/init.d/reboot') + >>> q.resolve() + PosixPath('/etc/rc.d/init.d/halt') + +Querying path properties:: + + >>> q.exists() + True + >>> q.is_dir() + False + >>> q.st_mode + 33261 + +Opening a file:: + + >>> with q.open() as f: f.readline() + ... + '#!/bin/bash\n' + + +Pure paths +---------- + +Pure path objects provide path-handling operations which don't actually +access a filesystem. There are three ways to access these classes, which +we also call *flavours*: + + +.. class:: PurePosixPath + + A subclass of :class:`PurePath`, this path flavour represents non-Windows + filesystem paths:: + + >>> PurePosixPath('/etc') + PurePosixPath('/etc') + +.. class:: PureNTPath + + A subclass of :class:`PurePath`, this path flavour represents Windows + filesystem paths:: + + >>> PureNTPath('c:/Program Files/') + PureNTPath('c:\\Program Files') + +.. class:: PurePath + + A generic class that represents the system's path flavour (instantiating + it creates either a :class:`PurePosixPath` or a :class:`PureNTPath`):: + + >>> PurePath('setup.py') + PurePosixPath('setup.py') + + +Regardless of the system you're running on, you can instantiate all of +these classes, since they don't provide any operation that does system calls. + + +Constructing paths +^^^^^^^^^^^^^^^^^^ + +Path constructors accept an arbitrary number of positional arguments. +When called without any argument, a path object points to the current +directory:: + + >>> PurePath() + PurePosixPath('.') + +Any argument can be a string or bytes object representing an arbitrary number +of path segments, but it can also be another path object:: + + >>> PurePath('foo', 'some/path', 'bar') + PurePosixPath('foo/some/path/bar') + >>> PurePath(Path('foo'), Path('bar')) + PurePosixPath('foo/bar') + +When several absolute paths are given, the last is taken as an anchor +(mimicking ``os.path.join``'s behaviour):: + + >>> PurePath('/etc', '/usr', 'lib64') + PurePosixPath('/usr/lib64') + >>> PureNTPath('c:/Windows', 'd:bar') + PureNTPath('d:bar') + +However, in a Windows path, changing the local root doesn't discard the +previous drive setting:: + + >>> PureNTPath('c:/Windows', '/Program Files') + PureNTPath('c:\\Program Files') + +Spurious slashes and single dots are collapsed, but double dots (``'..'``) +are not, since this would change the meaning of a path in the face of +symbolic links:: + + >>> PurePath('foo//bar') + PurePosixPath('foo/bar') + >>> PurePath('foo/./bar') + PurePosixPath('foo/bar') + >>> PurePath('foo/../bar') + PurePosixPath('foo/../bar') + +(a na?ve approach would make ``PurePosixPath('foo/../bar')`` equivalent +to ``PurePosixPath('bar')``, which is wrong if ``foo`` is a symbolic link +to another directory) + + +General properties +^^^^^^^^^^^^^^^^^^ + +Paths are immutable and hashable. Paths of a same flavour are comparable +and orderable. These properties respect the flavour's case-folding +semantics:: + + >>> PurePosixPath('foo') == PurePosixPath('FOO') + False + >>> PureNTPath('foo') == PureNTPath('FOO') + True + >>> PureNTPath('FOO') in { PureNTPath('foo') } + True + >>> PureNTPath('C:') < PureNTPath('d:') + True + +Paths of a different flavour compare unequal and cannot be ordered:: + + >>> PureNTPath('foo') == PurePosixPath('foo') + False + >>> PureNTPath('foo') < PurePosixPath('foo') + Traceback (most recent call last): + File "", line 1, in + TypeError: unorderable types: PureNTPath() < PurePosixPath() + + +Operators +^^^^^^^^^ + +Indexing a path helps create child paths, similarly to ``os.path.join``:: + + >>> p = PurePath('/etc') + >>> p + PurePosixPath('/etc') + >>> p['passwd'] + PurePosixPath('/etc/passwd') + >>> p['init.d/apache2'] + PurePosixPath('/etc/init.d/apache2') + +The string representation of a path is the raw filesystem path itself, which +you can pass to any function taking a file path as a string:: + + >>> p = PurePath('/etc') + >>> str(p) + '/etc' + +Similarly, calling ``bytes`` on a path gives the raw filesystem path as a +bytes object:: + + >>> bytes(p) + b'/etc' + + +Accessing individual parts +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To access the individual "parts" (components) of a path, use the following +property: + +.. data:: PurePath.parts + + An immutable sequence-like object giving access to the path's various + components. Indexing this object returns individual strings, while + slicing this object returns other path objects of the same flavour:: + + >>> p = PurePath('/usr/bin/python3') + >>> p.parts + + >>> p.parts[0] + '/' + >>> p.parts[-1] + 'python3' + >>> p.parts[1:] + PurePosixPath('usr/bin/python3') + >>> p.parts[:-1] + PurePosixPath('/usr/bin') + + >>> p = PureNTPath('c:/Program Files/PSF') + >>> p.parts[0] + 'c:\\' + >>> p.parts[1:] + PureNTPath('Program Files\\PSF') + + (note how the drive and local root are regrouped in a single part) + + +Methods and properties +^^^^^^^^^^^^^^^^^^^^^^ + +Pure paths provide the following methods an properties: + +.. data:: PurePath.drive + + A string representing the drive letter or name, if any:: + + >>> PureNTPath('c:/Program Files/').drive + 'c:' + >>> PureNTPath('/Program Files/').drive + '' + >>> PurePosixPath('/etc').drive + '' + + UNC shares are also considered drives:: + + >>> PureNTPath('//some/share/foo.txt').drive + '\\\\some\\share' + +.. data:: PurePath.root + + A string representing the (local or global) root, if any:: + + >>> PureNTPath('c:/Program Files/').root + '\\' + >>> PureNTPath('c:Program Files/').root + '' + >>> PurePosixPath('/etc').root + '/' + + UNC shares always have a root:: + + >>> PureNTPath('//some/share').root + '\\' + + +.. data:: PurePath.ext + + A string representing the file extension of the final component, if any:: + + >>> PurePosixPath('my/library/setup.py').ext + '.py' + >>> PurePosixPath('my/library.tar.gz').ext + '.tar.gz' + >>> PurePosixPath('my/library').ext + '' + + UNC drive names are not considered:: + + >>> PureNTPath('//some/share/setup.py').ext + '.py' + >>> PureNTPath('//some.txt/share.py').ext + '' + + +.. method:: PurePath.as_bytes() + + Equivalent to calling ``bytes()`` on the path object:: + + >>> PurePosixPath('/etc').as_bytes() + b'/etc' + + +.. method:: PurePath.as_posix() + + Return a string representation of the path with forward slashes (``/``):: + + >>> p = PureNTPath('c:\\windows') + >>> str(p) + 'c:\\windows' + >>> p.as_posix() + 'c:/windows' + + +.. method:: PurePath.is_absolute() + + Return whether the path is absolute or not. A path is considered absolute + if it has both a root and (if the flavour allows) a drive:: + + >>> PurePosixPath('/a/b').is_absolute() + True + >>> PurePosixPath('a/b').is_absolute() + False + + >>> PureNTPath('c:/a/b').is_absolute() + True + >>> PureNTPath('/a/b').is_absolute() + False + >>> PureNTPath('c:').is_absolute() + False + >>> PureNTPath('//some/share').is_absolute() + True + + +.. method:: PurePath.is_reserved() + + With :class:`PureNTPath`, return True if the path is considered reserved + under Windows, False otherwise. With :class:`PurePosixPath`, False is + always returned. + + >>> PureNTPath('nul').is_reserved() + True + >>> PurePosixPath('nul').is_reserved() + False + + File system calls on reserved paths can fail mysteriously or have + unintended effects. + + +.. method:: PurePath.join(*other) + + Calling this method is equivalent to indexing the path with each of + the *other* arguments in turn:: + + >>> PurePosixPath('/etc').join('passwd') + PurePosixPath('/etc/passwd') + >>> PurePosixPath('/etc').join(PurePosixPath('passwd')) + PurePosixPath('/etc/passwd') + >>> PurePosixPath('/etc').join('init.d', 'apache2') + PurePosixPath('/etc/init.d/apache2') + >>> PureNTPath('c:').join('/Program Files') + PureNTPath('c:\\Program Files') + + +.. method:: PurePath.match(pattern) + + Match this path against the provided glob-style pattern. Return True + if matching is successful, False otherwise. + + If *pattern* is relative, the path can be either relative or absolute, + and matching is done from the right:: + + >>> PurePath('a/b.py').match('*.py') + True + >>> PurePath('/a/b/c.py').match('b/*.py') + True + >>> PurePath('/a/b/c.py').match('a/*.py') + False + + If *pattern* is absolute, the path must be absolute, and the whole path + must match:: + + >>> PurePath('/a.py').match('/*.py') + True + >>> PurePath('a/b.py').match('/*.py') + False + + As with other methods, case-sensitivity is observed:: + + >>> PureNTPath('b.py').match('*.PY') + True + + +.. method:: PurePath.normcase() + + Return a case-folded version of the path. Calling this method is *not* + needed before comparing path objects. + + +.. method:: PurePath.parent(level=1) + + Return the path's parent at the *level*'th level. If *level* is not given, + return the path's immediate parent:: + + >>> p = PurePosixPath('/a/b/c/d') + >>> p.parent() + PurePosixPath('/a/b/c') + >>> p.parent(2) + PurePosixPath('/a/b') + >>> p.parent(3) + PurePosixPath('/a') + >>> p.parent(4) + PurePosixPath('/') + + .. note:: + This is a purely lexical operation, hence the following behaviour:: + + >>> p = PurePosixPath('foo/..') + >>> p.parent() + PurePosixPath('foo') + + If you want to walk an arbitrary filesystem path upwards, it is + recommended to first call :meth:`Path.resolve` so as to resolve + symlinks and eliminate `".."` components. + + +.. method:: PurePath.parents() + + Iterate over the path's parents from the most to the least specific:: + + >>> for p in PureNTPath('c:/foo/bar/setup.py').parents(): p + ... + PureNTPath('c:\\foo\\bar') + PureNTPath('c:\\foo') + PureNTPath('c:\\') + + +.. method:: PurePath.relative() + + Return the path object stripped of its drive and root, if any:: + + >>> PurePosixPath('/etc/passwd').relative() + PurePosixPath('etc/passwd') + >>> PurePosixPath('lib/setup.py').relative() + PurePosixPath('lib/setup.py') + + >>> PureNTPath('//some/share/setup.py').relative() + PureNTPath('setup.py') + >>> PureNTPath('//some/share/lib/setup.py').relative() + PureNTPath('lib\\setup.py') + + +.. method:: PurePath.relative_to(*other) + + Compute a version of this path relative to the path represented by + *other*. If it's impossible, ValueError is raised:: + + >>> p = PurePosixPath('/etc/passwd') + >>> p.relative_to('/') + PurePosixPath('etc/passwd') + >>> p.relative_to('/etc') + PurePosixPath('passwd') + >>> p.relative_to('/usr') + Traceback (most recent call last): + File "", line 1, in + File "pathlib.py", line 694, in relative_to + .format(str(self), str(formatted))) + ValueError: '/etc/passwd' does not start with '/usr' + + +Concrete paths +-------------- + +Concrete paths are subclasses of the pure path classes. In addition to +operations provided by the latter, they also provide methods to do system +calls on path objects. There are three ways to instantiate concrete paths: + + +.. class:: PosixPath + + A subclass of :class:`Path` and :class:`PurePosixPath`, this class + represents concrete non-Windows filesystem paths:: + + >>> PosixPath('/etc') + PosixPath('/etc') + +.. class:: NTPath + + A subclass of :class:`Path` and :class:`PureNTPath`, this class represents + concrete Windows filesystem paths:: + + >>> NTPath('c:/Program Files/') + NTPath('c:\\Program Files') + +.. class:: Path + + A subclass of :class:`PurePath`, this class represents concrete paths of + the system's path flavour (instantiating it creates either a + :class:`PosixPath` or a :class:`NTPath`):: + + >>> Path('setup.py') + PosixPath('setup.py') + + +You can only instantiate the class flavour that corresponds to your system +(allowing system calls on non-compatible path flavours could lead to +bugs or failures in your application):: + + >>> import os + >>> os.name + 'posix' + >>> Path('setup.py') + PosixPath('setup.py') + >>> PosixPath('setup.py') + PosixPath('setup.py') + >>> NTPath('setup.py') + Traceback (most recent call last): + File "", line 1, in + File "pathlib.py", line 798, in __new__ + % (cls.__name__,)) + NotImplementedError: cannot instantiate 'NTPath' on your system + + +Iterating +^^^^^^^^^ + +When a concrete path points to a directory, iterating over it yields path +objects of the directory contents:: + + >>> p = Path('docs') + >>> for child in p: child + ... + PosixPath('docs/conf.py') + PosixPath('docs/_templates') + PosixPath('docs/make.bat') + PosixPath('docs/index.rst') + PosixPath('docs/_build') + PosixPath('docs/_static') + PosixPath('docs/Makefile') + + +Methods +^^^^^^^ + +Concrete paths provide the following methods in addition to pure paths +methods. Many of these methods can raise an :exc:`OSError` if a system +call fails (for example because the path doesn't exist): + +.. classmethod:: Path.cwd() + + Return a new path object representing the current directory (as returned + by :func:`os.getcwd`):: + + >>> Path.cwd() + PosixPath('/home/antoine/pathlib') + + +.. method:: Path.stat() + + Return information about this path (similarly to :func:`os.stat`). + The result is cached accross calls. + + >>> p = Path('setup.py') + >>> p.stat().st_size + 956 + >>> p.stat().st_mtime + 1327883547.852554 + + This information can also be accessed through :ref:`helper attributes `. + + +.. method:: Path.restat() + + Like :meth:`Path.stat`, but ignores the cached value and always invokes + the underlying system call. + + +.. method:: Path.chmod(mode) + + Change the file mode and permissions, like :func:`os.chmod`:: + + >>> p = Path('setup.py') + >>> p.stat().st_mode + 33277 + >>> p.chmod(0o444) + >>> p.restat().st_mode + 33060 + + +.. method:: Path.exists() + + Whether the path points to an existing file or directory:: + + >>> from pathlib import * + >>> Path('.').exists() + True + >>> Path('setup.py').exists() + True + >>> Path('/etc').exists() + True + >>> Path('nonexistentfile').exists() + False + + +.. method:: Path.glob(pattern) + + Glob the given *pattern* in the directory represented by this path, + yielding all matching files (of any kind):: + + >>> sorted(Path('.').glob('*.py')) + [PosixPath('pathlib.py'), PosixPath('setup.py'), PosixPath('test_pathlib.py')] + >>> sorted(Path('.').glob('*/*.py')) + [PosixPath('docs/conf.py')] + + +.. method:: Path.is_dir() + + Return True if the path points to a directory (or a symbolic link + pointing to a directory), False if it points to another kind of file. + + +.. method:: Path.is_file() + + Return True if the path points to a regular file (or a symbolic link + pointing to a regular file), False if it points to another kind of file. + + +.. method:: Path.is_symlink() + + Return True if the path points to a symbolic link, False otherwise. + + +.. method:: Path.lchmod(mode) + + Like :meth:`Path.chmod` but, if the path points to a symbolic link, the + symbolic link's mode is changed rather than its target's. + + +.. method:: Path.lstat() + + Like :meth:`Path.stat` but, if the path points to a symbolic link, return + the symbolic link's information rather than its target's. + + +.. method:: Path.mkdir(mode=0o777, parents=False) + + Create a new directory at this given path. If *mode* is given, it is + combined with the process' ``umask`` value to determine the file mode + and access flags. If the path already exists, :exc:`OSError` is raised. + + If *parents* is True, any missing parents of this path are created + as needed. If *parents* is False (the default), a missing parent raises + :exc:`OSError`. + + +.. method:: Path.open(mode='r', buffering=-1, encoding=None, errors=None, newline=None) + + Open the file pointed to by the path, like the built-in :func:`open` + function does:: + + >>> p = Path('setup.py') + >>> with p.open() as f: + ... f.readline() + ... + '#!/usr/bin/env python3\n' + + +.. method:: Path.raw_open(flags, mode=0o777) + + Open the file pointed to by the path and return a numeric file descriptor, + as :func:`os.open` does:: + + >>> p = Path('setup.py') + >>> fd = p.raw_open(os.O_RDONLY) + >>> os.read(fd, 10) + b'#!/usr/bin' + >>> os.close(fd) + + +.. method:: Path.rename(target) + + Rename this file or directory to the given *target*. *target* can be + either a string or another path object:: + + >>> p = Path('foo') + >>> p.open('w').write('some text') + 9 + >>> target = Path('bar') + >>> p.rename(target) + >>> target.open().read() + 'some text' + + +.. method:: Path.resolve() + + Make the path absolute, resolving any symlinks. A new path object is + returned:: + + >>> p = Path() + >>> p + PosixPath('.') + >>> p.resolve() + PosixPath('/home/antoine/pathlib') + + `".."` components are also eliminated (this is the only method to do so):: + + >>> p = Path('docs/../setup.py') + >>> p.resolve() + PosixPath('/home/antoine/pathlib/setup.py') + + If the path doesn't exist, an :exc:`OSError` is raised. If an infinite + loop is encountered along the resolution path, :exc:`ValueError` is raised. + + +.. method:: Path.rglob(pattern) + + Like :meth:`glob`, but glob recursively from any subdirectories as well:: + + >>> sorted(Path().rglob("*.py")) + [PosixPath('build/lib/pathlib.py'), + PosixPath('docs/conf.py'), + PosixPath('pathlib.py'), + PosixPath('setup.py'), + PosixPath('test_pathlib.py')] + + +.. method:: Path.rmdir() + + Remove this directory. The directory must be empty. + + +.. method:: Path.symlink_to(target, target_is_directory=False) + + Make this path a symbolic link to *target*. Under Windows, + *target_is_directory* must be True (default False) if the link's target + is a directory. Under POSIX, *target_is_directory*'s value is ignored. + + >>> p = Path('mylink') + >>> p.symlink_to('setup.py') + >>> p.resolve() + PosixPath('/home/antoine/pathlib/setup.py') + >>> p.stat().st_size + 956 + >>> p.lstat().st_size + 8 + + .. note:: + The order of arguments (link, target) is the reverse + of :func:`os.symlink`'s. + + +.. method:: Path.touch(mode=0o777, exist_ok=True) + + Create a file at this given path. If *mode* is given, it is combined + with the process' ``umask`` value to determine the file mode and access + flags. If the file already exists, the function succeeds if *exist_ok* + is true, otherwise :exc:`OSError` is raised. + + +.. method:: Path.unlink() + + Remove this file or symbolic link. If the path points to a directory, + use :func:`Path.rmdir` instead. + + +.. _st_attrs: + +Attributes +^^^^^^^^^^ + +Concrete paths provide the following attributes: + +.. data:: + Path.st_mode + Path.st_ino + Path.st_dev + Path.st_nlink + Path.st_uid + Path.st_gid + Path.st_size + Path.st_atime + Path.st_mtime + Path.st_ctime + ... + + Helper attributes returning the corresponding fields on :meth:`Path.stat`'s + result:: + + >>> p = Path('setup.py') + >>> p.st_size + 956 + >>> p.st_mtime + 1327939910.2178059 diff --git a/lib/pathlib/docs/make.bat b/lib/pathlib/docs/make.bat new file mode 100644 --- /dev/null +++ b/lib/pathlib/docs/make.bat @@ -0,0 +1,190 @@ + at ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +set I18NSPHINXOPTS=%SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\pathlib.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\pathlib.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +:end diff --git a/lib/pathlib/pathlib.py b/lib/pathlib/pathlib.py new file mode 100644 --- /dev/null +++ b/lib/pathlib/pathlib.py @@ -0,0 +1,1265 @@ +import fnmatch +import io +import ntpath +import os +import posixpath +import sys +import weakref +try: + import threading +except ImportError: + import dummy_threading as threading + +from collections import Sequence, defaultdict +from errno import EINVAL, ENOENT, EEXIST +from functools import wraps +from itertools import chain, count +from operator import attrgetter +from stat import S_ISDIR, S_ISLNK, S_ISREG + + +supports_symlinks = True +try: + import nt +except ImportError: + nt = None +else: + if sys.getwindowsversion()[:2] >= (6, 0): + from nt import _getfinalpathname + else: + supports_symlinks = False + _getfinalpathname = None + + +__all__ = [ + "PurePath", "PurePosixPath", "PureNTPath", + "Path", "PosixPath", "NTPath", + ] + +# +# Internals +# + +def _is_wildcard_pattern(pat): + # Whether this pattern needs actual matching using fnmatch, or can + # be looked up directly as a file. + return "*" in pat or "?" in pat or "[" in pat + + +class _Flavour(object): + """A flavour implements a particular (platform-specific) set of path + semantics.""" + + def __init__(self): + self.join = self.sep.join + + def parse_parts(self, parts): + parsed = [] + sep = self.sep + altsep = self.altsep + drv = root = '' + it = reversed(parts) + for part in it: + if altsep: + part = part.replace(altsep, sep) + drv, root, rel = self.splitroot(part) + rel = rel.rstrip(sep) + parsed.extend(x for x in reversed(rel.split(sep)) if x and x != '.') + if drv or root: + if not drv: + # If no drive is present, try to find one in the previous + # parts. This makes the result of parsing e.g. + # ("C:", "/", "a") reasonably intuitive. + for part in it: + drv = self.splitroot(part)[0] + if drv: + break + break + if drv or root: + parsed.append(drv + root) + parsed.reverse() + return drv, root, parsed + + +class _NTFlavour(_Flavour): + # Reference for NT paths can be found at + # http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx + + sep = '\\' + altsep = '/' + has_drv = True + pathmod = ntpath + + is_supported = (nt is not None) + + drive_letters = ( + set(chr(x) for x in range(ord('a'), ord('z') + 1)) | + set(chr(x) for x in range(ord('A'), ord('Z') + 1)) + ) + ext_namespace_prefix = '\\\\?\\' + + reserved_names = ( + {'CON', 'PRN', 'AUX', 'NUL'} | + {'COM%d' % i for i in range(1, 10)} | + {'LPT%d' % i for i in range(1, 10)} + ) + + # Interesting findings about extended paths: + # - '\\?\c:\a', '//?/c:\a' and '//?/c:/a' are all supported + # but '\\?\c:/a' is not + # - extended paths are always absolute; "relative" extended paths will + # fail. + + def splitroot(self, part, sep=sep): + first = part[0:1] + second = part[1:2] + if (second == sep and first == sep): + # XXX extended paths should also disable the collapsing of "." + # components (according to MSDN docs). + prefix, part = self._split_extended_path(part) + first = part[0:1] + second = part[1:2] + else: + prefix = '' + third = part[2:3] + if (second == sep and first == sep and third != sep): + # is a UNC path: + # vvvvvvvvvvvvvvvvvvvvv root + # \\machine\mountpoint\directory\etc\... + # directory ^^^^^^^^^^^^^^ + index = part.find(sep, 2) + if index != -1: + index2 = part.find(sep, index + 1) + # a UNC path can't have two slashes in a row + # (after the initial two) + if index2 != index + 1: + if index2 == -1: + index2 = len(part) + if prefix: + return prefix + part[1:index2], sep, part[index2+1:] + else: + return part[:index2], sep, part[index2+1:] + drv = root = '' + if second == ':' and first in self.drive_letters: + drv = part[:2] + part = part[2:] + first = third + if first == sep: + root = first + part = part.lstrip(sep) + return prefix + drv, root, part + + def casefold(self, s): + return s.lower() + + def casefold_parts(self, parts): + return [p.lower() for p in parts] + + def resolve(self, path): + s = str(path) + if not s: + return os.getcwd() + if _getfinalpathname is not None: + return self._ext_to_normal(_getfinalpathname(s)) + # Means fallback on absolute + return None + + def _split_extended_path(self, s, ext_prefix=ext_namespace_prefix): + prefix = '' + if s.startswith(ext_prefix): + prefix = s[:4] + s = s[4:] + if s.startswith('UNC\\'): + prefix += s[:3] + s = '\\' + s[3:] + return prefix, s + + def _ext_to_normal(self, s): + # Turn back an extended path into a normal DOS-like path + return self._split_extended_path(s)[1] + + def is_reserved(self, parts): + # NOTE: the rules for reserved names seem somewhat complicated + # (e.g. r"..\NUL" is reserved but not r"foo\NUL"). + # We err on the side of caution and return True for paths which are + # not considered reserved by Windows. + if not parts: + return False + if parts[0].startswith('\\\\'): + # UNC paths are never reserved + return False + return parts[-1].partition('.')[0].upper() in self.reserved_names + + +_NO_FD = None + +class _PosixFlavour(_Flavour): + sep = '/' + altsep = '' + has_drv = False + pathmod = posixpath + + is_supported = (os.name != 'nt') + + def splitroot(self, part, sep=sep): + if part and part[0] == sep: + return '', sep, part.lstrip(sep) + else: + return '', '', part + + def casefold(self, s): + return s + + def casefold_parts(self, parts): + return parts + + def resolve(self, path): + sep = self.sep + def split(p): + return [x for x in p.split(sep) if x] + def absparts(p): + # Our own abspath(), since the posixpath one makes + # the mistake of "normalizing" the path without resolving the + # symlinks first. + if not p.startswith(sep): + return split(os.getcwd()) + split(p) + else: + return split(p) + def close(fd): + if fd != _NO_FD: + os.close(fd) + parts = absparts(str(path))[::-1] + accessor = path._accessor + resolved = cur = "" + resolved_fd = _NO_FD + symlinks = {} + try: + while parts: + part = parts.pop() + cur = resolved + sep + part + if cur in symlinks and symlinks[cur] <= len(parts): + # We've already seen the symlink and there's not less + # work to do than the last time. + raise ValueError("Symlink loop from %r" % cur) + try: + target = accessor.readlink(cur, part, dir_fd=resolved_fd) + except OSError as e: + if e.errno != EINVAL: + raise + # Not a symlink + resolved_fd = accessor.walk_down(cur, part, dir_fd=resolved_fd) + resolved = cur + else: + # Take note of remaining work from this symlink + symlinks[cur] = len(parts) + if target.startswith(sep): + # Symlink points to absolute path + resolved = "" + close(resolved_fd) + resolved_fd = _NO_FD + parts.extend(split(target)[::-1]) + finally: + close(resolved_fd) + return resolved or sep + + def is_reserved(self, parts): + return False + + +_nt_flavour = _NTFlavour() +_posix_flavour = _PosixFlavour() + + +_fds_refs = defaultdict(int) +_fds_refs_lock = threading.Lock() + +def _add_fd_ref(fd, lock=_fds_refs_lock): + with lock: + _fds_refs[fd] += 1 + +def _sub_fd_ref(fd, lock=_fds_refs_lock): + with lock: + nrefs = _fds_refs[fd] - 1 + if nrefs > 0: + _fds_refs[fd] = nrefs + else: + del _fds_refs[fd] + os.close(fd) + + +class _Accessor: + """An accessor implements a particular (system-specific or not) way of + accessing paths on the filesystem.""" + + +if sys.version_info >= (3, 3): + supports_openat = (os.listdir in os.supports_fd and + os.supports_dir_fd >= { os.chmod, os.stat, os.mkdir, os.open, + os.readlink, os.rename, os.symlink, os.unlink, } + ) +else: + supports_openat = False + +if supports_openat: + + def _fdnamepair(pathobj): + """Get a (parent fd, name) pair from a path object, suitable for use + with the various *at functions.""" + parent_fd = pathobj._parent_fd + if parent_fd is not None: + return parent_fd, pathobj._parts[-1] + else: + return _NO_FD, str(pathobj) + + + class _OpenatAccessor(_Accessor): + + def _wrap_atfunc(atfunc): + @wraps(atfunc) + def wrapped(pathobj, *args, **kwargs): + parent_fd, name = _fdnamepair(pathobj) + return atfunc(name, *args, dir_fd=parent_fd, **kwargs) + return staticmethod(wrapped) + + def _wrap_binary_atfunc(atfunc): + @wraps(atfunc) + def wrapped(pathobjA, pathobjB, *args, **kwargs): + parent_fd_A, nameA = _fdnamepair(pathobjA) + # We allow pathobjB to be a plain str, for convenience + if isinstance(pathobjB, Path): + parent_fd_B, nameB = _fdnamepair(pathobjB) + else: + # If it's a str then at best it's cwd-relative + parent_fd_B, nameB = _NO_FD, str(pathobjB) + return atfunc(nameA, nameB, *args, + src_dir_fd=parent_fd_A, dst_dir_fd=parent_fd_B, + **kwargs) + return staticmethod(wrapped) + + stat = _wrap_atfunc(os.stat) + + lstat = _wrap_atfunc(os.lstat) + + open = _wrap_atfunc(os.open) + + chmod = _wrap_atfunc(os.chmod) + + def lchmod(self, pathobj, mode): + return self.chmod(pathobj, mode, follow_symlinks=False) + + mkdir = _wrap_atfunc(os.mkdir) + + unlink = _wrap_atfunc(os.unlink) + + rmdir = _wrap_atfunc(os.rmdir) + + def listdir(self, pathobj): + fd = self._make_fd(pathobj, tolerant=False) + return os.listdir(fd) + + rename = _wrap_binary_atfunc(os.rename) + + def symlink(self, target, pathobj, target_is_directory): + parent_fd, name = _fdnamepair(pathobj) + os.symlink(str(target), name, dir_fd=parent_fd) + + def _make_fd(self, pathobj, tolerant=True): + fd = pathobj._cached_fd + if fd is not None: + return fd + try: + fd = self.open(pathobj, os.O_RDONLY) + except (PermissionError, FileNotFoundError): + if tolerant: + # If the path doesn't exist or is forbidden, just let us + # gracefully fallback on fd-less code. + return None + raise + # This ensures the stat information is consistent with the fd. + try: + st = pathobj._cached_stat = os.fstat(fd) + except: + os.close(fd) + raise + if tolerant and not S_ISDIR(st.st_mode): + # Not a directory => no point in keeping the fd + os.close(fd) + return None + else: + pathobj._cached_fd = fd + pathobj._add_managed_fd(fd) + return fd + + def init_path(self, pathobj): + self._make_fd(pathobj) + + def make_child(self, pathobj, args): + drv, root, parts = pathobj._flavour.parse_parts(args) + if drv or root: + # Anchored path => we can't do any better + return None + # NOTE: In the code below, we want to expose errors instead of + # risking race conditions when e.g. a non-existing directory gets + # later created. This means we want e.g. non-existing path + # components or insufficient permissions to raise an OSError. + pathfd = self._make_fd(pathobj, tolerant=False) + if not parts: + # This is the same path + newpath = pathobj._from_parsed_parts( + pathobj._drv, pathobj._root, pathobj._parts, init=False) + newpath._init(template=pathobj, fd=pathfd) + return newpath + parent_fd = pathfd + for part in parts[:-1]: + fd = os.open(part, os.O_RDONLY, dir_fd=parent_fd) + if parent_fd != pathfd: + # Forget intermediate fds + os.close(parent_fd) + parent_fd = fd + # The last component may or may not exist, it doesn't matter: we + # have the fd of its parent + newpath = pathobj._from_parsed_parts( + pathobj._drv, pathobj._root, pathobj._parts + parts, init=False) + newpath._init(template=pathobj, parent_fd=parent_fd) + return newpath + + # Helpers for resolve() + def walk_down(self, path, name, dir_fd): + if dir_fd != _NO_FD: + try: + return os.open(name, os.O_RDONLY, dir_fd=dir_fd) + finally: + os.close(dir_fd) + else: + return os.open(path, os.O_RDONLY) + + def readlink(self, path, name, dir_fd): + if dir_fd != _NO_FD: + return os.readlink(name, dir_fd=dir_fd) + else: + return os.readlink(path) + + _openat_accessor = _OpenatAccessor() + + +class _NormalAccessor(_Accessor): + + def _wrap_strfunc(strfunc): + @wraps(strfunc) + def wrapped(pathobj, *args): + return strfunc(str(pathobj), *args) + return staticmethod(wrapped) + + def _wrap_binary_strfunc(strfunc): + @wraps(strfunc) + def wrapped(pathobjA, pathobjB, *args): + return strfunc(str(pathobjA), str(pathobjB), *args) + return staticmethod(wrapped) + + stat = _wrap_strfunc(os.stat) + + lstat = _wrap_strfunc(os.lstat) + + open = _wrap_strfunc(os.open) + + listdir = _wrap_strfunc(os.listdir) + + chmod = _wrap_strfunc(os.chmod) + + if hasattr(os, "lchmod"): + lchmod = _wrap_strfunc(os.lchmod) + else: + def lchmod(self, pathobj, mode): + raise NotImplementedError("lchmod() not available on this system") + + mkdir = _wrap_strfunc(os.mkdir) + + unlink = _wrap_strfunc(os.unlink) + + rmdir = _wrap_strfunc(os.rmdir) + + rename = _wrap_binary_strfunc(os.rename) + + if nt: + symlink = _wrap_binary_strfunc(os.symlink) + else: + # Under POSIX, os.symlink() takes two args + @staticmethod + def symlink(a, b, target_is_directory): + return os.symlink(str(a), str(b)) + + def init_path(self, pathobj): + pass + + def make_child(self, pathobj, args): + return None + + # Helpers for resolve() + def walk_down(self, path, name, dir_fd): + assert dir_fd == _NO_FD + return _NO_FD + + def readlink(self, path, name, dir_fd): + assert dir_fd == _NO_FD + return os.readlink(path) + +_normal_accessor = _NormalAccessor() + + +# +# Public API +# + +class _PathParts(Sequence): + """This object provides sequence-like access to the parts of a path. + Don't try to construct it yourself.""" + __slots__ = ('_pathcls', '_parts') + + def __init__(self, path): + # We don't store the instance to avoid reference cycles + self._pathcls = type(path) + self._parts = path._parts + + def __len__(self): + return len(self._parts) + + def __getitem__(self, idx): + if isinstance(idx, slice): + return self._pathcls(*self._parts[idx]) + return self._parts[idx] + + def __repr__(self): + return "<{}.parts: {!r}>".format(self._pathcls.__name__, self._parts) + + +class PurePath(object): + """PurePath represents a filesystem path and offers operations which + don't imply any actual filesystem I/O. Depending on your system, + instantiating a PurePath will return either a PurePosixPath or a + PureNTPath object. You can also instantiate either of these classes + directly, regardless of your system. + """ + __slots__ = ( + '_drv', '_root', '_parts', + '_str', '_hash', '_pparts', '_cached_cparts', + ) + + def __new__(cls, *args): + """Construct a PurePath from one or several strings and or existing + PurePath objects. The strings and path objects are combined so as + to yield a canonicalized path, which is incorporated into the + new PurePath object. + """ + if cls is PurePath: + cls = PureNTPath if os.name == 'nt' else PurePosixPath + return cls._from_parts(args) + + @classmethod + def _parse_args(cls, args): + # This is useful when you don't want to create an instance, just + # canonicalize some constructor arguments. + parts = [] + for a in args: + if isinstance(a, PurePath): + parts += a._parts + elif isinstance(a, str): + # Assuming a str + parts.append(a) + else: + raise TypeError( + "argument should be a path or str object, not %r" + % type(a)) + return cls._flavour.parse_parts(parts) + + @classmethod + def _from_parts(cls, args, init=True): + # We need to call _parse_args on the instance, so as to get the + # right flavour. + self = object.__new__(cls) + drv, root, parts = self._parse_args(args) + self._drv = drv + self._root = root + self._parts = parts + if init: + self._init() + return self + + @classmethod + def _from_parsed_parts(cls, drv, root, parts, init=True): + self = object.__new__(cls) + self._drv = drv + self._root = root + self._parts = parts + if init: + self._init() + return self + + @classmethod + def _format_parsed_parts(cls, drv, root, parts): + if drv or root: + return drv + root + cls._flavour.join(parts[1:]) + else: + return cls._flavour.join(parts) + + def _init(self): + # Overriden in concrete Path + pass + + def _make_child(self, args): + # Overriden in concrete Path + parts = self._parts[:] + parts.extend(args) + return self._from_parts(parts) + + def __str__(self): + """Return the string representation of the path, suitable for + passing to system calls.""" + try: + return self._str + except AttributeError: + self._str = self._format_parsed_parts(self._drv, self._root, + self._parts) or '.' + return self._str + + def as_posix(self): + """Return the string representation of the path with forward (/) + slashes.""" + f = self._flavour + return str(self).replace(f.sep, '/') + + def as_bytes(self): + """Return the bytes representation of the path. This is only + recommended to use under Unix.""" + return os.fsencode(str(self)) + + __bytes__ = as_bytes + + def __repr__(self): + return "{}({!r})".format(self.__class__.__name__, str(self)) + + @property + def _cparts(self): + # Cached casefolded parts, for hashing and comparison + try: + return self._cached_cparts + except AttributeError: + self._cached_cparts = self._flavour.casefold_parts(self._parts) + return self._cached_cparts + + def __eq__(self, other): + return self._cparts == other._cparts and self._flavour is other._flavour + + def __ne__(self, other): + return not self == other + + def __hash__(self): + try: + return self._hash + except AttributeError: + self._hash = hash(tuple(self._cparts)) + return self._hash + + def __lt__(self, other): + if self._flavour is not other._flavour: + return NotImplemented + return self._cparts < other._cparts + + def __le__(self, other): + if self._flavour is not other._flavour: + return NotImplemented + return self._cparts <= other._cparts + + def __gt__(self, other): + if self._flavour is not other._flavour: + return NotImplemented + return self._cparts > other._cparts + + def __ge__(self, other): + if self._flavour is not other._flavour: + return NotImplemented + return self._cparts >= other._cparts + + drive = property(attrgetter('_drv'), + doc="""The drive prefix (letter or UNC path), if any""") + + root = property(attrgetter('_root'), + doc="""The root of the path, if any""") + + @property + def ext(self): + """The final component's extension, if any.""" + parts = self._parts + if len(parts) == (1 if (self._drv or self._root) else 0): + return '' + basename = parts[-1] + if basename == '.': + return '' + i = basename.find('.') + if i == -1: + return '' + return basename[i:] + + def relative(self): + """Return a new path without any drive and root. + """ + if self._drv or self._root: + return self._from_parsed_parts('', '', self._parts[1:]) + else: + return self._from_parsed_parts('', '', self._parts) + + def relative_to(self, *other): + """Return the relative path to another path identified by the passed + arguments. If the operation is not possible (because this is not + a subpath of the other path), raise ValueError. + """ + # For the purpose of this method, drive and root are considered + # separate parts, i.e.: + # Path('c:/').relative('c:') gives Path('/') + # Path('c:/').relative('/') raise ValueError + if not other: + raise TypeError("need at least one argument") + parts = self._parts + drv = self._drv + root = self._root + if drv or root: + if root: + abs_parts = [drv, root] + parts[1:] + else: + abs_parts = [drv] + parts[1:] + else: + abs_parts = parts + to_drv, to_root, to_parts = self._parse_args(other) + if to_drv or to_root: + if to_root: + to_abs_parts = [to_drv, to_root] + to_parts[1:] + else: + to_abs_parts = [to_drv] + to_parts[1:] + else: + to_abs_parts = to_parts + n = len(to_abs_parts) + if n == 0 and (drv or root) or abs_parts[:n] != to_abs_parts: + formatted = self._format_parsed_parts(to_drv, to_root, to_parts) + raise ValueError("{!r} does not start with {!r}" + .format(str(self), str(formatted))) + return self._from_parsed_parts('', '', abs_parts[n:]) + + @property + def parts(self): + """An object providing sequence-like access to the + components in the filesystem path.""" + try: + return self._pparts + except AttributeError: + self._pparts = _PathParts(self) + return self._pparts + + def join(self, *args): + """Combine this path with one or several arguments, and return a + new path representing either a subpath (if all arguments are relative + paths) or a totally different path (if one of the arguments is + anchored). + """ + return self._make_child(args) + + def __getitem__(self, key): + if isinstance(key, tuple): + return self._make_child(key) + else: + return self._make_child((key,)) + + def parent(self, level=1): + """A parent or ancestor (if `level` is specified) of this path.""" + if level < 1: + raise ValueError("`level` must be a non-zero positive integer") + drv = self._drv + root = self._root + parts = self._parts[:-level] + if not parts: + if level > len(self._parts) - bool(drv or root): + raise ValueError("level greater than path length") + return self._from_parsed_parts(drv, root, parts) + + def parents(self): + """Iterate over this path's parents, in ascending order.""" + drv = self._drv + root = self._root + parts = self._parts + n = len(parts) + end = 0 if (drv or root) else -1 + for i in range(n - 1, end, -1): + yield self._from_parsed_parts(drv, root, parts[:i]) + + def is_absolute(self): + """True if the path is absolute (has both a root and, if applicable, + a drive).""" + if not self._root: + return False + return not self._flavour.has_drv or bool(self._drv) + + def normcase(self): + """Return this path, possibly lowercased if the path flavour has + case-insensitive path semantics. + Calling this method is not needed before comparing Path instances.""" + fix = self._flavour.casefold_parts + drv, = fix((self._drv,)) + root = self._root + parts = fix(self._parts) + return self._from_parsed_parts(drv, root, parts) + + def is_reserved(self): + """Return True if the path contains one of the special names reserved + by the system, if any.""" + return self._flavour.is_reserved(self._parts) + + def match(self, path_pattern): + """ + Return True if this path matches the given pattern. + """ + cf = self._flavour.casefold + path_pattern = cf(path_pattern) + drv, root, pat_parts = self._flavour.parse_parts((path_pattern,)) + if not pat_parts: + raise ValueError("empty pattern") + if drv and drv != cf(self._drv): + return False + if root and root != cf(self._root): + return False + parts = self._cparts + if drv or root: + if len(pat_parts) != len(parts): + return False + pat_parts = pat_parts[1:] + elif len(pat_parts) > len(parts): + return False + for part, pat in zip(reversed(parts), reversed(pat_parts)): + if not fnmatch.fnmatchcase(part, pat): + return False + return True + + +class PurePosixPath(PurePath): + _flavour = _posix_flavour + __slots__ = () + + +class PureNTPath(PurePath): + _flavour = _nt_flavour + __slots__ = () + + +# Filesystem-accessing classes + + +class Path(PurePath): + __slots__ = ( + '_accessor', + '_cached_stat', + '_closed', + # Used by _OpenatAccessor + '_cached_fd', + '_parent_fd', + '_managed_fds', + '__weakref__', + ) + + _wrs = {} + _wr_id = count() + + def __new__(cls, *args, **kwargs): + use_openat = kwargs.get('use_openat', False) + if cls is Path: + cls = NTPath if os.name == 'nt' else PosixPath + self = cls._from_parts(args, init=False) + if not self._flavour.is_supported: + raise NotImplementedError("cannot instantiate %r on your system" + % (cls.__name__,)) + self._init(use_openat) + return self + + def _init(self, use_openat=False, + # Private non-constructor arguments + template=None, parent_fd=None, fd=None, + ): + self._closed = False + self._managed_fds = None + self._parent_fd = parent_fd + self._cached_fd = fd + if parent_fd is not None: + self._add_managed_fd(parent_fd) + if fd is not None: + self._add_managed_fd(fd) + if template is not None: + self._accessor = template._accessor + elif use_openat: + if not supports_openat: + raise NotImplementedError("your system doesn't support openat()") + self._accessor = _openat_accessor + else: + self._accessor = _normal_accessor + self._accessor.init_path(self) + + def _make_child(self, args): + child = self._accessor.make_child(self, args) + if child is not None: + return child + parts = self._parts[:] + parts.extend(args) + return self._from_parts(parts) + + def _make_child_relpath(self, part): + # This is an optimization used for dir walking. `part` must be + # a single part relative to this path. + child = self._accessor.make_child(self, (part,)) + if child is not None: + return child + parts = self._parts + [part] + return self._from_parsed_parts(self._drv, self._root, parts) + + @property + def _stat(self): + try: + return self._cached_stat + except AttributeError: + pass + st = self._accessor.stat(self) + self._cached_stat = st + return st + + @classmethod + def _cleanup(cls, fds, wr_id=None): + if wr_id is not None: + del cls._wrs[wr_id] + while fds: + _sub_fd_ref(fds.pop()) + + def _add_managed_fd(self, fd): + """Add a file descriptor managed by this object.""" + if fd is None: + return + fds = self._managed_fds + if fds is None: + # This setup is done lazily so that most path objects avoid it + fds = self._managed_fds = [] + cleanup = type(self)._cleanup + # We can't hash the weakref directly since distinct Path objects + # can compare equal. + wr_id = next(self._wr_id) + wr = weakref.ref(self, lambda wr: cleanup(fds, wr_id)) + self._wrs[wr_id] = wr + _add_fd_ref(fd) + fds.append(fd) + + def _sub_managed_fd(self, fd): + """Remove a file descriptor managed by this object.""" + self._managed_fds.remove(fd) + _sub_fd_ref(fd) + + def __enter__(self): + if self._closed: + self._raise_closed() + return self + + def __exit__(self, t, v, tb): + self._closed = True + fds = self._managed_fds + if fds is not None: + self._managed_fds = None + self._cached_fd = None + self._parent_fd = None + self._cleanup(fds) + + def _raise_closed(self): + raise ValueError("I/O operation on closed path") + + def _opener(self, name, flags, mode=0o777): + # A stub for the opener argument to built-in open() + return self._accessor.open(self, flags, mode) + + def _select_children(self, pattern_parts, recursive): + # Helper for globbing + # XXX symlink loops + if not pattern_parts: + yield self + return + if not self.is_dir(): + return + pat = pattern_parts[0] + child_parts = pattern_parts[1:] + if _is_wildcard_pattern(pat): + cf = self._flavour.casefold + for name in self._accessor.listdir(self): + name = cf(name) + if fnmatch.fnmatchcase(name, pat): + child_path = self._make_child_relpath(name) + for p in child_path._select_children(child_parts, False): + yield p + elif recursive: + child_path = self._make_child_relpath(name) + for p in child_path._select_children(pattern_parts, recursive): + yield p + else: + child_path = self._make_child_relpath(pat) + if child_path.exists(): + for p in child_path._select_children(child_parts, False): + yield p + if recursive: + for name in self._accessor.listdir(self): + child_path = self._make_child_relpath(name) + for p in child_path._select_children(pattern_parts, recursive): + yield p + + # Public API + + @classmethod + def cwd(cls, use_openat=False): + """Return a new path pointing to the current working directory + (as returned by os.getcwd()). + """ + return cls(os.getcwd(), use_openat=use_openat) + + def __iter__(self): + """Iterate over the files in this directory. Does not yield any + result for the special paths '.' and '..'. + """ + if self._closed: + self._raise_closed() + for name in self._accessor.listdir(self): + if name in {'.', '..'}: + # Yielding a path object for these makes little sense + continue + yield self._make_child_relpath(name) + if self._closed: + self._raise_closed() + + def __getattr__(self, name): + if name.startswith('st_'): + return getattr(self._stat, name) + return super(Path, self).__getattribute__(name) + + def glob(self, pattern): + """Iterate over this subtree and yield all existing files (of any + kind, including directories) matching the given pattern. + """ + pattern = self._flavour.casefold(pattern) + drv, root, pattern_parts = self._flavour.parse_parts((pattern,)) + if drv or root: + raise NotImplementedError("Non-relative patterns are unsupported") + for p in self._select_children(pattern_parts, recursive=False): + yield p + + def rglob(self, pattern): + """Recursively yield all existing files (of any kind, including + directories) matching the given pattern, anywhere in this subtree. + """ + pattern = self._flavour.casefold(pattern) + drv, root, pattern_parts = self._flavour.parse_parts((pattern,)) + if drv or root: + raise NotImplementedError("Non-relative patterns are unsupported") + for p in self._select_children(pattern_parts, recursive=True): + yield p + + def absolute(self): + """Return an absolute version of this path. This function works + even if the path doesn't point to anything. + + No normalization is done, i.e. all '.' and '..' will be kept along. + Use resolve() to get the canonical path to a file. + """ + # XXX untested yet! + if self._closed: + self._raise_closed() + if self.is_absolute(): + return self + # FIXME this must defer to the specific flavour (and, under Windows, + # use nt._getfullpathname()) + obj = self._from_parts([os.getcwd()] + self._parts, init=False) + obj._init(template=self, parent_fd=self._parent_fd, fd=self._cached_fd) + return obj + + def resolve(self): + """ + Make the path absolute, resolving all symlinks on the way and also + normalizing it (for example turning slashes into backslashes under + Windows). + """ + if self._closed: + self._raise_closed() + s = self._flavour.resolve(self) + if s is None: + # No symlink resolution => for consistency, raise an error if + # the path doesn't exist or is forbidden + self._stat + s = str(self.absolute()) + # Now we have no symlinks in the path, it's safe to normalize it. + normed = self._flavour.pathmod.normpath(s) + obj = self._from_parts((normed,), init=False) + obj._init(template=self, parent_fd=self._parent_fd, fd=self._cached_fd) + return obj + + def stat(self): + """ + Return the result of the stat() system call on this path, like + os.stat() does. + """ + return self._stat + + def restat(self): + """ + Same as stat(), but resets the internal cache to force a fresh value. + """ + try: + del self._cached_stat + except AttributeError: + pass + return self._stat + + def raw_open(self, flags, mode=0o777): + """ + Open the file pointed by this path and return a file descriptor, + as os.open() does. + """ + if self._closed: + self._raise_closed() + return self._accessor.open(self, flags, mode) + + def open(self, mode='r', buffering=-1, encoding=None, + errors=None, newline=None): + """ + Open the file pointed by this path and return a file object, as + the built-in open() function does. + """ + if self._closed: + self._raise_closed() + if sys.version_info >= (3, 3): + return io.open(str(self), mode, buffering, encoding, errors, newline, + opener=self._opener) + else: + return io.open(str(self), mode, buffering, encoding, errors, newline) + + def touch(self, mode=0o777, exist_ok=True): + """ + Create this file with the given access mode, if it doesn't exist. + """ + if self._closed: + self._raise_closed() + flags = os.O_CREAT + if not exist_ok: + flags |= os.O_EXCL + fd = self.raw_open(flags, mode) + os.close(fd) + + def mkdir(self, mode=0o777, parents=False): + if self._closed: + self._raise_closed() + if not parents: + self._accessor.mkdir(self, mode) + else: + try: + self._accessor.mkdir(self, mode) + except OSError as e: + if e.errno != ENOENT: + raise + self.parent().mkdir(mode, True) + self._accessor.mkdir(self, mode) + + def chmod(self, mode): + """ + Change the permissions of the path, like os.chmod(). + """ + if self._closed: + self._raise_closed() + self._accessor.chmod(self, mode) + + def lchmod(self, mode): + """ + Like chmod(), except if the path points to a symlink, the symlink's + permissions are changed, rather than its target's. + """ + if self._closed: + self._raise_closed() + self._accessor.lchmod(self, mode) + + def unlink(self): + """ + Remove this file or link. + If the path is a directory, use rmdir() instead. + """ + if self._closed: + self._raise_closed() + self._accessor.unlink(self) + + def rmdir(self): + """ + Remove this directory. The directory must be empty. + """ + if self._closed: + self._raise_closed() + self._accessor.rmdir(self) + + def lstat(self): + """ + Like stat(), except if the path points to a symlink, the symlink's + status information is returned, rather than its target's. + """ + if self._closed: + self._raise_closed() + return self._accessor.lstat(self) + + def rename(self, target): + """ + Rename this path to the given path. + """ + if self._closed: + self._raise_closed() + self._accessor.rename(self, target) + + def symlink_to(self, target, target_is_directory=False): + """ + Make this path a symlink pointing to the given path. + Note the order of arguments (self, target) is the reverse of os.symlink's. + """ + if self._closed: + self._raise_closed() + self._accessor.symlink(target, self, target_is_directory) + + # Convenience functions for querying the stat results + + def exists(self): + """ + Whether this path exists. + """ + try: + self.restat() + except OSError as e: + if e.errno != ENOENT: + raise + return False + return True + + def is_dir(self): + """ + Whether this path is a directory. + """ + return S_ISDIR(self._stat.st_mode) + + def is_file(self): + """ + Whether this path is a regular file (also True for symlinks pointing + to regular files). + """ + return S_ISREG(self._stat.st_mode) + + def is_symlink(self): + """ + Whether this path is a symbolic link. + """ + st = self.lstat() + return S_ISLNK(st.st_mode) + + +class PosixPath(Path, PurePosixPath): + __slots__ = () + +class NTPath(Path, PureNTPath): + __slots__ = () + diff --git a/lib/pathlib/setup.py b/lib/pathlib/setup.py new file mode 100755 --- /dev/null +++ b/lib/pathlib/setup.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +import sys +from distutils.core import setup + + +setup( + name='pathlib', + version=open('VERSION.txt').read().strip(), + py_modules=['pathlib'], + license='MIT License', + description='Object-oriented filesystem paths', + long_description=open('README.txt').read(), + author='Antoine Pitrou', + author_email='solipsis at pitrou.net', + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Operating System :: OS Independent', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3.2', + 'Topic :: Software Development :: Libraries', + 'Topic :: System :: Filesystems', + ], + download_url='https://pypi.python.org/pypi/pathlib/', + url='http://readthedocs.org/docs/pathlib/', +) diff --git a/lib/pathlib/test_pathlib.py b/lib/pathlib/test_pathlib.py new file mode 100755 --- /dev/null +++ b/lib/pathlib/test_pathlib.py @@ -0,0 +1,1417 @@ +import collections +import io +import os +import errno +import pathlib +import sys +import shutil +import tempfile +import unittest +from contextlib import contextmanager + +try: + from test import support +except ImportError: + from test import test_support as support +TESTFN = support.TESTFN + + +class _BaseFlavourTest(unittest.TestCase): + + def _check_parse_parts(self, arg, expected): + f = self.flavour.parse_parts + sep = self.flavour.sep + altsep = self.flavour.altsep + actual = f([x.replace('/', sep) for x in arg]) + self.assertEqual(actual, expected) + if altsep: + actual = f([x.replace('/', altsep) for x in arg]) + self.assertEqual(actual, expected) + + def test_parse_parts_common(self): + check = self._check_parse_parts + sep = self.flavour.sep + # Unanchored parts + check([], ('', '', [])) + check(['a'], ('', '', ['a'])) + check(['a/'], ('', '', ['a'])) + check(['a', 'b'], ('', '', ['a', 'b'])) + # Expansion + check(['a/b'], ('', '', ['a', 'b'])) + check(['a/b/'], ('', '', ['a', 'b'])) + check(['a', 'b/c', 'd'], ('', '', ['a', 'b', 'c', 'd'])) + # Collapsing and stripping excess slashes + check(['a', 'b//c', 'd'], ('', '', ['a', 'b', 'c', 'd'])) + check(['a', 'b/c/', 'd'], ('', '', ['a', 'b', 'c', 'd'])) + # Eliminating standalone dots + check(['.'], ('', '', [])) + check(['.', '.', 'b'], ('', '', ['b'])) + check(['a', '.', 'b'], ('', '', ['a', 'b'])) + check(['a', '.', '.'], ('', '', ['a'])) + # The first part is anchored + check(['/a/b'], ('', sep, [sep, 'a', 'b'])) + check(['/a', 'b'], ('', sep, [sep, 'a', 'b'])) + check(['/a/', 'b'], ('', sep, [sep, 'a', 'b'])) + # Ignoring parts before an anchored part + check(['a', '/b', 'c'], ('', sep, [sep, 'b', 'c'])) + check(['a', '/b', '/c'], ('', sep, [sep, 'c'])) + + +class PosixFlavourTest(_BaseFlavourTest): + flavour = pathlib._posix_flavour + + def test_parse_parts(self): + check = self._check_parse_parts + # Paths which look like NT paths aren't treated specially + check(['c:a'], ('', '', ['c:a'])) + check(['c:\\a'], ('', '', ['c:\\a'])) + check(['\\a'], ('', '', ['\\a'])) + + def test_splitroot(self): + f = self.flavour.splitroot + self.assertEqual(f(''), ('', '', '')) + self.assertEqual(f('a'), ('', '', 'a')) + self.assertEqual(f('a/b'), ('', '', 'a/b')) + self.assertEqual(f('a/b/'), ('', '', 'a/b/')) + self.assertEqual(f('/a'), ('', '/', 'a')) + self.assertEqual(f('/a/b'), ('', '/', 'a/b')) + self.assertEqual(f('/a/b/'), ('', '/', 'a/b/')) + # The root is collapsed when there are redundant slashes + self.assertEqual(f('//a'), ('', '/', 'a')) + self.assertEqual(f('///a/b'), ('', '/', 'a/b')) + # Paths which look like NT paths aren't treated specially + self.assertEqual(f('c:/a/b'), ('', '', 'c:/a/b')) + self.assertEqual(f('\\/a/b'), ('', '', '\\/a/b')) + self.assertEqual(f('\\a\\b'), ('', '', '\\a\\b')) + + +class NTFlavourTest(_BaseFlavourTest): + flavour = pathlib._nt_flavour + + def test_parse_parts(self): + check = self._check_parse_parts + # First part is anchored + check(['c:'], ('c:', '', ['c:'])) + check(['c:\\'], ('c:', '\\', ['c:\\'])) + check(['\\'], ('', '\\', ['\\'])) + check(['c:a'], ('c:', '', ['c:', 'a'])) + check(['c:\\a'], ('c:', '\\', ['c:\\', 'a'])) + check(['\\a'], ('', '\\', ['\\', 'a'])) + # UNC paths + check(['\\\\a\\b'], ('\\\\a\\b', '\\', ['\\\\a\\b\\'])) + check(['\\\\a\\b\\'], ('\\\\a\\b', '\\', ['\\\\a\\b\\'])) + check(['\\\\a\\b\\c'], ('\\\\a\\b', '\\', ['\\\\a\\b\\', 'c'])) + # Second part is anchored, so that the first part is ignored + check(['a', 'Z:b', 'c'], ('Z:', '', ['Z:', 'b', 'c'])) + check(['a', 'Z:\\b', 'c'], ('Z:', '\\', ['Z:\\', 'b', 'c'])) + check(['a', '\\b', 'c'], ('', '\\', ['\\', 'b', 'c'])) + # UNC paths + check(['a', '\\\\b\\c', 'd'], ('\\\\b\\c', '\\', ['\\\\b\\c\\', 'd'])) + # Collapsing and stripping excess slashes + check(['a', 'Z:\\\\b\\\\c\\', 'd\\'], ('Z:', '\\', ['Z:\\', 'b', 'c', 'd'])) + # UNC paths + check(['a', '\\\\b\\c\\\\', 'd'], ('\\\\b\\c', '\\', ['\\\\b\\c\\', 'd'])) + # Extended paths + check(['\\\\?\\c:\\'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\'])) + check(['\\\\?\\c:\\a'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\', 'a'])) + # Extended UNC paths (format is "\\?\UNC\server\share") + check(['\\\\?\\UNC\\b\\c'], ('\\\\?\\UNC\\b\\c', '\\', ['\\\\?\\UNC\\b\\c\\'])) + check(['\\\\?\\UNC\\b\\c\\d'], ('\\\\?\\UNC\\b\\c', '\\', ['\\\\?\\UNC\\b\\c\\', 'd'])) + + def test_splitroot(self): + f = self.flavour.splitroot + self.assertEqual(f(''), ('', '', '')) + self.assertEqual(f('a'), ('', '', 'a')) + self.assertEqual(f('a\\b'), ('', '', 'a\\b')) + self.assertEqual(f('\\a'), ('', '\\', 'a')) + self.assertEqual(f('\\a\\b'), ('', '\\', 'a\\b')) + self.assertEqual(f('c:a\\b'), ('c:', '', 'a\\b')) + self.assertEqual(f('c:\\a\\b'), ('c:', '\\', 'a\\b')) + # Redundant slashes in the root are collapsed + self.assertEqual(f('\\\\a'), ('', '\\', 'a')) + self.assertEqual(f('\\\\\\a/b'), ('', '\\', 'a/b')) + self.assertEqual(f('c:\\\\a'), ('c:', '\\', 'a')) + self.assertEqual(f('c:\\\\\\a/b'), ('c:', '\\', 'a/b')) + # Valid UNC paths + self.assertEqual(f('\\\\a\\b'), ('\\\\a\\b', '\\', '')) + self.assertEqual(f('\\\\a\\b\\'), ('\\\\a\\b', '\\', '')) + self.assertEqual(f('\\\\a\\b\\c\\d'), ('\\\\a\\b', '\\', 'c\\d')) + # These are non-UNC paths (according to ntpath.py and test_ntpath) + # However, command.com says such paths are invalid, so it's + # difficult to know what the right semantics are + self.assertEqual(f('\\\\\\a\\b'), ('', '\\', 'a\\b')) + self.assertEqual(f('\\\\a'), ('', '\\', 'a')) + + +# +# Tests for the pure classes +# + +class _BasePurePathTest(unittest.TestCase): + + # keys are canonical paths, values are list of tuples of arguments + # supposed to produce equal paths + equivalences = { + 'a/b': [ + ('a', 'b'), ('a/', 'b'), ('a', 'b/'), ('a/', 'b/'), + ('a/b/',), ('a//b',), ('a//b//',), + # empty components get removed + ('', 'a', 'b'), ('a', '', 'b'), ('a', 'b', ''), + ], + '/b/c/d': [ + ('a', '/b/c', 'd'), ('a', '//b//c', 'd/'), + ('/a', '/b/c', 'd'), + # empty components get removed + ('/', 'b', '', 'c/d'), ('/', '', 'b/c/d'), ('', '/b/c/d'), + ], + } + + def setUp(self): + p = self.cls('a') + self.flavour = p._flavour + self.sep = self.flavour.sep + self.altsep = self.flavour.altsep + + def test_constructor_common(self): + P = self.cls + p = P('a') + self.assertIsInstance(p, P) + P('a', 'b', 'c') + P('/a', 'b', 'c') + P('a/b/c') + P('/a/b/c') + self.assertEqual(P(P('a')), P('a')) + self.assertEqual(P(P('a'), 'b'), P('a/b')) + self.assertEqual(P(P('a'), P('b')), P('a/b')) + + def test_join_common(self): + P = self.cls + p = P('a/b') + pp = p.join('c') + self.assertEqual(pp, P('a/b/c')) + self.assertIs(type(pp), type(p)) + pp = p.join('c', 'd') + self.assertEqual(pp, P('a/b/c/d')) + pp = p.join(P('c')) + self.assertEqual(pp, P('a/b/c')) + pp = p.join('/c') + self.assertEqual(pp, P('/c')) + + def test_getitem_common(self): + # Basically the same as join() + P = self.cls + p = P('a/b') + pp = p['c'] + self.assertEqual(pp, P('a/b/c')) + self.assertIs(type(pp), type(p)) + pp = p['c', 'd'] + self.assertEqual(pp, P('a/b/c/d')) + pp = p[P('c')] + self.assertEqual(pp, P('a/b/c')) + pp = p['/c'] + self.assertEqual(pp, P('/c')) + + def _check_str(self, expected, args): + p = self.cls(*args) + self.assertEqual(str(p), expected.replace('/', self.sep)) + + def test_str_common(self): + # Canonicalized paths roundtrip + for pathstr in ('a', 'a/b', 'a/b/c', '/', '/a/b', '/a/b/c'): + self._check_str(pathstr, (pathstr,)) + # Special case for the empty path + self._check_str('.', ('',)) + # Other tests for str() are in test_equivalences() + + def test_as_posix_common(self): + P = self.cls + for pathstr in ('a', 'a/b', 'a/b/c', '/', '/a/b', '/a/b/c'): + self.assertEqual(P(pathstr).as_posix(), pathstr) + # Other tests for as_posix() are in test_equivalences() + + @unittest.skipIf(sys.version_info < (3, 2), + 'os.fsencode has been introduced in version 3.2') + def test_as_bytes_common(self): + sep = os.fsencode(self.sep) + P = self.cls + self.assertEqual(P('a/b').as_bytes(), b'a' + sep + b'b') + self.assertEqual(bytes(P('a/b')), b'a' + sep + b'b') + + def test_repr_common(self): + for pathstr in ('a', 'a/b', 'a/b/c', '/', '/a/b', '/a/b/c'): + p = self.cls(pathstr) + clsname = p.__class__.__name__ + r = repr(p) + # The repr() is in the form ClassName("canonical path") + self.assertTrue(r.startswith(clsname + '('), r) + self.assertTrue(r.endswith(')'), r) + inner = r[len(clsname) + 1 : -1] + self.assertEqual(eval(inner), str(p)) + + def test_eq_common(self): + P = self.cls + self.assertEqual(P('a/b'), P('a/b')) + self.assertEqual(P('a/b'), P('a', 'b')) + self.assertNotEqual(P('a/b'), P('a')) + self.assertNotEqual(P('a/b'), P('/a/b')) + self.assertNotEqual(P('a/b'), P()) + self.assertNotEqual(P('/a/b'), P('/')) + self.assertNotEqual(P(), P('/')) + + def test_match_common(self): + P = self.cls + self.assertRaises(ValueError, P('a').match, '') + self.assertRaises(ValueError, P('a').match, '.') + # Simple relative pattern + self.assertTrue(P('b.py').match('b.py')) + self.assertTrue(P('a/b.py').match('b.py')) + self.assertTrue(P('/a/b.py').match('b.py')) + self.assertFalse(P('a.py').match('b.py')) + self.assertFalse(P('b/py').match('b.py')) + self.assertFalse(P('/a.py').match('b.py')) + self.assertFalse(P('b.py/c').match('b.py')) + # Wilcard relative pattern + self.assertTrue(P('b.py').match('*.py')) + self.assertTrue(P('a/b.py').match('*.py')) + self.assertTrue(P('/a/b.py').match('*.py')) + self.assertFalse(P('b.pyc').match('*.py')) + self.assertFalse(P('b./py').match('*.py')) + self.assertFalse(P('b.py/c').match('*.py')) + # Multi-part relative pattern + self.assertTrue(P('ab/c.py').match('a*/*.py')) + self.assertTrue(P('/d/ab/c.py').match('a*/*.py')) + self.assertFalse(P('a.py').match('a*/*.py')) + self.assertFalse(P('/dab/c.py').match('a*/*.py')) + self.assertFalse(P('ab/c.py/d').match('a*/*.py')) + # Absolute pattern + self.assertTrue(P('/b.py').match('/*.py')) + self.assertFalse(P('b.py').match('/*.py')) + self.assertFalse(P('a/b.py').match('/*.py')) + self.assertFalse(P('/a/b.py').match('/*.py')) + # Multi-part absolute pattern + self.assertTrue(P('/a/b.py').match('/a/*.py')) + self.assertFalse(P('/ab.py').match('/a/*.py')) + self.assertFalse(P('/a/b/c.py').match('/a/*.py')) + + def test_ordering_common(self): + # Ordering is tuple-alike + def assertLess(a, b): + self.assertLess(a, b) + self.assertGreater(b, a) + P = self.cls + a = P('a') + b = P('a/b') + c = P('abc') + d = P('b') + assertLess(a, b) + assertLess(a, c) + assertLess(a, d) + assertLess(b, c) + assertLess(c, d) + P = self.cls + a = P('/a') + b = P('/a/b') + c = P('/abc') + d = P('/b') + assertLess(a, b) + assertLess(a, c) + assertLess(a, d) + assertLess(b, c) + assertLess(c, d) + + def test_parts_common(self): + sep = self.sep + P = self.cls + p = P('a/b') + parts = p.parts + # The object gets reused + self.assertIs(parts, p.parts) + # Sequence protocol + self.assertIsInstance(parts, collections.Sequence) + self.assertEqual(len(parts), 2) + self.assertEqual(parts[0], 'a') + self.assertEqual(list(parts), ['a', 'b']) + self.assertEqual(parts[:], P('a/b')) + self.assertEqual(parts[0:1], P('a')) + p = P('/a/b') + parts = p.parts + self.assertEqual(len(parts), 3) + self.assertEqual(parts[0], sep) + self.assertEqual(list(parts), [sep, 'a', 'b']) + self.assertEqual(parts[:], P('/a/b')) + self.assertEqual(parts[:2], P('/a')) + self.assertEqual(parts[1:], P('a/b')) + + def test_equivalences(self): + for k, tuples in self.equivalences.items(): + canon = k.replace('/', self.sep) + posix = k.replace(self.sep, '/') + if canon != posix: + tuples = tuples + [ + tuple(part.replace('/', self.sep) for part in t) + for t in tuples + ] + tuples.append((posix, )) + pcanon = self.cls(canon) + for t in tuples: + p = self.cls(*t) + self.assertEqual(p, pcanon, "failed with args {}".format(t)) + self.assertEqual(hash(p), hash(pcanon)) + self.assertEqual(str(p), canon) + self.assertEqual(p.as_posix(), posix) + + def test_parent_common(self): + # Relative + P = self.cls + p = P('a/b/c') + self.assertEqual(p.parent(), P('a/b')) + self.assertEqual(p.parent(2), P('a')) + self.assertEqual(p.parent(3), P()) + self.assertRaises(ValueError, p.parent, 4) + # Anchored + p = P('/a/b/c') + self.assertEqual(p.parent(), P('/a/b')) + self.assertEqual(p.parent(2), P('/a')) + self.assertEqual(p.parent(3), P('/')) + self.assertRaises(ValueError, p.parent, 4) + # Invalid level values + self.assertRaises(ValueError, p.parent, 0) + self.assertRaises(ValueError, p.parent, -1) + + def test_parents_common(self): + # Relative + P = self.cls + p = P('a/b/c') + it = p.parents() + self.assertEqual(next(it), P('a/b')) + self.assertEqual(list(it), [P('a'), P()]) + # Anchored + p = P('/a/b/c') + it = p.parents() + self.assertEqual(next(it), P('/a/b')) + self.assertEqual(list(it), [P('/a'), P('/')]) + + def test_drive_common(self): + P = self.cls + self.assertEqual(P('a/b').drive, '') + self.assertEqual(P('/a/b').drive, '') + self.assertEqual(P('').drive, '') + + def test_root_common(self): + P = self.cls + sep = self.sep + self.assertEqual(P('').root, '') + self.assertEqual(P('a/b').root, '') + self.assertEqual(P('/').root, sep) + self.assertEqual(P('/a/b').root, sep) + + def test_ext_common(self): + P = self.cls + self.assertEqual(P('').ext, '') + self.assertEqual(P('.').ext, '') + self.assertEqual(P('/').ext, '') + self.assertEqual(P('a/b').ext, '') + self.assertEqual(P('/a/b').ext, '') + self.assertEqual(P('/a/b/.').ext, '') + self.assertEqual(P('a/b.py').ext, '.py') + self.assertEqual(P('/a/b.py').ext, '.py') + self.assertEqual(P('a/b.tar.gz').ext, '.tar.gz') + self.assertEqual(P('/a/b.tar.gz').ext, '.tar.gz') + + def test_relative_common(self): + P = self.cls + p = P('a/b') + self.assertEqual(p.relative(), P('a/b')) + p = P('/a/b') + self.assertEqual(p.relative(), P('a/b')) + p = P('/') + self.assertEqual(p.relative(), P()) + + def test_relative_to_common(self): + P = self.cls + p = P('a/b') + self.assertRaises(TypeError, p.relative_to) + self.assertEqual(p.relative_to(P()), P('a/b')) + self.assertEqual(p.relative_to(P('a')), P('b')) + self.assertEqual(p.relative_to(P('a/b')), P()) + # With several args + self.assertEqual(p.relative_to('a', 'b'), P()) + # Unrelated paths + self.assertRaises(ValueError, p.relative_to, P('c')) + self.assertRaises(ValueError, p.relative_to, P('a/b/c')) + self.assertRaises(ValueError, p.relative_to, P('a/c')) + self.assertRaises(ValueError, p.relative_to, P('/a')) + p = P('/a/b') + self.assertEqual(p.relative_to(P('/')), P('a/b')) + self.assertEqual(p.relative_to(P('/a')), P('b')) + self.assertEqual(p.relative_to(P('/a/b')), P()) + # Unrelated paths + self.assertRaises(ValueError, p.relative_to, P('/c')) + self.assertRaises(ValueError, p.relative_to, P('/a/b/c')) + self.assertRaises(ValueError, p.relative_to, P('/a/c')) + self.assertRaises(ValueError, p.relative_to, P()) + self.assertRaises(ValueError, p.relative_to, P('a')) + + +class PurePosixPathTest(_BasePurePathTest): + cls = pathlib.PurePosixPath + + def test_root(self): + P = self.cls + # This is an UNC path under Windows + self.assertEqual(P('//a/b').root, '/') + + def test_eq(self): + P = self.cls + self.assertNotEqual(P('a/b'), P('A/b')) + + def test_match(self): + P = self.cls + self.assertFalse(P('A.py').match('a.PY')) + + def test_is_absolute(self): + P = self.cls + self.assertFalse(P().is_absolute()) + self.assertFalse(P('a').is_absolute()) + self.assertFalse(P('a/b/').is_absolute()) + self.assertTrue(P('/').is_absolute()) + self.assertTrue(P('/a').is_absolute()) + self.assertTrue(P('/a/b/').is_absolute()) + + def test_normcase(self): + P = self.cls + p = P('/Aa/Bb/Cc').normcase() + self.assertEqual(P('/Aa/Bb/Cc'), p) + self.assertEqual('/Aa/Bb/Cc', str(p)) + + def test_is_reserved(self): + P = self.cls + self.assertIs(False, P('').is_reserved()) + self.assertIs(False, P('/').is_reserved()) + self.assertIs(False, P('/foo/bar').is_reserved()) + self.assertIs(False, P('/dev/con/PRN/NUL').is_reserved()) + + +class PureNTPathTest(_BasePurePathTest): + cls = pathlib.PureNTPath + + equivalences = _BasePurePathTest.equivalences.copy() + equivalences.update({ + 'c:a': [ ('c:', 'a'), ('c:', 'a/'), ('/', 'c:', 'a') ], + 'c:/a': [ + ('c:/', 'a'), ('c:', '/', 'a'), ('c:', '/a'), + ('/z', 'c:/', 'a'), ('//x/y', 'c:/', 'a'), + ], + '//a/b/': [ ('//a/b',) ], + '//a/b/c': [ + ('//a/b', 'c'), ('//a/b/', 'c'), + ], + }) + + def test_str(self): + p = self.cls('a/b/c') + self.assertEqual(str(p), 'a\\b\\c') + p = self.cls('c:/a/b/c') + self.assertEqual(str(p), 'c:\\a\\b\\c') + p = self.cls('//a/b') + self.assertEqual(str(p), '\\\\a\\b\\') + p = self.cls('//a/b/c') + self.assertEqual(str(p), '\\\\a\\b\\c') + p = self.cls('//a/b/c/d') + self.assertEqual(str(p), '\\\\a\\b\\c\\d') + + def test_eq(self): + P = self.cls + self.assertEqual(P('c:a/b'), P('c:a/b')) + self.assertEqual(P('c:a/b'), P('c:', 'a', 'b')) + self.assertNotEqual(P('c:a/b'), P('d:a/b')) + self.assertNotEqual(P('c:a/b'), P('c:/a/b')) + self.assertNotEqual(P('/a/b'), P('c:/a/b')) + # Case-insensitivity + self.assertEqual(P('a/B'), P('A/b')) + self.assertEqual(P('C:a/B'), P('c:A/b')) + self.assertEqual(P('//Some/SHARE/a/B'), P('//somE/share/A/b')) + + def test_match_common(self): + P = self.cls + # Absolute patterns + self.assertTrue(P('c:/b.py').match('/*.py')) + self.assertTrue(P('c:/b.py').match('c:*.py')) + self.assertTrue(P('c:/b.py').match('c:/*.py')) + self.assertFalse(P('d:/b.py').match('c:/*.py')) # wrong drive + self.assertFalse(P('b.py').match('/*.py')) + self.assertFalse(P('b.py').match('c:*.py')) + self.assertFalse(P('b.py').match('c:/*.py')) + self.assertFalse(P('c:b.py').match('/*.py')) + self.assertFalse(P('c:b.py').match('c:/*.py')) + self.assertFalse(P('/b.py').match('c:*.py')) + self.assertFalse(P('/b.py').match('c:/*.py')) + # UNC patterns + self.assertTrue(P('//some/share/a.py').match('/*.py')) + self.assertTrue(P('//some/share/a.py').match('//some/share/*.py')) + self.assertFalse(P('//other/share/a.py').match('//some/share/*.py')) + self.assertFalse(P('//some/share/a/b.py').match('//some/share/*.py')) + # Case-insensitivity + self.assertTrue(P('B.py').match('b.PY')) + self.assertTrue(P('c:/a/B.Py').match('C:/A/*.pY')) + self.assertTrue(P('//Some/Share/B.Py').match('//somE/sharE/*.pY')) + + def test_ordering_common(self): + # Case-insensitivity + def assertOrderedEqual(a, b): + self.assertLessEqual(a, b) + self.assertGreaterEqual(b, a) + P = self.cls + p = P('c:A/b') + q = P('C:a/B') + assertOrderedEqual(p, q) + self.assertFalse(p < q) + self.assertFalse(p > q) + p = P('//some/Share/A/b') + q = P('//Some/SHARE/a/B') + assertOrderedEqual(p, q) + self.assertFalse(p < q) + self.assertFalse(p > q) + + def test_parts(self): + P = self.cls + p = P('c:a/b') + parts = p.parts + self.assertEqual(len(parts), 3) + self.assertEqual(list(parts), ['c:', 'a', 'b']) + self.assertEqual(parts[:2], P('c:a')) + self.assertEqual(parts[1:], P('a/b')) + p = P('c:/a/b') + parts = p.parts + self.assertEqual(len(parts), 3) + self.assertEqual(list(parts), ['c:\\', 'a', 'b']) + self.assertEqual(parts[:2], P('c:/a')) + self.assertEqual(parts[1:], P('a/b')) + p = P('//a/b/c/d') + parts = p.parts + self.assertEqual(len(parts), 3) + self.assertEqual(list(parts), ['\\\\a\\b\\', 'c', 'd']) + self.assertEqual(parts[:2], P('//a/b/c')) + self.assertEqual(parts[1:], P('c/d')) + + def test_parent(self): + # Anchored + P = self.cls + p = P('z:a/b/c') + self.assertEqual(p.parent(), P('z:a/b')) + self.assertEqual(p.parent(2), P('z:a')) + self.assertEqual(p.parent(3), P('z:')) + self.assertRaises(ValueError, p.parent, 4) + p = P('z:/a/b/c') + self.assertEqual(p.parent(), P('z:/a/b')) + self.assertEqual(p.parent(2), P('z:/a')) + self.assertEqual(p.parent(3), P('z:/')) + self.assertRaises(ValueError, p.parent, 4) + p = P('//a/b/c/d') + self.assertEqual(p.parent(), P('//a/b/c')) + self.assertEqual(p.parent(2), P('//a/b')) + self.assertRaises(ValueError, p.parent, 3) + + def test_parents(self): + # Anchored + P = self.cls + p = P('z:a/b/') + self.assertEqual(list(p.parents()), [P('z:a'), P('z:')]) + p = P('z:/a/b/') + self.assertEqual(list(p.parents()), [P('z:/a'), P('z:/')]) + p = P('//a/b/c/d') + self.assertEqual(list(p.parents()), [P('//a/b/c'), P('//a/b')]) + + def test_drive(self): + P = self.cls + self.assertEqual(P('c:').drive, 'c:') + self.assertEqual(P('c:a/b').drive, 'c:') + self.assertEqual(P('c:/').drive, 'c:') + self.assertEqual(P('c:/a/b/').drive, 'c:') + self.assertEqual(P('//a/b').drive, '\\\\a\\b') + self.assertEqual(P('//a/b/').drive, '\\\\a\\b') + self.assertEqual(P('//a/b/c/d').drive, '\\\\a\\b') + + def test_root(self): + P = self.cls + self.assertEqual(P('c:').root, '') + self.assertEqual(P('c:a/b').root, '') + self.assertEqual(P('c:/').root, '\\') + self.assertEqual(P('c:/a/b/').root, '\\') + self.assertEqual(P('//a/b').root, '\\') + self.assertEqual(P('//a/b/').root, '\\') + self.assertEqual(P('//a/b/c/d').root, '\\') + + def test_ext(self): + P = self.cls + self.assertEqual(P('c:').ext, '') + self.assertEqual(P('c:/').ext, '') + self.assertEqual(P('c:a/b').ext, '') + self.assertEqual(P('c:/a/b').ext, '') + self.assertEqual(P('c:a/b.py').ext, '.py') + self.assertEqual(P('c:/a/b.py').ext, '.py') + self.assertEqual(P('c:a/b.tar.gz').ext, '.tar.gz') + self.assertEqual(P('c:/a/b.tar.gz').ext, '.tar.gz') + self.assertEqual(P('//My.py/Share.php').ext, '') + self.assertEqual(P('//My.py/Share.php/a/b').ext, '') + + def test_relative(self): + P = self.cls + p = P('c:a/b') + self.assertEqual(p.relative(), P('a/b')) + p = P('c:/a/b') + self.assertEqual(p.relative(), P('a/b')) + p = P('c:') + self.assertEqual(p.relative(), P()) + p = P('c:/') + self.assertEqual(p.relative(), P()) + + def test_relative_to(self): + P = self.cls + p = P('c:a/b') + self.assertEqual(p.relative_to(P('c:')), P('a/b')) + self.assertEqual(p.relative_to(P('c:a')), P('b')) + self.assertEqual(p.relative_to(P('c:a/b')), P()) + # Unrelated paths + self.assertRaises(ValueError, p.relative_to, P()) + self.assertRaises(ValueError, p.relative_to, P('d:')) + self.assertRaises(ValueError, p.relative_to, P('a')) + self.assertRaises(ValueError, p.relative_to, P('/a')) + self.assertRaises(ValueError, p.relative_to, P('c:a/b/c')) + self.assertRaises(ValueError, p.relative_to, P('c:a/c')) + self.assertRaises(ValueError, p.relative_to, P('c:/a')) + p = P('c:/a/b') + self.assertEqual(p.relative_to(P('c:')), P('/a/b')) + self.assertEqual(p.relative_to(P('c:/')), P('a/b')) + self.assertEqual(p.relative_to(P('c:/a')), P('b')) + self.assertEqual(p.relative_to(P('c:/a/b')), P()) + # Unrelated paths + self.assertRaises(ValueError, p.relative_to, P('c:/c')) + self.assertRaises(ValueError, p.relative_to, P('c:/a/b/c')) + self.assertRaises(ValueError, p.relative_to, P('c:/a/c')) + self.assertRaises(ValueError, p.relative_to, P('c:a')) + self.assertRaises(ValueError, p.relative_to, P('d:')) + self.assertRaises(ValueError, p.relative_to, P('d:/')) + self.assertRaises(ValueError, p.relative_to, P('/a')) + self.assertRaises(ValueError, p.relative_to, P('//c/a')) + # UNC paths + p = P('//a/b/c/d') + self.assertEqual(p.relative_to(P('//a/b')), P('c/d')) + self.assertEqual(p.relative_to(P('//a/b/c')), P('d')) + self.assertEqual(p.relative_to(P('//a/b/c/d')), P()) + # Unrelated paths + self.assertRaises(ValueError, p.relative_to, P('/a/b/c')) + self.assertRaises(ValueError, p.relative_to, P('c:/a/b/c')) + self.assertRaises(ValueError, p.relative_to, P('//z/b/c')) + self.assertRaises(ValueError, p.relative_to, P('//a/z/c')) + + def test_is_absolute(self): + P = self.cls + # Under NT, only paths with both a drive and a root are absolute + self.assertFalse(P().is_absolute()) + self.assertFalse(P('a').is_absolute()) + self.assertFalse(P('a/b/').is_absolute()) + self.assertFalse(P('/').is_absolute()) + self.assertFalse(P('/a').is_absolute()) + self.assertFalse(P('/a/b/').is_absolute()) + self.assertFalse(P('c:').is_absolute()) + self.assertFalse(P('c:a').is_absolute()) + self.assertFalse(P('c:a/b/').is_absolute()) + self.assertTrue(P('c:/').is_absolute()) + self.assertTrue(P('c:/a').is_absolute()) + self.assertTrue(P('c:/a/b/').is_absolute()) + # UNC paths are absolute by definition + self.assertTrue(P('//a/b').is_absolute()) + self.assertTrue(P('//a/b/').is_absolute()) + self.assertTrue(P('//a/b/c').is_absolute()) + self.assertTrue(P('//a/b/c/d').is_absolute()) + + def test_normcase(self): + P = self.cls + p = P('D:/Aa/Bb/Cc').normcase() + self.assertEqual(P('d:/aa/bb/cc'), p) + self.assertEqual(r'd:\aa\bb\cc', str(p)) + + def test_is_reserved(self): + P = self.cls + self.assertIs(False, P('').is_reserved()) + self.assertIs(False, P('/').is_reserved()) + self.assertIs(False, P('/foo/bar').is_reserved()) + self.assertIs(True, P('con').is_reserved()) + self.assertIs(True, P('NUL').is_reserved()) + self.assertIs(True, P('NUL.txt').is_reserved()) + self.assertIs(True, P('com1').is_reserved()) + self.assertIs(True, P('com9.bar').is_reserved()) + self.assertIs(False, P('bar.com9').is_reserved()) + self.assertIs(True, P('lpt1').is_reserved()) + self.assertIs(True, P('lpt9.bar').is_reserved()) + self.assertIs(False, P('bar.lpt9').is_reserved()) + # Only the last component matters + self.assertIs(False, P('c:/NUL/con/baz').is_reserved()) + # UNC paths are never reserved + self.assertIs(False, P('//my/share/nul/con/aux').is_reserved()) + + +class PurePathTest(_BasePurePathTest): + cls = pathlib.PurePath + + def test_concrete_class(self): + p = self.cls('a') + self.assertIs(type(p), + pathlib.PureNTPath if os.name == 'nt' else pathlib.PurePosixPath) + + def test_different_flavours_unequal(self): + p = pathlib.PurePosixPath('a') + q = pathlib.PureNTPath('a') + self.assertNotEqual(p, q) + + @unittest.skipIf(sys.version_info < (3, 0), + 'Most types are orderable in Python 2') + def test_different_flavours_unordered(self): + p = pathlib.PurePosixPath('a') + q = pathlib.PureNTPath('a') + with self.assertRaises(TypeError): + p < q + with self.assertRaises(TypeError): + p <= q + with self.assertRaises(TypeError): + p > q + with self.assertRaises(TypeError): + p >= q + + +# +# Tests for the concrete classes +# + +# Make sure any symbolic links in the base test path are resolved +BASE = os.path.realpath(TESTFN) +join = lambda *x: os.path.join(BASE, *x) +rel_join = lambda *x: os.path.join(TESTFN, *x) + +def symlink_skip_reason(): + if not pathlib.supports_symlinks: + return "no system support for symlinks" + try: + os.symlink(__file__, BASE) + except OSError as e: + return str(e) + else: + support.unlink(BASE) + return None + +symlink_skip_reason = symlink_skip_reason() + +only_nt = unittest.skipIf(os.name != 'nt', + 'test requires a Windows-compatible system') +only_posix = unittest.skipIf(os.name == 'nt', + 'test requires a POSIX-compatible system') +with_symlinks = unittest.skipIf(symlink_skip_reason, symlink_skip_reason) + + + at only_posix +class PosixPathAsPureTest(PurePosixPathTest): + cls = pathlib.PosixPath + + at only_nt +class NTPathAsPureTest(PureNTPathTest): + cls = pathlib.NTPath + + +class _BasePathTest(unittest.TestCase): + """Tests for the FS-accessing functionalities of the Path classes.""" + + using_openat = False + + # (BASE) + # | + # |-- dirA/ + # |-- linkC -> "../dirB" + # |-- dirB/ + # | |-- fileB + # |-- linkD -> "../dirB" + # |-- dirC/ + # | |-- fileC + # | |-- fileD + # |-- fileA + # |-- linkA -> "fileA" + # |-- linkB -> "dirB" + # + + def setUp(self): + os.mkdir(BASE) + self.addCleanup(support.rmtree, BASE) + os.mkdir(join('dirA')) + os.mkdir(join('dirB')) + os.mkdir(join('dirC')) + os.mkdir(join('dirC', 'dirD')) + with open(join('fileA'), 'wb') as f: + f.write(b"this is file A\n") + with open(join('dirB', 'fileB'), 'wb') as f: + f.write(b"this is file B\n") + with open(join('dirC', 'fileC'), 'wb') as f: + f.write(b"this is file C\n") + with open(join('dirC', 'dirD', 'fileD'), 'wb') as f: + f.write(b"this is file D\n") + if not symlink_skip_reason: + if os.name == 'nt': + # Workaround for http://bugs.python.org/issue13772 + def dirlink(src, dest): + os.symlink(src, dest, target_is_directory=True) + else: + def dirlink(src, dest): + os.symlink(src, dest) + # Relative symlinks + os.symlink('fileA', join('linkA')) + dirlink('dirB', join('linkB')) + dirlink(os.path.join('..', 'dirB'), join('dirA', 'linkC')) + # This one goes upwards but doesn't create a loop + dirlink(os.path.join('..', 'dirB'), join('dirB', 'linkD')) + + def assertSame(self, path_a, path_b): + self.assertTrue(os.path.samefile(str(path_a), str(path_b)), + "%r and %r don't point to the same file" % + (path_a, path_b)) + + def assertFileNotFound(self, func, *args, **kwargs): + exc = FileNotFoundError if sys.version_info >= (3, 3) else EnvironmentError + with self.assertRaises(exc) as cm: + func(*args, **kwargs) + self.assertEqual(cm.exception.errno, errno.ENOENT) + + def _test_cwd(self, p): + q = self.cls(os.getcwd()) + self.assertEqual(p, q) + self.assertEqual(str(p), str(q)) + self.assertIs(type(p), type(q)) + self.assertTrue(p.is_absolute()) + + def test_cwd(self): + p = self.cls.cwd() + self._test_cwd(p) + + def test_empty_path(self): + # The empty path points to '.' + p = self.cls('') + self.assertEqual(p.stat(), os.stat('.')) + + def test_exists(self): + P = self.cls + p = P(BASE) + self.assertIs(True, p.exists()) + self.assertIs(True, p['dirA'].exists()) + self.assertIs(True, p['fileA'].exists()) + if not symlink_skip_reason: + self.assertIs(True, p['linkA'].exists()) + self.assertIs(True, p['linkB'].exists()) + self.assertIs(False, p['foo'].exists()) + self.assertIs(False, P('/xyzzy').exists()) + + def test_open(self): + p = self.cls(BASE) + with p['fileA'].open('r') as f: + self.assertIsInstance(f, io.TextIOBase) + self.assertEqual(f.read(), "this is file A\n") + with p['fileA'].open('rb') as f: + self.assertIsInstance(f, io.BufferedIOBase) + self.assertEqual(f.read().strip(), b"this is file A") + with p['fileA'].open('rb', buffering=0) as f: + self.assertIsInstance(f, io.RawIOBase) + self.assertEqual(f.read().strip(), b"this is file A") + + def test_iter(self): + P = self.cls + p = P(BASE) + self.assertIsInstance(p, collections.Iterable) + it = iter(p) + paths = set(it) + expected = ['dirA', 'dirB', 'dirC', 'fileA'] + if not symlink_skip_reason: + expected += ['linkA', 'linkB'] + self.assertEqual(paths, { P(BASE, q) for q in expected }) + + @with_symlinks + def test_iter_symlink(self): + # __iter__ on a symlink to a directory + P = self.cls + p = P(BASE, 'linkB') + paths = set(p) + expected = { P(BASE, 'linkB', q) for q in ['fileB', 'linkD'] } + self.assertEqual(paths, expected) + + def test_iter_nodir(self): + # __iter__ on something that is not a directory + p = self.cls(BASE, 'fileA') + with self.assertRaises(OSError) as cm: + list(p) + # ENOENT or EINVAL under Windows, ENOTDIR otherwise + # (see issue #12802) + self.assertIn(cm.exception.errno, (errno.ENOTDIR, + errno.ENOENT, errno.EINVAL)) + + def test_glob_common(self): + def _check(glob, expected): + self.assertEqual(set(glob), { P(BASE, q) for q in expected }) + P = self.cls + p = P(BASE) + it = p.glob("fileA") + self.assertIsInstance(it, collections.Iterator) + _check(it, ["fileA"]) + _check(p.glob("fileB"), []) + _check(p.glob("dir*/file*"), ["dirB/fileB", "dirC/fileC"]) + if symlink_skip_reason: + _check(p.glob("*A"), ['dirA', 'fileA']) + else: + _check(p.glob("*A"), ['dirA', 'fileA', 'linkA']) + if symlink_skip_reason: + _check(p.glob("*B/*"), ['dirB/fileB']) + else: + _check(p.glob("*B/*"), ['dirB/fileB', 'dirB/linkD', + 'linkB/fileB', 'linkB/linkD']) + if symlink_skip_reason: + _check(p.glob("*/fileB"), ['dirB/fileB']) + else: + _check(p.glob("*/fileB"), ['dirB/fileB', 'linkB/fileB']) + + def test_rglob_common(self): + def _check(glob, expected): + self.assertEqual(set(glob), { P(BASE, q) for q in expected }) + P = self.cls + p = P(BASE) + it = p.rglob("fileA") + self.assertIsInstance(it, collections.Iterator) + # XXX cannot test because of symlink loops in the test setup + #_check(it, ["fileA"]) + #_check(p.rglob("fileB"), ["dirB/fileB"]) + #_check(p.rglob("*/fileA"), [""]) + #_check(p.rglob("*/fileB"), ["dirB/fileB"]) + #_check(p.rglob("file*"), ["fileA", "dirB/fileB"]) + # No symlink loops here + p = P(BASE, "dirC") + _check(p.rglob("file*"), ["dirC/fileC", "dirC/dirD/fileD"]) + _check(p.rglob("*/*"), ["dirC/dirD/fileD"]) + + def test_glob_dotdot(self): + # ".." is not special in globs + P = self.cls + p = P(BASE) + self.assertEqual(set(p.glob("..")), { P(BASE, "..") }) + self.assertEqual(set(p.glob("dirA/../file*")), { P(BASE, "dirA/../fileA") }) + self.assertEqual(set(p.glob("../xyzzy")), set()) + + def _check_resolve_relative(self, p, expected): + q = p.resolve() + self.assertEqual(q, expected) + + def _check_resolve_absolute(self, p, expected): + q = p.resolve() + self.assertEqual(q, expected) + + @with_symlinks + def test_resolve_common(self): + P = self.cls + p = P(BASE, 'foo') + with self.assertRaises(OSError) as cm: + p.resolve() + self.assertEqual(cm.exception.errno, errno.ENOENT) + # These are all relative symlinks + p = P(BASE, 'dirB', 'fileB') + self._check_resolve_relative(p, p) + p = P(BASE, 'linkA') + self._check_resolve_relative(p, P(BASE, 'fileA')) + p = P(BASE, 'dirA', 'linkC', 'fileB') + self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB')) + p = P(BASE, 'dirB', 'linkD', 'fileB') + self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB')) + # Now create absolute symlinks + d = tempfile.mkdtemp(suffix='-dirD') + self.addCleanup(support.rmtree, d) + os.symlink(os.path.join(d), join('dirA', 'linkX')) + os.symlink(join('dirB'), os.path.join(d, 'linkY')) + p = P(BASE, 'dirA', 'linkX', 'linkY', 'fileB') + self._check_resolve_absolute(p, P(BASE, 'dirB', 'fileB')) + + def test_with(self): + p = self.cls(BASE) + it = iter(p) + it2 = iter(p) + next(it2) + with p: + pass + # I/O operation on closed path + self.assertRaises(ValueError, next, it) + self.assertRaises(ValueError, next, it2) + self.assertRaises(ValueError, p.open) + self.assertRaises(ValueError, p.raw_open, os.O_RDONLY) + self.assertRaises(ValueError, p.resolve) + self.assertRaises(ValueError, p.absolute) + self.assertRaises(ValueError, p.__enter__) + + def test_chmod(self): + p = self.cls(BASE)['fileA'] + mode = p.stat().st_mode + # Clear writable bit + new_mode = mode & ~0o222 + p.chmod(new_mode) + self.assertEqual(p.restat().st_mode, new_mode) + # Set writable bit + new_mode = mode | 0o222 + p.chmod(new_mode) + self.assertEqual(p.restat().st_mode, new_mode) + + # XXX also need a test for lchmod + + def test_stat(self): + # NOTE: this notation helps trigger openat()-specific behaviour + # (first opens the parent dir and then the file using the dir fd) + p = self.cls(BASE)['fileA'] + st = p.stat() + self.assertEqual(p.stat(), st) + self.assertEqual(p.restat(), st) + # Change file mode by flipping write bit + p.chmod(st.st_mode ^ 0o222) + self.addCleanup(p.chmod, st.st_mode) + # Cached value didn't change + self.assertEqual(p.stat(), st) + # restat() invalidates the cache + self.assertNotEqual(p.restat(), st) + self.assertNotEqual(p.stat(), st) + + @with_symlinks + def test_lstat(self): + p = self.cls(BASE)['linkA'] + st = p.stat() + self.assertNotEqual(st, p.lstat()) + + def test_lstat_nosymlink(self): + p = self.cls(BASE)['fileA'] + st = p.stat() + self.assertEqual(st, p.lstat()) + + def test_st_fields(self): + p = self.cls(BASE)['fileA'] + self.assertEqual(p.st_size, 15) + p.st_mtime + p.st_mode + with self.assertRaises(AttributeError): + p.st_foo + with self.assertRaises(AttributeError): + p.foo + + def test_unlink(self): + p = self.cls(BASE)['fileA'] + p.unlink() + self.assertFileNotFound(p.restat) + self.assertFileNotFound(p.unlink) + + def test_rmdir(self): + p = self.cls(BASE)['dirA'] + for q in p: + q.unlink() + p.rmdir() + self.assertFileNotFound(p.restat) + self.assertFileNotFound(p.unlink) + + def test_rename(self): + P = self.cls(BASE) + p = P['fileA'] + size = p.stat().st_size + # Renaming to another path + q = P['dirA', 'fileAA'] + p.rename(q) + self.assertEqual(q.stat().st_size, size) + self.assertFileNotFound(p.restat) + # Renaming to a str of a relative path + r = rel_join('fileAAA') + q.rename(r) + self.assertEqual(os.stat(r).st_size, size) + self.assertFileNotFound(q.restat) + + def test_touch(self): + P = self.cls(BASE) + p = P['newfileA'] + self.assertFalse(p.exists()) + p.touch() + self.assertTrue(p.exists()) + p.touch() + p = P['newfileB'] + self.assertFalse(p.exists()) + p.touch(mode=0o700, exist_ok=False) + self.assertTrue(p.exists()) + self.assertRaises(OSError, p.touch, exist_ok=False) + # XXX better test `mode` arg + + def test_mkdir(self): + P = self.cls(BASE) + p = P['newdirA'] + self.assertFalse(p.exists()) + p.mkdir() + self.assertTrue(p.exists()) + self.assertTrue(p.is_dir()) + with self.assertRaises(OSError) as cm: + p.mkdir() + self.assertEqual(cm.exception.errno, errno.EEXIST) + # XXX test `mode` arg + + def test_mkdir_parents(self): + # Creating a chain of directories + p = self.cls(BASE, 'newdirB', 'newdirC') + self.assertFalse(p.exists()) + with self.assertRaises(OSError) as cm: + p.mkdir() + self.assertEqual(cm.exception.errno, errno.ENOENT) + p.mkdir(parents=True) + self.assertTrue(p.exists()) + self.assertTrue(p.is_dir()) + with self.assertRaises(OSError) as cm: + p.mkdir(parents=True) + self.assertEqual(cm.exception.errno, errno.EEXIST) + # XXX test `mode` arg + + @with_symlinks + def test_symlink_to(self): + P = self.cls(BASE) + target = P['fileA'] + # Symlinking a path target + link = P['dirA', 'linkAA'] + link.symlink_to(target) + self.assertEqual(link.stat(), target.stat()) + self.assertNotEqual(link.lstat(), target.stat()) + # Symlinking a str target + link = P['dirA', 'linkAAA'] + link.symlink_to(str(target)) + self.assertEqual(link.stat(), target.stat()) + self.assertNotEqual(link.lstat(), target.stat()) + self.assertFalse(link.is_dir()) + # Symlinking to a directory + target = P['dirB'] + link = P['dirA', 'linkAAAA'] + link.symlink_to(target, target_is_directory=True) + self.assertEqual(link.stat(), target.stat()) + self.assertNotEqual(link.lstat(), target.stat()) + self.assertTrue(link.is_dir()) + self.assertTrue(list(link)) + + def test_is_dir(self): + P = self.cls(BASE) + self.assertTrue(P['dirA'].is_dir()) + self.assertFalse(P['fileA'].is_dir()) + if not symlink_skip_reason: + self.assertFalse(P['linkA'].is_dir()) + self.assertTrue(P['linkB'].is_dir()) + + def test_is_file(self): + P = self.cls(BASE) + self.assertTrue(P['fileA'].is_file()) + self.assertFalse(P['dirA'].is_file()) + if not symlink_skip_reason: + self.assertTrue(P['linkA'].is_file()) + self.assertFalse(P['linkB'].is_file()) + + def test_is_symlink(self): + P = self.cls(BASE) + self.assertFalse(P['fileA'].is_symlink()) + self.assertFalse(P['dirA'].is_symlink()) + if not symlink_skip_reason: + self.assertTrue(P['linkA'].is_symlink()) + self.assertTrue(P['linkB'].is_symlink()) + + +class PathTest(_BasePathTest): + cls = pathlib.Path + + def test_concrete_class(self): + p = self.cls('a') + self.assertIs(type(p), + pathlib.NTPath if os.name == 'nt' else pathlib.PosixPath) + + def test_unsupported_flavour(self): + if os.name == 'nt': + self.assertRaises(NotImplementedError, pathlib.PosixPath) + else: + self.assertRaises(NotImplementedError, pathlib.NTPath) + + + at only_posix +class PosixPathTest(_BasePathTest): + cls = pathlib.PosixPath + + def _check_symlink_loop(self, *args): + path = self.cls(*args) + with self.assertRaises(ValueError): + print(path.resolve()) + + @with_symlinks + def test_resolve_loop(self): + # Loop detection for broken symlinks under POSIX + P = self.cls + # Loops with relative symlinks + os.symlink('linkX/inside', join('linkX')) + self._check_symlink_loop(BASE, 'linkX') + os.symlink('linkY', join('linkY')) + self._check_symlink_loop(BASE, 'linkY') + os.symlink('linkZ/../linkZ', join('linkZ')) + self._check_symlink_loop(BASE, 'linkZ') + # Loops with absolute symlinks + os.symlink(join('linkU/inside'), join('linkU')) + self._check_symlink_loop(BASE, 'linkU') + os.symlink(join('linkV'), join('linkV')) + self._check_symlink_loop(BASE, 'linkV') + os.symlink(join('linkW/../linkW'), join('linkW')) + self._check_symlink_loop(BASE, 'linkW') + + def test_glob(self): + P = self.cls + p = P(BASE) + self.assertEqual(set(p.glob("FILEa")), set()) + + def test_rglob(self): + P = self.cls + p = P(BASE, "dirC") + self.assertEqual(set(p.rglob("FILEd")), set()) + + +if pathlib.supports_openat: + class _RecordingOpenatAccessor(pathlib._OpenatAccessor): + """A custom Accessor implementation to inspect the resolve() algorithm. + """ + + def __init__(self): + super().__init__() + self._readlinkat_fds = [] + self._walk_fds = [] + + def readlink(self, path, name, dir_fd): + self._readlinkat_fds.append((dir_fd, name)) + return super().readlink(path, name, dir_fd=dir_fd) + + def walk_down(self, path, name, dir_fd): + self._walk_fds.append((dir_fd, name)) + return super().walk_down(path, name, dir_fd=dir_fd) + + +class Mock: + def __init__(self, fullname): + parts = fullname.split('.') + obj = __import__('.'.join(parts[:-1])) + for part in parts[1:]: + module = obj + obj = getattr(obj, part) + self.module = module + self.qualname = parts[-1] + self.orig_func = obj + + def __enter__(self): + def wrapper(*args, **kwargs): + self.calls += 1 + self.call_params.append((args, kwargs)) + return self.orig_func(*args, **kwargs) + self.calls = 0 + self.call_params = [] + setattr(self.module, self.qualname, wrapper) + return self + + def __exit__(self, *_): + setattr(self.module, self.qualname, self.orig_func) + + + at unittest.skipUnless(pathlib.supports_openat, + "test needs the openat() family of functions") + at only_posix +class PosixOpenatPathTest(PosixPathTest): + cls = staticmethod( + lambda *args, **kwargs: + pathlib.PosixPath(*args, use_openat=True, **kwargs) + ) + + using_openat = True + + def _check_symlink_loop(self, *args): + # with openat(), ELOOP is returned as soon as you try to construct + # the path + with self.assertRaises(OSError) as cm: + path = self.cls(*args) + path.resolve() + self.assertEqual(cm.exception.errno, errno.ELOOP) + + def _check_resolve_relative(self, p, expected): + self.assertIsInstance(p._accessor, pathlib._OpenatAccessor) + p._accessor = _RecordingOpenatAccessor() + q = p.resolve() + self.assertEqual(q, expected) + # Only the first lookup was absolute + def _check_fds(fds): + self.assertEqual(pathlib._NO_FD, fds[0][0]) + for fd, name in fds[1:]: + self.assertGreaterEqual(fd, 0) + self.assertFalse(name.startswith("/"), name) + _check_fds(p._accessor._readlinkat_fds) + _check_fds(p._accessor._walk_fds) + + def _check_resolve_absolute(self, p, expected): + self.assertIsInstance(p._accessor, pathlib._OpenatAccessor) + p._accessor = _RecordingOpenatAccessor() + q = p.resolve() + self.assertEqual(q, expected) + # At least one other lookup was absolute + def _check_fds(fds): + self.assertEqual(pathlib._NO_FD, fds[0][0]) + self.assertTrue(any(fd == pathlib._NO_FD + for fd, _ in fds[1:]), fds) + _check_fds(p._accessor._readlinkat_fds) + _check_fds(p._accessor._walk_fds) + + def test_weakref_same_path(self): + # Implementation detail: separate weakrefs must be created even + # when two paths hash the same + n = len(pathlib.Path._wrs) + a = self.cls(BASE) + b = self.cls(BASE) + self.assertEqual(hash(a), hash(b)) + self.assertEqual(len(pathlib.Path._wrs), n + 2) + del a, b + support.gc_collect() + self.assertEqual(len(pathlib.Path._wrs), n) + + def test_iter(self): + with Mock("os.listdir") as mock_listdir: + super().test_iter() + self.assertEqual(mock_listdir.calls, 1) + # A file descriptor was passed + args = mock_listdir.call_params[0][0] + fd = args[0] + self.assertIsInstance(fd, int) + self.assertGreaterEqual(fd, 0) + + def test_cwd(self): + p = pathlib.PosixPath.cwd(use_openat=True) + self._test_cwd(p) + + # XXX can't mock os.openat since _OpenatAccessor caches the os.openat lookup. + + + at only_nt +class NTPathTest(_BasePathTest): + cls = pathlib.NTPath + + def test_glob(self): + P = self.cls + p = P(BASE) + self.assertEqual(set(p.glob("FILEa")), { P(BASE, "fileA") }) + + def test_rglob(self): + P = self.cls + p = P(BASE, "dirC") + self.assertEqual(set(p.rglob("FILEd")), { P(BASE, "dirC/dirD/fileD") }) + + +def test_main(): + support.run_unittest( + PosixFlavourTest, NTFlavourTest, + PurePosixPathTest, PureNTPathTest, PurePathTest, + PosixPathAsPureTest, NTPathAsPureTest, + PosixPathTest, PosixOpenatPathTest, NTPathTest, PathTest, + ) + +if __name__ == "__main__": + test_main() diff --git a/perf.py b/perf.py --- a/perf.py +++ b/perf.py @@ -1481,6 +1481,17 @@ return SimpleBenchmark(MeasureMako, *args, **kwargs) +def MeasurePathlib(python, options): + bm_path = Relative("performance/bm_pathlib.py") + pathlib_path = Relative("lib/pathlib") + bm_env = BuildEnv({"PYTHONPATH": pathlib_path}, options.inherit_env) + return MeasureGeneric(python, options, bm_path, bm_env, iteration_scaling=10) + + +def BM_pathlib(*args, **kwargs): + return SimpleBenchmark(MeasurePathlib, *args, **kwargs) + + def MeasurePickle(python, options, extra_args): """Test the performance of Python's pickle implementations. @@ -1990,7 +2001,8 @@ "2n3": ["calls", "math", "fastpickle", "fastunpickle", "json_dump", "json_load", "regex", "threading", "nqueens", "unpack_sequence", "richards", - "logging", "normal_startup", "startup_nosite"], + "logging", "normal_startup", "startup_nosite", + "pathlib"], # After 2to3-conversion "py3k": ["2to3", "2n3", "mako"] } diff --git a/performance/bm_pathlib.py b/performance/bm_pathlib.py new file mode 100644 --- /dev/null +++ b/performance/bm_pathlib.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python + +"""Wrapper script for testing the performance of pathlib operations. + +This benchmark stresses the creation of small objects, globbing, and system +calls. +""" + +# Python imports +import itertools +import optparse +import os +import shutil +import tempfile +import time + +# Local imports +import util +from compat import xrange, izip + +# pathlib imports +from pathlib import Path + + +NUM_FILES = 2000 + + +def generate_files(): + for i in itertools.count(): + for ext in [".py", ".txt", ".tar.gz", ""]: + yield os.path.join(TMP_PATH, str(i) + ext) + + +def setup(): + global TMP_PATH + TMP_PATH = tempfile.mkdtemp() + for _, fn in izip(xrange(NUM_FILES), generate_files()): + with open(fn, "w") as f: + f.write(fn) + + +def teardown(): + shutil.rmtree(TMP_PATH) + + +def test_pathlib(count): + base_path = Path(TMP_PATH) + + # Warm up the filesystem cache and keep some objects in memory. + path_objects = list(base_path) + for p in path_objects: + p.stat() + assert len(path_objects) == NUM_FILES + + times = [] + for _ in xrange(count // 2): + t0 = time.time() + # Do something simple with each path. + for p in base_path: + p.st_mtime + for p in base_path.glob("*.py"): + p.st_mtime + for p in base_path: + p.st_mtime + for p in base_path.glob("*.py"): + p.st_mtime + t1 = time.time() + times.append(t1 - t0) + return times + + +if __name__ == "__main__": + parser = optparse.OptionParser( + usage="%prog [options]", + description=("Test the performance of pathlib operations.")) + util.add_standard_options_to(parser) + options, args = parser.parse_args() + + setup() + try: + util.run_benchmark(options, options.num_runs, test_pathlib) + finally: + teardown() diff --git a/performance/compat.py b/performance/compat.py --- a/performance/compat.py +++ b/performance/compat.py @@ -13,6 +13,7 @@ maxint = sys.maxint reduce = reduce imap = itertools.imap + izip = itertools.izip def u_lit(s): r"""Make an unicode string from a regular string literal, intepreting \uXXXX escapes""" @@ -36,6 +37,7 @@ maxint = sys.maxsize # good enough reduce = functools.reduce imap = map + izip = zip def u_lit(s): return s # Avoid syntax errors under 2.5 -- Repository URL: http://hg.python.org/benchmarks From solipsis at pitrou.net Tue Jul 24 06:02:31 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 24 Jul 2012 06:02:31 +0200 Subject: [Python-checkins] Daily reference leaks (00db71b3c5bd): sum=0 Message-ID: results for 00db71b3c5bd on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/refloghe4wgW', '-x'] From python-checkins at python.org Tue Jul 24 12:46:14 2012 From: python-checkins at python.org (ned.deily) Date: Tue, 24 Jul 2012 12:46:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE0MTk3?= =?utf-8?q?=3A_For_OS_X_framework_builds=2C_ensure_links_to_the_shared?= Message-ID: <3WhGT22JMkzPV7@mail.python.org> http://hg.python.org/cpython/rev/2d4f290ea71c changeset: 78264:2d4f290ea71c branch: 3.2 parent: 78262:52032b13243e user: Ned Deily date: Tue Jul 24 03:31:48 2012 -0700 summary: Issue #14197: For OS X framework builds, ensure links to the shared library are created with the proper ABI suffix. files: Makefile.pre.in | 3 +++ Misc/NEWS | 3 +++ Misc/python-config.in | 3 ++- 3 files changed, 8 insertions(+), 1 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1158,8 +1158,11 @@ # Install a number of symlinks to keep software that expects a normal unix # install (which includes python-config) happy. frameworkinstallmaclib: + ln -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(LDVERSION).a" + ln -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(LDVERSION).dylib" ln -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(VERSION).a" ln -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(VERSION).dylib" + ln -fs "../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/libpython$(LDVERSION).dylib" ln -fs "../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/libpython$(VERSION).dylib" # This installs the IDE, the Launcher and other apps into /Applications diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -402,6 +402,9 @@ Build ----- +- Issue #14197: For OS X framework builds, ensure links to the shared + library are created with the proper ABI suffix. + - Issue #14472: Update .gitignore. Patch by Matej Cepl. - The Windows build now uses OpenSSL 1.0.0j and bzip2 1.0.6. diff --git a/Misc/python-config.in b/Misc/python-config.in --- a/Misc/python-config.in +++ b/Misc/python-config.in @@ -52,7 +52,8 @@ if opt == '--ldflags': if not getvar('Py_ENABLE_SHARED'): libs.insert(0, '-L' + getvar('LIBPL')) - libs.extend(getvar('LINKFORSHARED').split()) + if not getvar('PYTHONFRAMEWORK'): + libs.extend(getvar('LINKFORSHARED').split()) print(' '.join(libs)) elif opt == '--extension-suffix': -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 24 12:46:16 2012 From: python-checkins at python.org (ned.deily) Date: Tue, 24 Jul 2012 12:46:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2314197=3A_merge?= Message-ID: <3WhGT40Sl2zPVC@mail.python.org> http://hg.python.org/cpython/rev/51ac5f06dd04 changeset: 78265:51ac5f06dd04 parent: 78263:00db71b3c5bd parent: 78264:2d4f290ea71c user: Ned Deily date: Tue Jul 24 03:45:39 2012 -0700 summary: Issue #14197: merge files: Makefile.pre.in | 3 +++ Misc/NEWS | 3 +++ Misc/python-config.in | 3 ++- 3 files changed, 8 insertions(+), 1 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1238,8 +1238,11 @@ # Install a number of symlinks to keep software that expects a normal unix # install (which includes python-config) happy. frameworkinstallmaclib: + ln -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(LDVERSION).a" + ln -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(LDVERSION).dylib" ln -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(VERSION).a" ln -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(VERSION).dylib" + ln -fs "../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/libpython$(LDVERSION).dylib" ln -fs "../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/libpython$(VERSION).dylib" # This installs the IDE, the Launcher and other apps into /Applications diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -229,6 +229,9 @@ Build ----- +- Issue #14197: For OS X framework builds, ensure links to the shared + library are created with the proper ABI suffix. + - Issue #14330: For cross builds, don't use host python, use host search paths for host compiler. diff --git a/Misc/python-config.in b/Misc/python-config.in --- a/Misc/python-config.in +++ b/Misc/python-config.in @@ -52,7 +52,8 @@ if opt == '--ldflags': if not getvar('Py_ENABLE_SHARED'): libs.insert(0, '-L' + getvar('LIBPL')) - libs.extend(getvar('LINKFORSHARED').split()) + if not getvar('PYTHONFRAMEWORK'): + libs.extend(getvar('LINKFORSHARED').split()) print(' '.join(libs)) elif opt == '--extension-suffix': -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 24 18:48:17 2012 From: python-checkins at python.org (eli.bendersky) Date: Tue, 24 Jul 2012 18:48:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Clarify_what_happens_if_sh?= =?utf-8?q?allow_is_false=2E_Also=2C_the_caching_note_is_not_really?= Message-ID: <3WhQVn2s6mzN7t@mail.python.org> http://hg.python.org/cpython/rev/a7fbb5bba6c6 changeset: 78266:a7fbb5bba6c6 user: Eli Bendersky date: Tue Jul 24 19:47:34 2012 +0300 summary: Clarify what happens if shallow is false. Also, the caching note is not really correct since the cache gets occasionally cleared; therefore I removed it. files: Doc/library/filecmp.rst | 7 ++----- 1 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Doc/library/filecmp.rst b/Doc/library/filecmp.rst --- a/Doc/library/filecmp.rst +++ b/Doc/library/filecmp.rst @@ -21,11 +21,8 @@ Compare the files named *f1* and *f2*, returning ``True`` if they seem equal, ``False`` otherwise. - Unless *shallow* is given and is false, files with identical :func:`os.stat` - signatures are taken to be equal. - - Files that were compared using this function will not be compared again unless - their :func:`os.stat` signature changes. + If *shallow* is true, files with identical :func:`os.stat` signatures are + taken to be equal. Otherwise, the contents of the files are compared. Note that no external programs are called from this function, giving it portability and efficiency. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 24 18:51:50 2012 From: python-checkins at python.org (eli.bendersky) Date: Tue, 24 Jul 2012 18:51:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315321=3A_update_P?= =?utf-8?q?yPI_upload_doc_to_say_--no-raw_passed_to_rst2html=2Epy=2E?= Message-ID: <3WhQZt4p9czPW6@mail.python.org> http://hg.python.org/cpython/rev/f315cfa22630 changeset: 78267:f315cfa22630 user: Eli Bendersky date: Tue Jul 24 19:51:06 2012 +0300 summary: Issue #15321: update PyPI upload doc to say --no-raw passed to rst2html.py. Patch by Chris Jerdonek files: Doc/distutils/uploading.rst | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Doc/distutils/uploading.rst b/Doc/distutils/uploading.rst --- a/Doc/distutils/uploading.rst +++ b/Doc/distutils/uploading.rst @@ -73,4 +73,6 @@ $ python setup.py --long-description | rst2html.py > output.html :mod:`docutils` will display a warning if there's something wrong with your -syntax. +syntax. Because PyPI applies additional checks (e.g. by passing ``--no-raw`` +to ``rst2html.py`` in the command above), running the command above without +warnings is not sufficient for PyPI to convert the content successfully. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 24 19:45:29 2012 From: python-checkins at python.org (eli.bendersky) Date: Tue, 24 Jul 2012 19:45:29 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Cleanup_the_doc_a_bit=3A_r?= =?utf-8?q?emove_useless_example_and_sentence?= Message-ID: <3WhRmn1VHYzPN8@mail.python.org> http://hg.python.org/cpython/rev/bfda7d8c8a38 changeset: 78268:bfda7d8c8a38 user: Eli Bendersky date: Tue Jul 24 20:44:48 2012 +0300 summary: Cleanup the doc a bit: remove useless example and sentence files: Doc/library/filecmp.rst | 14 +------------- 1 files changed, 1 insertions(+), 13 deletions(-) diff --git a/Doc/library/filecmp.rst b/Doc/library/filecmp.rst --- a/Doc/library/filecmp.rst +++ b/Doc/library/filecmp.rst @@ -48,23 +48,11 @@ one of the three returned lists. -Example:: - - >>> import filecmp - >>> filecmp.cmp('undoc.rst', 'undoc.rst') - True - >>> filecmp.cmp('undoc.rst', 'index.rst') - False - - .. _dircmp-objects: The :class:`dircmp` class ------------------------- -:class:`dircmp` instances are built using this constructor: - - .. class:: dircmp(a, b, ignore=None, hide=None) Construct a new directory comparison object, to compare the directories *a* and @@ -80,7 +68,7 @@ .. method:: report() - Print (to ``sys.stdout``) a comparison between *a* and *b*. + Print (to :data:`sys.stdout`) a comparison between *a* and *b*. .. method:: report_partial_closure() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 24 20:24:58 2012 From: python-checkins at python.org (r.david.murray) Date: Tue, 24 Jul 2012 20:24:58 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogIzE1MjMyOiBtYWtl?= =?utf-8?q?_NEWS_entry_more_accurate=2E?= Message-ID: <3WhSfL6WtRzPYx@mail.python.org> http://hg.python.org/cpython/rev/0caff799e4bf changeset: 78269:0caff799e4bf branch: 3.2 parent: 78264:2d4f290ea71c user: R David Murray date: Tue Jul 24 14:22:19 2012 -0400 summary: #15232: make NEWS entry more accurate. files: Misc/NEWS | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -103,7 +103,7 @@ Initial patch by Serhiy Storchaka. - Issue #15232: when mangle_from is True, email.Generator now correctly mangles - lines that start with 'From' that occur in a MIME preamble or epilogue. + lines that start with 'From ' that occur in a MIME preamble or epilogue. - Issue #13922: argparse no longer incorrectly strips '--'s that appear after the first one. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 24 20:25:00 2012 From: python-checkins at python.org (r.david.murray) Date: Tue, 24 Jul 2012 20:25:00 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_=2315232=3A_make_NEWS_entry_more_accurate=2E?= Message-ID: <3WhSfN5KQFzPZF@mail.python.org> http://hg.python.org/cpython/rev/d53524c43d0e changeset: 78270:d53524c43d0e parent: 78268:bfda7d8c8a38 parent: 78269:0caff799e4bf user: R David Murray date: Tue Jul 24 14:24:13 2012 -0400 summary: #15232: make NEWS entry more accurate. files: Misc/NEWS | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -57,7 +57,7 @@ Initial patch by Serhiy Storchaka. - Issue #15232: when mangle_from is True, email.Generator now correctly mangles - lines that start with 'From' that occur in a MIME preamble or epilogue. + lines that start with 'From ' that occur in a MIME preamble or epilogue. - Issue #15094: Incorrectly placed #endif in _tkinter.c. Patch by Serhiy Storchaka. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 24 20:25:02 2012 From: python-checkins at python.org (r.david.murray) Date: Tue, 24 Jul 2012 20:25:02 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE1MjMyOiBtYWtl?= =?utf-8?q?_NEWS_entry_more_accurate=2E?= Message-ID: <3WhSfQ1PTpzPZX@mail.python.org> http://hg.python.org/cpython/rev/e9ffde2c7da3 changeset: 78271:e9ffde2c7da3 branch: 2.7 parent: 78261:d56306b78b64 user: R David Murray date: Tue Jul 24 14:24:42 2012 -0400 summary: #15232: make NEWS entry more accurate. files: Misc/NEWS | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -95,7 +95,7 @@ Initial patch by Serhiy Storchaka. - Issue #15232: when mangle_from is True, email.Generator now correctly mangles - lines that start with 'From' that occur in a MIME preamble or epilog. + lines that start with 'From ' that occur in a MIME preamble or epilog. - Issue #13922: argparse no longer incorrectly strips '--'s that appear after the first one. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 24 21:26:01 2012 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 24 Jul 2012 21:26:01 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315413=3A_os=2Etim?= =?utf-8?q?es=28=29_had_disappeared_under_Windows=2E?= Message-ID: <3WhV0n4lfczPZj@mail.python.org> http://hg.python.org/cpython/rev/d9a881b0d6ca changeset: 78272:d9a881b0d6ca parent: 78270:d53524c43d0e user: Antoine Pitrou date: Tue Jul 24 21:23:53 2012 +0200 summary: Issue #15413: os.times() had disappeared under Windows. files: Misc/NEWS | 2 + Modules/posixmodule.c | 54 +++++++++++++++--------------- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -52,6 +52,8 @@ Library ------- +- Issue #15413: os.times() had disappeared under Windows. + - Issue #15402: An issue in the struct module that caused sys.getsizeof to return incorrect results for struct.Struct instances has been fixed. Initial patch by Serhiy Storchaka. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -7453,8 +7453,11 @@ static PyTypeObject TimesResultType; - -#if defined(HAVE_TIMES) || defined(MS_WINDOWS) +#ifdef MS_WINDOWS +#define HAVE_TIMES /* mandatory, for the method table */ +#endif + +#ifdef HAVE_TIMES static PyObject * build_times_result(double user, double system, @@ -7492,10 +7495,6 @@ times. The object behaves like a named tuple with these fields:\n\ (utime, stime, cutime, cstime, elapsed_time)"); -#endif - - -#ifdef HAVE_TIMES #if defined(PYCC_VACPP) && defined(PYOS_OS2) static long system_uptime(void) @@ -7520,26 +7519,6 @@ (double)0 /* t.tms_cstime / HZ */, (double)system_uptime() / 1000); } -#else /* not OS2 */ -#define NEED_TICKS_PER_SECOND -static long ticks_per_second = -1; -static PyObject * -posix_times(PyObject *self, PyObject *noargs) -{ - struct tms t; - clock_t c; - errno = 0; - c = times(&t); - if (c == (clock_t) -1) - return posix_error(); - return build_times_result( - (double)t.tms_utime / ticks_per_second, - (double)t.tms_stime / ticks_per_second, - (double)t.tms_cutime / ticks_per_second, - (double)t.tms_cstime / ticks_per_second, - (double)c / ticks_per_second); -} -#endif /* not OS2 */ #elif defined(MS_WINDOWS) static PyObject * posix_times(PyObject *self, PyObject *noargs) @@ -7562,7 +7541,28 @@ (double)0, (double)0); } -#endif +#else /* Neither Windows nor OS/2 */ +#define NEED_TICKS_PER_SECOND +static long ticks_per_second = -1; +static PyObject * +posix_times(PyObject *self, PyObject *noargs) +{ + struct tms t; + clock_t c; + errno = 0; + c = times(&t); + if (c == (clock_t) -1) + return posix_error(); + return build_times_result( + (double)t.tms_utime / ticks_per_second, + (double)t.tms_stime / ticks_per_second, + (double)t.tms_cutime / ticks_per_second, + (double)t.tms_cstime / ticks_per_second, + (double)c / ticks_per_second); +} +#endif + +#endif /* HAVE_TIMES */ #ifdef HAVE_GETSID -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 24 21:39:23 2012 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 24 Jul 2012 21:39:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?benchmarks=3A_Update_pathlib_copy_to_?= =?utf-8?q?fix_compatibility_with_Windows_under_Python_2=2E7?= Message-ID: <3WhVJC1vzDzPb1@mail.python.org> http://hg.python.org/benchmarks/rev/917a9950b4b1 changeset: 159:917a9950b4b1 user: Antoine Pitrou date: Tue Jul 24 21:37:10 2012 +0200 summary: Update pathlib copy to fix compatibility with Windows under Python 2.7 files: lib/pathlib/pathlib.py | 8 ++++++-- 1 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/pathlib/pathlib.py b/lib/pathlib/pathlib.py --- a/lib/pathlib/pathlib.py +++ b/lib/pathlib/pathlib.py @@ -24,7 +24,7 @@ except ImportError: nt = None else: - if sys.getwindowsversion()[:2] >= (6, 0): + if sys.getwindowsversion()[:2] >= (6, 0) and sys.version_info >= (3, 2): from nt import _getfinalpathname else: supports_symlinks = False @@ -481,7 +481,11 @@ rename = _wrap_binary_strfunc(os.rename) if nt: - symlink = _wrap_binary_strfunc(os.symlink) + if supports_symlinks: + symlink = _wrap_binary_strfunc(os.symlink) + else: + def symlink(a, b, target_is_directory): + raise NotImplementedError("symlink() not available on this system") else: # Under POSIX, os.symlink() takes two args @staticmethod -- Repository URL: http://hg.python.org/benchmarks From solipsis at pitrou.net Wed Jul 25 06:02:22 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 25 Jul 2012 06:02:22 +0200 Subject: [Python-checkins] Daily reference leaks (d9a881b0d6ca): sum=0 Message-ID: results for d9a881b0d6ca on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogG9s15c', '-x'] From python-checkins at python.org Wed Jul 25 10:49:52 2012 From: python-checkins at python.org (martin.v.loewis) Date: Wed, 25 Jul 2012 10:49:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE1MzE4?= =?utf-8?q?=3A_Prevent_writing_to_sys=2Estdin=2E?= Message-ID: <3WhqrJ006KzPSt@mail.python.org> http://hg.python.org/cpython/rev/a82fd35e28be changeset: 78273:a82fd35e28be branch: 3.2 parent: 78269:0caff799e4bf user: Martin v. L?wis date: Wed Jul 25 10:47:20 2012 +0200 summary: Issue #15318: Prevent writing to sys.stdin. Patch by Roger Serwy and myself. files: Lib/idlelib/NEWS.txt | 2 ++ Lib/idlelib/PyShell.py | 16 +++++++++++++++- Lib/idlelib/run.py | 25 +++++++++++++++++++++---- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,6 +1,8 @@ What's New in IDLE 3.2.4? ========================= +- Issue #15318: Prevent writing to sys.stdin. + - Issue #13532, #15319: Check that arguments to sys.stdout.write are strings. - Issue # 12510: Attempt to get certain tool tips no longer crashes IDLE. diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -12,6 +12,7 @@ import tokenize import traceback import types +import io import linecache from code import InteractiveInterpreter @@ -410,6 +411,9 @@ except socket.timeout as err: self.display_no_subprocess_error() return None + # Can't regiter self.tkconsole.stdin, since run.py wants to + # call non-TextIO methods on it (such as getvar) + # XXX should be renamed to "console" self.rpcclt.register("stdin", self.tkconsole) self.rpcclt.register("stdout", self.tkconsole.stdout) self.rpcclt.register("stderr", self.tkconsole.stderr) @@ -850,13 +854,14 @@ self.save_stderr = sys.stderr self.save_stdin = sys.stdin from idlelib import IOBinding + self.stdin = PseudoInputFile(self) self.stdout = PseudoFile(self, "stdout", IOBinding.encoding) self.stderr = PseudoFile(self, "stderr", IOBinding.encoding) self.console = PseudoFile(self, "console", IOBinding.encoding) if not use_subprocess: sys.stdout = self.stdout sys.stderr = self.stderr - sys.stdin = self + sys.stdin = self.stdin try: # page help() text to shell. import pydoc # import must be done here to capture i/o rebinding. @@ -1256,6 +1261,15 @@ def isatty(self): return True +class PseudoInputFile(object): + def __init__(self, shell): + self.readline = shell.readline + self.isatty = shell.isatty + + def write(self, s): + raise io.UnsupportedOperation("not writable") + writelines = write + usage_msg = """\ diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -256,7 +256,7 @@ def __getattribute__(self, name): # When accessing the 'rpc' attribute, or 'write', use ours - if name in ('rpc', 'write'): + if name in ('rpc', 'write', 'writelines'): return io.TextIOBase.__getattribute__(self, name) # Else only look into the remote object only return getattr(self.rpc, name) @@ -264,20 +264,37 @@ def __setattr__(self, name, value): return setattr(self.rpc, name, value) + @staticmethod + def _ensure_string(func): + def f(self, s): + if not isinstance(s, str): + raise TypeError('must be str, not ' + type(s).__name__) + return func(self, s) + return f + +class _RPCOutputFile(_RPCFile): + @_RPCFile._ensure_string def write(self, s): if not isinstance(s, str): raise TypeError('must be str, not ' + type(s).__name__) return self.rpc.write(s) +class _RPCInputFile(_RPCFile): + @_RPCFile._ensure_string + def write(self, s): + raise io.UnsupportedOperation("not writable") + writelines = write + class MyHandler(rpc.RPCHandler): def handle(self): """Override base method""" executive = Executive(self) self.register("exec", executive) - sys.stdin = self.console = self.get_remote_proxy("stdin") - sys.stdout = _RPCFile(self.get_remote_proxy("stdout")) - sys.stderr = _RPCFile(self.get_remote_proxy("stderr")) + self.console = self.get_remote_proxy("stdin") + sys.stdin = _RPCInputFile(self.console) + sys.stdout = _RPCOutputFile(self.get_remote_proxy("stdout")) + sys.stderr = _RPCOutputFile(self.get_remote_proxy("stderr")) # page help() text to shell. import pydoc # import must be done here to capture i/o binding pydoc.pager = pydoc.plainpager -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 25 10:49:54 2012 From: python-checkins at python.org (martin.v.loewis) Date: Wed, 25 Jul 2012 10:49:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4y?= Message-ID: <3WhqrL5f5XzPTD@mail.python.org> http://hg.python.org/cpython/rev/cffdb7d76691 changeset: 78274:cffdb7d76691 parent: 78272:d9a881b0d6ca parent: 78273:a82fd35e28be user: Martin v. L?wis date: Wed Jul 25 10:49:32 2012 +0200 summary: merge 3.2 files: Lib/idlelib/NEWS.txt | 2 ++ Lib/idlelib/PyShell.py | 16 +++++++++++++++- Lib/idlelib/run.py | 25 +++++++++++++++++++++---- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,6 +1,8 @@ What's New in IDLE 3.3.0? ========================= +- Issue #15318: Prevent writing to sys.stdin. + - Issue #4832: Modify IDLE to save files with .py extension by default on Windows and OS X (Tk 8.5) as it already does with X11 Tk. diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -12,6 +12,7 @@ import tokenize import traceback import types +import io import linecache from code import InteractiveInterpreter @@ -410,6 +411,9 @@ except socket.timeout as err: self.display_no_subprocess_error() return None + # Can't regiter self.tkconsole.stdin, since run.py wants to + # call non-TextIO methods on it (such as getvar) + # XXX should be renamed to "console" self.rpcclt.register("stdin", self.tkconsole) self.rpcclt.register("stdout", self.tkconsole.stdout) self.rpcclt.register("stderr", self.tkconsole.stderr) @@ -854,13 +858,14 @@ self.save_stderr = sys.stderr self.save_stdin = sys.stdin from idlelib import IOBinding + self.stdin = PseudoInputFile(self) self.stdout = PseudoFile(self, "stdout", IOBinding.encoding) self.stderr = PseudoFile(self, "stderr", IOBinding.encoding) self.console = PseudoFile(self, "console", IOBinding.encoding) if not use_subprocess: sys.stdout = self.stdout sys.stderr = self.stderr - sys.stdin = self + sys.stdin = self.stdin try: # page help() text to shell. import pydoc # import must be done here to capture i/o rebinding. @@ -1272,6 +1277,15 @@ def isatty(self): return True +class PseudoInputFile(object): + def __init__(self, shell): + self.readline = shell.readline + self.isatty = shell.isatty + + def write(self, s): + raise io.UnsupportedOperation("not writable") + writelines = write + usage_msg = """\ diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -269,7 +269,7 @@ def __getattribute__(self, name): # When accessing the 'rpc' attribute, or 'write', use ours - if name in ('rpc', 'write'): + if name in ('rpc', 'write', 'writelines'): return io.TextIOBase.__getattribute__(self, name) # Else only look into the remote object only return getattr(self.rpc, name) @@ -277,20 +277,37 @@ def __setattr__(self, name, value): return setattr(self.rpc, name, value) + @staticmethod + def _ensure_string(func): + def f(self, s): + if not isinstance(s, str): + raise TypeError('must be str, not ' + type(s).__name__) + return func(self, s) + return f + +class _RPCOutputFile(_RPCFile): + @_RPCFile._ensure_string def write(self, s): if not isinstance(s, str): raise TypeError('must be str, not ' + type(s).__name__) return self.rpc.write(s) +class _RPCInputFile(_RPCFile): + @_RPCFile._ensure_string + def write(self, s): + raise io.UnsupportedOperation("not writable") + writelines = write + class MyHandler(rpc.RPCHandler): def handle(self): """Override base method""" executive = Executive(self) self.register("exec", executive) - sys.stdin = self.console = self.get_remote_proxy("stdin") - sys.stdout = _RPCFile(self.get_remote_proxy("stdout")) - sys.stderr = _RPCFile(self.get_remote_proxy("stderr")) + self.console = self.get_remote_proxy("stdin") + sys.stdin = _RPCInputFile(self.console) + sys.stdout = _RPCOutputFile(self.get_remote_proxy("stdout")) + sys.stderr = _RPCOutputFile(self.get_remote_proxy("stderr")) sys.displayhook = rpc.displayhook # page help() text to shell. import pydoc # import must be done here to capture i/o binding -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 25 10:56:35 2012 From: python-checkins at python.org (martin.v.loewis) Date: Wed, 25 Jul 2012 10:56:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE1MzE4?= =?utf-8?q?=3A_Prevent_writing_to_sys=2Estdin=2E?= Message-ID: <3Whr0349YRzPSn@mail.python.org> http://hg.python.org/cpython/rev/fa7d4ecc6357 changeset: 78275:fa7d4ecc6357 branch: 2.7 parent: 78271:e9ffde2c7da3 user: Martin v. L?wis date: Wed Jul 25 10:56:22 2012 +0200 summary: Issue #15318: Prevent writing to sys.stdin. Patch by Roger Serwy and myself. files: Lib/idlelib/NEWS.txt | 2 ++ Lib/idlelib/PyShell.py | 16 +++++++++++++++- Lib/idlelib/run.py | 27 +++++++++++++++++++++------ 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,6 +1,8 @@ What's New in IDLE 2.7.4? ========================= +- Issue #15318: Prevent writing to sys.stdin. + - Issue #13532, #15319: Check that arguments to sys.stdout.write are strings. - Issue # 12510: Attempt to get certain tool tips no longer crashes IDLE. diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -11,6 +11,7 @@ import threading import traceback import types +import io import linecache from code import InteractiveInterpreter @@ -422,6 +423,9 @@ except socket.timeout, err: self.display_no_subprocess_error() return None + # Can't regiter self.tkconsole.stdin, since run.py wants to + # call non-TextIO methods on it (such as getvar) + # XXX should be renamed to "console" self.rpcclt.register("stdin", self.tkconsole) self.rpcclt.register("stdout", self.tkconsole.stdout) self.rpcclt.register("stderr", self.tkconsole.stderr) @@ -875,13 +879,14 @@ self.save_stderr = sys.stderr self.save_stdin = sys.stdin from idlelib import IOBinding + self.stdin = PseudoInputFile(self) self.stdout = PseudoFile(self, "stdout", IOBinding.encoding) self.stderr = PseudoFile(self, "stderr", IOBinding.encoding) self.console = PseudoFile(self, "console", IOBinding.encoding) if not use_subprocess: sys.stdout = self.stdout sys.stderr = self.stderr - sys.stdin = self + sys.stdin = self.stdin # self.history = self.History(self.text) # @@ -1279,6 +1284,15 @@ def isatty(self): return True +class PseudoInputFile(object): + def __init__(self, shell): + self.readline = shell.readline + self.isatty = shell.isatty + + def write(self, s): + raise io.UnsupportedOperation("not writable") + writelines = write + usage_msg = """\ diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -260,7 +260,7 @@ def __getattribute__(self, name): # When accessing the 'rpc' attribute, or 'write', use ours - if name in ('rpc', 'write'): + if name in ('rpc', 'write', 'writelines'): return io.TextIOBase.__getattribute__(self, name) # Else only look into the remote object only return getattr(self.rpc, name) @@ -268,20 +268,35 @@ def __setattr__(self, name, value): return setattr(self.rpc, name, value) + @staticmethod + def _ensure_string(func): + def f(self, s): + if not isinstance(s, basestring): + raise TypeError('must be str, not ' + type(s).__name__) + return func(self, s) + return f + +class _RPCOutputFile(_RPCFile): + @_RPCFile._ensure_string def write(self, s): - if not isinstance(s, (basestring, bytearray)): - raise TypeError('must be string, not ' + type(s).__name__) return self.rpc.write(s) +class _RPCInputFile(_RPCFile): + @_RPCFile._ensure_string + def write(self, s): + raise io.UnsupportedOperation("not writable") + writelines = write + class MyHandler(rpc.RPCHandler): def handle(self): """Override base method""" executive = Executive(self) self.register("exec", executive) - sys.stdin = self.console = self.get_remote_proxy("stdin") - sys.stdout = _RPCFile(self.get_remote_proxy("stdout")) - sys.stderr = _RPCFile(self.get_remote_proxy("stderr")) + self.console = self.get_remote_proxy("stdin") + sys.stdin = _RPCInputFile(self.console) + sys.stdout = _RPCOutputFile(self.get_remote_proxy("stdout")) + sys.stderr = _RPCOutputFile(self.get_remote_proxy("stderr")) from idlelib import IOBinding sys.stdin.encoding = sys.stdout.encoding = \ sys.stderr.encoding = IOBinding.encoding -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 25 11:33:15 2012 From: python-checkins at python.org (martin.v.loewis) Date: Wed, 25 Jul 2012 11:33:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzcxNjM6?= =?utf-8?q?_Propagate_return_value_of_sys=2Estdout=2Ewrite=2E?= Message-ID: <3WhrpM0cnSzPQG@mail.python.org> http://hg.python.org/cpython/rev/f72965374b2a changeset: 78276:f72965374b2a branch: 3.2 parent: 78273:a82fd35e28be user: Martin v. L?wis date: Wed Jul 25 11:32:26 2012 +0200 summary: Issue #7163: Propagate return value of sys.stdout.write. Patch by Roger Serwy. files: Lib/idlelib/NEWS.txt | 2 ++ Lib/idlelib/OutputWindow.py | 1 + Lib/idlelib/PyShell.py | 7 ++++--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,6 +1,8 @@ What's New in IDLE 3.2.4? ========================= +- Issue #7163: Propagate return value of sys.stdout.write. + - Issue #15318: Prevent writing to sys.stdin. - Issue #13532, #15319: Check that arguments to sys.stdout.write are strings. diff --git a/Lib/idlelib/OutputWindow.py b/Lib/idlelib/OutputWindow.py --- a/Lib/idlelib/OutputWindow.py +++ b/Lib/idlelib/OutputWindow.py @@ -40,6 +40,7 @@ self.text.insert(mark, s, tags) self.text.see(mark) self.text.update() + return len(s) def writelines(self, lines): for line in lines: diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -760,7 +760,7 @@ def write(self, s): "Override base class method" - self.tkconsole.stderr.write(s) + return self.tkconsole.stderr.write(s) def display_port_binding_error(self): tkMessageBox.showerror( @@ -1229,7 +1229,7 @@ def write(self, s, tags=()): try: self.text.mark_gravity("iomark", "right") - OutputWindow.write(self, s, tags, "iomark") + count = OutputWindow.write(self, s, tags, "iomark") self.text.mark_gravity("iomark", "left") except: raise ###pass # ### 11Aug07 KBK if we are expecting exceptions @@ -1238,6 +1238,7 @@ self.canceled = 0 if not use_subprocess: raise KeyboardInterrupt + return count class PseudoFile(object): @@ -1249,7 +1250,7 @@ def write(self, s): if not isinstance(s, str): raise TypeError('must be str, not ' + type(s).__name__) - self.shell.write(s, self.tags) + return self.shell.write(s, self.tags) def writelines(self, lines): for line in lines: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 25 11:33:16 2012 From: python-checkins at python.org (martin.v.loewis) Date: Wed, 25 Jul 2012 11:33:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4y?= Message-ID: <3WhrpN4X1bzPVS@mail.python.org> http://hg.python.org/cpython/rev/1da53d86d722 changeset: 78277:1da53d86d722 parent: 78274:cffdb7d76691 parent: 78276:f72965374b2a user: Martin v. L?wis date: Wed Jul 25 11:33:02 2012 +0200 summary: merge 3.2 files: Lib/idlelib/NEWS.txt | 2 ++ Lib/idlelib/OutputWindow.py | 1 + Lib/idlelib/PyShell.py | 7 ++++--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,6 +1,8 @@ What's New in IDLE 3.3.0? ========================= +- Issue #7163: Propagate return value of sys.stdout.write. + - Issue #15318: Prevent writing to sys.stdin. - Issue #4832: Modify IDLE to save files with .py extension by diff --git a/Lib/idlelib/OutputWindow.py b/Lib/idlelib/OutputWindow.py --- a/Lib/idlelib/OutputWindow.py +++ b/Lib/idlelib/OutputWindow.py @@ -40,6 +40,7 @@ self.text.insert(mark, s, tags) self.text.see(mark) self.text.update() + return len(s) def writelines(self, lines): for line in lines: diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -764,7 +764,7 @@ def write(self, s): "Override base class method" - self.tkconsole.stderr.write(s) + return self.tkconsole.stderr.write(s) def display_port_binding_error(self): tkMessageBox.showerror( @@ -1245,7 +1245,7 @@ 'Non-BMP character not supported in Tk') try: self.text.mark_gravity("iomark", "right") - OutputWindow.write(self, s, tags, "iomark") + count = OutputWindow.write(self, s, tags, "iomark") self.text.mark_gravity("iomark", "left") except: raise ###pass # ### 11Aug07 KBK if we are expecting exceptions @@ -1254,6 +1254,7 @@ self.canceled = 0 if not use_subprocess: raise KeyboardInterrupt + return count class PseudoFile(object): @@ -1265,7 +1266,7 @@ def write(self, s): if not isinstance(s, str): raise TypeError('must be str, not ' + type(s).__name__) - self.shell.write(s, self.tags) + return self.shell.write(s, self.tags) def writelines(self, lines): for line in lines: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 25 20:20:55 2012 From: python-checkins at python.org (vinay.sajip) Date: Wed, 25 Jul 2012 20:20:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE1NDQ1?= =?utf-8?q?=3A_Updated_logging_configuration_documentation_to_highlight?= Message-ID: <3Wj4WC4D30zPdQ@mail.python.org> http://hg.python.org/cpython/rev/f30b49a5072e changeset: 78278:f30b49a5072e branch: 2.7 parent: 78275:fa7d4ecc6357 user: Vinay Sajip date: Wed Jul 25 19:12:35 2012 +0100 summary: Issue #15445: Updated logging configuration documentation to highlight potential security risk posed by listen() in certain scenarios. files: Doc/library/logging.config.rst | 19 +++++++++++++++++++ 1 files changed, 19 insertions(+), 0 deletions(-) diff --git a/Doc/library/logging.config.rst b/Doc/library/logging.config.rst --- a/Doc/library/logging.config.rst +++ b/Doc/library/logging.config.rst @@ -112,6 +112,19 @@ send it to the socket as a string of bytes preceded by a four-byte length string packed in binary using ``struct.pack('>L', n)``. + .. note:: Because portions of the configuration are passed through + :func:`eval`, use of this function may open its users to a security risk. + While the function only binds to a socket on ``localhost``, and so does + not accept connections from remote machines, there are scenarios where + untrusted code could be run under the account of the process which calls + :func:`listen`. Specifically, if the process calling :func:`listen` runs + on a multi-user machine where users cannot trust each other, then a + malicious user could arrange to run essentially arbitrary code in a + victim user's process, simply by connecting to the victim's + :func:`listen` socket and sending a configuration which runs whatever + code the attacker wants to have executed in the victim's process. This is + especially easy to do if the default port is used, but not hard even if a + different port is used). .. function:: stopListening() @@ -701,6 +714,12 @@ :class:`Formatter` subclass. Subclasses of :class:`Formatter` can present exception tracebacks in an expanded or condensed format. +.. note:: Due to the use of :func:`eval` as described above, there are + potential security risks which result from using the :func:`listen` to send + and receive configurations via sockets. The risks are limited to where + multiple users with no mutual trust run code on the same machine; see the + :func:`listen` documentation for more information. + .. seealso:: Module :mod:`logging` -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 25 20:20:57 2012 From: python-checkins at python.org (vinay.sajip) Date: Wed, 25 Jul 2012 20:20:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE1NDQ1?= =?utf-8?q?=3A_Updated_logging_configuration_documentation_to_highlight?= Message-ID: <3Wj4WF1jHjzPCy@mail.python.org> http://hg.python.org/cpython/rev/e5d7d202f2bf changeset: 78279:e5d7d202f2bf branch: 3.2 parent: 78276:f72965374b2a user: Vinay Sajip date: Wed Jul 25 19:19:25 2012 +0100 summary: Issue #15445: Updated logging configuration documentation to highlight potential security risk posed by listen() in certain scenarios. files: Doc/library/logging.config.rst | 19 +++++++++++++++++++ 1 files changed, 19 insertions(+), 0 deletions(-) diff --git a/Doc/library/logging.config.rst b/Doc/library/logging.config.rst --- a/Doc/library/logging.config.rst +++ b/Doc/library/logging.config.rst @@ -109,6 +109,19 @@ send it to the socket as a string of bytes preceded by a four-byte length string packed in binary using ``struct.pack('>L', n)``. + .. note:: Because portions of the configuration are passed through + :func:`eval`, use of this function may open its users to a security risk. + While the function only binds to a socket on ``localhost``, and so does + not accept connections from remote machines, there are scenarios where + untrusted code could be run under the account of the process which calls + :func:`listen`. Specifically, if the process calling :func:`listen` runs + on a multi-user machine where users cannot trust each other, then a + malicious user could arrange to run essentially arbitrary code in a + victim user's process, simply by connecting to the victim's + :func:`listen` socket and sending a configuration which runs whatever + code the attacker wants to have executed in the victim's process. This is + especially easy to do if the default port is used, but not hard even if a + different port is used). .. function:: stopListening() @@ -694,6 +707,12 @@ :class:`Formatter` subclass. Subclasses of :class:`Formatter` can present exception tracebacks in an expanded or condensed format. +.. note:: Due to the use of :func:`eval` as described above, there are + potential security risks which result from using the :func:`listen` to send + and receive configurations via sockets. The risks are limited to where + multiple users with no mutual trust run code on the same machine; see the + :func:`listen` documentation for more information. + .. seealso:: Module :mod:`logging` -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 25 20:20:58 2012 From: python-checkins at python.org (vinay.sajip) Date: Wed, 25 Jul 2012 20:20:58 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Closes_=2315445=3A_Merged_documentation_update_from_3=2E?= =?utf-8?q?2=2E?= Message-ID: <3Wj4WG51L9zPdM@mail.python.org> http://hg.python.org/cpython/rev/410be02de1c6 changeset: 78280:410be02de1c6 parent: 78277:1da53d86d722 parent: 78279:e5d7d202f2bf user: Vinay Sajip date: Wed Jul 25 19:20:32 2012 +0100 summary: Closes #15445: Merged documentation update from 3.2. files: Doc/library/logging.config.rst | 19 +++++++++++++++++++ 1 files changed, 19 insertions(+), 0 deletions(-) diff --git a/Doc/library/logging.config.rst b/Doc/library/logging.config.rst --- a/Doc/library/logging.config.rst +++ b/Doc/library/logging.config.rst @@ -109,6 +109,19 @@ send it to the socket as a string of bytes preceded by a four-byte length string packed in binary using ``struct.pack('>L', n)``. + .. note:: Because portions of the configuration are passed through + :func:`eval`, use of this function may open its users to a security risk. + While the function only binds to a socket on ``localhost``, and so does + not accept connections from remote machines, there are scenarios where + untrusted code could be run under the account of the process which calls + :func:`listen`. Specifically, if the process calling :func:`listen` runs + on a multi-user machine where users cannot trust each other, then a + malicious user could arrange to run essentially arbitrary code in a + victim user's process, simply by connecting to the victim's + :func:`listen` socket and sending a configuration which runs whatever + code the attacker wants to have executed in the victim's process. This is + especially easy to do if the default port is used, but not hard even if a + different port is used). .. function:: stopListening() @@ -694,6 +707,12 @@ :class:`Formatter` subclass. Subclasses of :class:`Formatter` can present exception tracebacks in an expanded or condensed format. +.. note:: Due to the use of :func:`eval` as described above, there are + potential security risks which result from using the :func:`listen` to send + and receive configurations via sockets. The risks are limited to where + multiple users with no mutual trust run code on the same machine; see the + :func:`listen` documentation for more information. + .. seealso:: Module :mod:`logging` -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 25 22:42:19 2012 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 25 Jul 2012 22:42:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_Mention_the_*l?= =?utf-8?q?imit*_argument_of_TextIO=2Ereadline=28=29=2E?= Message-ID: <3Wj7fM3rcYzPKv@mail.python.org> http://hg.python.org/cpython/rev/f8669955a13e changeset: 78281:f8669955a13e branch: 3.2 parent: 78279:e5d7d202f2bf user: Antoine Pitrou date: Wed Jul 25 22:38:33 2012 +0200 summary: Mention the *limit* argument of TextIO.readline(). files: Doc/library/io.rst | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Doc/library/io.rst b/Doc/library/io.rst --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -699,11 +699,13 @@ Read and return at most *n* characters from the stream as a single :class:`str`. If *n* is negative or ``None``, reads until EOF. - .. method:: readline() + .. method:: readline(limit=-1) Read until newline or EOF and return a single ``str``. If the stream is already at EOF, an empty string is returned. + If *limit* is specified, at most *limit* characters will be read. + .. method:: seek(offset, whence=SEEK_SET) Change the stream position to the given *offset*. Behaviour depends -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 25 22:42:21 2012 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 25 Jul 2012 22:42:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Mention_the_*l?= =?utf-8?q?imit*_argument_of_TextIO=2Ereadline=28=29=2E?= Message-ID: <3Wj7fP0kDKzPMQ@mail.python.org> http://hg.python.org/cpython/rev/03767b12adee changeset: 78282:03767b12adee branch: 2.7 parent: 78278:f30b49a5072e user: Antoine Pitrou date: Wed Jul 25 22:38:33 2012 +0200 summary: Mention the *limit* argument of TextIO.readline(). files: Doc/library/io.rst | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Doc/library/io.rst b/Doc/library/io.rst --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -696,11 +696,13 @@ Read and return at most *n* characters from the stream as a single :class:`unicode`. If *n* is negative or ``None``, reads until EOF. - .. method:: readline() + .. method:: readline(limit=-1) Read until newline or EOF and return a single ``unicode``. If the stream is already at EOF, an empty string is returned. + If *limit* is specified, at most *limit* characters will be read. + .. method:: seek(offset, whence=SEEK_SET) Change the stream position to the given *offset*. Behaviour depends -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 25 22:42:22 2012 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 25 Jul 2012 22:42:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Mention_the_*limit*_argument_of_TextIO=2Ereadline=28=29?= =?utf-8?q?=2E?= Message-ID: <3Wj7fQ3bqHzPN0@mail.python.org> http://hg.python.org/cpython/rev/a9a1d3d6d0dc changeset: 78283:a9a1d3d6d0dc parent: 78280:410be02de1c6 parent: 78281:f8669955a13e user: Antoine Pitrou date: Wed Jul 25 22:40:05 2012 +0200 summary: Mention the *limit* argument of TextIO.readline(). files: Doc/library/io.rst | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Doc/library/io.rst b/Doc/library/io.rst --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -708,11 +708,13 @@ Read and return at most *n* characters from the stream as a single :class:`str`. If *n* is negative or ``None``, reads until EOF. - .. method:: readline() + .. method:: readline(limit=-1) Read until newline or EOF and return a single ``str``. If the stream is already at EOF, an empty string is returned. + If *limit* is specified, at most *limit* characters will be read. + .. method:: seek(offset, whence=SEEK_SET) Change the stream position to the given *offset*. Behaviour depends -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jul 25 23:04:27 2012 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 25 Jul 2012 23:04:27 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?benchmarks=3A_Add_a_=28hopefully_accu?= =?utf-8?q?rate=29_license_file=2E?= Message-ID: <3Wj87v4J4dzNp3@mail.python.org> http://hg.python.org/benchmarks/rev/b590acb01622 changeset: 160:b590acb01622 user: Antoine Pitrou date: Wed Jul 25 23:02:17 2012 +0200 summary: Add a (hopefully accurate) license file. files: LICENSE.txt | 35 +++++++++++++++++++++++++++++++++++ 1 files changed, 35 insertions(+), 0 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,35 @@ + +Files found in the lib/ directory are copied from third-party software +projects, each of which has its own distribution terms (look for LICENSE +files or information at the beginning of each file). + +Some code was contributed by Google and other contributors under a PSF +contributor agreement, as part of the Unladen Swallow project. + +Except when otherwise stated, other software and documentation is licensed +as follows: + + The MIT License + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + +Except for the lib/ directory, the list of authors can be found by inspecting +version control history. -- Repository URL: http://hg.python.org/benchmarks From python-checkins at python.org Thu Jul 26 00:54:04 2012 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 26 Jul 2012 00:54:04 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE1MzIw?= =?utf-8?q?=3A_Make_iterating_the_list_of_tests_thread-safe_when_running_t?= =?utf-8?q?ests?= Message-ID: <3WjBZN57x9zP9v@mail.python.org> http://hg.python.org/cpython/rev/d7a64e095930 changeset: 78284:d7a64e095930 branch: 3.2 parent: 78281:f8669955a13e user: Antoine Pitrou date: Thu Jul 26 00:45:19 2012 +0200 summary: Issue #15320: Make iterating the list of tests thread-safe when running tests in multiprocess mode. Patch by Chris Jerdonek. files: Lib/test/regrtest.py | 40 ++++++++++++++++++++++--------- Misc/NEWS | 3 ++ 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -550,16 +550,7 @@ from subprocess import Popen, PIPE debug_output_pat = re.compile(r"\[\d+ refs\]$") output = Queue() - def tests_and_args(): - for test in tests: - args_tuple = ( - (test, verbose, quiet), - dict(huntrleaks=huntrleaks, use_resources=use_resources, - debug=debug, output_on_failure=verbose3, - failfast=failfast, match_tests=match_tests) - ) - yield (test, args_tuple) - pending = tests_and_args() + pending = MultiprocessTests(tests) opt_args = support.args_from_interpreter_flags() base_cmd = [sys.executable] + opt_args + ['-m', 'test.regrtest'] def work(): @@ -567,10 +558,16 @@ try: while True: try: - test, args_tuple = next(pending) + test = next(pending) except StopIteration: output.put((None, None, None, None)) return + args_tuple = ( + (test, verbose, quiet), + dict(huntrleaks=huntrleaks, use_resources=use_resources, + debug=debug, output_on_failure=verbose3, + failfast=failfast, match_tests=match_tests) + ) # -E is needed by some tests, e.g. test_import # Running the child from the same working directory ensures # that TEMPDIR for the child is the same when @@ -622,7 +619,7 @@ test_index += 1 except KeyboardInterrupt: interrupted = True - pending.close() + pending.interrupted = True for worker in workers: worker.join() else: @@ -766,6 +763,25 @@ tests.append(modname) return stdtests + sorted(tests) +# We do not use a generator so multiple threads can call next(). +class MultiprocessTests(object): + + """A thread-safe iterator over tests for multiprocess mode.""" + + def __init__(self, tests): + self.interrupted = False + self.lock = threading.Lock() + self.tests = tests + + def __iter__(self): + return self + + def __next__(self): + with self.lock: + if self.interrupted: + raise StopIteration('tests interrupted') + return next(self.tests) + def replace_stdout(): """Set stdout encoder error handler to backslashreplace (as stderr error handler) to avoid UnicodeEncodeError when printing a traceback""" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -378,6 +378,9 @@ Tests ----- +- Issue #15320: Make iterating the list of tests thread-safe when running + tests in multiprocess mode. Patch by Chris Jerdonek. + - Issue #15230: Adopted a more systematic approach in the runpy tests - Issue #15300: Ensure the temporary test working directories are in the same -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 26 00:54:06 2012 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 26 Jul 2012 00:54:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2315320=3A_Make_iterating_the_list_of_tests_threa?= =?utf-8?q?d-safe_when_running_tests?= Message-ID: <3WjBZQ3RwDzPMQ@mail.python.org> http://hg.python.org/cpython/rev/43ae2a243eca changeset: 78285:43ae2a243eca parent: 78283:a9a1d3d6d0dc parent: 78284:d7a64e095930 user: Antoine Pitrou date: Thu Jul 26 00:47:15 2012 +0200 summary: Issue #15320: Make iterating the list of tests thread-safe when running tests in multiprocess mode. Patch by Chris Jerdonek. files: Lib/test/regrtest.py | 42 ++++++++++++++++++++++--------- Misc/NEWS | 3 ++ 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -614,17 +614,7 @@ from subprocess import Popen, PIPE debug_output_pat = re.compile(r"\[\d+ refs\]$") output = Queue() - def tests_and_args(): - for test in tests: - args_tuple = ( - (test, verbose, quiet), - dict(huntrleaks=huntrleaks, use_resources=use_resources, - debug=debug, output_on_failure=verbose3, - timeout=timeout, failfast=failfast, - match_tests=match_tests) - ) - yield (test, args_tuple) - pending = tests_and_args() + pending = MultiprocessTests(tests) opt_args = support.args_from_interpreter_flags() base_cmd = [sys.executable] + opt_args + ['-m', 'test.regrtest'] def work(): @@ -632,10 +622,17 @@ try: while True: try: - test, args_tuple = next(pending) + test = next(pending) except StopIteration: output.put((None, None, None, None)) return + args_tuple = ( + (test, verbose, quiet), + dict(huntrleaks=huntrleaks, use_resources=use_resources, + debug=debug, output_on_failure=verbose3, + timeout=timeout, failfast=failfast, + match_tests=match_tests) + ) # -E is needed by some tests, e.g. test_import # Running the child from the same working directory ensures # that TEMPDIR for the child is the same when @@ -694,7 +691,7 @@ test_index += 1 except KeyboardInterrupt: interrupted = True - pending.close() + pending.interrupted = True for worker in workers: worker.join() else: @@ -840,6 +837,25 @@ tests.append(mod) return stdtests + sorted(tests) +# We do not use a generator so multiple threads can call next(). +class MultiprocessTests(object): + + """A thread-safe iterator over tests for multiprocess mode.""" + + def __init__(self, tests): + self.interrupted = False + self.lock = threading.Lock() + self.tests = tests + + def __iter__(self): + return self + + def __next__(self): + with self.lock: + if self.interrupted: + raise StopIteration('tests interrupted') + return next(self.tests) + def replace_stdout(): """Set stdout encoder error handler to backslashreplace (as stderr error handler) to avoid UnicodeEncodeError when printing a traceback""" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -211,6 +211,9 @@ Tests ----- +- Issue #15320: Make iterating the list of tests thread-safe when running + tests in multiprocess mode. Patch by Chris Jerdonek. + - Issue #15168: Move importlib.test to test.test_importlib. - Issue #15091: Reactivate a test on UNIX which was failing thanks to a -- Repository URL: http://hg.python.org/cpython From ncoghlan at gmail.com Thu Jul 26 03:03:05 2012 From: ncoghlan at gmail.com (Nick Coghlan) Date: Thu, 26 Jul 2012 11:03:05 +1000 Subject: [Python-checkins] cpython (3.2): Issue #15445: Updated logging configuration documentation to highlight In-Reply-To: <3Wj4WF1jHjzPCy@mail.python.org> References: <3Wj4WF1jHjzPCy@mail.python.org> Message-ID: On Thu, Jul 26, 2012 at 4:20 AM, vinay.sajip wrote: > + .. note:: Because portions of the configuration are passed through > + :func:`eval`, use of this function may open its users to a security risk. > + While the function only binds to a socket on ``localhost``, and so does > + not accept connections from remote machines, there are scenarios where > + untrusted code could be run under the account of the process which calls > + :func:`listen`. Specifically, if the process calling :func:`listen` runs > + on a multi-user machine where users cannot trust each other, then a > + malicious user could arrange to run essentially arbitrary code in a > + victim user's process, simply by connecting to the victim's > + :func:`listen` socket and sending a configuration which runs whatever > + code the attacker wants to have executed in the victim's process. This is > + especially easy to do if the default port is used, but not hard even if a > + different port is used). Looking at PEP 391, it appears it should be possible to replace the current use of eval() with a combination of the much safer ast.literal_eval() and the str.format attribute/item access micro-language. Worth exploring for 3.4 (http://bugs.python.org/issue15452), as it would be better to actually try to close this attack vector rather than just documenting that it exists. Cheers, Nick. -- Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia From solipsis at pitrou.net Thu Jul 26 06:03:39 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 26 Jul 2012 06:03:39 +0200 Subject: [Python-checkins] Daily reference leaks (43ae2a243eca): sum=0 Message-ID: results for 43ae2a243eca on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogU7BMe1', '-x'] From python-checkins at python.org Thu Jul 26 16:20:04 2012 From: python-checkins at python.org (andrew.svetlov) Date: Thu, 26 Jul 2012 16:20:04 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE1MDQx?= =?utf-8?q?=3A_update_=22see_also=22_list_in_tkinter_documentation=2E?= Message-ID: <3Wjb6r6Ck3zPHF@mail.python.org> http://hg.python.org/cpython/rev/aa296d685e02 changeset: 78286:aa296d685e02 branch: 3.2 parent: 78284:d7a64e095930 user: Andrew Svetlov date: Thu Jul 26 17:02:57 2012 +0300 summary: Issue #15041: update "see also" list in tkinter documentation. files: Doc/library/tkinter.rst | 21 ++++++++++++++++++--- Misc/NEWS | 2 ++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -19,12 +19,27 @@ The Python Tkinter Topic Guide provides a great deal of information on using Tk from Python and links to other sources of information on Tk. + `TKDocs `_ + Extensive tutorial plus friendlier widget pages for some of the widgets. + + `Tkinter reference: a GUI for Python `_ + On-line reference material. + + `Tkinter docs from effbot `_ + Online reference for tkinter supported by effbot.org. + + `Tcl/Tk manual `_ + Official manual for the latest tcl/tk version. + + `Programming Python `_ + Book by Mark Lutz, has excellent coverage of Tkinter. + + `Modern Tkinter for Busy Python Developers `_ + Book by Mark Rozerman about building attractive and modern graphical user interfaces with Python and Tkinter. + `An Introduction to Tkinter `_ Fredrik Lundh's on-line reference material. - `Tkinter reference: a GUI for Python `_ - On-line reference material. - `Python and Tkinter Programming `_ The book by John Grayson (ISBN 1-884777-81-3). diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -98,6 +98,8 @@ Library ------- +- Issue #15041: update "see also" list in tkinter documentation. + - Issue #15402: An issue in the struct module that caused sys.getsizeof to return incorrect results for struct.Struct instances has been fixed. Initial patch by Serhiy Storchaka. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 26 16:20:06 2012 From: python-checkins at python.org (andrew.svetlov) Date: Thu, 26 Jul 2012 16:20:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2315041=3A_update_=22see_also=22_list_in_tkinter_?= =?utf-8?q?documentation=2E?= Message-ID: <3Wjb6t4fCGzPPc@mail.python.org> http://hg.python.org/cpython/rev/e2ab56295b56 changeset: 78287:e2ab56295b56 parent: 78285:43ae2a243eca parent: 78286:aa296d685e02 user: Andrew Svetlov date: Thu Jul 26 17:16:24 2012 +0300 summary: Issue #15041: update "see also" list in tkinter documentation. files: Doc/library/tkinter.rst | 21 ++++++++++++++++++--- Misc/NEWS | 2 ++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -19,12 +19,27 @@ The Python Tkinter Topic Guide provides a great deal of information on using Tk from Python and links to other sources of information on Tk. + `TKDocs `_ + Extensive tutorial plus friendlier widget pages for some of the widgets. + + `Tkinter reference: a GUI for Python `_ + On-line reference material. + + `Tkinter docs from effbot `_ + Online reference for tkinter supported by effbot.org. + + `Tcl/Tk manual `_ + Official manual for the latest tcl/tk version. + + `Programming Python `_ + Book by Mark Lutz, has excellent coverage of Tkinter. + + `Modern Tkinter for Busy Python Developers `_ + Book by Mark Rozerman about building attractive and modern graphical user interfaces with Python and Tkinter. + `An Introduction to Tkinter `_ Fredrik Lundh's on-line reference material. - `Tkinter reference: a GUI for Python `_ - On-line reference material. - `Python and Tkinter Programming `_ The book by John Grayson (ISBN 1-884777-81-3). diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -52,6 +52,8 @@ Library ------- +- Issue #15041: update "see also" list in tkinter documentation. + - Issue #15413: os.times() had disappeared under Windows. - Issue #15402: An issue in the struct module that caused sys.getsizeof to -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 26 16:20:08 2012 From: python-checkins at python.org (andrew.svetlov) Date: Thu, 26 Jul 2012 16:20:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE1MDQx?= =?utf-8?q?=3A_Update_=22see_also=22_list_in_tkinter_documentation=2E?= Message-ID: <3Wjb6w10xlzPHF@mail.python.org> http://hg.python.org/cpython/rev/c947f493ccec changeset: 78288:c947f493ccec branch: 2.7 parent: 78282:03767b12adee user: Andrew Svetlov date: Thu Jul 26 17:19:40 2012 +0300 summary: Issue #15041: Update "see also" list in tkinter documentation. files: Doc/library/tkinter.rst | 21 ++++++++++++++++++--- Misc/NEWS | 2 ++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -23,12 +23,27 @@ The Python Tkinter Topic Guide provides a great deal of information on using Tk from Python and links to other sources of information on Tk. + `TKDocs `_ + Extensive tutorial plus friendlier widget pages for some of the widgets. + + `Tkinter reference: a GUI for Python `_ + On-line reference material. + + `Tkinter docs from effbot `_ + Online reference for tkinter supported by effbot.org. + + `Tcl/Tk manual `_ + Official manual for the latest tcl/tk version. + + `Programming Python `_ + Book by Mark Lutz, has excellent coverage of Tkinter. + + `Modern Tkinter for Busy Python Developers `_ + Book by Mark Rozerman about building attractive and modern graphical user interfaces with Python and Tkinter. + `An Introduction to Tkinter `_ Fredrik Lundh's on-line reference material. - `Tkinter reference: a GUI for Python `_ - On-line reference material. - `Python and Tkinter Programming `_ The book by John Grayson (ISBN 1-884777-81-3). diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,6 +9,8 @@ Core and Builtins ----------------- +- Issue #15041: Update "see also" list in tkinter documentation. + - Issue #14579: Fix error handling bug in the utf-16 decoder. Patch by Serhiy Storchaka. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 26 21:21:41 2012 From: python-checkins at python.org (jason.coombs) Date: Thu, 26 Jul 2012 21:21:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Restored_test_by_specifyin?= =?utf-8?q?g_that_the_symlink_links_to_a_target_=28currently?= Message-ID: <3Wjjps2ZfbzPP3@mail.python.org> http://hg.python.org/cpython/rev/5bf7afd944a2 changeset: 78289:5bf7afd944a2 parent: 78287:e2ab56295b56 user: Jason R. Coombs date: Thu Jul 26 15:21:17 2012 -0400 summary: Restored test by specifying that the symlink links to a target (currently required for Windows symlinks). See issue15093 for details. files: Lib/test/test_import.py | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -721,12 +721,11 @@ # now create a symlink to the tagged package # sample -> sample-tagged - os.symlink(self.tagged, self.package_name) + os.symlink(self.tagged, self.package_name, target_is_directory=True) self.addCleanup(test.support.unlink, self.package_name) importlib.invalidate_caches() - # disabled because os.isdir currently fails (see issue 15093) - # self.assertEqual(os.path.isdir(self.package_name), True) + self.assertEqual(os.path.isdir(self.package_name), True) assert os.path.isfile(os.path.join(self.package_name, '__init__.py')) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jul 26 22:23:40 2012 From: python-checkins at python.org (martin.v.loewis) Date: Thu, 26 Jul 2012 22:23:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315456=3A_Fix_code?= =?utf-8?q?_=5F=5Fsizeof=5F=5F_after_=2312399_change=2E?= Message-ID: <3WjlBN2JXLzPQ4@mail.python.org> http://hg.python.org/cpython/rev/5093cfdff2a9 changeset: 78290:5093cfdff2a9 user: Martin v. L?wis date: Thu Jul 26 22:23:23 2012 +0200 summary: Issue #15456: Fix code __sizeof__ after #12399 change. Patch by Serhiy Storchaka. files: Lib/test/test_sys.py | 6 ++++++ Misc/NEWS | 3 +++ Objects/codeobject.c | 18 +++++++++++++++++- 3 files changed, 26 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -702,6 +702,12 @@ check(get_cell().__closure__[0], size(h + 'P')) # code check(get_cell().__code__, size(h + '5i9Pi3P')) + check(get_cell.__code__, size(h + '5i9Pi3P')) + def get_cell2(x): + def inner(): + return x + return inner + check(get_cell2.__code__, size(h + '5i9Pi3P') + 1) # complex check(complex(0,1), size(h + '2d')) # method_descriptor (descriptor object) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #15456: Fix code __sizeof__ after #12399 change. + Patch by Serhiy Storchaka. + - Issue #15404: Refleak in PyMethodObject repr. - Issue #15394: An issue in PyModule_Create that caused references to diff --git a/Objects/codeobject.c b/Objects/codeobject.c --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -375,6 +375,17 @@ } static PyObject * +code_sizeof(PyCodeObject *co, void *unused) +{ + Py_ssize_t res; + + res = sizeof(PyCodeObject); + if (co->co_cell2arg != NULL && co->co_cellvars != NULL) + res += PyTuple_GET_SIZE(co->co_cellvars) * sizeof(unsigned char); + return PyLong_FromSsize_t(res); +} + +static PyObject * code_repr(PyCodeObject *co) { int lineno; @@ -480,6 +491,11 @@ /* XXX code objects need to participate in GC? */ +static struct PyMethodDef code_methods[] = { + {"__sizeof__", (PyCFunction)code_sizeof, METH_NOARGS}, + {NULL, NULL} /* sentinel */ +}; + PyTypeObject PyCode_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "code", @@ -508,7 +524,7 @@ offsetof(PyCodeObject, co_weakreflist), /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ - 0, /* tp_methods */ + code_methods, /* tp_methods */ code_memberlist, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 27 00:12:16 2012 From: python-checkins at python.org (barry.warsaw) Date: Fri, 27 Jul 2012 00:12:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_-_Issue_=2315458=3A_python?= =?utf-8?q?-config_gets_a_new_option_--configdir_to_print_the?= Message-ID: <3Wjnbh4lkDzPP3@mail.python.org> http://hg.python.org/cpython/rev/ddf15cd9be4a changeset: 78291:ddf15cd9be4a user: Barry Warsaw date: Thu Jul 26 18:12:07 2012 -0400 summary: - Issue #15458: python-config gets a new option --configdir to print the $LIBPL value. files: Misc/NEWS | 3 +++ Misc/python-config.in | 5 ++++- 2 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -184,6 +184,9 @@ Tools/Demos ----------- +- Issue #15458: python-config gets a new option --configdir to print the + $LIBPL value. + - Move importlib.test.benchmark to Tools/importbench. - Issue #12605: The gdb hooks for debugging CPython (within Tools/gdb) have diff --git a/Misc/python-config.in b/Misc/python-config.in --- a/Misc/python-config.in +++ b/Misc/python-config.in @@ -7,7 +7,7 @@ import sysconfig valid_opts = ['prefix', 'exec-prefix', 'includes', 'libs', 'cflags', - 'ldflags', 'extension-suffix', 'help', 'abiflags'] + 'ldflags', 'extension-suffix', 'help', 'abiflags', 'configdir'] def exit_with_usage(code=1): print("Usage: {0} [{1}]".format( @@ -61,3 +61,6 @@ elif opt == '--abiflags': print(sys.abiflags) + + elif opt == '--configdir': + print(sysconfig.get_config_var('LIBPL')) -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri Jul 27 05:55:58 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 27 Jul 2012 05:55:58 +0200 Subject: [Python-checkins] Daily reference leaks (ddf15cd9be4a): sum=1 Message-ID: results for ddf15cd9be4a on branch "default" -------------------------------------------- test_site leaked [0, 1, 0] references, sum=1 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogzr7S4w', '-x'] From python-checkins at python.org Fri Jul 27 11:55:37 2012 From: python-checkins at python.org (vinay.sajip) Date: Fri, 27 Jul 2012 11:55:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Improved_cookb?= =?utf-8?q?ook_entry_and_fixed_typo=2E?= Message-ID: <3Wk5CF5XSpzPPd@mail.python.org> http://hg.python.org/cpython/rev/225bc86a0d75 changeset: 78292:225bc86a0d75 branch: 2.7 parent: 78288:c947f493ccec user: Vinay Sajip date: Fri Jul 27 10:52:18 2012 +0100 summary: Improved cookbook entry and fixed typo. files: Doc/howto/logging-cookbook.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -763,7 +763,7 @@ As this behaviour is broken, the incorrect BOM insertion code is being removed from Python 2.7.4 and later. However, it is not being replaced, and if you -want to produce RFC 5424-compliant messages which includes a BOM, an optional +want to produce RFC 5424-compliant messages which include a BOM, an optional pure-ASCII sequence before it and arbitrary Unicode after it, encoded using UTF-8, then you need to do the following: @@ -781,8 +781,8 @@ way, it will remain unchanged after UTF-8 encoding). #. Replace the Unicode section with whatever placeholders you like; if the data - which appears there after substitution is Unicode, that's fine -- it will be - encoded using UTF-8. + which appears there after substitution contains characters outside the ASCII + range, that's fine -- it will be encoded using UTF-8. If the formatted message is Unicode, it *will* be encoded using UTF-8 encoding by ``SysLogHandler``. If you follow the above rules, you should be able to -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 27 11:55:39 2012 From: python-checkins at python.org (vinay.sajip) Date: Fri, 27 Jul 2012 11:55:39 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_Improved_cookb?= =?utf-8?q?ook_entry_and_fixed_typo=2E?= Message-ID: <3Wk5CH2b7szPRq@mail.python.org> http://hg.python.org/cpython/rev/e18f5301f406 changeset: 78293:e18f5301f406 branch: 3.2 parent: 78286:aa296d685e02 user: Vinay Sajip date: Fri Jul 27 10:54:10 2012 +0100 summary: Improved cookbook entry and fixed typo. files: Doc/howto/logging-cookbook.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -1562,7 +1562,7 @@ As this behaviour is broken, the incorrect BOM insertion code is being removed from Python 3.2.4 and later. However, it is not being replaced, and if you -want to produce RFC 5424-compliant messages which includes a BOM, an optional +want to produce RFC 5424-compliant messages which include a BOM, an optional pure-ASCII sequence before it and arbitrary Unicode after it, encoded using UTF-8, then you need to do the following: @@ -1580,8 +1580,8 @@ way, it will remain unchanged after UTF-8 encoding). #. Replace the Unicode section with whatever placeholders you like; if the data - which appears there after substitution is Unicode, that's fine -- it will be - encoded using UTF-8. + which appears there after substitution contains characters outside the ASCII + range, that's fine -- it will be encoded using UTF-8. The formatted message *will* be encoded using UTF-8 encoding by ``SysLogHandler``. If you follow the above rules, you should be able to produce -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 27 11:55:40 2012 From: python-checkins at python.org (vinay.sajip) Date: Fri, 27 Jul 2012 11:55:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Merged_documentation_update_from_3=2E2=2E?= Message-ID: <3Wk5CJ5W9gzPRd@mail.python.org> http://hg.python.org/cpython/rev/90b36463082e changeset: 78294:90b36463082e parent: 78291:ddf15cd9be4a parent: 78293:e18f5301f406 user: Vinay Sajip date: Fri Jul 27 10:55:16 2012 +0100 summary: Merged documentation update from 3.2. files: Doc/howto/logging-cookbook.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -1589,7 +1589,7 @@ As this behaviour is broken, the incorrect BOM insertion code is being removed from Python 3.2.4 and later. However, it is not being replaced, and if you -want to produce RFC 5424-compliant messages which includes a BOM, an optional +want to produce RFC 5424-compliant messages which include a BOM, an optional pure-ASCII sequence before it and arbitrary Unicode after it, encoded using UTF-8, then you need to do the following: @@ -1607,8 +1607,8 @@ way, it will remain unchanged after UTF-8 encoding). #. Replace the Unicode section with whatever placeholders you like; if the data - which appears there after substitution is Unicode, that's fine -- it will be - encoded using UTF-8. + which appears there after substitution contains characters outside the ASCII + range, that's fine -- it will be encoded using UTF-8. The formatted message *will* be encoded using UTF-8 encoding by ``SysLogHandler``. If you follow the above rules, you should be able to produce -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 27 13:08:45 2012 From: python-checkins at python.org (richard.oudkerk) Date: Fri, 27 Jul 2012 13:08:45 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315364=3A_Fix_sysc?= =?utf-8?q?onfig=2Eget=5Fconfig=5Fvar=28=27srcdir=27=29_to_be_an_absolute_?= =?utf-8?q?path=2E?= Message-ID: <3Wk6qd140rzMXk@mail.python.org> http://hg.python.org/cpython/rev/d2f448dbc30d changeset: 78295:d2f448dbc30d user: Richard Oudkerk date: Fri Jul 27 12:06:55 2012 +0100 summary: Issue #15364: Fix sysconfig.get_config_var('srcdir') to be an absolute path. files: Lib/distutils/sysconfig.py | 17 ++++++ Lib/distutils/tests/test_sysconfig.py | 28 +++++++++++ Lib/sysconfig.py | 38 ++++++-------- Lib/test/test_sysconfig.py | 28 +++++++++++ Misc/NEWS | 3 + 5 files changed, 92 insertions(+), 22 deletions(-) diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -533,6 +533,23 @@ _config_vars['prefix'] = PREFIX _config_vars['exec_prefix'] = EXEC_PREFIX + # Always convert srcdir to an absolute path + srcdir = _config_vars.get('srcdir', project_base) + if os.name == 'posix': + if python_build: + # If srcdir is a relative path (typically '.' or '..') + # then it should be interpreted relative to the directory + # containing Makefile. + base = os.path.dirname(get_makefile_filename()) + srcdir = os.path.join(base, srcdir) + else: + # srcdir is not meaningful since the installation is + # spread about the filesystem. We choose the + # directory containing the Makefile since we know it + # exists. + srcdir = os.path.dirname(get_makefile_filename()) + _config_vars['srcdir'] = os.path.abspath(os.path.normpath(srcdir)) + # Convert srcdir into an absolute path if it appears necessary. # Normally it is relative to the build directory. However, during # testing, for example, we might be running a non-installed python diff --git a/Lib/distutils/tests/test_sysconfig.py b/Lib/distutils/tests/test_sysconfig.py --- a/Lib/distutils/tests/test_sysconfig.py +++ b/Lib/distutils/tests/test_sysconfig.py @@ -53,6 +53,34 @@ self.assertTrue(isinstance(cvars, dict)) self.assertTrue(cvars) + def test_srcdir(self): + # See Issues #15322, #15364. + srcdir = sysconfig.get_config_var('srcdir') + + self.assertTrue(os.path.isabs(srcdir), srcdir) + self.assertTrue(os.path.isdir(srcdir), srcdir) + + if sysconfig.python_build: + # The python executable has not been installed so srcdir + # should be a full source checkout. + Python_h = os.path.join(srcdir, 'Include', 'Python.h') + self.assertTrue(os.path.exists(Python_h), Python_h) + self.assertTrue(sysconfig._is_python_source_dir(srcdir)) + elif os.name == 'posix': + self.assertEqual(sysconfig.get_makefile_filename(), srcdir) + + def test_srcdir_independent_of_cwd(self): + # srcdir should be independent of the current working directory + # See Issues #15322, #15364. + srcdir = sysconfig.get_config_var('srcdir') + cwd = os.getcwd() + try: + os.chdir('..') + srcdir2 = sysconfig.get_config_var('srcdir') + finally: + os.chdir(cwd) + self.assertEqual(srcdir, srcdir2) + def test_customize_compiler(self): # not testing if default compiler is not unix diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -533,28 +533,22 @@ # the init-function. _CONFIG_VARS['userbase'] = _getuserbase() - if 'srcdir' not in _CONFIG_VARS: - _CONFIG_VARS['srcdir'] = _PROJECT_BASE - else: - _CONFIG_VARS['srcdir'] = _safe_realpath(_CONFIG_VARS['srcdir']) - - # Convert srcdir into an absolute path if it appears necessary. - # Normally it is relative to the build directory. However, during - # testing, for example, we might be running a non-installed python - # from a different directory. - if _PYTHON_BUILD and os.name == "posix": - base = _PROJECT_BASE - try: - cwd = os.getcwd() - except OSError: - cwd = None - if (not os.path.isabs(_CONFIG_VARS['srcdir']) and - base != cwd): - # srcdir is relative and we are not in the same directory - # as the executable. Assume executable is in the build - # directory and make srcdir absolute. - srcdir = os.path.join(base, _CONFIG_VARS['srcdir']) - _CONFIG_VARS['srcdir'] = os.path.normpath(srcdir) + # Always convert srcdir to an absolute path + srcdir = _CONFIG_VARS.get('srcdir', _PROJECT_BASE) + if os.name == 'posix': + if _PYTHON_BUILD: + # If srcdir is a relative path (typically '.' or '..') + # then it should be interpreted relative to the directory + # containing Makefile. + base = os.path.dirname(get_makefile_filename()) + srcdir = os.path.join(base, srcdir) + else: + # srcdir is not meaningful since the installation is + # spread about the filesystem. We choose the + # directory containing the Makefile since we know it + # exists. + srcdir = os.path.dirname(get_makefile_filename()) + _CONFIG_VARS['srcdir'] = _safe_realpath(srcdir) # OS X platforms require special customization to handle # multi-architecture, multi-os-version installers diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py @@ -340,6 +340,34 @@ self.assertEqual(status, 0) self.assertEqual(my_platform, test_platform) + def test_srcdir(self): + # See Issues #15322, #15364. + srcdir = sysconfig.get_config_var('srcdir') + + self.assertTrue(os.path.isabs(srcdir), srcdir) + self.assertTrue(os.path.isdir(srcdir), srcdir) + + if sysconfig._PYTHON_BUILD: + # The python executable has not been installed so srcdir + # should be a full source checkout. + Python_h = os.path.join(srcdir, 'Include', 'Python.h') + self.assertTrue(os.path.exists(Python_h), Python_h) + self.assertTrue(sysconfig._is_python_source_dir(srcdir)) + elif os.name == 'posix': + self.assertEqual(sysconfig.get_makefile_filename(), srcdir) + + def test_srcdir_independent_of_cwd(self): + # srcdir should be independent of the current working directory + # See Issues #15322, #15364. + srcdir = sysconfig.get_config_var('srcdir') + cwd = os.getcwd() + try: + os.chdir('..') + srcdir2 = sysconfig.get_config_var('srcdir') + finally: + os.chdir(cwd) + self.assertEqual(srcdir, srcdir2) + class MakefileTests(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -55,6 +55,9 @@ Library ------- +- Issue #15364: Fix sysconfig.get_config_var('srcdir') to be an + absolute path. + - Issue #15041: update "see also" list in tkinter documentation. - Issue #15413: os.times() had disappeared under Windows. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 27 15:57:32 2012 From: python-checkins at python.org (richard.oudkerk) Date: Fri, 27 Jul 2012 15:57:32 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzYwNTY6?= =?utf-8?q?_Make_multiprocessing_use_setblocking=28True=29_on_the_sockets_?= =?utf-8?q?it_uses=2E?= Message-ID: <3WkBZN2qTBzN4g@mail.python.org> http://hg.python.org/cpython/rev/4e85e4743757 changeset: 78296:4e85e4743757 branch: 2.7 parent: 78292:225bc86a0d75 user: Richard Oudkerk date: Fri Jul 27 14:05:46 2012 +0100 summary: Issue #6056: Make multiprocessing use setblocking(True) on the sockets it uses. Original patch by J Derek Wilson. files: Lib/multiprocessing/connection.py | 5 ++ Lib/test/test_multiprocessing.py | 36 ++++++++++++++++++- Misc/ACKS | 1 + Misc/NEWS | 3 + 4 files changed, 44 insertions(+), 1 deletions(-) diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -186,6 +186,8 @@ ''' if duplex: s1, s2 = socket.socketpair() + s1.setblocking(True) + s2.setblocking(True) c1 = _multiprocessing.Connection(os.dup(s1.fileno())) c2 = _multiprocessing.Connection(os.dup(s2.fileno())) s1.close() @@ -251,6 +253,7 @@ self._socket = socket.socket(getattr(socket, family)) try: self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self._socket.setblocking(True) self._socket.bind(address) self._socket.listen(backlog) self._address = self._socket.getsockname() @@ -269,6 +272,7 @@ def accept(self): s, self._last_accepted = self._socket.accept() + s.setblocking(True) fd = duplicate(s.fileno()) conn = _multiprocessing.Connection(fd) s.close() @@ -286,6 +290,7 @@ ''' family = address_type(address) s = socket.socket( getattr(socket, family) ) + s.setblocking(True) t = _init_timeout() while 1: diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py --- a/Lib/test/test_multiprocessing.py +++ b/Lib/test/test_multiprocessing.py @@ -2315,8 +2315,42 @@ flike.flush() assert sio.getvalue() == 'foo' +# +# Test interaction with socket timeouts - see Issue #6056 +# + +class TestTimeouts(unittest.TestCase): + @classmethod + def _test_timeout(cls, child, address): + time.sleep(1) + child.send(123) + child.close() + conn = multiprocessing.connection.Client(address) + conn.send(456) + conn.close() + + def test_timeout(self): + old_timeout = socket.getdefaulttimeout() + try: + socket.setdefaulttimeout(0.1) + parent, child = multiprocessing.Pipe(duplex=True) + l = multiprocessing.connection.Listener(family='AF_INET') + p = multiprocessing.Process(target=self._test_timeout, + args=(child, l.address)) + p.start() + child.close() + self.assertEqual(parent.recv(), 123) + parent.close() + conn = l.accept() + self.assertEqual(conn.recv(), 456) + conn.close() + l.close() + p.join(10) + finally: + socket.setdefaulttimeout(old_timeout) + testcases_other = [OtherTest, TestInvalidHandle, TestInitializers, - TestStdinBadfiledescriptor] + TestStdinBadfiledescriptor, TestTimeouts] # # diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -931,6 +931,7 @@ Gerald S. Williams Frank Willison Greg V. Wilson +J Derek Wilson Jody Winston Collin Winter Dik Winter diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -129,6 +129,9 @@ - Issue #14653: email.utils.mktime_tz() no longer relies on system mktime() when timezone offest is supplied. +- Issue #6056: Make multiprocessing use setblocking(True) on the + sockets it uses. Original patch by J Derek Wilson. + - Issue #15101: Make pool finalizer avoid joining current thread. - Issue #15054: A bug in tokenize.tokenize that caused string literals -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 27 15:57:34 2012 From: python-checkins at python.org (richard.oudkerk) Date: Fri, 27 Jul 2012 15:57:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzYwNTY6?= =?utf-8?q?_Make_multiprocessing_use_setblocking=28True=29_on_the_sockets_?= =?utf-8?q?it_uses=2E?= Message-ID: <3WkBZQ14PtzPLx@mail.python.org> http://hg.python.org/cpython/rev/290f04722be3 changeset: 78297:290f04722be3 branch: 3.2 parent: 78293:e18f5301f406 user: Richard Oudkerk date: Fri Jul 27 14:06:11 2012 +0100 summary: Issue #6056: Make multiprocessing use setblocking(True) on the sockets it uses. Original patch by J Derek Wilson. files: Lib/multiprocessing/connection.py | 5 ++ Lib/test/test_multiprocessing.py | 36 ++++++++++++++++++- Misc/ACKS | 1 + Misc/NEWS | 3 + 4 files changed, 44 insertions(+), 1 deletions(-) diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -199,6 +199,8 @@ ''' if duplex: s1, s2 = socket.socketpair() + s1.setblocking(True) + s2.setblocking(True) c1 = _multiprocessing.Connection(os.dup(s1.fileno())) c2 = _multiprocessing.Connection(os.dup(s2.fileno())) s1.close() @@ -264,6 +266,7 @@ self._socket = socket.socket(getattr(socket, family)) try: self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self._socket.setblocking(True) self._socket.bind(address) self._socket.listen(backlog) self._address = self._socket.getsockname() @@ -282,6 +285,7 @@ def accept(self): s, self._last_accepted = self._socket.accept() + s.setblocking(True) fd = duplicate(s.fileno()) conn = _multiprocessing.Connection(fd) s.close() @@ -299,6 +303,7 @@ ''' family = address_type(address) with socket.socket( getattr(socket, family) ) as s: + s.setblocking(True) t = _init_timeout() while 1: diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py --- a/Lib/test/test_multiprocessing.py +++ b/Lib/test/test_multiprocessing.py @@ -2395,9 +2395,43 @@ with self.assertRaises(ValueError): multiprocessing.connection.Listener('/var/test.pipe') +# +# Test interaction with socket timeouts - see Issue #6056 +# + +class TestTimeouts(unittest.TestCase): + @classmethod + def _test_timeout(cls, child, address): + time.sleep(1) + child.send(123) + child.close() + conn = multiprocessing.connection.Client(address) + conn.send(456) + conn.close() + + def test_timeout(self): + old_timeout = socket.getdefaulttimeout() + try: + socket.setdefaulttimeout(0.1) + parent, child = multiprocessing.Pipe(duplex=True) + l = multiprocessing.connection.Listener(family='AF_INET') + p = multiprocessing.Process(target=self._test_timeout, + args=(child, l.address)) + p.start() + child.close() + self.assertEqual(parent.recv(), 123) + parent.close() + conn = l.accept() + self.assertEqual(conn.recv(), 456) + conn.close() + l.close() + p.join(10) + finally: + socket.setdefaulttimeout(old_timeout) testcases_other = [OtherTest, TestInvalidHandle, TestInitializers, - TestStdinBadfiledescriptor, TestInvalidFamily] + TestStdinBadfiledescriptor, TestInvalidFamily, + TestTimeouts] # # diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1021,6 +1021,7 @@ Gerald S. Williams Frank Willison Greg V. Wilson +J Derek Wilson Jody Winston Collin Winter Dik Winter diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -98,6 +98,9 @@ Library ------- +- Issue #6056: Make multiprocessing use setblocking(True) on the + sockets it uses. Original patch by J Derek Wilson. + - Issue #15041: update "see also" list in tkinter documentation. - Issue #15402: An issue in the struct module that caused sys.getsizeof to -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 27 15:57:35 2012 From: python-checkins at python.org (richard.oudkerk) Date: Fri, 27 Jul 2012 15:57:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=236056=3A_Make_mult?= =?utf-8?q?iprocessing_use_setblocking=28True=29_on_the_sockets_it_uses=2E?= Message-ID: <3WkBZR5KqmzPLx@mail.python.org> http://hg.python.org/cpython/rev/f03839401420 changeset: 78298:f03839401420 parent: 78295:d2f448dbc30d user: Richard Oudkerk date: Fri Jul 27 14:19:00 2012 +0100 summary: Issue #6056: Make multiprocessing use setblocking(True) on the sockets it uses. Original patch by J Derek Wilson. files: Lib/multiprocessing/connection.py | 5 ++ Lib/test/test_multiprocessing.py | 36 ++++++++++++++++++- Misc/ACKS | 1 + Misc/NEWS | 3 + 4 files changed, 44 insertions(+), 1 deletions(-) diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -497,6 +497,8 @@ ''' if duplex: s1, s2 = socket.socketpair() + s1.setblocking(True) + s2.setblocking(True) c1 = Connection(s1.detach()) c2 = Connection(s2.detach()) else: @@ -561,6 +563,7 @@ if os.name == 'posix': self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self._socket.setblocking(True) self._socket.bind(address) self._socket.listen(backlog) self._address = self._socket.getsockname() @@ -579,6 +582,7 @@ def accept(self): s, self._last_accepted = self._socket.accept() + s.setblocking(True) return Connection(s.detach()) def close(self): @@ -593,6 +597,7 @@ ''' family = address_type(address) with socket.socket( getattr(socket, family) ) as s: + s.setblocking(True) s.connect(address) return Connection(s.detach()) diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py --- a/Lib/test/test_multiprocessing.py +++ b/Lib/test/test_multiprocessing.py @@ -3312,9 +3312,43 @@ child_flags, grandchild_flags = json.loads(data.decode('ascii')) self.assertEqual(child_flags, grandchild_flags) +# +# Test interaction with socket timeouts - see Issue #6056 +# + +class TestTimeouts(unittest.TestCase): + @classmethod + def _test_timeout(cls, child, address): + time.sleep(1) + child.send(123) + child.close() + conn = multiprocessing.connection.Client(address) + conn.send(456) + conn.close() + + def test_timeout(self): + old_timeout = socket.getdefaulttimeout() + try: + socket.setdefaulttimeout(0.1) + parent, child = multiprocessing.Pipe(duplex=True) + l = multiprocessing.connection.Listener(family='AF_INET') + p = multiprocessing.Process(target=self._test_timeout, + args=(child, l.address)) + p.start() + child.close() + self.assertEqual(parent.recv(), 123) + parent.close() + conn = l.accept() + self.assertEqual(conn.recv(), 456) + conn.close() + l.close() + p.join(10) + finally: + socket.setdefaulttimeout(old_timeout) + testcases_other = [OtherTest, TestInvalidHandle, TestInitializers, TestStdinBadfiledescriptor, TestWait, TestInvalidFamily, - TestFlags] + TestFlags, TestTimeouts] # # diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1130,6 +1130,7 @@ Sue Williams Frank Willison Greg V. Wilson +J Derek Wilson Jody Winston Collin Winter Dik Winter diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -55,6 +55,9 @@ Library ------- +- Issue #6056: Make multiprocessing use setblocking(True) on the + sockets it uses. Original patch by J Derek Wilson. + - Issue #15364: Fix sysconfig.get_config_var('srcdir') to be an absolute path. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 27 15:57:37 2012 From: python-checkins at python.org (richard.oudkerk) Date: Fri, 27 Jul 2012 15:57:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?b?KTogRHVtbXkgbWVyZ2Uu?= Message-ID: <3WkBZT1LbqzPLQ@mail.python.org> http://hg.python.org/cpython/rev/f691b32cc1fd changeset: 78299:f691b32cc1fd parent: 78298:f03839401420 parent: 78297:290f04722be3 user: Richard Oudkerk date: Fri Jul 27 14:55:17 2012 +0100 summary: Dummy merge. files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jul 27 20:04:35 2012 From: python-checkins at python.org (richard.oudkerk) Date: Fri, 27 Jul 2012 20:04:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devguide=3A_Add_interest_area?= Message-ID: <3WkJ3R0RpxzNP0@mail.python.org> http://hg.python.org/devguide/rev/87f27e1b3f55 changeset: 531:87f27e1b3f55 user: Richard Oudkerk date: Fri Jul 27 18:58:05 2012 +0100 summary: Add interest area files: experts.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/experts.rst b/experts.rst --- a/experts.rst +++ b/experts.rst @@ -149,7 +149,7 @@ modulefinder theller (inactive), jvr msilib loewis msvcrt -multiprocessing jnoller +multiprocessing jnoller, sbt* netrc nis nntplib pitrou -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sat Jul 28 00:15:50 2012 From: python-checkins at python.org (ned.deily) Date: Sat, 28 Jul 2012 00:15:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devguide=3A_Issue_=2315311=3A_Expand_?= =?utf-8?q?section_on_helping_with_the_Developer=27s_Guide?= Message-ID: <3WkPdL3rSjzPMR@mail.python.org> http://hg.python.org/devguide/rev/706b1fa362a4 changeset: 532:706b1fa362a4 user: Ned Deily date: Fri Jul 27 15:15:18 2012 -0700 summary: Issue #15311: Expand section on helping with the Developer's Guide documentation. (Patch by Chris Jerdonek) files: docquality.rst | 14 ++++++++++---- 1 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docquality.rst b/docquality.rst --- a/docquality.rst +++ b/docquality.rst @@ -69,8 +69,14 @@ Helping with the Developer's Guide ---------------------------------- -This developer guide lives in a `separate source code repository`_, but is -otherwise managed using the same process as is used for the main Python -documentation. +The Developer's Guide uses the same process as the main Python +documentation, except for some small differences. +The source lives in a `separate repository`_. To build and view the +documentation, install `Sphinx`_ and issue the following command: :: -.. _separate source code repository: http://hg.python.org/devguide + make html + +Changes to the documentation are published immediately using an update hook. + +.. _separate repository: http://hg.python.org/devguide +.. _Sphinx: http://sphinx.pocoo.org/ -- Repository URL: http://hg.python.org/devguide From solipsis at pitrou.net Sat Jul 28 06:05:10 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 28 Jul 2012 06:05:10 +0200 Subject: [Python-checkins] Daily reference leaks (f691b32cc1fd): sum=0 Message-ID: results for f691b32cc1fd on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogRm8dFt', '-x'] From python-checkins at python.org Sat Jul 28 08:38:20 2012 From: python-checkins at python.org (ned.deily) Date: Sat, 28 Jul 2012 08:38:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315364=3A_Fix_test?= =?utf-8?q?=5Fsrcdir_for_the_installed_case=2E?= Message-ID: <3Wkcn80GT1zPPd@mail.python.org> http://hg.python.org/cpython/rev/c2618b916081 changeset: 78300:c2618b916081 user: Ned Deily date: Fri Jul 27 23:37:04 2012 -0700 summary: Issue #15364: Fix test_srcdir for the installed case. files: Lib/distutils/tests/test_sysconfig.py | 3 ++- Lib/test/test_sysconfig.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/distutils/tests/test_sysconfig.py b/Lib/distutils/tests/test_sysconfig.py --- a/Lib/distutils/tests/test_sysconfig.py +++ b/Lib/distutils/tests/test_sysconfig.py @@ -67,7 +67,8 @@ self.assertTrue(os.path.exists(Python_h), Python_h) self.assertTrue(sysconfig._is_python_source_dir(srcdir)) elif os.name == 'posix': - self.assertEqual(sysconfig.get_makefile_filename(), srcdir) + self.assertEqual(os.path.dirname(sysconfig.get_makefile_filename()), + srcdir) def test_srcdir_independent_of_cwd(self): # srcdir should be independent of the current working directory diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py @@ -354,7 +354,8 @@ self.assertTrue(os.path.exists(Python_h), Python_h) self.assertTrue(sysconfig._is_python_source_dir(srcdir)) elif os.name == 'posix': - self.assertEqual(sysconfig.get_makefile_filename(), srcdir) + self.assertEqual(os.path.dirname(sysconfig.get_makefile_filename()), + srcdir) def test_srcdir_independent_of_cwd(self): # srcdir should be independent of the current working directory -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 28 12:28:10 2012 From: python-checkins at python.org (stefan.krah) Date: Sat, 28 Jul 2012 12:28:10 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2312834=3A_Fix_PyBu?= =?utf-8?q?ffer=5FToContiguous=28=29_for_non-contiguous_arrays=2E?= Message-ID: <3WkjtL3tdyzPTf@mail.python.org> http://hg.python.org/cpython/rev/8fbbc7c8748e changeset: 78301:8fbbc7c8748e user: Stefan Krah date: Sat Jul 28 12:25:55 2012 +0200 summary: Issue #12834: Fix PyBuffer_ToContiguous() for non-contiguous arrays. files: Include/abstract.h | 5 +- Lib/test/test_buffer.py | 291 +++++++++++++++++++++++++- Misc/NEWS | 2 + Modules/_testbuffer.c | 44 +++ Objects/abstract.c | 56 ----- Objects/bytearrayobject.c | 2 +- Objects/bytesobject.c | 1 - Objects/memoryobject.c | 77 ++++++- 8 files changed, 410 insertions(+), 68 deletions(-) diff --git a/Include/abstract.h b/Include/abstract.h --- a/Include/abstract.h +++ b/Include/abstract.h @@ -535,11 +535,12 @@ + /* Implementation in memoryobject.c */ PyAPI_FUNC(int) PyBuffer_ToContiguous(void *buf, Py_buffer *view, - Py_ssize_t len, char fort); + Py_ssize_t len, char order); PyAPI_FUNC(int) PyBuffer_FromContiguous(Py_buffer *view, void *buf, - Py_ssize_t len, char fort); + Py_ssize_t len, char order); /* Copy len bytes of data from the contiguous chunk of memory diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -53,6 +53,11 @@ 'f':0, 'd':0, 'P':0 } +# NumPy does not have 'n' or 'N': +if numpy_array: + del NATIVE['n'] + del NATIVE['N'] + if struct: try: # Add "qQ" if present in native mode. @@ -855,11 +860,49 @@ is_contiguous(result, 'F') and order == 'C': # The flattened list is already in C-order. expected = ndarray(flattened, shape=shape, format=ff) - contig = get_contiguous(result, PyBUF_READ, order) + contig = get_contiguous(result, PyBUF_READ, order) self.assertEqual(contig.tobytes(), b) self.assertTrue(cmp_contig(contig, expected)) + if ndim == 0: + continue + + nmemb = len(flattened) + ro = 0 if readonly else ND_WRITABLE + + ### See comment in test_py_buffer_to_contiguous for an + ### explanation why these tests are valid. + + # To 'C' + contig = py_buffer_to_contiguous(result, 'C', PyBUF_FULL_RO) + self.assertEqual(len(contig), nmemb * itemsize) + initlst = [struct.unpack_from(fmt, contig, n*itemsize)[0] + for n in range(nmemb)] + + y = ndarray(initlst, shape=shape, flags=ro, format=fmt) + self.assertEqual(memoryview(y), memoryview(result)) + + # To 'F' + contig = py_buffer_to_contiguous(result, 'F', PyBUF_FULL_RO) + self.assertEqual(len(contig), nmemb * itemsize) + initlst = [struct.unpack_from(fmt, contig, n*itemsize)[0] + for n in range(nmemb)] + + y = ndarray(initlst, shape=shape, flags=ro|ND_FORTRAN, + format=fmt) + self.assertEqual(memoryview(y), memoryview(result)) + + # To 'A' + contig = py_buffer_to_contiguous(result, 'A', PyBUF_FULL_RO) + self.assertEqual(len(contig), nmemb * itemsize) + initlst = [struct.unpack_from(fmt, contig, n*itemsize)[0] + for n in range(nmemb)] + + f = ND_FORTRAN if is_contiguous(result, 'F') else 0 + y = ndarray(initlst, shape=shape, flags=f|ro, format=fmt) + self.assertEqual(memoryview(y), memoryview(result)) + if is_memoryview_format(fmt): try: m = memoryview(result) @@ -1805,6 +1848,9 @@ self.assertEqual(mvlist, ylist) if numpy_array: + # XXX NumPy (as far as it compiles with 3.3) currently + # segfaults here. Wait for a stable 3.3 compatible version. + continue shape = t[3] if 0 in shape: continue # http://projects.scipy.org/numpy/ticket/1910 @@ -1884,6 +1930,9 @@ self.assertEqual(mr.tolist(), yrlist) if numpy_array: + # XXX NumPy (as far as it compiles with 3.3) currently + # segfaults here. Wait for a stable 3.3 compatible version. + continue if 0 in lshape or 0 in rshape: continue # http://projects.scipy.org/numpy/ticket/1910 @@ -2020,6 +2069,246 @@ nd = ndarray(list(range(12)), shape=[2,2,3], format='L') self.assertEqual(hash(nd), hash(nd.tobytes())) + def test_py_buffer_to_contiguous(self): + + # The requests are used in _testbuffer.c:py_buffer_to_contiguous + # to generate buffers without full information for testing. + requests = ( + # distinct flags + PyBUF_INDIRECT, PyBUF_STRIDES, PyBUF_ND, PyBUF_SIMPLE, + # compound requests + PyBUF_FULL, PyBUF_FULL_RO, + PyBUF_RECORDS, PyBUF_RECORDS_RO, + PyBUF_STRIDED, PyBUF_STRIDED_RO, + PyBUF_CONTIG, PyBUF_CONTIG_RO, + ) + + # no buffer interface + self.assertRaises(TypeError, py_buffer_to_contiguous, {}, 'F', + PyBUF_FULL_RO) + + # scalar, read-only request + nd = ndarray(9, shape=(), format="L", flags=ND_WRITABLE) + for order in ['C', 'F', 'A']: + for request in requests: + b = py_buffer_to_contiguous(nd, order, request) + self.assertEqual(b, nd.tobytes()) + + # zeros in shape + nd = ndarray([1], shape=[0], format="L", flags=ND_WRITABLE) + for order in ['C', 'F', 'A']: + for request in requests: + b = py_buffer_to_contiguous(nd, order, request) + self.assertEqual(b, b'') + + nd = ndarray(list(range(8)), shape=[2, 0, 7], format="L", + flags=ND_WRITABLE) + for order in ['C', 'F', 'A']: + for request in requests: + b = py_buffer_to_contiguous(nd, order, request) + self.assertEqual(b, b'') + + ### One-dimensional arrays are trivial, since Fortran and C order + ### are the same. + + # one-dimensional + for f in [0, ND_FORTRAN]: + nd = ndarray([1], shape=[1], format="h", flags=f|ND_WRITABLE) + ndbytes = nd.tobytes() + for order in ['C', 'F', 'A']: + for request in requests: + b = py_buffer_to_contiguous(nd, order, request) + self.assertEqual(b, ndbytes) + + nd = ndarray([1, 2, 3], shape=[3], format="b", flags=f|ND_WRITABLE) + ndbytes = nd.tobytes() + for order in ['C', 'F', 'A']: + for request in requests: + b = py_buffer_to_contiguous(nd, order, request) + self.assertEqual(b, ndbytes) + + # one-dimensional, non-contiguous input + nd = ndarray([1, 2, 3], shape=[2], strides=[2], flags=ND_WRITABLE) + ndbytes = nd.tobytes() + for order in ['C', 'F', 'A']: + for request in [PyBUF_STRIDES, PyBUF_FULL]: + b = py_buffer_to_contiguous(nd, order, request) + self.assertEqual(b, ndbytes) + + nd = nd[::-1] + ndbytes = nd.tobytes() + for order in ['C', 'F', 'A']: + for request in requests: + try: + b = py_buffer_to_contiguous(nd, order, request) + except BufferError: + continue + self.assertEqual(b, ndbytes) + + ### + ### Multi-dimensional arrays: + ### + ### The goal here is to preserve the logical representation of the + ### input array but change the physical representation if necessary. + ### + ### _testbuffer example: + ### ==================== + ### + ### C input array: + ### -------------- + ### >>> nd = ndarray(list(range(12)), shape=[3, 4]) + ### >>> nd.tolist() + ### [[0, 1, 2, 3], + ### [4, 5, 6, 7], + ### [8, 9, 10, 11]] + ### + ### Fortran output: + ### --------------- + ### >>> py_buffer_to_contiguous(nd, 'F', PyBUF_FULL_RO) + ### >>> b'\x00\x04\x08\x01\x05\t\x02\x06\n\x03\x07\x0b' + ### + ### The return value corresponds to this input list for + ### _testbuffer's ndarray: + ### >>> nd = ndarray([0,4,8,1,5,9,2,6,10,3,7,11], shape=[3,4], + ### flags=ND_FORTRAN) + ### >>> nd.tolist() + ### [[0, 1, 2, 3], + ### [4, 5, 6, 7], + ### [8, 9, 10, 11]] + ### + ### The logical array is the same, but the values in memory are now + ### in Fortran order. + ### + ### NumPy example: + ### ============== + ### _testbuffer's ndarray takes lists to initialize the memory. + ### Here's the same sequence in NumPy: + ### + ### C input: + ### -------- + ### >>> nd = ndarray(buffer=bytearray(list(range(12))), + ### shape=[3, 4], dtype='B') + ### >>> nd + ### array([[ 0, 1, 2, 3], + ### [ 4, 5, 6, 7], + ### [ 8, 9, 10, 11]], dtype=uint8) + ### + ### Fortran output: + ### --------------- + ### >>> fortran_buf = nd.tostring(order='F') + ### >>> fortran_buf + ### b'\x00\x04\x08\x01\x05\t\x02\x06\n\x03\x07\x0b' + ### + ### >>> nd = ndarray(buffer=fortran_buf, shape=[3, 4], + ### dtype='B', order='F') + ### + ### >>> nd + ### array([[ 0, 1, 2, 3], + ### [ 4, 5, 6, 7], + ### [ 8, 9, 10, 11]], dtype=uint8) + ### + + # multi-dimensional, contiguous input + lst = list(range(12)) + for f in [0, ND_FORTRAN]: + nd = ndarray(lst, shape=[3, 4], flags=f|ND_WRITABLE) + if numpy_array: + na = numpy_array(buffer=bytearray(lst), + shape=[3, 4], dtype='B', + order='C' if f == 0 else 'F') + + # 'C' request + if f == ND_FORTRAN: # 'F' to 'C' + x = ndarray(transpose(lst, [4, 3]), shape=[3, 4], + flags=ND_WRITABLE) + expected = x.tobytes() + else: + expected = nd.tobytes() + for request in requests: + try: + b = py_buffer_to_contiguous(nd, 'C', request) + except BufferError: + continue + + self.assertEqual(b, expected) + + # Check that output can be used as the basis for constructing + # a C array that is logically identical to the input array. + y = ndarray([v for v in b], shape=[3, 4], flags=ND_WRITABLE) + self.assertEqual(memoryview(y), memoryview(nd)) + + if numpy_array: + self.assertEqual(b, na.tostring(order='C')) + + # 'F' request + if f == 0: # 'C' to 'F' + x = ndarray(transpose(lst, [3, 4]), shape=[4, 3], + flags=ND_WRITABLE) + else: + x = ndarray(lst, shape=[3, 4], flags=ND_WRITABLE) + expected = x.tobytes() + for request in [PyBUF_FULL, PyBUF_FULL_RO, PyBUF_INDIRECT, + PyBUF_STRIDES, PyBUF_ND]: + try: + b = py_buffer_to_contiguous(nd, 'F', request) + except BufferError: + continue + self.assertEqual(b, expected) + + # Check that output can be used as the basis for constructing + # a Fortran array that is logically identical to the input array. + y = ndarray([v for v in b], shape=[3, 4], flags=ND_FORTRAN|ND_WRITABLE) + self.assertEqual(memoryview(y), memoryview(nd)) + + if numpy_array: + self.assertEqual(b, na.tostring(order='F')) + + # 'A' request + if f == ND_FORTRAN: + x = ndarray(lst, shape=[3, 4], flags=ND_WRITABLE) + expected = x.tobytes() + else: + expected = nd.tobytes() + for request in [PyBUF_FULL, PyBUF_FULL_RO, PyBUF_INDIRECT, + PyBUF_STRIDES, PyBUF_ND]: + try: + b = py_buffer_to_contiguous(nd, 'A', request) + except BufferError: + continue + + self.assertEqual(b, expected) + + # Check that output can be used as the basis for constructing + # an array with order=f that is logically identical to the input + # array. + y = ndarray([v for v in b], shape=[3, 4], flags=f|ND_WRITABLE) + self.assertEqual(memoryview(y), memoryview(nd)) + + if numpy_array: + self.assertEqual(b, na.tostring(order='A')) + + # multi-dimensional, non-contiguous input + nd = ndarray(list(range(12)), shape=[3, 4], flags=ND_WRITABLE|ND_PIL) + + # 'C' + b = py_buffer_to_contiguous(nd, 'C', PyBUF_FULL_RO) + self.assertEqual(b, nd.tobytes()) + y = ndarray([v for v in b], shape=[3, 4], flags=ND_WRITABLE) + self.assertEqual(memoryview(y), memoryview(nd)) + + # 'F' + b = py_buffer_to_contiguous(nd, 'F', PyBUF_FULL_RO) + x = ndarray(transpose(lst, [3, 4]), shape=[4, 3], flags=ND_WRITABLE) + self.assertEqual(b, x.tobytes()) + y = ndarray([v for v in b], shape=[3, 4], flags=ND_FORTRAN|ND_WRITABLE) + self.assertEqual(memoryview(y), memoryview(nd)) + + # 'A' + b = py_buffer_to_contiguous(nd, 'A', PyBUF_FULL_RO) + self.assertEqual(b, nd.tobytes()) + y = ndarray([v for v in b], shape=[3, 4], flags=ND_WRITABLE) + self.assertEqual(memoryview(y), memoryview(nd)) + def test_memoryview_construction(self): items_shape = [(9, []), ([1,2,3], [3]), (list(range(2*3*5)), [2,3,5])] diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #12834: Fix PyBuffer_ToContiguous() for non-contiguous arrays. + - Issue #15456: Fix code __sizeof__ after #12399 change. Patch by Serhiy Storchaka. diff --git a/Modules/_testbuffer.c b/Modules/_testbuffer.c --- a/Modules/_testbuffer.c +++ b/Modules/_testbuffer.c @@ -2397,6 +2397,49 @@ return PyMemoryView_GetContiguous(obj, (int)type, ord); } +/* PyBuffer_ToContiguous() */ +static PyObject * +py_buffer_to_contiguous(PyObject *self, PyObject *args) +{ + PyObject *obj; + PyObject *order; + PyObject *ret = NULL; + int flags; + char ord; + Py_buffer view; + char *buf = NULL; + + if (!PyArg_ParseTuple(args, "OOi", &obj, &order, &flags)) { + return NULL; + } + + if (PyObject_GetBuffer(obj, &view, flags) < 0) { + return NULL; + } + + ord = get_ascii_order(order); + if (ord == CHAR_MAX) { + goto out; + } + + buf = PyMem_Malloc(view.len); + if (buf == NULL) { + PyErr_NoMemory(); + goto out; + } + + if (PyBuffer_ToContiguous(buf, &view, view.len, ord) < 0) { + goto out; + } + + ret = PyBytes_FromStringAndSize(buf, view.len); + +out: + PyBuffer_Release(&view); + PyMem_XFree(buf); + return ret; +} + static int fmtcmp(const char *fmt1, const char *fmt2) { @@ -2734,6 +2777,7 @@ {"get_pointer", get_pointer, METH_VARARGS, NULL}, {"get_sizeof_void_p", (PyCFunction)get_sizeof_void_p, METH_NOARGS, NULL}, {"get_contiguous", get_contiguous, METH_VARARGS, NULL}, + {"py_buffer_to_contiguous", py_buffer_to_contiguous, METH_VARARGS, NULL}, {"is_contiguous", is_contiguous, METH_VARARGS, NULL}, {"cmp_contig", cmp_contig, METH_VARARGS, NULL}, {NULL, NULL} diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -445,62 +445,6 @@ } } - /* view is not checked for consistency in either of these. It is - assumed that the size of the buffer is view->len in - view->len / view->itemsize elements. - */ - -int -PyBuffer_ToContiguous(void *buf, Py_buffer *view, Py_ssize_t len, char fort) -{ - int k; - void (*addone)(int, Py_ssize_t *, const Py_ssize_t *); - Py_ssize_t *indices, elements; - char *dest, *ptr; - - if (len > view->len) { - len = view->len; - } - - if (PyBuffer_IsContiguous(view, fort)) { - /* simplest copy is all that is needed */ - memcpy(buf, view->buf, len); - return 0; - } - - /* Otherwise a more elaborate scheme is needed */ - - /* XXX(nnorwitz): need to check for overflow! */ - indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*(view->ndim)); - if (indices == NULL) { - PyErr_NoMemory(); - return -1; - } - for (k=0; kndim;k++) { - indices[k] = 0; - } - - if (fort == 'F') { - addone = _Py_add_one_to_index_F; - } - else { - addone = _Py_add_one_to_index_C; - } - dest = buf; - /* XXX : This is not going to be the fastest code in the world - several optimizations are possible. - */ - elements = len / view->itemsize; - while (elements--) { - addone(view->ndim, indices, view->shape); - ptr = PyBuffer_GetPointer(view, indices); - memcpy(dest, ptr, view->itemsize); - dest += view->itemsize; - } - PyMem_Free(indices); - return 0; -} - int PyBuffer_FromContiguous(Py_buffer *view, void *buf, Py_ssize_t len, char fort) { diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -789,7 +789,7 @@ size = view.len; if (PyByteArray_Resize((PyObject *)self, size) < 0) goto fail; if (PyBuffer_ToContiguous(self->ob_bytes, &view, size, 'C') < 0) - goto fail; + goto fail; PyBuffer_Release(&view); return 0; fail: diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2591,7 +2591,6 @@ new = PyBytes_FromStringAndSize(NULL, view.len); if (!new) goto fail; - /* XXX(brett.cannon): Better way to get to internal buffer? */ if (PyBuffer_ToContiguous(((PyBytesObject *)new)->ob_sval, &view, view.len, 'C') < 0) goto fail; diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -438,15 +438,17 @@ view->strides[i] = view->strides[i-1] * view->shape[i-1]; } -/* Copy src to a C-contiguous representation. Assumptions: +/* Copy src to a contiguous representation. order is one of 'C', 'F' (Fortran) + or 'A' (Any). Assumptions: src has PyBUF_FULL information, src->ndim >= 1, len(mem) == src->len. */ static int -buffer_to_c_contiguous(char *mem, Py_buffer *src) +buffer_to_contiguous(char *mem, Py_buffer *src, char order) { Py_buffer dest; Py_ssize_t *strides; int ret; + assert(src->ndim >= 1); assert(src->shape != NULL); assert(src->strides != NULL); @@ -456,12 +458,22 @@ return -1; } - /* initialize dest as a C-contiguous buffer */ + /* initialize dest */ dest = *src; dest.buf = mem; - /* shape is constant and shared */ + /* shape is constant and shared: the logical representation of the + array is unaltered. */ + + /* The physical representation determined by strides (and possibly + suboffsets) may change. */ dest.strides = strides; - init_strides_from_shape(&dest); + if (order == 'C' || order == 'A') { + init_strides_from_shape(&dest); + } + else { + init_fortran_strides_from_shape(&dest); + } + dest.suboffsets = NULL; ret = copy_buffer(&dest, src); @@ -922,6 +934,57 @@ /****************************************************************************/ +/* Previously in abstract.c */ +/****************************************************************************/ + +typedef struct { + Py_buffer view; + Py_ssize_t array[1]; +} Py_buffer_full; + +int +PyBuffer_ToContiguous(void *buf, Py_buffer *src, Py_ssize_t len, char order) +{ + Py_buffer_full *fb = NULL; + int ret; + + assert(order == 'C' || order == 'F' || order == 'A'); + + if (len != src->len) { + PyErr_SetString(PyExc_ValueError, + "PyBuffer_ToContiguous: len != view->len"); + return -1; + } + + if (PyBuffer_IsContiguous(src, order)) { + memcpy((char *)buf, src->buf, len); + return 0; + } + + /* buffer_to_contiguous() assumes PyBUF_FULL */ + fb = PyMem_Malloc(sizeof *fb + 3 * src->ndim * (sizeof *fb->array)); + if (fb == NULL) { + PyErr_NoMemory(); + return -1; + } + fb->view.ndim = src->ndim; + fb->view.shape = fb->array; + fb->view.strides = fb->array + src->ndim; + fb->view.suboffsets = fb->array + 2 * src->ndim; + + init_shared_values(&fb->view, src); + init_shape_strides(&fb->view, src); + init_suboffsets(&fb->view, src); + + src = &fb->view; + + ret = buffer_to_contiguous(buf, src, order); + PyMem_Free(fb); + return ret; +} + + +/****************************************************************************/ /* Release/GC management */ /****************************************************************************/ @@ -1889,7 +1952,7 @@ if (bytes == NULL) return NULL; - if (buffer_to_c_contiguous(PyBytes_AS_STRING(bytes), src) < 0) { + if (buffer_to_contiguous(PyBytes_AS_STRING(bytes), src, 'C') < 0) { Py_DECREF(bytes); return NULL; } @@ -2423,7 +2486,7 @@ PyErr_NoMemory(); return -1; } - if (buffer_to_c_contiguous(mem, view) < 0) { + if (buffer_to_contiguous(mem, view, 'C') < 0) { PyMem_Free(mem); return -1; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 28 13:56:22 2012 From: python-checkins at python.org (stefan.krah) Date: Sat, 28 Jul 2012 13:56:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Add_unused_parameter_to_a_?= =?utf-8?q?couple_of_METH=5FNOARGS_functions=2E_The_previous?= Message-ID: <3Wklr665HvzPPT@mail.python.org> http://hg.python.org/cpython/rev/bd6f9315a0f0 changeset: 78302:bd6f9315a0f0 user: Stefan Krah date: Sat Jul 28 13:53:47 2012 +0200 summary: Add unused parameter to a couple of METH_NOARGS functions. The previous form is used in many places in the source tree, but was found to be incorrect in a recent tracker discussion. files: Modules/_decimal/_decimal.c | 16 ++++++++-------- 1 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -632,7 +632,7 @@ } static PyObject * -signaldict_copy(PyObject *self) +signaldict_copy(PyObject *self, PyObject *args UNUSED) { return flags_as_dict(SdFlags(self)); } @@ -1412,7 +1412,7 @@ #endif static PyObject * -context_copy(PyObject *self) +context_copy(PyObject *self, PyObject *args UNUSED) { PyObject *copy; @@ -1530,7 +1530,7 @@ /* Return a new reference to the current context */ static PyObject * -PyDec_GetCurrentContext(void) +PyDec_GetCurrentContext(PyObject *self UNUSED, PyObject *args UNUSED) { PyObject *context; @@ -1551,7 +1551,7 @@ if (v == default_context_template || v == basic_context_template || v == extended_context_template) { - v = context_copy(v); + v = context_copy(v, NULL); if (v == NULL) { return NULL; } @@ -1600,7 +1600,7 @@ } /* Set up a new thread local context. */ - tl_context = context_copy(default_context_template); + tl_context = context_copy(default_context_template, NULL); if (tl_context == NULL) { return NULL; } @@ -1657,7 +1657,7 @@ /* Return a new reference to the current context */ static PyObject * -PyDec_GetCurrentContext(void) +PyDec_GetCurrentContext(PyObject *self UNUSED, PyObject *args UNUSED) { PyObject *context; @@ -1690,7 +1690,7 @@ if (v == default_context_template || v == basic_context_template || v == extended_context_template) { - v = context_copy(v); + v = context_copy(v, NULL); if (v == NULL) { return NULL; } @@ -1734,7 +1734,7 @@ return NULL; } - self->local = context_copy(local); + self->local = context_copy(local, NULL); if (self->local == NULL) { self->global = NULL; Py_DECREF(self); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 28 14:11:58 2012 From: python-checkins at python.org (stefan.krah) Date: Sat, 28 Jul 2012 14:11:58 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Add_unused_parameter_to_a_?= =?utf-8?q?METH=5FNOARGS_function=2E?= Message-ID: <3WkmB6385GzPPd@mail.python.org> http://hg.python.org/cpython/rev/c15edc6b9b97 changeset: 78303:c15edc6b9b97 user: Stefan Krah date: Sat Jul 28 14:10:02 2012 +0200 summary: Add unused parameter to a METH_NOARGS function. files: Objects/memoryobject.c | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -1019,7 +1019,7 @@ } static PyObject * -memory_release(PyMemoryViewObject *self) +memory_release(PyMemoryViewObject *self, PyObject *noargs) { if (_memory_release(self) < 0) return NULL; @@ -1064,7 +1064,7 @@ static PyObject * memory_exit(PyObject *self, PyObject *args) { - return memory_release((PyMemoryViewObject *)self); + return memory_release((PyMemoryViewObject *)self, NULL); } @@ -2639,12 +2639,12 @@ static PyMethodDef memory_methods[] = { - {"release", (PyCFunction)memory_release, METH_NOARGS}, + {"release", (PyCFunction)memory_release, METH_NOARGS, NULL}, {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL}, {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL}, {"cast", (PyCFunction)memory_cast, METH_VARARGS|METH_KEYWORDS, NULL}, - {"__enter__", memory_enter, METH_NOARGS}, - {"__exit__", memory_exit, METH_VARARGS}, + {"__enter__", memory_enter, METH_NOARGS, NULL}, + {"__exit__", memory_exit, METH_VARARGS, NULL}, {NULL, NULL} }; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 28 19:11:08 2012 From: python-checkins at python.org (richard.oudkerk) Date: Sat, 28 Jul 2012 19:11:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=231692335=3A_Move_i?= =?utf-8?q?nitial_args_assignment_to_BaseException=2E=5F=5Fnew=5F=5F?= Message-ID: <3WktqJ2t3QzPTf@mail.python.org> http://hg.python.org/cpython/rev/68e2690a471d changeset: 78304:68e2690a471d user: Richard Oudkerk date: Sat Jul 28 17:45:28 2012 +0100 summary: Issue #1692335: Move initial args assignment to BaseException.__new__ to help pickling of naive subclasses. files: Lib/test/test_exceptions.py | 16 +++++++++++++++- Misc/NEWS | 3 +++ Objects/exceptions.c | 11 ++++++++++- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -10,6 +10,15 @@ from test.support import (TESTFN, unlink, run_unittest, captured_output, gc_collect, cpython_only, no_tracing) +class NaiveException(Exception): + def __init__(self, x): + self.x = x + +class SlottedNaiveException(Exception): + __slots__ = ('x',) + def __init__(self, x): + self.x = x + # XXX This is not really enough, each *operation* should be tested! class ExceptionTests(unittest.TestCase): @@ -296,6 +305,10 @@ {'args' : ('\u3042', 0, 1, 'ouch'), 'object' : '\u3042', 'reason' : 'ouch', 'start' : 0, 'end' : 1}), + (NaiveException, ('foo',), + {'args': ('foo',), 'x': 'foo'}), + (SlottedNaiveException, ('foo',), + {'args': ('foo',), 'x': 'foo'}), ] try: # More tests are in test_WindowsError @@ -316,7 +329,8 @@ raise else: # Verify module name - self.assertEqual(type(e).__module__, 'builtins') + if not type(e).__name__.endswith('NaiveException'): + self.assertEqual(type(e).__module__, 'builtins') # Verify no ref leaks in Exc_str() s = str(e) for checkArgName in expected: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #1692335: Move initial args assignment to + BaseException.__new__ to help pickling of naive subclasses. + - Issue #12834: Fix PyBuffer_ToContiguous() for non-contiguous arrays. - Issue #15456: Fix code __sizeof__ after #12399 change. diff --git a/Objects/exceptions.c b/Objects/exceptions.c --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -44,6 +44,12 @@ self->traceback = self->cause = self->context = NULL; self->suppress_context = 0; + if (args) { + self->args = args; + Py_INCREF(args); + return (PyObject *)self; + } + self->args = PyTuple_New(0); if (!self->args) { Py_DECREF(self); @@ -56,12 +62,15 @@ static int BaseException_init(PyBaseExceptionObject *self, PyObject *args, PyObject *kwds) { + PyObject *tmp; + if (!_PyArg_NoKeywords(Py_TYPE(self)->tp_name, kwds)) return -1; - Py_XDECREF(self->args); + tmp = self->args; self->args = args; Py_INCREF(self->args); + Py_XDECREF(tmp); return 0; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 28 19:44:24 2012 From: python-checkins at python.org (martin.v.loewis) Date: Sat, 28 Jul 2012 19:44:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315466=3A_Stop_usi?= =?utf-8?q?ng_TYPE=5FINT64_in_marshal=2C?= Message-ID: <3WkvYh0SYQzPWD@mail.python.org> http://hg.python.org/cpython/rev/461e84fc8c60 changeset: 78305:461e84fc8c60 user: Martin v. L?wis date: Sat Jul 28 19:44:05 2012 +0200 summary: Issue #15466: Stop using TYPE_INT64 in marshal, to make importlib.h (and other byte code files) equal between 32-bit and 64-bit systems. files: Misc/NEWS | 3 + Python/importlib.h | 4666 ++++++++++++++++---------------- Python/marshal.c | 16 +- 3 files changed, 2341 insertions(+), 2344 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #15466: Stop using TYPE_INT64 in marshal, to make bytecode + files + - Issue #1692335: Move initial args assignment to BaseException.__new__ to help pickling of naive subclasses. diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -31,6 +31,9 @@ #define TYPE_STOPITER 'S' #define TYPE_ELLIPSIS '.' #define TYPE_INT 'i' +/* TYPE_INT64 is deprecated. It is not + generated anymore, and support for reading it + will be removed in Python 3.4. */ #define TYPE_INT64 'I' #define TYPE_FLOAT 'f' #define TYPE_BINARY_FLOAT 'g' @@ -121,15 +124,6 @@ w_byte((char)((x>>24) & 0xff), p); } -#if SIZEOF_LONG > 4 -static void -w_long64(long x, WFILE *p) -{ - w_long(x, p); - w_long(x>>32, p); -} -#endif - /* We assume that Python longs are stored internally in base some power of 2**15; for the sake of portability we'll always read and write them in base exactly 2**15. */ @@ -219,8 +213,8 @@ #if SIZEOF_LONG > 4 long y = Py_ARITHMETIC_RIGHT_SHIFT(long, x, 31); if (y && y != -1) { - w_byte(TYPE_INT64, p); - w_long64(x, p); + /* Too large for TYPE_INT */ + w_PyLong((PyLongObject*)v, p); } else #endif -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 28 19:51:52 2012 From: python-checkins at python.org (martin.v.loewis) Date: Sat, 28 Jul 2012 19:51:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Commit_unsaved_edits=2E?= Message-ID: <3WkvkJ4Bs3zPRy@mail.python.org> http://hg.python.org/cpython/rev/ec7267fa8b84 changeset: 78306:ec7267fa8b84 user: Martin v. L?wis date: Sat Jul 28 19:51:41 2012 +0200 summary: Commit unsaved edits. files: Misc/NEWS | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,8 +10,8 @@ Core and Builtins ----------------- -- Issue #15466: Stop using TYPE_INT64 in marshal, to make bytecode - files +- Issue #15466: Stop using TYPE_INT64 in marshal, to make importlib.h + (and other byte code files) equal between 32-bit and 64-bit systems. - Issue #1692335: Move initial args assignment to BaseException.__new__ to help pickling of naive subclasses. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 28 20:47:34 2012 From: python-checkins at python.org (martin.v.loewis) Date: Sat, 28 Jul 2012 20:47:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315431=3A_Add_=5Ff?= =?utf-8?q?reeze=5Fimportlib_project_to_regenerate_importlib=2Eh_on?= Message-ID: <3WkwyZ3NzdzPV3@mail.python.org> http://hg.python.org/cpython/rev/fe29a657bde9 changeset: 78307:fe29a657bde9 user: Martin v. L??wis date: Sat Jul 28 20:46:52 2012 +0200 summary: Issue #15431: Add _freeze_importlib project to regenerate importlib.h on Windows. Patch by Kristj??n Valur J??nsson. files: Misc/NEWS | 3 + Modules/_freeze_importlib.c | 11 +- PCbuild/_freeze_importlib.vcxproj | 188 ++++++++++ PCbuild/_freeze_importlib.vcxproj.filters | 27 + PCbuild/pcbuild.sln | 16 + 5 files changed, 241 insertions(+), 4 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -256,6 +256,9 @@ Build ----- +- Issue #15431: Add _freeze_importlib project to regenerate importlib.h + on Windows. Patch by Kristj?n Valur J?nsson. + - Issue #14197: For OS X framework builds, ensure links to the shared library are created with the proper ABI suffix. diff --git a/Modules/_freeze_importlib.c b/Modules/_freeze_importlib.c --- a/Modules/_freeze_importlib.c +++ b/Modules/_freeze_importlib.c @@ -8,7 +8,9 @@ #include #include #include +#ifndef MS_WINDOWS #include +#endif /* To avoid a circular dependency on frozen.o, we create our own structure @@ -19,9 +21,6 @@ {0, 0, 0} /* sentinel */ }; -struct _frozen *PyImport_FrozenModules = _PyImport_FrozenModules; - - const char header[] = "/* Auto-generated by Modules/_freeze_importlib.c */"; int @@ -35,6 +34,8 @@ unsigned char *data; PyObject *code, *marshalled; + PyImport_FrozenModules = _PyImport_FrozenModules; + if (argc != 3) { fprintf(stderr, "need to specify input and output paths\n"); return 2; @@ -89,7 +90,9 @@ data = (unsigned char *) PyBytes_AS_STRING(marshalled); data_size = PyBytes_GET_SIZE(marshalled); - outfile = fopen(outpath, "wb"); + /* Open the file in text mode. The hg checkout should be using the eol extension, + which in turn should cause the existing file to use CRLF */ + outfile = fopen(outpath, "wt"); if (outfile == NULL) { fprintf(stderr, "cannot open '%s' for writing\n", outpath); return 1; diff --git a/PCbuild/_freeze_importlib.vcxproj b/PCbuild/_freeze_importlib.vcxproj new file mode 100644 --- /dev/null +++ b/PCbuild/_freeze_importlib.vcxproj @@ -0,0 +1,188 @@ +??? + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {19C0C13F-47CA-4432-AFF3-799A296A4DDC} + Win32Proj + _freeze_importlib + + + + Application + true + Unicode + + + Application + true + Unicode + + + Application + false + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + $(TargetPath) ..\Lib\importlib\_bootstrap.py ..\Python\importlib.h + + + creating importlib.h + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + $(TargetPath) ..\Lib\importlib\_bootstrap.py ..\Python\importlib.h + + + creating importlib.h + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + $(TargetPath) ..\Lib\importlib\_bootstrap.py ..\Python\importlib.h + + + creating importlib.h + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + $(TargetPath) ..\Lib\importlib\_bootstrap.py ..\Python\importlib.h + + + creating importlib.h + + + + + + + + {cf7ac3d1-e2df-41d2-bea6-1e2556cdea26} + true + true + false + true + false + + + + + + + + + \ No newline at end of file diff --git a/PCbuild/_freeze_importlib.vcxproj.filters b/PCbuild/_freeze_importlib.vcxproj.filters new file mode 100644 --- /dev/null +++ b/PCbuild/_freeze_importlib.vcxproj.filters @@ -0,0 +1,27 @@ +??? + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Source Files + + + \ No newline at end of file diff --git a/PCbuild/pcbuild.sln b/PCbuild/pcbuild.sln --- a/PCbuild/pcbuild.sln +++ b/PCbuild/pcbuild.sln @@ -72,6 +72,8 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pywlauncher", "pywlauncher.vcxproj", "{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_freeze_importlib", "_freeze_importlib.vcxproj", "{19C0C13F-47CA-4432-AFF3-799A296A4DDC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -600,6 +602,20 @@ {1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Release|Win32.Build.0 = Release|Win32 {1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Release|x64.ActiveCfg = Release|Win32 {1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Release|x64.Build.0 = Release|Win32 + {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Debug|Win32.ActiveCfg = Debug|Win32 + {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Debug|Win32.Build.0 = Debug|Win32 + {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Debug|x64.ActiveCfg = Debug|x64 + {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Debug|x64.Build.0 = Debug|x64 + {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGInstrument|Win32.ActiveCfg = Release|Win32 + {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGInstrument|Win32.Build.0 = Release|Win32 + {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGInstrument|x64.ActiveCfg = Release|Win32 + {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGUpdate|Win32.ActiveCfg = Release|Win32 + {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGUpdate|Win32.Build.0 = Release|Win32 + {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGUpdate|x64.ActiveCfg = Release|Win32 + {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Release|Win32.ActiveCfg = Release|Win32 + {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Release|Win32.Build.0 = Release|Win32 + {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Release|x64.ActiveCfg = Release|x64 + {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 28 21:34:09 2012 From: python-checkins at python.org (martin.v.loewis) Date: Sat, 28 Jul 2012 21:34:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2314578=3A_Support_?= =?utf-8?q?modules_registered_in_the_Windows_registry_again=2E?= Message-ID: <3Wky0K5hhGzPWx@mail.python.org> http://hg.python.org/cpython/rev/bd58c421057c changeset: 78308:bd58c421057c user: Martin v. L?wis date: Sat Jul 28 21:33:05 2012 +0200 summary: Issue #14578: Support modules registered in the Windows registry again. Patch by Amaury Forgeot d'Arc. files: Lib/importlib/_bootstrap.py | 78 +- Misc/NEWS | 2 + Python/importlib.h | 8135 +++++++++++----------- 3 files changed, 4235 insertions(+), 3980 deletions(-) diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -722,6 +722,56 @@ return _imp.init_frozen(fullname) +class WindowsRegistryImporter: + + """Meta path import for modules declared in the Windows registry. + """ + + REGISTRY_KEY = ( + "Software\\Python\\PythonCore\\{sys_version}" + "\\Modules\\{fullname}") + REGISTRY_KEY_DEBUG = ( + "Software\\Python\\PythonCore\\{sys_version}" + "\\Modules\\{fullname}\\Debug") + DEBUG_BUILD = False # Changed in _setup() + + @classmethod + def _open_registry(cls, key): + try: + return _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, key) + except WindowsError: + return _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, key) + + @classmethod + def _search_registry(cls, fullname): + if cls.DEBUG_BUILD: + registry_key = cls.REGISTRY_KEY_DEBUG + else: + registry_key = cls.REGISTRY_KEY + key = registry_key.format(fullname=fullname, + sys_version=sys.version[:3]) + try: + with cls._open_registry(key) as hkey: + filepath = _winreg.QueryValue(hkey, "") + except WindowsError: + return None + return filepath + + @classmethod + def find_module(cls, fullname, path=None): + """Find module named in the registry.""" + filepath = cls._search_registry(fullname) + if filepath is None: + return None + try: + _os.stat(filepath) + except OSError: + return None + for loader, suffixes, _ in _get_supported_file_loaders(): + if filepath.endswith(tuple(suffixes)): + return loader(fullname, filepath) + + class _LoaderBasics: """Base class of common code needed by both SourceLoader and @@ -1538,6 +1588,17 @@ return package +def _get_supported_file_loaders(): + """Returns a list of file-based module loaders. + + Each item is a tuple (loader, suffixes, allow_packages). + """ + extensions = ExtensionFileLoader, _imp.extension_suffixes(), False + source = SourceFileLoader, SOURCE_SUFFIXES, True + bytecode = SourcelessFileLoader, BYTECODE_SUFFIXES, True + return [extensions, source, bytecode] + + def __import__(name, globals={}, locals={}, fromlist=[], level=0): """Import a module. @@ -1620,6 +1681,10 @@ thread_module = None weakref_module = BuiltinImporter.load_module('_weakref') + if builtin_os == 'nt': + winreg_module = BuiltinImporter.load_module('winreg') + setattr(self_module, '_winreg', winreg_module) + setattr(self_module, '_os', os_module) setattr(self_module, '_thread', thread_module) setattr(self_module, '_weakref', weakref_module) @@ -1629,14 +1694,17 @@ setattr(self_module, '_relax_case', _make_relax_case()) if builtin_os == 'nt': SOURCE_SUFFIXES.append('.pyw') + if '_d.pyd' in _imp.extension_suffixes(): + WindowsRegistryImporter.DEBUG_BUILD = True def _install(sys_module, _imp_module): """Install importlib as the implementation of import.""" _setup(sys_module, _imp_module) - extensions = ExtensionFileLoader, _imp_module.extension_suffixes(), False - source = SourceFileLoader, SOURCE_SUFFIXES, True - bytecode = SourcelessFileLoader, BYTECODE_SUFFIXES, True - supported_loaders = [extensions, source, bytecode] + supported_loaders = _get_supported_file_loaders() sys.path_hooks.extend([FileFinder.path_hook(*supported_loaders)]) - sys.meta_path.extend([BuiltinImporter, FrozenImporter, PathFinder]) + sys.meta_path.append(BuiltinImporter) + sys.meta_path.append(FrozenImporter) + if _os.__name__ == 'nt': + sys.meta_path.append(WindowsRegistryImporter) + sys.meta_path.append(PathFinder) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #14578: Support modules registered in the Windows registry again. + - Issue #15466: Stop using TYPE_INT64 in marshal, to make importlib.h (and other byte code files) equal between 32-bit and 64-bit systems. diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 28 21:55:52 2012 From: python-checkins at python.org (martin.v.loewis) Date: Sat, 28 Jul 2012 21:55:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315431=3A_Declare_?= =?utf-8?q?PyImport=5FFrozenModules_conditionally_on_Unix_only=2E?= Message-ID: <3WkyTN3z8CzN3P@mail.python.org> http://hg.python.org/cpython/rev/7967cb63e50e changeset: 78309:7967cb63e50e user: Martin v. L?wis date: Sat Jul 28 21:55:20 2012 +0200 summary: Issue #15431: Declare PyImport_FrozenModules conditionally on Unix only. files: Modules/_freeze_importlib.c | 11 +++++++++-- 1 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Modules/_freeze_importlib.c b/Modules/_freeze_importlib.c --- a/Modules/_freeze_importlib.c +++ b/Modules/_freeze_importlib.c @@ -21,6 +21,13 @@ {0, 0, 0} /* sentinel */ }; +#ifndef MS_WINDOWS +/* On Windows, this links with the regular pythonXY.dll, so this variable comes + from frozen.obj. In the Makefile, frozen.o is not linked into this executable, + so we define the variable here. */ +struct _frozen *PyImport_FrozenModules; +#endif + const char header[] = "/* Auto-generated by Modules/_freeze_importlib.c */"; int @@ -91,8 +98,8 @@ data_size = PyBytes_GET_SIZE(marshalled); /* Open the file in text mode. The hg checkout should be using the eol extension, - which in turn should cause the existing file to use CRLF */ - outfile = fopen(outpath, "wt"); + which in turn should cause the EOL style match the C library's text mode */ + outfile = fopen(outpath, "w"); if (outfile == NULL) { fprintf(stderr, "cannot open '%s' for writing\n", outpath); return 1; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jul 28 22:00:29 2012 From: python-checkins at python.org (martin.v.loewis) Date: Sat, 28 Jul 2012 22:00:29 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315431=3A_Drop_=5F?= =?utf-8?q?freeze=5Fimportlib_from_all_build_configurations=2C?= Message-ID: <3WkyZj2PXmzPS9@mail.python.org> http://hg.python.org/cpython/rev/deb421baf671 changeset: 78310:deb421baf671 user: Martin v. L?wis date: Sat Jul 28 21:59:05 2012 +0200 summary: Issue #15431: Drop _freeze_importlib from all build configurations, to prevent constant regeneration of importlib.h. files: PCbuild/pcbuild.sln | 6 ------ 1 files changed, 0 insertions(+), 6 deletions(-) diff --git a/PCbuild/pcbuild.sln b/PCbuild/pcbuild.sln --- a/PCbuild/pcbuild.sln +++ b/PCbuild/pcbuild.sln @@ -603,19 +603,13 @@ {1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Release|x64.ActiveCfg = Release|Win32 {1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Release|x64.Build.0 = Release|Win32 {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Debug|Win32.ActiveCfg = Debug|Win32 - {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Debug|Win32.Build.0 = Debug|Win32 {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Debug|x64.ActiveCfg = Debug|x64 - {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Debug|x64.Build.0 = Debug|x64 {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGInstrument|Win32.ActiveCfg = Release|Win32 - {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGInstrument|Win32.Build.0 = Release|Win32 {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGInstrument|x64.ActiveCfg = Release|Win32 {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGUpdate|Win32.ActiveCfg = Release|Win32 - {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGUpdate|Win32.Build.0 = Release|Win32 {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGUpdate|x64.ActiveCfg = Release|Win32 {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Release|Win32.ActiveCfg = Release|Win32 - {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Release|Win32.Build.0 = Release|Win32 {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Release|x64.ActiveCfg = Release|x64 - {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 29 05:36:16 2012 From: python-checkins at python.org (meador.inge) Date: Sun, 29 Jul 2012 05:36:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE1NDAy?= =?utf-8?q?=3A_Simplify_Struct=2E=5F=5Fsizeof=5F=5F_and_make_tests_more_pr?= =?utf-8?q?ecise=2E?= Message-ID: <3Wl8hc0HMvzPWR@mail.python.org> http://hg.python.org/cpython/rev/37554bda2014 changeset: 78311:37554bda2014 branch: 2.7 parent: 78296:4e85e4743757 user: Meador Inge date: Sat Jul 28 21:58:44 2012 -0500 summary: Issue #15402: Simplify Struct.__sizeof__ and make tests more precise. files: Lib/test/test_struct.py | 52 +++++++++++++++++++++++----- Modules/_struct.c | 8 +--- 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -3,7 +3,8 @@ import unittest import struct import inspect -from test.test_support import run_unittest, check_warnings, check_py3k_warnings +from test.test_support import (run_unittest, check_warnings, + check_py3k_warnings, cpython_only) import sys ISBIGENDIAN = sys.byteorder == "big" @@ -32,6 +33,33 @@ class StructTest(unittest.TestCase): + def setUp(self): + # due to missing size_t information from struct, it is assumed that + # sizeof(Py_ssize_t) = sizeof(void*) + self.header = 'PP' + if hasattr(sys, "gettotalrefcount"): + self.header += '2P' + + def check_sizeof(self, format_str, number_of_codes): + def size(fmt): + """Wrapper around struct.calcsize which enforces the alignment + of the end of a structure to the alignment requirement of pointer. + + Note: This wrapper should only be used if a pointer member is + included and no member with a size larger than a pointer exists. + """ + return struct.calcsize(fmt + '0P') + + struct_obj = struct.Struct(format_str) + # The size of 'PyStructObject' + totalsize = size(self.header + '5P') + # The size taken up by the 'formatcode' dynamic array + totalsize += size('3P') * (number_of_codes + 1) + result = sys.getsizeof(struct_obj) + msg = 'wrong size for %s: got %d, expected %d' \ + % (type(struct_obj), result, totalsize) + self.assertEqual(result, totalsize, msg) + def check_float_coerce(self, format, number): # SF bug 1530559. struct.pack raises TypeError where it used # to convert. @@ -544,15 +572,19 @@ hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2) self.assertRaises(struct.error, struct.calcsize, hugecount2) - def test_sizeof(self): - self.assertGreater(sys.getsizeof(struct.Struct('BHILfdspP')), - sys.getsizeof(struct.Struct('B'))) - self.assertGreater(sys.getsizeof(struct.Struct('123B')), - sys.getsizeof(struct.Struct('B'))) - self.assertGreater(sys.getsizeof(struct.Struct('B' * 1234)), - sys.getsizeof(struct.Struct('123B'))) - self.assertGreater(sys.getsizeof(struct.Struct('1234B')), - sys.getsizeof(struct.Struct('123B'))) + @cpython_only + def test__sizeof__(self): + for code in integer_codes: + self.check_sizeof(code, 1) + self.check_sizeof('BHILfdspP', 9) + self.check_sizeof('B' * 1234, 1234) + self.check_sizeof('fd', 2) + self.check_sizeof('xxxxxxxxxxxxxx', 0) + self.check_sizeof('100H', 100) + self.check_sizeof('187s', 1) + self.check_sizeof('20p', 1) + self.check_sizeof('0s', 1) + self.check_sizeof('0c', 0) def test_main(): run_unittest(StructTest) diff --git a/Modules/_struct.c b/Modules/_struct.c --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -1697,15 +1697,11 @@ "S.__sizeof__() -> size of S in memory, in bytes"); static PyObject * -s_sizeof(PyStructObject *self) +s_sizeof(PyStructObject *self, void *unused) { Py_ssize_t size; - formatcode *code; - size = sizeof(PyStructObject) + sizeof(formatcode); - for (code = self->s_codes; code->fmtdef != NULL; code++) { - size += sizeof(formatcode); - } + size = sizeof(PyStructObject) + sizeof(formatcode) * (self->s_len + 1); return PyLong_FromSsize_t(size); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 29 05:36:18 2012 From: python-checkins at python.org (meador.inge) Date: Sun, 29 Jul 2012 05:36:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE1NDAy?= =?utf-8?q?=3A_Simplify_Struct=2E=5F=5Fsizeof=5F=5F_and_make_tests_more_pr?= =?utf-8?q?ecise=2E?= Message-ID: <3Wl8hf66RCzPXx@mail.python.org> http://hg.python.org/cpython/rev/97dd2090a36c changeset: 78312:97dd2090a36c branch: 3.2 parent: 78297:290f04722be3 user: Meador Inge date: Sat Jul 28 22:16:39 2012 -0500 summary: Issue #15402: Simplify Struct.__sizeof__ and make tests more precise. files: Lib/test/test_struct.py | 51 +++++++++++++++++++++++----- Modules/_struct.c | 8 +--- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -3,7 +3,7 @@ import struct import sys -from test.support import run_unittest +from test.support import run_unittest, cpython_only ISBIGENDIAN = sys.byteorder == "big" IS32BIT = sys.maxsize == 0x7fffffff @@ -30,6 +30,33 @@ return string_reverse(value) class StructTest(unittest.TestCase): + def setUp(self): + # due to missing size_t information from struct, it is assumed that + # sizeof(Py_ssize_t) = sizeof(void*) + self.header = 'PP' + if hasattr(sys, "gettotalrefcount"): + self.header += '2P' + + def check_sizeof(self, format_str, number_of_codes): + def size(fmt): + """Wrapper around struct.calcsize which enforces the alignment + of the end of a structure to the alignment requirement of pointer. + + Note: This wrapper should only be used if a pointer member is + included and no member with a size larger than a pointer exists. + """ + return struct.calcsize(fmt + '0P') + + struct_obj = struct.Struct(format_str) + # The size of 'PyStructObject' + totalsize = size(self.header + '5P') + # The size taken up by the 'formatcode' dynamic array + totalsize += size('3P') * (number_of_codes + 1) + result = sys.getsizeof(struct_obj) + msg = 'wrong size for %s: got %d, expected %d' \ + % (type(struct_obj), result, totalsize) + self.assertEqual(result, totalsize, msg) + def test_isbigendian(self): self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN) @@ -556,15 +583,19 @@ s = struct.Struct('i') s.__init__('ii') - def test_sizeof(self): - self.assertGreater(sys.getsizeof(struct.Struct('BHILfdspP')), - sys.getsizeof(struct.Struct('B'))) - self.assertGreater(sys.getsizeof(struct.Struct('123B')), - sys.getsizeof(struct.Struct('B'))) - self.assertGreater(sys.getsizeof(struct.Struct('B' * 1234)), - sys.getsizeof(struct.Struct('123B'))) - self.assertGreater(sys.getsizeof(struct.Struct('1234B')), - sys.getsizeof(struct.Struct('123B'))) + @cpython_only + def test__sizeof__(self): + for code in integer_codes: + self.check_sizeof(code, 1) + self.check_sizeof('BHILfdspP', 9) + self.check_sizeof('B' * 1234, 1234) + self.check_sizeof('fd', 2) + self.check_sizeof('xxxxxxxxxxxxxx', 0) + self.check_sizeof('100H', 100) + self.check_sizeof('187s', 1) + self.check_sizeof('20p', 1) + self.check_sizeof('0s', 1) + self.check_sizeof('0c', 0) def test_main(): run_unittest(StructTest) diff --git a/Modules/_struct.c b/Modules/_struct.c --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -1669,15 +1669,11 @@ "S.__sizeof__() -> size of S in memory, in bytes"); static PyObject * -s_sizeof(PyStructObject *self) +s_sizeof(PyStructObject *self, void *unused) { Py_ssize_t size; - formatcode *code; - size = sizeof(PyStructObject) + sizeof(formatcode); - for (code = self->s_codes; code->fmtdef != NULL; code++) { - size += sizeof(formatcode); - } + size = sizeof(PyStructObject) + sizeof(formatcode) * (self->s_len + 1); return PyLong_FromSsize_t(size); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 29 05:36:20 2012 From: python-checkins at python.org (meador.inge) Date: Sun, 29 Jul 2012 05:36:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?b?KTogSXNzdWUgIzE1NDAyOiBTaW1wbGlmeSBTdHJ1Y3QuX19zaXplb2ZfXyBh?= =?utf-8?q?nd_make_tests_more_precise=2E?= Message-ID: <3Wl8hh3yyDzPXT@mail.python.org> http://hg.python.org/cpython/rev/0eedf56f9a38 changeset: 78313:0eedf56f9a38 parent: 78310:deb421baf671 parent: 78312:97dd2090a36c user: Meador Inge date: Sat Jul 28 22:32:50 2012 -0500 summary: Issue #15402: Simplify Struct.__sizeof__ and make tests more precise. files: Lib/test/test_struct.py | 51 +++++++++++++++++++++++----- Modules/_struct.c | 8 +--- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -3,7 +3,7 @@ import struct import sys -from test.support import run_unittest +from test.support import run_unittest, cpython_only ISBIGENDIAN = sys.byteorder == "big" IS32BIT = sys.maxsize == 0x7fffffff @@ -40,6 +40,33 @@ return string_reverse(value) class StructTest(unittest.TestCase): + def setUp(self): + # due to missing size_t information from struct, it is assumed that + # sizeof(Py_ssize_t) = sizeof(void*) + self.header = 'PP' + if hasattr(sys, "gettotalrefcount"): + self.header += '2P' + + def check_sizeof(self, format_str, number_of_codes): + def size(fmt): + """Wrapper around struct.calcsize which enforces the alignment + of the end of a structure to the alignment requirement of pointer. + + Note: This wrapper should only be used if a pointer member is + included and no member with a size larger than a pointer exists. + """ + return struct.calcsize(fmt + '0P') + + struct_obj = struct.Struct(format_str) + # The size of 'PyStructObject' + totalsize = size(self.header + '5P') + # The size taken up by the 'formatcode' dynamic array + totalsize += size('3P') * (number_of_codes + 1) + result = sys.getsizeof(struct_obj) + msg = 'wrong size for %s: got %d, expected %d' \ + % (type(struct_obj), result, totalsize) + self.assertEqual(result, totalsize, msg) + def test_isbigendian(self): self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN) @@ -572,15 +599,19 @@ s = struct.Struct('i') s.__init__('ii') - def test_sizeof(self): - self.assertGreater(sys.getsizeof(struct.Struct('BHILfdspP')), - sys.getsizeof(struct.Struct('B'))) - self.assertGreater(sys.getsizeof(struct.Struct('123B')), - sys.getsizeof(struct.Struct('B'))) - self.assertGreater(sys.getsizeof(struct.Struct('B' * 1234)), - sys.getsizeof(struct.Struct('123B'))) - self.assertGreater(sys.getsizeof(struct.Struct('1234B')), - sys.getsizeof(struct.Struct('123B'))) + @cpython_only + def test__sizeof__(self): + for code in integer_codes: + self.check_sizeof(code, 1) + self.check_sizeof('BHILfdspP', 9) + self.check_sizeof('B' * 1234, 1234) + self.check_sizeof('fd', 2) + self.check_sizeof('xxxxxxxxxxxxxx', 0) + self.check_sizeof('100H', 100) + self.check_sizeof('187s', 1) + self.check_sizeof('20p', 1) + self.check_sizeof('0s', 1) + self.check_sizeof('0c', 0) def test_main(): run_unittest(StructTest) diff --git a/Modules/_struct.c b/Modules/_struct.c --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -1756,15 +1756,11 @@ "S.__sizeof__() -> size of S in memory, in bytes"); static PyObject * -s_sizeof(PyStructObject *self) +s_sizeof(PyStructObject *self, void *unused) { Py_ssize_t size; - formatcode *code; - size = sizeof(PyStructObject) + sizeof(formatcode); - for (code = self->s_codes; code->fmtdef != NULL; code++) { - size += sizeof(formatcode); - } + size = sizeof(PyStructObject) + sizeof(formatcode) * (self->s_len + 1); return PyLong_FromSsize_t(size); } -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sun Jul 29 06:01:35 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 29 Jul 2012 06:01:35 +0200 Subject: [Python-checkins] Daily reference leaks (deb421baf671): sum=0 Message-ID: results for deb421baf671 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogB1Zu5x', '-x'] From python-checkins at python.org Sun Jul 29 10:09:05 2012 From: python-checkins at python.org (martin.v.loewis) Date: Sun, 29 Jul 2012 10:09:05 +0200 (CEST) Subject: [Python-checkins] r88981 - tracker Message-ID: <3WlGlP6NYZzPXB@mail.python.org> Author: martin.v.loewis Date: Sun Jul 29 10:09:05 2012 New Revision: 88981 Log: The tracker is now in Mercurial, on hg.python.org/tracker. Removed: tracker/ From python-checkins at python.org Sun Jul 29 12:30:52 2012 From: python-checkins at python.org (nick.coghlan) Date: Sun, 29 Jul 2012 12:30:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Close_=2315425=3A_Eliminat?= =?utf-8?q?e_more_importlib_related_traceback_noise?= Message-ID: <3WlKv02C6CzPVg@mail.python.org> http://hg.python.org/cpython/rev/75a30a478dc7 changeset: 78314:75a30a478dc7 user: Nick Coghlan date: Sun Jul 29 20:30:36 2012 +1000 summary: Close #15425: Eliminate more importlib related traceback noise files: Lib/importlib/_bootstrap.py | 11 +- Lib/test/test_import.py | 68 + Misc/NEWS | 3 + Python/import.c | 30 +- Python/importlib.h | 8325 +++++++++++----------- 5 files changed, 4281 insertions(+), 4156 deletions(-) diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -1472,7 +1472,7 @@ parent = name.rpartition('.')[0] if parent: if parent not in sys.modules: - import_(parent) + _recursive_import(import_, parent) # Crazy side-effects! if name in sys.modules: return sys.modules[name] @@ -1550,6 +1550,12 @@ _lock_unlock_module(name) return module +def _recursive_import(import_, name): + """Common exit point for recursive calls to the import machinery + + This simplifies the process of stripping importlib from tracebacks + """ + return import_(name) def _handle_fromlist(module, fromlist, import_): """Figure out what __import__ should return. @@ -1569,7 +1575,8 @@ fromlist.extend(module.__all__) for x in fromlist: if not hasattr(module, x): - import_('{}.{}'.format(module.__name__, x)) + _recursive_import(import_, + '{}.{}'.format(module.__name__, x)) return module diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -844,6 +844,74 @@ self.fail("ZeroDivisionError should have been raised") self.assert_traceback(tb, [__file__, 'foo.py', 'bar.py']) + # A few more examples from issue #15425 + def test_syntax_error(self): + self.create_module("foo", "invalid syntax is invalid") + try: + import foo + except SyntaxError as e: + tb = e.__traceback__ + else: + self.fail("SyntaxError should have been raised") + self.assert_traceback(tb, [__file__]) + + def _setup_broken_package(self, parent, child): + pkg_name = "_parent_foo" + def cleanup(): + rmtree(pkg_name) + unload(pkg_name) + os.mkdir(pkg_name) + self.addCleanup(cleanup) + # Touch the __init__.py + init_path = os.path.join(pkg_name, '__init__.py') + with open(init_path, 'w') as f: + f.write(parent) + bar_path = os.path.join(pkg_name, 'bar.py') + with open(bar_path, 'w') as f: + f.write(child) + importlib.invalidate_caches() + return init_path, bar_path + + def test_broken_submodule(self): + init_path, bar_path = self._setup_broken_package("", "1/0") + try: + import _parent_foo.bar + except ZeroDivisionError as e: + tb = e.__traceback__ + else: + self.fail("ZeroDivisionError should have been raised") + self.assert_traceback(tb, [__file__, bar_path]) + + def test_broken_from(self): + init_path, bar_path = self._setup_broken_package("", "1/0") + try: + from _parent_foo import bar + except ZeroDivisionError as e: + tb = e.__traceback__ + else: + self.fail("ImportError should have been raised") + self.assert_traceback(tb, [__file__, bar_path]) + + def test_broken_parent(self): + init_path, bar_path = self._setup_broken_package("1/0", "") + try: + import _parent_foo.bar + except ZeroDivisionError as e: + tb = e.__traceback__ + else: + self.fail("ZeroDivisionError should have been raised") + self.assert_traceback(tb, [__file__, init_path]) + + def test_broken_parent_from(self): + init_path, bar_path = self._setup_broken_package("1/0", "") + try: + from _parent_foo import bar + except ZeroDivisionError as e: + tb = e.__traceback__ + else: + self.fail("ZeroDivisionError should have been raised") + self.assert_traceback(tb, [__file__, init_path]) + @cpython_only def test_import_bug(self): # We simulate a bug in importlib and check that it's not stripped diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #15425: Eliminated traceback noise from more situations involving + importlib + - Issue #14578: Support modules registered in the Windows registry again. - Issue #15466: Stop using TYPE_INT64 in marshal, to make importlib.h diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -1154,14 +1154,27 @@ { const char *importlib_filename = ""; const char *exec_funcname = "_exec_module"; + const char *get_code_funcname = "get_code"; + const char *recursive_import = "_recursive_import"; int always_trim = 0; + int trim_get_code = 0; int in_importlib = 0; PyObject *exception, *value, *base_tb, *tb; PyObject **prev_link, **outer_link = NULL; /* Synopsis: if it's an ImportError, we trim all importlib chunks - from the traceback. Otherwise, we trim only those chunks which - end with a call to "_exec_module". */ + from the traceback. If it's a SyntaxError, we trim any chunks that + end with a call to "get_code", We always trim chunks + which end with a call to "_exec_module". */ + + /* Thanks to issue 15425, we also strip any chunk ending with + * _recursive_import. This is used when making a recursive call to the + * full import machinery which means the inner stack gets stripped early + * and the normal heuristics won't fire properly for outer frames. A + * more elegant mechanism would be nice, as this one can misfire if + * builtins.__import__ has been replaced with a custom implementation. + * However, the current approach at least gets the job done. + */ PyErr_Fetch(&exception, &value, &base_tb); if (!exception || Py_VerboseFlag) @@ -1169,6 +1182,9 @@ if (PyType_IsSubtype((PyTypeObject *) exception, (PyTypeObject *) PyExc_ImportError)) always_trim = 1; + if (PyType_IsSubtype((PyTypeObject *) exception, + (PyTypeObject *) PyExc_SyntaxError)) + trim_get_code = 1; prev_link = &base_tb; tb = base_tb; @@ -1191,8 +1207,14 @@ if (in_importlib && (always_trim || - PyUnicode_CompareWithASCIIString(code->co_name, - exec_funcname) == 0)) { + (PyUnicode_CompareWithASCIIString(code->co_name, + exec_funcname) == 0) || + (PyUnicode_CompareWithASCIIString(code->co_name, + recursive_import) == 0) || + (trim_get_code && + PyUnicode_CompareWithASCIIString(code->co_name, + get_code_funcname) == 0) + )) { PyObject *tmp = *outer_link; *outer_link = next; Py_XINCREF(next); diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 29 16:39:02 2012 From: python-checkins at python.org (martin.v.loewis) Date: Sun, 29 Jul 2012 16:39:02 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE1NDY3?= =?utf-8?q?=3A_Move_helpers_for_=5F=5Fsizeof=5F=5F_tests_into_test=5Fsuppo?= =?utf-8?b?cnQu?= Message-ID: <3WlRPL24SgzPYt@mail.python.org> http://hg.python.org/cpython/rev/efade142ef01 changeset: 78315:efade142ef01 branch: 3.2 parent: 78312:97dd2090a36c user: Martin v. L?wis date: Sun Jul 29 16:33:05 2012 +0200 summary: Issue #15467: Move helpers for __sizeof__ tests into test_support. Patch by Serhiy Storchaka. files: Lib/test/support.py | 28 +++ Lib/test/test_struct.py | 39 +---- Lib/test/test_sys.py | 202 +++++++++++---------------- Misc/NEWS | 3 + 4 files changed, 124 insertions(+), 148 deletions(-) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -23,6 +23,9 @@ import sysconfig import fnmatch import logging.handlers +import struct +import tempfile +import _testcapi try: import _thread, threading @@ -984,6 +987,31 @@ return final_opt and final_opt != '-O0' +_header = '2P' +if hasattr(sys, "gettotalrefcount"): + _header = '2P' + _header +_vheader = _header + 'P' + +def calcobjsize(fmt): + return struct.calcsize(_header + fmt + '0P') + +def calcvobjsize(fmt): + return struct.calcsize(_vheader + fmt + '0P') + + +_TPFLAGS_HAVE_GC = 1<<14 +_TPFLAGS_HEAPTYPE = 1<<9 + +def check_sizeof(test, o, size): + result = sys.getsizeof(o) + # add GC header size + if ((type(o) == type) and (o.__flags__ & _TPFLAGS_HEAPTYPE) or\ + ((type(o) != type) and (type(o).__flags__ & _TPFLAGS_HAVE_GC))): + size += _testcapi.SIZEOF_PYGC_HEAD + msg = 'wrong size for %s: got %d, expected %d' \ + % (type(o), result, size) + test.assertEqual(result, size, msg) + #======================================================================= # Decorator for running a function in a different locale, correctly resetting # it afterwards. diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -3,7 +3,7 @@ import struct import sys -from test.support import run_unittest, cpython_only +from test import support ISBIGENDIAN = sys.byteorder == "big" IS32BIT = sys.maxsize == 0x7fffffff @@ -30,32 +30,6 @@ return string_reverse(value) class StructTest(unittest.TestCase): - def setUp(self): - # due to missing size_t information from struct, it is assumed that - # sizeof(Py_ssize_t) = sizeof(void*) - self.header = 'PP' - if hasattr(sys, "gettotalrefcount"): - self.header += '2P' - - def check_sizeof(self, format_str, number_of_codes): - def size(fmt): - """Wrapper around struct.calcsize which enforces the alignment - of the end of a structure to the alignment requirement of pointer. - - Note: This wrapper should only be used if a pointer member is - included and no member with a size larger than a pointer exists. - """ - return struct.calcsize(fmt + '0P') - - struct_obj = struct.Struct(format_str) - # The size of 'PyStructObject' - totalsize = size(self.header + '5P') - # The size taken up by the 'formatcode' dynamic array - totalsize += size('3P') * (number_of_codes + 1) - result = sys.getsizeof(struct_obj) - msg = 'wrong size for %s: got %d, expected %d' \ - % (type(struct_obj), result, totalsize) - self.assertEqual(result, totalsize, msg) def test_isbigendian(self): self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN) @@ -583,7 +557,14 @@ s = struct.Struct('i') s.__init__('ii') - @cpython_only + def check_sizeof(self, format_str, number_of_codes): + # The size of 'PyStructObject' + totalsize = support.calcobjsize('5P') + # The size taken up by the 'formatcode' dynamic array + totalsize += struct.calcsize('3P') * (number_of_codes + 1) + support.check_sizeof(self, struct.Struct(format_str), totalsize) + + @support.cpython_only def test__sizeof__(self): for code in integer_codes: self.check_sizeof(code, 1) @@ -598,7 +579,7 @@ self.check_sizeof('0c', 0) def test_main(): - run_unittest(StructTest) + support.run_unittest(StructTest) if __name__ == '__main__': test_main() diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -570,22 +570,8 @@ class SizeofTest(unittest.TestCase): - TPFLAGS_HAVE_GC = 1<<14 - TPFLAGS_HEAPTYPE = 1<<9 - def setUp(self): - self.c = len(struct.pack('c', b' ')) - self.H = len(struct.pack('H', 0)) - self.i = len(struct.pack('i', 0)) - self.l = len(struct.pack('l', 0)) - self.P = len(struct.pack('P', 0)) - # due to missing size_t information from struct, it is assumed that - # sizeof(Py_ssize_t) = sizeof(void*) - self.header = 'PP' - self.vheader = self.header + 'P' - if hasattr(sys, "gettotalrefcount"): - self.header += '2P' - self.vheader += '2P' + self.P = struct.calcsize('P') self.longdigit = sys.int_info.sizeof_digit import _testcapi self.gc_headsize = _testcapi.SIZEOF_PYGC_HEAD @@ -595,123 +581,102 @@ self.file.close() test.support.unlink(test.support.TESTFN) - def check_sizeof(self, o, size): - result = sys.getsizeof(o) - # add GC header size - if ((type(o) == type) and (o.__flags__ & self.TPFLAGS_HEAPTYPE) or\ - ((type(o) != type) and (type(o).__flags__ & self.TPFLAGS_HAVE_GC))): - size += self.gc_headsize - msg = 'wrong size for %s: got %d, expected %d' \ - % (type(o), result, size) - self.assertEqual(result, size, msg) - - def calcsize(self, fmt): - """Wrapper around struct.calcsize which enforces the alignment of the - end of a structure to the alignment requirement of pointer. - - Note: This wrapper should only be used if a pointer member is included - and no member with a size larger than a pointer exists. - """ - return struct.calcsize(fmt + '0P') + check_sizeof = test.support.check_sizeof def test_gc_head_size(self): # Check that the gc header size is added to objects tracked by the gc. - h = self.header - vh = self.vheader - size = self.calcsize + vsize = test.support.calcvobjsize gc_header_size = self.gc_headsize # bool objects are not gc tracked - self.assertEqual(sys.getsizeof(True), size(vh) + self.longdigit) + self.assertEqual(sys.getsizeof(True), vsize('') + self.longdigit) # but lists are - self.assertEqual(sys.getsizeof([]), size(vh + 'PP') + gc_header_size) + self.assertEqual(sys.getsizeof([]), vsize('PP') + gc_header_size) def test_default(self): - h = self.header - vh = self.vheader - size = self.calcsize - self.assertEqual(sys.getsizeof(True), size(vh) + self.longdigit) - self.assertEqual(sys.getsizeof(True, -1), size(vh) + self.longdigit) + vsize = test.support.calcvobjsize + self.assertEqual(sys.getsizeof(True), vsize('') + self.longdigit) + self.assertEqual(sys.getsizeof(True, -1), vsize('') + self.longdigit) def test_objecttypes(self): # check all types defined in Objects/ - h = self.header - vh = self.vheader - size = self.calcsize + size = test.support.calcobjsize + vsize = test.support.calcvobjsize check = self.check_sizeof # bool - check(True, size(vh) + self.longdigit) + check(True, vsize('') + self.longdigit) # buffer # XXX # builtin_function_or_method - check(len, size(h + '3P')) + check(len, size('3P')) # XXX check layout # bytearray samples = [b'', b'u'*100000] for sample in samples: x = bytearray(sample) - check(x, size(vh + 'iPP') + x.__alloc__() * self.c) + check(x, vsize('iPP') + x.__alloc__()) # bytearray_iterator - check(iter(bytearray()), size(h + 'PP')) + check(iter(bytearray()), size('PP')) # cell def get_cell(): x = 42 def inner(): return x return inner - check(get_cell().__closure__[0], size(h + 'P')) + check(get_cell().__closure__[0], size('P')) # code - check(get_cell().__code__, size(h + '5i8Pi3P')) + check(get_cell().__code__, size('5i8Pi3P')) # complex - check(complex(0,1), size(h + '2d')) + check(complex(0,1), size('2d')) # method_descriptor (descriptor object) - check(str.lower, size(h + '2PP')) + check(str.lower, size('2PP')) # classmethod_descriptor (descriptor object) # XXX # member_descriptor (descriptor object) import datetime - check(datetime.timedelta.days, size(h + '2PP')) + check(datetime.timedelta.days, size('2PP')) # getset_descriptor (descriptor object) import collections - check(collections.defaultdict.default_factory, size(h + '2PP')) + check(collections.defaultdict.default_factory, size('2PP')) # wrapper_descriptor (descriptor object) - check(int.__add__, size(h + '2P2P')) + check(int.__add__, size('2P2P')) # method-wrapper (descriptor object) - check({}.__iter__, size(h + '2P')) + check({}.__iter__, size('2P')) # dict - check({}, size(h + '3P2P' + 8*'P2P')) + check({}, size('3P2P' + 8*'P2P')) longdict = {1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8} - check(longdict, size(h + '3P2P' + 8*'P2P') + 16*size('P2P')) + check(longdict, size('3P2P' + 8*'P2P') + 16*struct.calcsize('P2P')) # dictionary-keyiterator - check({}.keys(), size(h + 'P')) + check({}.keys(), size('P')) # dictionary-valueiterator - check({}.values(), size(h + 'P')) + check({}.values(), size('P')) # dictionary-itemiterator - check({}.items(), size(h + 'P')) + check({}.items(), size('P')) + # dictionary iterator + check(iter({}), size('P2PPP')) # dictproxy class C(object): pass - check(C.__dict__, size(h + 'P')) + check(C.__dict__, size('P')) # BaseException - check(BaseException(), size(h + '5P')) + check(BaseException(), size('5P')) # UnicodeEncodeError - check(UnicodeEncodeError("", "", 0, 0, ""), size(h + '5P 2P2PP')) + check(UnicodeEncodeError("", "", 0, 0, ""), size('5P 2P2PP')) # UnicodeDecodeError - # XXX -# check(UnicodeDecodeError("", "", 0, 0, ""), size(h + '5P2PP')) + check(UnicodeDecodeError("", b"", 0, 0, ""), size('5P 2P2PP')) # UnicodeTranslateError - check(UnicodeTranslateError("", 0, 1, ""), size(h + '5P 2P2PP')) + check(UnicodeTranslateError("", 0, 1, ""), size('5P 2P2PP')) # ellipses - check(Ellipsis, size(h + '')) + check(Ellipsis, size('')) # EncodingMap import codecs, encodings.iso8859_3 x = codecs.charmap_build(encodings.iso8859_3.decoding_table) - check(x, size(h + '32B2iB')) + check(x, size('32B2iB')) # enumerate - check(enumerate([]), size(h + 'l3P')) + check(enumerate([]), size('l3P')) # reverse - check(reversed(''), size(h + 'PP')) + check(reversed(''), size('PP')) # float - check(float(0), size(h + 'd')) + check(float(0), size('d')) # sys.floatinfo - check(sys.float_info, size(vh) + self.P * len(sys.float_info)) + check(sys.float_info, vsize('') + self.P * len(sys.float_info)) # frame import inspect CO_MAXBLOCKS = 20 @@ -720,10 +685,10 @@ nfrees = len(x.f_code.co_freevars) extras = x.f_code.co_stacksize + x.f_code.co_nlocals +\ ncells + nfrees - 1 - check(x, size(vh + '12P3i' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P')) + check(x, vsize('12P3i' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P')) # function def func(): pass - check(func, size(h + '11P')) + check(func, size('11P')) class c(): @staticmethod def foo(): @@ -732,68 +697,68 @@ def bar(cls): pass # staticmethod - check(foo, size(h + 'P')) + check(foo, size('P')) # classmethod - check(bar, size(h + 'P')) + check(bar, size('P')) # generator def get_gen(): yield 1 - check(get_gen(), size(h + 'Pi2P')) + check(get_gen(), size('Pi2P')) # iterator - check(iter('abc'), size(h + 'lP')) + check(iter('abc'), size('lP')) # callable-iterator import re - check(re.finditer('',''), size(h + '2P')) + check(re.finditer('',''), size('2P')) # list samples = [[], [1,2,3], ['1', '2', '3']] for sample in samples: - check(sample, size(vh + 'PP') + len(sample)*self.P) + check(sample, vsize('PP') + len(sample)*self.P) # sortwrapper (list) # XXX # cmpwrapper (list) # XXX # listiterator (list) - check(iter([]), size(h + 'lP')) + check(iter([]), size('lP')) # listreverseiterator (list) - check(reversed([]), size(h + 'lP')) + check(reversed([]), size('lP')) # long - check(0, size(vh)) - check(1, size(vh) + self.longdigit) - check(-1, size(vh) + self.longdigit) + check(0, vsize('')) + check(1, vsize('') + self.longdigit) + check(-1, vsize('') + self.longdigit) PyLong_BASE = 2**sys.int_info.bits_per_digit - check(int(PyLong_BASE), size(vh) + 2*self.longdigit) - check(int(PyLong_BASE**2-1), size(vh) + 2*self.longdigit) - check(int(PyLong_BASE**2), size(vh) + 3*self.longdigit) - # memory - check(memoryview(b''), size(h + 'PP2P2i7P')) + check(int(PyLong_BASE), vsize('') + 2*self.longdigit) + check(int(PyLong_BASE**2-1), vsize('') + 2*self.longdigit) + check(int(PyLong_BASE**2), vsize('') + 3*self.longdigit) + # memoryview + check(memoryview(b''), size('PP2P2i7P')) # module - check(unittest, size(h + '3P')) + check(unittest, size('3P')) # None - check(None, size(h + '')) + check(None, size('')) # NotImplementedType - check(NotImplemented, size(h)) + check(NotImplemented, size('')) # object - check(object(), size(h + '')) + check(object(), size('')) # property (descriptor object) class C(object): def getx(self): return self.__x def setx(self, value): self.__x = value def delx(self): del self.__x x = property(getx, setx, delx, "") - check(x, size(h + '4Pi')) + check(x, size('4Pi')) # PyCapsule # XXX # rangeiterator - check(iter(range(1)), size(h + '4l')) + check(iter(range(1)), size('4l')) # reverse - check(reversed(''), size(h + 'PP')) + check(reversed(''), size('PP')) # range - check(range(1), size(h + '4P')) - check(range(66000), size(h + '4P')) + check(range(1), size('4P')) + check(range(66000), size('4P')) # set # frozenset PySet_MINSIZE = 8 samples = [[], range(10), range(50)] - s = size(h + '3P2P' + PySet_MINSIZE*'lP' + 'lP') + s = size('3P2P' + PySet_MINSIZE*'PP' + 'PP') for sample in samples: minused = len(sample) if minused == 0: tmp = 1 @@ -810,18 +775,18 @@ check(set(sample), s + newsize*struct.calcsize('lP')) check(frozenset(sample), s + newsize*struct.calcsize('lP')) # setiterator - check(iter(set()), size(h + 'P3P')) + check(iter(set()), size('P3P')) # slice - check(slice(0), size(h + '3P')) + check(slice(0), size('3P')) # super - check(super(int), size(h + '3P')) + check(super(int), size('3P')) # tuple - check((), size(vh)) - check((1,2,3), size(vh) + 3*self.P) + check((), vsize('')) + check((1,2,3), vsize('') + 3*self.P) # type # (PyTypeObject + PyNumberMethods + PyMappingMethods + # PySequenceMethods + PyBufferProcs) - s = size(vh + 'P2P15Pl4PP9PP11PI') + size('16Pi17P 3P 10P 2P 2P') + s = vsize('P2P15Pl4PP9PP11PI') + struct.calcsize('16Pi17P 3P 10P 2P 2P') check(int, s) # class class newstyleclass(object): pass @@ -832,39 +797,38 @@ # we need to test for both sizes, because we don't know if the string # has been cached for s in samples: - basicsize = size(h + 'PPPiP') + usize * (len(s) + 1) + basicsize = size('PPPiP') + usize * (len(s) + 1) check(s, basicsize) # weakref import weakref - check(weakref.ref(int), size(h + '2Pl2P')) + check(weakref.ref(int), size('2Pl2P')) # weakproxy # XXX # weakcallableproxy - check(weakref.proxy(int), size(h + '2Pl2P')) + check(weakref.proxy(int), size('2Pl2P')) def test_pythontypes(self): # check all types defined in Python/ - h = self.header - vh = self.vheader - size = self.calcsize + size = test.support.calcobjsize + vsize = test.support.calcvobjsize check = self.check_sizeof # _ast.AST import _ast - check(_ast.AST(), size(h + '')) + check(_ast.AST(), size('')) # imp.NullImporter import imp - check(imp.NullImporter(self.file.name), size(h + '')) + check(imp.NullImporter(self.file.name), size('')) try: raise TypeError except TypeError: tb = sys.exc_info()[2] # traceback if tb != None: - check(tb, size(h + '2P2i')) + check(tb, size('2P2i')) # symtable entry # XXX # sys.flags - check(sys.flags, size(vh) + self.P * len(sys.flags)) + check(sys.flags, vsize('') + self.P * len(sys.flags)) def test_main(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -383,6 +383,9 @@ Tests ----- +- Issue #15467: Move helpers for __sizeof__ tests into test_support. + Patch by Serhiy Storchaka. + - Issue #15320: Make iterating the list of tests thread-safe when running tests in multiprocess mode. Patch by Chris Jerdonek. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 29 16:39:09 2012 From: python-checkins at python.org (martin.v.loewis) Date: Sun, 29 Jul 2012 16:39:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2315467=3A_Merge_3=2E2?= Message-ID: <3WlRPT4xqdzPbq@mail.python.org> http://hg.python.org/cpython/rev/d43ff8eb4cb3 changeset: 78316:d43ff8eb4cb3 parent: 78314:75a30a478dc7 parent: 78315:efade142ef01 user: Martin v. L?wis date: Sun Jul 29 16:38:45 2012 +0200 summary: Issue #15467: Merge 3.2 files: Lib/test/support.py | 28 +++ Lib/test/test_struct.py | 40 +--- Lib/test/test_sys.py | 214 +++++++++------------- Lib/test/test_xml_etree_c.py | 24 +- Misc/NEWS | 3 + 5 files changed, 138 insertions(+), 171 deletions(-) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -25,6 +25,7 @@ import logging.handlers import struct import tempfile +import _testcapi try: import _thread, threading @@ -1082,6 +1083,33 @@ return final_opt != '' and final_opt != '-O0' +_header = 'nP' +_align = '0n' +if hasattr(sys, "gettotalrefcount"): + _header = '2P' + _header + _align = '0P' +_vheader = _header + 'n' + +def calcobjsize(fmt): + return struct.calcsize(_header + fmt + _align) + +def calcvobjsize(fmt): + return struct.calcsize(_vheader + fmt + _align) + + +_TPFLAGS_HAVE_GC = 1<<14 +_TPFLAGS_HEAPTYPE = 1<<9 + +def check_sizeof(test, o, size): + result = sys.getsizeof(o) + # add GC header size + if ((type(o) == type) and (o.__flags__ & _TPFLAGS_HEAPTYPE) or\ + ((type(o) != type) and (type(o).__flags__ & _TPFLAGS_HAVE_GC))): + size += _testcapi.SIZEOF_PYGC_HEAD + msg = 'wrong size for %s: got %d, expected %d' \ + % (type(o), result, size) + test.assertEqual(result, size, msg) + #======================================================================= # Decorator for running a function in a different locale, correctly resetting # it afterwards. diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -3,7 +3,7 @@ import struct import sys -from test.support import run_unittest, cpython_only +from test import support ISBIGENDIAN = sys.byteorder == "big" IS32BIT = sys.maxsize == 0x7fffffff @@ -40,33 +40,6 @@ return string_reverse(value) class StructTest(unittest.TestCase): - def setUp(self): - # due to missing size_t information from struct, it is assumed that - # sizeof(Py_ssize_t) = sizeof(void*) - self.header = 'PP' - if hasattr(sys, "gettotalrefcount"): - self.header += '2P' - - def check_sizeof(self, format_str, number_of_codes): - def size(fmt): - """Wrapper around struct.calcsize which enforces the alignment - of the end of a structure to the alignment requirement of pointer. - - Note: This wrapper should only be used if a pointer member is - included and no member with a size larger than a pointer exists. - """ - return struct.calcsize(fmt + '0P') - - struct_obj = struct.Struct(format_str) - # The size of 'PyStructObject' - totalsize = size(self.header + '5P') - # The size taken up by the 'formatcode' dynamic array - totalsize += size('3P') * (number_of_codes + 1) - result = sys.getsizeof(struct_obj) - msg = 'wrong size for %s: got %d, expected %d' \ - % (type(struct_obj), result, totalsize) - self.assertEqual(result, totalsize, msg) - def test_isbigendian(self): self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN) @@ -599,7 +572,14 @@ s = struct.Struct('i') s.__init__('ii') - @cpython_only + def check_sizeof(self, format_str, number_of_codes): + # The size of 'PyStructObject' + totalsize = support.calcobjsize('2n3P') + # The size taken up by the 'formatcode' dynamic array + totalsize += struct.calcsize('P2n0P') * (number_of_codes + 1) + support.check_sizeof(self, struct.Struct(format_str), totalsize) + + @support.cpython_only def test__sizeof__(self): for code in integer_codes: self.check_sizeof(code, 1) @@ -614,7 +594,7 @@ self.check_sizeof('0c', 0) def test_main(): - run_unittest(StructTest) + support.run_unittest(StructTest) if __name__ == '__main__': test_main() diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -612,22 +612,8 @@ class SizeofTest(unittest.TestCase): - TPFLAGS_HAVE_GC = 1<<14 - TPFLAGS_HEAPTYPE = 1<<9 - def setUp(self): - self.c = len(struct.pack('c', b' ')) - self.H = len(struct.pack('H', 0)) - self.i = len(struct.pack('i', 0)) - self.l = len(struct.pack('l', 0)) - self.P = len(struct.pack('P', 0)) - # due to missing size_t information from struct, it is assumed that - # sizeof(Py_ssize_t) = sizeof(void*) - self.header = 'PP' - self.vheader = self.header + 'P' - if hasattr(sys, "gettotalrefcount"): - self.header += '2P' - self.vheader += '2P' + self.P = struct.calcsize('P') self.longdigit = sys.int_info.sizeof_digit import _testcapi self.gc_headsize = _testcapi.SIZEOF_PYGC_HEAD @@ -637,129 +623,108 @@ self.file.close() test.support.unlink(test.support.TESTFN) - def check_sizeof(self, o, size): - result = sys.getsizeof(o) - # add GC header size - if ((type(o) == type) and (o.__flags__ & self.TPFLAGS_HEAPTYPE) or\ - ((type(o) != type) and (type(o).__flags__ & self.TPFLAGS_HAVE_GC))): - size += self.gc_headsize - msg = 'wrong size for %s: got %d, expected %d' \ - % (type(o), result, size) - self.assertEqual(result, size, msg) - - def calcsize(self, fmt): - """Wrapper around struct.calcsize which enforces the alignment of the - end of a structure to the alignment requirement of pointer. - - Note: This wrapper should only be used if a pointer member is included - and no member with a size larger than a pointer exists. - """ - return struct.calcsize(fmt + '0P') + check_sizeof = test.support.check_sizeof def test_gc_head_size(self): # Check that the gc header size is added to objects tracked by the gc. - h = self.header - vh = self.vheader - size = self.calcsize + vsize = test.support.calcvobjsize gc_header_size = self.gc_headsize # bool objects are not gc tracked - self.assertEqual(sys.getsizeof(True), size(vh) + self.longdigit) + self.assertEqual(sys.getsizeof(True), vsize('') + self.longdigit) # but lists are - self.assertEqual(sys.getsizeof([]), size(vh + 'PP') + gc_header_size) + self.assertEqual(sys.getsizeof([]), vsize('Pn') + gc_header_size) def test_default(self): - h = self.header - vh = self.vheader - size = self.calcsize - self.assertEqual(sys.getsizeof(True), size(vh) + self.longdigit) - self.assertEqual(sys.getsizeof(True, -1), size(vh) + self.longdigit) + size = test.support.calcvobjsize + self.assertEqual(sys.getsizeof(True), size('') + self.longdigit) + self.assertEqual(sys.getsizeof(True, -1), size('') + self.longdigit) def test_objecttypes(self): # check all types defined in Objects/ - h = self.header - vh = self.vheader - size = self.calcsize + size = test.support.calcobjsize + vsize = test.support.calcvobjsize check = self.check_sizeof # bool - check(True, size(vh) + self.longdigit) + check(True, vsize('') + self.longdigit) # buffer # XXX # builtin_function_or_method - check(len, size(h + '3P')) + check(len, size('3P')) # XXX check layout # bytearray samples = [b'', b'u'*100000] for sample in samples: x = bytearray(sample) - check(x, size(vh + 'iPP') + x.__alloc__() * self.c) + check(x, vsize('inP') + x.__alloc__()) # bytearray_iterator - check(iter(bytearray()), size(h + 'PP')) + check(iter(bytearray()), size('nP')) # cell def get_cell(): x = 42 def inner(): return x return inner - check(get_cell().__closure__[0], size(h + 'P')) + check(get_cell().__closure__[0], size('P')) # code - check(get_cell().__code__, size(h + '5i9Pi3P')) - check(get_cell.__code__, size(h + '5i9Pi3P')) + check(get_cell().__code__, size('5i9Pi3P')) + check(get_cell.__code__, size('5i9Pi3P')) def get_cell2(x): def inner(): return x return inner - check(get_cell2.__code__, size(h + '5i9Pi3P') + 1) + check(get_cell2.__code__, size('5i9Pi3P') + 1) # complex - check(complex(0,1), size(h + '2d')) + check(complex(0,1), size('2d')) # method_descriptor (descriptor object) - check(str.lower, size(h + '3PP')) + check(str.lower, size('3PP')) # classmethod_descriptor (descriptor object) # XXX # member_descriptor (descriptor object) import datetime - check(datetime.timedelta.days, size(h + '3PP')) + check(datetime.timedelta.days, size('3PP')) # getset_descriptor (descriptor object) import collections - check(collections.defaultdict.default_factory, size(h + '3PP')) + check(collections.defaultdict.default_factory, size('3PP')) # wrapper_descriptor (descriptor object) - check(int.__add__, size(h + '3P2P')) + check(int.__add__, size('3P2P')) # method-wrapper (descriptor object) - check({}.__iter__, size(h + '2P')) + check({}.__iter__, size('2P')) # dict - check({}, size(h + '3P' + '4P' + 8*'P2P')) + check({}, size('n2P' + '2nPn' + 8*'n2P')) longdict = {1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8} - check(longdict, size(h + '3P' + '4P') + 16*size('P2P')) + check(longdict, size('n2P' + '2nPn') + 16*struct.calcsize('n2P')) # dictionary-keyiterator - check({}.keys(), size(h + 'P')) + check({}.keys(), size('P')) # dictionary-valueiterator - check({}.values(), size(h + 'P')) + check({}.values(), size('P')) # dictionary-itemiterator - check({}.items(), size(h + 'P')) + check({}.items(), size('P')) + # dictionary iterator + check(iter({}), size('P2nPn')) # dictproxy class C(object): pass - check(C.__dict__, size(h + 'P')) + check(C.__dict__, size('P')) # BaseException - check(BaseException(), size(h + '5Pi')) + check(BaseException(), size('5Pi')) # UnicodeEncodeError - check(UnicodeEncodeError("", "", 0, 0, ""), size(h + '5Pi 2P2PP')) + check(UnicodeEncodeError("", "", 0, 0, ""), size('5Pi 2P2nP')) # UnicodeDecodeError - # XXX -# check(UnicodeDecodeError("", "", 0, 0, ""), size(h + '5P2PP')) + check(UnicodeDecodeError("", b"", 0, 0, ""), size('5Pi 2P2nP')) # UnicodeTranslateError - check(UnicodeTranslateError("", 0, 1, ""), size(h + '5Pi 2P2PP')) + check(UnicodeTranslateError("", 0, 1, ""), size('5Pi 2P2nP')) # ellipses - check(Ellipsis, size(h + '')) + check(Ellipsis, size('')) # EncodingMap import codecs, encodings.iso8859_3 x = codecs.charmap_build(encodings.iso8859_3.decoding_table) - check(x, size(h + '32B2iB')) + check(x, size('32B2iB')) # enumerate - check(enumerate([]), size(h + 'l3P')) + check(enumerate([]), size('n3P')) # reverse - check(reversed(''), size(h + 'PP')) + check(reversed(''), size('nP')) # float - check(float(0), size(h + 'd')) + check(float(0), size('d')) # sys.floatinfo - check(sys.float_info, size(vh) + self.P * len(sys.float_info)) + check(sys.float_info, vsize('') + self.P * len(sys.float_info)) # frame import inspect CO_MAXBLOCKS = 20 @@ -768,10 +733,10 @@ nfrees = len(x.f_code.co_freevars) extras = x.f_code.co_stacksize + x.f_code.co_nlocals +\ ncells + nfrees - 1 - check(x, size(vh + '12P3i' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P')) + check(x, vsize('12P3i' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P')) # function def func(): pass - check(func, size(h + '12P')) + check(func, size('12P')) class c(): @staticmethod def foo(): @@ -780,68 +745,68 @@ def bar(cls): pass # staticmethod - check(foo, size(h + 'PP')) + check(foo, size('PP')) # classmethod - check(bar, size(h + 'PP')) + check(bar, size('PP')) # generator def get_gen(): yield 1 - check(get_gen(), size(h + 'Pi2P')) + check(get_gen(), size('Pb2P')) # iterator - check(iter('abc'), size(h + 'lP')) + check(iter('abc'), size('lP')) # callable-iterator import re - check(re.finditer('',''), size(h + '2P')) + check(re.finditer('',''), size('2P')) # list samples = [[], [1,2,3], ['1', '2', '3']] for sample in samples: - check(sample, size(vh + 'PP') + len(sample)*self.P) + check(sample, vsize('Pn') + len(sample)*self.P) # sortwrapper (list) # XXX # cmpwrapper (list) # XXX # listiterator (list) - check(iter([]), size(h + 'lP')) + check(iter([]), size('lP')) # listreverseiterator (list) - check(reversed([]), size(h + 'lP')) + check(reversed([]), size('nP')) # long - check(0, size(vh)) - check(1, size(vh) + self.longdigit) - check(-1, size(vh) + self.longdigit) + check(0, vsize('')) + check(1, vsize('') + self.longdigit) + check(-1, vsize('') + self.longdigit) PyLong_BASE = 2**sys.int_info.bits_per_digit - check(int(PyLong_BASE), size(vh) + 2*self.longdigit) - check(int(PyLong_BASE**2-1), size(vh) + 2*self.longdigit) - check(int(PyLong_BASE**2), size(vh) + 3*self.longdigit) + check(int(PyLong_BASE), vsize('') + 2*self.longdigit) + check(int(PyLong_BASE**2-1), vsize('') + 2*self.longdigit) + check(int(PyLong_BASE**2), vsize('') + 3*self.longdigit) # memoryview - check(memoryview(b''), size(h + 'PPiP4P2i5P3c2P')) + check(memoryview(b''), size('Pnin 2P2n2i5P 3cPn')) # module - check(unittest, size(h + '3P')) + check(unittest, size('PnP')) # None - check(None, size(h + '')) + check(None, size('')) # NotImplementedType - check(NotImplemented, size(h)) + check(NotImplemented, size('')) # object - check(object(), size(h + '')) + check(object(), size('')) # property (descriptor object) class C(object): def getx(self): return self.__x def setx(self, value): self.__x = value def delx(self): del self.__x x = property(getx, setx, delx, "") - check(x, size(h + '4Pi')) + check(x, size('4Pi')) # PyCapsule # XXX # rangeiterator - check(iter(range(1)), size(h + '4l')) + check(iter(range(1)), size('4l')) # reverse - check(reversed(''), size(h + 'PP')) + check(reversed(''), size('nP')) # range - check(range(1), size(h + '4P')) - check(range(66000), size(h + '4P')) + check(range(1), size('4P')) + check(range(66000), size('4P')) # set # frozenset PySet_MINSIZE = 8 samples = [[], range(10), range(50)] - s = size(h + '3P2P' + PySet_MINSIZE*'lP' + 'lP') + s = size('3n2P' + PySet_MINSIZE*'nP' + 'nP') for sample in samples: minused = len(sample) if minused == 0: tmp = 1 @@ -855,31 +820,31 @@ check(set(sample), s) check(frozenset(sample), s) else: - check(set(sample), s + newsize*struct.calcsize('lP')) - check(frozenset(sample), s + newsize*struct.calcsize('lP')) + check(set(sample), s + newsize*struct.calcsize('nP')) + check(frozenset(sample), s + newsize*struct.calcsize('nP')) # setiterator - check(iter(set()), size(h + 'P3P')) + check(iter(set()), size('P3n')) # slice - check(slice(0), size(h + '3P')) + check(slice(0), size('3P')) # super - check(super(int), size(h + '3P')) + check(super(int), size('3P')) # tuple - check((), size(vh)) - check((1,2,3), size(vh) + 3*self.P) + check((), vsize('')) + check((1,2,3), vsize('') + 3*self.P) # type # static type: PyTypeObject - s = size(vh + 'P2P15Pl4PP9PP11PI') + s = vsize('P2n15Pl4Pn9Pn11PI') check(int, s) # (PyTypeObject + PyNumberMethods + PyMappingMethods + # PySequenceMethods + PyBufferProcs + 4P) - s = size(vh + 'P2P15Pl4PP9PP11PI') + size('34P 3P 10P 2P 4P') + s = vsize('P2n15Pl4Pn9Pn11PI') + struct.calcsize('34P 3P 10P 2P 4P') # Separate block for PyDictKeysObject with 4 entries - s += size("PPPP") + 4*size("PPP") + s += struct.calcsize("2nPn") + 4*struct.calcsize("n2P") # class class newstyleclass(object): pass check(newstyleclass, s) # dict with shared keys - check(newstyleclass().__dict__, size(h+"PPP4P")) + check(newstyleclass().__dict__, size('n2P' + '2nPn')) # unicode # each tuple contains a string and its expected character size # don't put any static strings here, as they may contain @@ -887,8 +852,8 @@ samples = ['1'*100, '\xff'*50, '\u0100'*40, '\uffff'*100, '\U00010000'*30, '\U0010ffff'*100] - asciifields = h + "PPiP" - compactfields = asciifields + "PPP" + asciifields = "nniP" + compactfields = asciifields + "nPn" unicodefields = compactfields + "P" for s in samples: maxchar = ord(max(s)) @@ -912,32 +877,31 @@ # TODO: add check that forces layout of unicodefields # weakref import weakref - check(weakref.ref(int), size(h + '2Pl2P')) + check(weakref.ref(int), size('2Pn2P')) # weakproxy # XXX # weakcallableproxy - check(weakref.proxy(int), size(h + '2Pl2P')) + check(weakref.proxy(int), size('2Pn2P')) def test_pythontypes(self): # check all types defined in Python/ - h = self.header - vh = self.vheader - size = self.calcsize + size = test.support.calcobjsize + vsize = test.support.calcvobjsize check = self.check_sizeof # _ast.AST import _ast - check(_ast.AST(), size(h + 'P')) + check(_ast.AST(), size('P')) try: raise TypeError except TypeError: tb = sys.exc_info()[2] # traceback if tb != None: - check(tb, size(h + '2P2i')) + check(tb, size('2P2i')) # symtable entry # XXX # sys.flags - check(sys.flags, size(vh) + self.P * len(sys.flags)) + check(sys.flags, vsize('') + self.P * len(sys.flags)) def test_main(): diff --git a/Lib/test/test_xml_etree_c.py b/Lib/test/test_xml_etree_c.py --- a/Lib/test/test_xml_etree_c.py +++ b/Lib/test/test_xml_etree_c.py @@ -41,38 +41,30 @@ @unittest.skipUnless(cET, 'requires _elementtree') + at support.cpython_only class SizeofTest(unittest.TestCase): def setUp(self): - import _testcapi - gc_headsize = _testcapi.SIZEOF_PYGC_HEAD - # object header - header = 'PP' - if hasattr(sys, "gettotalrefcount"): - # debug header - header = 'PP' + header - # fields - element = header + '5P' - self.elementsize = gc_headsize + struct.calcsize(element) + self.elementsize = support.calcobjsize('5P') # extra self.extra = struct.calcsize('PiiP4P') + check_sizeof = support.check_sizeof + def test_element(self): e = cET.Element('a') - self.assertEqual(sys.getsizeof(e), self.elementsize) + self.check_sizeof(e, self.elementsize) def test_element_with_attrib(self): e = cET.Element('a', href='about:') - self.assertEqual(sys.getsizeof(e), - self.elementsize + self.extra) + self.check_sizeof(e, self.elementsize + self.extra) def test_element_with_children(self): e = cET.Element('a') for i in range(5): cET.SubElement(e, 'span') # should have space for 8 children now - self.assertEqual(sys.getsizeof(e), - self.elementsize + self.extra + - struct.calcsize('8P')) + self.check_sizeof(e, self.elementsize + self.extra + + struct.calcsize('8P')) def test_main(): from test import test_xml_etree, test_xml_etree_c diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -238,6 +238,9 @@ Tests ----- +- Issue #15467: Move helpers for __sizeof__ tests into test_support. + Patch by Serhiy Storchaka. + - Issue #15320: Make iterating the list of tests thread-safe when running tests in multiprocess mode. Patch by Chris Jerdonek. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 29 16:39:26 2012 From: python-checkins at python.org (martin.v.loewis) Date: Sun, 29 Jul 2012 16:39:26 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE1NDY3?= =?utf-8?q?=3A_Move_helpers_for_=5F=5Fsizeof=5F=5F_tests_into_test=5Fsuppo?= =?utf-8?b?cnQu?= Message-ID: <3WlRPp2w2nzPb6@mail.python.org> http://hg.python.org/cpython/rev/fa95b04e67fd changeset: 78317:fa95b04e67fd branch: 2.7 parent: 78311:37554bda2014 user: Martin v. L?wis date: Sun Jul 29 16:30:50 2012 +0200 summary: Issue #15467: Move helpers for __sizeof__ tests into test_support. Patch by Serhiy Storchaka. files: Lib/test/test_struct.py | 42 +---- Lib/test/test_support.py | 28 +++ Lib/test/test_sys.py | 207 +++++++++++--------------- Misc/NEWS | 3 + 4 files changed, 129 insertions(+), 151 deletions(-) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -3,8 +3,8 @@ import unittest import struct import inspect -from test.test_support import (run_unittest, check_warnings, - check_py3k_warnings, cpython_only) +from test import test_support as support +from test.test_support import (check_warnings, check_py3k_warnings) import sys ISBIGENDIAN = sys.byteorder == "big" @@ -33,33 +33,6 @@ class StructTest(unittest.TestCase): - def setUp(self): - # due to missing size_t information from struct, it is assumed that - # sizeof(Py_ssize_t) = sizeof(void*) - self.header = 'PP' - if hasattr(sys, "gettotalrefcount"): - self.header += '2P' - - def check_sizeof(self, format_str, number_of_codes): - def size(fmt): - """Wrapper around struct.calcsize which enforces the alignment - of the end of a structure to the alignment requirement of pointer. - - Note: This wrapper should only be used if a pointer member is - included and no member with a size larger than a pointer exists. - """ - return struct.calcsize(fmt + '0P') - - struct_obj = struct.Struct(format_str) - # The size of 'PyStructObject' - totalsize = size(self.header + '5P') - # The size taken up by the 'formatcode' dynamic array - totalsize += size('3P') * (number_of_codes + 1) - result = sys.getsizeof(struct_obj) - msg = 'wrong size for %s: got %d, expected %d' \ - % (type(struct_obj), result, totalsize) - self.assertEqual(result, totalsize, msg) - def check_float_coerce(self, format, number): # SF bug 1530559. struct.pack raises TypeError where it used # to convert. @@ -572,7 +545,14 @@ hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2) self.assertRaises(struct.error, struct.calcsize, hugecount2) - @cpython_only + def check_sizeof(self, format_str, number_of_codes): + # The size of 'PyStructObject' + totalsize = support.calcobjsize('5P') + # The size taken up by the 'formatcode' dynamic array + totalsize += struct.calcsize('3P') * (number_of_codes + 1) + support.check_sizeof(self, struct.Struct(format_str), totalsize) + + @support.cpython_only def test__sizeof__(self): for code in integer_codes: self.check_sizeof(code, 1) @@ -587,7 +567,7 @@ self.check_sizeof('0c', 0) def test_main(): - run_unittest(StructTest) + support.run_unittest(StructTest) if __name__ == '__main__': test_main() diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -18,6 +18,8 @@ import UserDict import re import time +import struct +import _testcapi try: import thread except ImportError: @@ -861,6 +863,32 @@ gc.collect() +_header = '2P' +if hasattr(sys, "gettotalrefcount"): + _header = '2P' + _header +_vheader = _header + 'P' + +def calcobjsize(fmt): + return struct.calcsize(_header + fmt + '0P') + +def calcvobjsize(fmt): + return struct.calcsize(_vheader + fmt + '0P') + + +_TPFLAGS_HAVE_GC = 1<<14 +_TPFLAGS_HEAPTYPE = 1<<9 + +def check_sizeof(test, o, size): + result = sys.getsizeof(o) + # add GC header size + if ((type(o) == type) and (o.__flags__ & _TPFLAGS_HEAPTYPE) or\ + ((type(o) != type) and (type(o).__flags__ & _TPFLAGS_HAVE_GC))): + size += _testcapi.SIZEOF_PYGC_HEAD + msg = 'wrong size for %s: got %d, expected %d' \ + % (type(o), result, size) + test.assertEqual(result, size, msg) + + #======================================================================= # Decorator for running a function in a different locale, correctly resetting # it afterwards. diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -490,22 +490,8 @@ class SizeofTest(unittest.TestCase): - TPFLAGS_HAVE_GC = 1<<14 - TPFLAGS_HEAPTYPE = 1L<<9 - def setUp(self): - self.c = len(struct.pack('c', ' ')) - self.H = len(struct.pack('H', 0)) - self.i = len(struct.pack('i', 0)) - self.l = len(struct.pack('l', 0)) - self.P = len(struct.pack('P', 0)) - # due to missing size_t information from struct, it is assumed that - # sizeof(Py_ssize_t) = sizeof(void*) - self.header = 'PP' - self.vheader = self.header + 'P' - if hasattr(sys, "gettotalrefcount"): - self.header += '2P' - self.vheader += '2P' + self.P = struct.calcsize('P') self.longdigit = sys.long_info.sizeof_digit import _testcapi self.gc_headsize = _testcapi.SIZEOF_PYGC_HEAD @@ -515,128 +501,109 @@ self.file.close() test.test_support.unlink(test.test_support.TESTFN) - def check_sizeof(self, o, size): - result = sys.getsizeof(o) - if ((type(o) == type) and (o.__flags__ & self.TPFLAGS_HEAPTYPE) or\ - ((type(o) != type) and (type(o).__flags__ & self.TPFLAGS_HAVE_GC))): - size += self.gc_headsize - msg = 'wrong size for %s: got %d, expected %d' \ - % (type(o), result, size) - self.assertEqual(result, size, msg) - - def calcsize(self, fmt): - """Wrapper around struct.calcsize which enforces the alignment of the - end of a structure to the alignment requirement of pointer. - - Note: This wrapper should only be used if a pointer member is included - and no member with a size larger than a pointer exists. - """ - return struct.calcsize(fmt + '0P') + check_sizeof = test.test_support.check_sizeof def test_gc_head_size(self): # Check that the gc header size is added to objects tracked by the gc. - h = self.header - size = self.calcsize + size = test.test_support.calcobjsize gc_header_size = self.gc_headsize # bool objects are not gc tracked - self.assertEqual(sys.getsizeof(True), size(h + 'l')) + self.assertEqual(sys.getsizeof(True), size('l')) # but lists are - self.assertEqual(sys.getsizeof([]), size(h + 'P PP') + gc_header_size) + self.assertEqual(sys.getsizeof([]), size('P PP') + gc_header_size) def test_default(self): - h = self.header - size = self.calcsize - self.assertEqual(sys.getsizeof(True, -1), size(h + 'l')) + size = test.test_support.calcobjsize + self.assertEqual(sys.getsizeof(True, -1), size('l')) def test_objecttypes(self): # check all types defined in Objects/ - h = self.header - vh = self.vheader - size = self.calcsize + size = test.test_support.calcobjsize + vsize = test.test_support.calcvobjsize check = self.check_sizeof # bool - check(True, size(h + 'l')) + check(True, size('l')) # buffer with test.test_support.check_py3k_warnings(): - check(buffer(''), size(h + '2P2Pil')) + check(buffer(''), size('2P2Pil')) # builtin_function_or_method - check(len, size(h + '3P')) + check(len, size('3P')) # bytearray samples = ['', 'u'*100000] for sample in samples: x = bytearray(sample) - check(x, size(vh + 'iPP') + x.__alloc__() * self.c) + check(x, vsize('iPP') + x.__alloc__()) # bytearray_iterator - check(iter(bytearray()), size(h + 'PP')) + check(iter(bytearray()), size('PP')) # cell def get_cell(): x = 42 def inner(): return x return inner - check(get_cell().func_closure[0], size(h + 'P')) + check(get_cell().func_closure[0], size('P')) # classobj (old-style class) class class_oldstyle(): def method(): pass - check(class_oldstyle, size(h + '7P')) + check(class_oldstyle, size('7P')) # instance (old-style class) - check(class_oldstyle(), size(h + '3P')) + check(class_oldstyle(), size('3P')) # instancemethod (old-style class) - check(class_oldstyle().method, size(h + '4P')) + check(class_oldstyle().method, size('4P')) # complex - check(complex(0,1), size(h + '2d')) + check(complex(0,1), size('2d')) # code - check(get_cell().func_code, size(h + '4i8Pi3P')) + check(get_cell().func_code, size('4i8Pi3P')) # BaseException - check(BaseException(), size(h + '3P')) + check(BaseException(), size('3P')) # UnicodeEncodeError - check(UnicodeEncodeError("", u"", 0, 0, ""), size(h + '5P2PP')) + check(UnicodeEncodeError("", u"", 0, 0, ""), size('5P2PP')) # UnicodeDecodeError - check(UnicodeDecodeError("", "", 0, 0, ""), size(h + '5P2PP')) + check(UnicodeDecodeError("", "", 0, 0, ""), size('5P2PP')) # UnicodeTranslateError - check(UnicodeTranslateError(u"", 0, 1, ""), size(h + '5P2PP')) + check(UnicodeTranslateError(u"", 0, 1, ""), size('5P2PP')) # method_descriptor (descriptor object) - check(str.lower, size(h + '2PP')) + check(str.lower, size('2PP')) # classmethod_descriptor (descriptor object) # XXX # member_descriptor (descriptor object) import datetime - check(datetime.timedelta.days, size(h + '2PP')) + check(datetime.timedelta.days, size('2PP')) # getset_descriptor (descriptor object) import __builtin__ - check(__builtin__.file.closed, size(h + '2PP')) + check(__builtin__.file.closed, size('2PP')) # wrapper_descriptor (descriptor object) - check(int.__add__, size(h + '2P2P')) + check(int.__add__, size('2P2P')) # dictproxy class C(object): pass - check(C.__dict__, size(h + 'P')) + check(C.__dict__, size('P')) # method-wrapper (descriptor object) - check({}.__iter__, size(h + '2P')) + check({}.__iter__, size('2P')) # dict - check({}, size(h + '3P2P' + 8*'P2P')) + check({}, size('3P2P' + 8*'P2P')) x = {1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8} - check(x, size(h + '3P2P' + 8*'P2P') + 16*size('P2P')) + check(x, size('3P2P' + 8*'P2P') + 16*struct.calcsize('P2P')) # dictionary-keyiterator - check({}.iterkeys(), size(h + 'P2PPP')) + check({}.iterkeys(), size('P2PPP')) # dictionary-valueiterator - check({}.itervalues(), size(h + 'P2PPP')) + check({}.itervalues(), size('P2PPP')) # dictionary-itemiterator - check({}.iteritems(), size(h + 'P2PPP')) + check({}.iteritems(), size('P2PPP')) # ellipses - check(Ellipsis, size(h + '')) + check(Ellipsis, size('')) # EncodingMap import codecs, encodings.iso8859_3 x = codecs.charmap_build(encodings.iso8859_3.decoding_table) - check(x, size(h + '32B2iB')) + check(x, size('32B2iB')) # enumerate - check(enumerate([]), size(h + 'l3P')) + check(enumerate([]), size('l3P')) # file - check(self.file, size(h + '4P2i4P3i3P3i')) + check(self.file, size('4P2i4P3i3P3i')) # float - check(float(0), size(h + 'd')) + check(float(0), size('d')) # sys.floatinfo - check(sys.float_info, size(vh) + self.P * len(sys.float_info)) + check(sys.float_info, vsize('') + self.P * len(sys.float_info)) # frame import inspect CO_MAXBLOCKS = 20 @@ -645,10 +612,10 @@ nfrees = len(x.f_code.co_freevars) extras = x.f_code.co_stacksize + x.f_code.co_nlocals +\ ncells + nfrees - 1 - check(x, size(vh + '12P3i' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P')) + check(x, vsize('12P3i' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P')) # function def func(): pass - check(func, size(h + '9P')) + check(func, size('9P')) class c(): @staticmethod def foo(): @@ -657,65 +624,65 @@ def bar(cls): pass # staticmethod - check(foo, size(h + 'P')) + check(foo, size('P')) # classmethod - check(bar, size(h + 'P')) + check(bar, size('P')) # generator def get_gen(): yield 1 - check(get_gen(), size(h + 'Pi2P')) + check(get_gen(), size('Pi2P')) # integer - check(1, size(h + 'l')) - check(100, size(h + 'l')) + check(1, size('l')) + check(100, size('l')) # iterator - check(iter('abc'), size(h + 'lP')) + check(iter('abc'), size('lP')) # callable-iterator import re - check(re.finditer('',''), size(h + '2P')) + check(re.finditer('',''), size('2P')) # list samples = [[], [1,2,3], ['1', '2', '3']] for sample in samples: - check(sample, size(vh + 'PP') + len(sample)*self.P) + check(sample, vsize('PP') + len(sample)*self.P) # sortwrapper (list) # XXX # cmpwrapper (list) # XXX # listiterator (list) - check(iter([]), size(h + 'lP')) + check(iter([]), size('lP')) # listreverseiterator (list) - check(reversed([]), size(h + 'lP')) + check(reversed([]), size('lP')) # long - check(0L, size(vh)) - check(1L, size(vh) + self.longdigit) - check(-1L, size(vh) + self.longdigit) + check(0L, vsize('')) + check(1L, vsize('') + self.longdigit) + check(-1L, vsize('') + self.longdigit) PyLong_BASE = 2**sys.long_info.bits_per_digit - check(long(PyLong_BASE), size(vh) + 2*self.longdigit) - check(long(PyLong_BASE**2-1), size(vh) + 2*self.longdigit) - check(long(PyLong_BASE**2), size(vh) + 3*self.longdigit) + check(long(PyLong_BASE), vsize('') + 2*self.longdigit) + check(long(PyLong_BASE**2-1), vsize('') + 2*self.longdigit) + check(long(PyLong_BASE**2), vsize('') + 3*self.longdigit) # module - check(unittest, size(h + 'P')) + check(unittest, size('P')) # None - check(None, size(h + '')) + check(None, size('')) # object - check(object(), size(h + '')) + check(object(), size('')) # property (descriptor object) class C(object): def getx(self): return self.__x def setx(self, value): self.__x = value def delx(self): del self.__x x = property(getx, setx, delx, "") - check(x, size(h + '4Pi')) + check(x, size('4Pi')) # PyCObject # PyCapsule # XXX # rangeiterator - check(iter(xrange(1)), size(h + '4l')) + check(iter(xrange(1)), size('4l')) # reverse - check(reversed(''), size(h + 'PP')) + check(reversed(''), size('PP')) # set # frozenset PySet_MINSIZE = 8 samples = [[], range(10), range(50)] - s = size(h + '3P2P' + PySet_MINSIZE*'lP' + 'lP') + s = size('3P2P' + PySet_MINSIZE*'lP' + 'lP') for sample in samples: minused = len(sample) if minused == 0: tmp = 1 @@ -732,23 +699,24 @@ check(set(sample), s + newsize*struct.calcsize('lP')) check(frozenset(sample), s + newsize*struct.calcsize('lP')) # setiterator - check(iter(set()), size(h + 'P3P')) + check(iter(set()), size('P3P')) # slice - check(slice(1), size(h + '3P')) + check(slice(1), size('3P')) # str - check('', struct.calcsize(vh + 'li') + 1) - check('abc', struct.calcsize(vh + 'li') + 1 + 3*self.c) + vh = test.test_support._vheader + check('', struct.calcsize(vh + 'lic')) + check('abc', struct.calcsize(vh + 'lic') + 3) # super - check(super(int), size(h + '3P')) + check(super(int), size('3P')) # tuple - check((), size(vh)) - check((1,2,3), size(vh) + 3*self.P) + check((), vsize('')) + check((1,2,3), vsize('') + 3*self.P) # tupleiterator - check(iter(()), size(h + 'lP')) + check(iter(()), size('lP')) # type # (PyTypeObject + PyNumberMethods + PyMappingMethods + # PySequenceMethods + PyBufferProcs) - s = size(vh + 'P2P15Pl4PP9PP11PI') + size('41P 10P 3P 6P') + s = vsize('P2P15Pl4PP9PP11PI') + struct.calcsize('41P 10P 3P 6P') class newstyleclass(object): pass check(newstyleclass, s) @@ -763,41 +731,40 @@ # we need to test for both sizes, because we don't know if the string # has been cached for s in samples: - check(s, size(h + 'PPlP') + usize * (len(s) + 1)) + check(s, size('PPlP') + usize * (len(s) + 1)) # weakref import weakref - check(weakref.ref(int), size(h + '2Pl2P')) + check(weakref.ref(int), size('2Pl2P')) # weakproxy # XXX # weakcallableproxy - check(weakref.proxy(int), size(h + '2Pl2P')) + check(weakref.proxy(int), size('2Pl2P')) # xrange - check(xrange(1), size(h + '3l')) - check(xrange(66000), size(h + '3l')) + check(xrange(1), size('3l')) + check(xrange(66000), size('3l')) def test_pythontypes(self): # check all types defined in Python/ - h = self.header - vh = self.vheader - size = self.calcsize + size = test.test_support.calcobjsize + vsize = test.test_support.calcvobjsize check = self.check_sizeof # _ast.AST import _ast - check(_ast.AST(), size(h + '')) + check(_ast.AST(), size('')) # imp.NullImporter import imp - check(imp.NullImporter(self.file.name), size(h + '')) + check(imp.NullImporter(self.file.name), size('')) try: raise TypeError except TypeError: tb = sys.exc_info()[2] # traceback if tb != None: - check(tb, size(h + '2P2i')) + check(tb, size('2P2i')) # symtable entry # XXX # sys.flags - check(sys.flags, size(vh) + self.P * len(sys.flags)) + check(sys.flags, vsize('') + self.P * len(sys.flags)) def test_main(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -887,6 +887,9 @@ Tests ----- +- Issue #15467: Move helpers for __sizeof__ tests into test_support. + Patch by Serhiy Storchaka. + - Issue #11689: Fix a variable scoping error in an sqlite3 test. Initial patch by Torsten Landschoff. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 29 19:07:34 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 29 Jul 2012 19:07:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE1NDg3?= =?utf-8?q?=3A_Add_a_=5F=5Fsizeof=5F=5F_implementation_for_buffered_I/O_ob?= =?utf-8?q?jects=2E?= Message-ID: <3WlVhk5jqDzPTd@mail.python.org> http://hg.python.org/cpython/rev/8a02a93c803a changeset: 78318:8a02a93c803a branch: 3.2 parent: 78315:efade142ef01 user: Antoine Pitrou date: Sun Jul 29 19:02:46 2012 +0200 summary: Issue #15487: Add a __sizeof__ implementation for buffered I/O objects. Patch by Serhiy Storchaka. files: Lib/test/test_io.py | 20 +++++++++++++++++--- Misc/NEWS | 3 +++ Modules/_io/bufferedio.c | 14 ++++++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -792,6 +792,20 @@ buf.raw = x +class SizeofTest: + + @support.cpython_only + def test_sizeof(self): + bufsize1 = 4096 + bufsize2 = 8192 + rawio = self.MockRawIO() + bufio = self.tp(rawio, buffer_size=bufsize1) + size = sys.getsizeof(bufio) - bufsize1 + rawio = self.MockRawIO() + bufio = self.tp(rawio, buffer_size=bufsize2) + self.assertEqual(sys.getsizeof(bufio), size + bufsize2) + + class BufferedReaderTest(unittest.TestCase, CommonBufferedTests): read_mode = "rb" @@ -983,7 +997,7 @@ "failed for {}: {} != 0".format(n, rawio._extraneous_reads)) -class CBufferedReaderTest(BufferedReaderTest): +class CBufferedReaderTest(BufferedReaderTest, SizeofTest): tp = io.BufferedReader def test_constructor(self): @@ -1245,7 +1259,7 @@ self.tp(self.MockRawIO(), 8, 12) -class CBufferedWriterTest(BufferedWriterTest): +class CBufferedWriterTest(BufferedWriterTest, SizeofTest): tp = io.BufferedWriter def test_constructor(self): @@ -1636,7 +1650,7 @@ # You can't construct a BufferedRandom over a non-seekable stream. test_unseekable = None -class CBufferedRandomTest(BufferedRandomTest): +class CBufferedRandomTest(BufferedRandomTest, SizeofTest): tp = io.BufferedRandom def test_constructor(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -98,6 +98,9 @@ Library ------- +- Issue #15487: Add a __sizeof__ implementation for buffered I/O objects. + Patch by Serhiy Storchaka. + - Issue #6056: Make multiprocessing use setblocking(True) on the sockets it uses. Original patch by J Derek Wilson. diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -383,6 +383,17 @@ Py_TYPE(self)->tp_free((PyObject *)self); } +static PyObject * +buffered_sizeof(buffered *self, void *unused) +{ + Py_ssize_t res; + + res = sizeof(buffered); + if (self->buffer) + res += self->buffer_size; + return PyLong_FromSsize_t(res); +} + static int buffered_traverse(buffered *self, visitproc visit, void *arg) { @@ -1591,6 +1602,7 @@ {"seek", (PyCFunction)buffered_seek, METH_VARARGS}, {"tell", (PyCFunction)buffered_tell, METH_NOARGS}, {"truncate", (PyCFunction)buffered_truncate, METH_VARARGS}, + {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, {NULL, NULL} }; @@ -1985,6 +1997,7 @@ {"flush", (PyCFunction)buffered_flush, METH_NOARGS}, {"seek", (PyCFunction)buffered_seek, METH_VARARGS}, {"tell", (PyCFunction)buffered_tell, METH_NOARGS}, + {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, {NULL, NULL} }; @@ -2384,6 +2397,7 @@ {"readline", (PyCFunction)buffered_readline, METH_VARARGS}, {"peek", (PyCFunction)buffered_peek, METH_VARARGS}, {"write", (PyCFunction)bufferedwriter_write, METH_VARARGS}, + {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, {NULL, NULL} }; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 29 19:07:36 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 29 Jul 2012 19:07:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2315487=3A_Add_a_=5F=5Fsizeof=5F=5F_implementatio?= =?utf-8?q?n_for_buffered_I/O_objects=2E?= Message-ID: <3WlVhm25KNzPVk@mail.python.org> http://hg.python.org/cpython/rev/1d811e1097ed changeset: 78319:1d811e1097ed parent: 78316:d43ff8eb4cb3 parent: 78318:8a02a93c803a user: Antoine Pitrou date: Sun Jul 29 19:04:57 2012 +0200 summary: Issue #15487: Add a __sizeof__ implementation for buffered I/O objects. Patch by Serhiy Storchaka. files: Lib/test/test_io.py | 20 +++++++++++++++++--- Misc/NEWS | 3 +++ Modules/_io/bufferedio.c | 14 ++++++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -802,6 +802,20 @@ buf.raw = x +class SizeofTest: + + @support.cpython_only + def test_sizeof(self): + bufsize1 = 4096 + bufsize2 = 8192 + rawio = self.MockRawIO() + bufio = self.tp(rawio, buffer_size=bufsize1) + size = sys.getsizeof(bufio) - bufsize1 + rawio = self.MockRawIO() + bufio = self.tp(rawio, buffer_size=bufsize2) + self.assertEqual(sys.getsizeof(bufio), size + bufsize2) + + class BufferedReaderTest(unittest.TestCase, CommonBufferedTests): read_mode = "rb" @@ -999,7 +1013,7 @@ "failed for {}: {} != 0".format(n, rawio._extraneous_reads)) -class CBufferedReaderTest(BufferedReaderTest): +class CBufferedReaderTest(BufferedReaderTest, SizeofTest): tp = io.BufferedReader def test_constructor(self): @@ -1260,7 +1274,7 @@ self.tp(self.MockRawIO(), 8, 12) -class CBufferedWriterTest(BufferedWriterTest): +class CBufferedWriterTest(BufferedWriterTest, SizeofTest): tp = io.BufferedWriter def test_constructor(self): @@ -1650,7 +1664,7 @@ # You can't construct a BufferedRandom over a non-seekable stream. test_unseekable = None -class CBufferedRandomTest(BufferedRandomTest): +class CBufferedRandomTest(BufferedRandomTest, SizeofTest): tp = io.BufferedRandom def test_constructor(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -334,6 +334,9 @@ Library ------- +- Issue #15487: Add a __sizeof__ implementation for buffered I/O objects. + Patch by Serhiy Storchaka. + - Issue #15187: Bugfix: remove temporary directories test_shutil was leaving behind. diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -398,6 +398,17 @@ Py_TYPE(self)->tp_free((PyObject *)self); } +static PyObject * +buffered_sizeof(buffered *self, void *unused) +{ + Py_ssize_t res; + + res = sizeof(buffered); + if (self->buffer) + res += self->buffer_size; + return PyLong_FromSsize_t(res); +} + static int buffered_traverse(buffered *self, visitproc visit, void *arg) { @@ -1699,6 +1710,7 @@ {"seek", (PyCFunction)buffered_seek, METH_VARARGS}, {"tell", (PyCFunction)buffered_tell, METH_NOARGS}, {"truncate", (PyCFunction)buffered_truncate, METH_VARARGS}, + {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, {NULL, NULL} }; @@ -2079,6 +2091,7 @@ {"flush", (PyCFunction)buffered_flush, METH_NOARGS}, {"seek", (PyCFunction)buffered_seek, METH_VARARGS}, {"tell", (PyCFunction)buffered_tell, METH_NOARGS}, + {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, {NULL, NULL} }; @@ -2470,6 +2483,7 @@ {"readline", (PyCFunction)buffered_readline, METH_VARARGS}, {"peek", (PyCFunction)buffered_peek, METH_VARARGS}, {"write", (PyCFunction)bufferedwriter_write, METH_VARARGS}, + {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, {NULL, NULL} }; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jul 29 19:12:30 2012 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 29 Jul 2012 19:12:30 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE1NDg3?= =?utf-8?q?=3A_Add_a_=5F=5Fsizeof=5F=5F_implementation_for_buffered_I/O_ob?= =?utf-8?q?jects=2E?= Message-ID: <3WlVpQ6z92zPVM@mail.python.org> http://hg.python.org/cpython/rev/1102e86b8739 changeset: 78320:1102e86b8739 branch: 2.7 parent: 78317:fa95b04e67fd user: Antoine Pitrou date: Sun Jul 29 19:02:46 2012 +0200 summary: Issue #15487: Add a __sizeof__ implementation for buffered I/O objects. Patch by Serhiy Storchaka. files: Lib/test/test_io.py | 22 ++++++++++++++++++---- Misc/NEWS | 3 +++ Modules/_io/bufferedio.c | 14 ++++++++++++++ 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -748,6 +748,20 @@ buf.raw = x +class SizeofTest: + + @support.cpython_only + def test_sizeof(self): + bufsize1 = 4096 + bufsize2 = 8192 + rawio = self.MockRawIO() + bufio = self.tp(rawio, buffer_size=bufsize1) + size = sys.getsizeof(bufio) - bufsize1 + rawio = self.MockRawIO() + bufio = self.tp(rawio, buffer_size=bufsize2) + self.assertEqual(sys.getsizeof(bufio), size + bufsize2) + + class BufferedReaderTest(unittest.TestCase, CommonBufferedTests): read_mode = "rb" @@ -931,7 +945,7 @@ "failed for {}: {} != 0".format(n, rawio._extraneous_reads)) -class CBufferedReaderTest(BufferedReaderTest): +class CBufferedReaderTest(BufferedReaderTest, SizeofTest): tp = io.BufferedReader def test_constructor(self): @@ -1194,7 +1208,7 @@ self.tp(self.MockRawIO(), 8, 12) -class CBufferedWriterTest(BufferedWriterTest): +class CBufferedWriterTest(BufferedWriterTest, SizeofTest): tp = io.BufferedWriter def test_constructor(self): @@ -1582,8 +1596,8 @@ f.flush() self.assertEqual(raw.getvalue(), b'1b\n2def\n3\n') - -class CBufferedRandomTest(CBufferedReaderTest, CBufferedWriterTest, BufferedRandomTest): +class CBufferedRandomTest(CBufferedReaderTest, CBufferedWriterTest, + BufferedRandomTest, SizeofTest): tp = io.BufferedRandom def test_constructor(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -92,6 +92,9 @@ Library ------- +- Issue #15487: Add a __sizeof__ implementation for buffered I/O objects. + Patch by Serhiy Storchaka. + - Issue #15402: An issue in the struct module that caused sys.getsizeof to return incorrect results for struct.Struct instances has been fixed. Initial patch by Serhiy Storchaka. diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -386,6 +386,17 @@ Py_TYPE(self)->tp_free((PyObject *)self); } +static PyObject * +buffered_sizeof(buffered *self, void *unused) +{ + Py_ssize_t res; + + res = sizeof(buffered); + if (self->buffer) + res += self->buffer_size; + return PyLong_FromSsize_t(res); +} + static int buffered_traverse(buffered *self, visitproc visit, void *arg) { @@ -1560,6 +1571,7 @@ {"seek", (PyCFunction)buffered_seek, METH_VARARGS}, {"tell", (PyCFunction)buffered_tell, METH_NOARGS}, {"truncate", (PyCFunction)buffered_truncate, METH_VARARGS}, + {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, {NULL, NULL} }; @@ -1952,6 +1964,7 @@ {"flush", (PyCFunction)buffered_flush, METH_NOARGS}, {"seek", (PyCFunction)buffered_seek, METH_VARARGS}, {"tell", (PyCFunction)buffered_tell, METH_NOARGS}, + {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, {NULL, NULL} }; @@ -2347,6 +2360,7 @@ {"readline", (PyCFunction)buffered_readline, METH_VARARGS}, {"peek", (PyCFunction)buffered_peek, METH_VARARGS}, {"write", (PyCFunction)bufferedwriter_write, METH_VARARGS}, + {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, {NULL, NULL} }; -- Repository URL: http://hg.python.org/cpython From amauryfa at gmail.com Mon Jul 2 21:34:03 2012 From: amauryfa at gmail.com (Amaury Forgeot d'Arc) Date: Mon, 02 Jul 2012 19:34:03 -0000 Subject: [Python-checkins] cpython: Issue #15166: Re-implement imp.get_tag() using sys.implementation Message-ID: > + tag = PyObject_GetAttrString(impl, "cache_tag"); > + if (tag == NULL) > + return NULL; > + raw_tag = PyUnicode_DATA(tag); > + Py_DECREF(tag); > + return raw_tag; This code will crash if the tag is not a string, e.g. after "sys.implementation.cache_tag = 42". And I am a bit worried about the returned pointer. Is it borrowed from the Python object? Can't the C caller keep the value? -- Amaury Forgeot d'Arc From root at python.org Sun Jul 29 20:00:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 20:00:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 20:05:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 20:05:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 20:10:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 20:10:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 20:15:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 20:15:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 20:20:16 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 20:20:16 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 20:25:04 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 20:25:04 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 20:30:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 20:30:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 20:35:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 20:35:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 20:40:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 20:40:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 20:45:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 20:45:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 20:50:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 20:50:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 20:55:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 20:55:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 21:00:08 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 21:00:08 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 21:05:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 21:05:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 21:10:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 21:10:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 21:15:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 21:15:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 21:20:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 21:20:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 21:25:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 21:25:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 21:30:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 21:30:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 21:35:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 21:35:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 21:40:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 21:40:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 21:45:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 21:45:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 21:50:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 21:50:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 21:55:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 21:55:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 22:00:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 22:00:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 22:05:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 22:05:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 22:10:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 22:10:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 22:15:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 22:15:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From root at python.org Sun Jul 29 22:20:01 2012 From: root at python.org (Cron Daemon) Date: Sun, 29 Jul 2012 22:20:01 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: /home/docs/build-devguide: line 3: hg: command not found From martin at v.loewis.de Sun Jul 29 23:24:51 2012 From: martin at v.loewis.de (martin at v.loewis.de) Date: Sun, 29 Jul 2012 23:24:51 +0200 Subject: [Python-checkins] cpython: pyexpat uses the new Unicode API In-Reply-To: References: Message-ID: <20120729232451.Horde.wQgvEUlCcOxQFaojxsCjY-A@webmail.df.eu> > Why is this PyUnicode_READY necessary? > Can tp_getattro pass unfinished unicode objects? There is no guarantee that it does pass READY strings. Giving such guarantee would be fairly error-prone, since people would now have to remember in what places they need to READY. So the guideline really is that you need to READY always whenever you access the internal representation. > I hope we don't have to update all extension modules? Of course not. Existing code will continue to work fine, with some really minor limitations (see the PEP for details). In fact, pyexpat worked just fine before Victor changed it (and continues to do so after the change, with potentially reduced memory consumption). Such code will not use the new API to access the flexible representation. If somebody changes the module to do so, they will have to add PyUnicode_READY calls. As Victor changed pyexpat to use the new API, he also added the READY calls (which are necessary precisely to continue supporting the old API, so they can go in Python 4). Regards, Martin From python-checkins at python.org Mon Jul 30 00:07:13 2012 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 30 Jul 2012 00:07:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE1NDg5?= =?utf-8?q?=3A_Add_a_=5F=5Fsizeof=5F=5F_implementation_for_BytesIO_objects?= =?utf-8?q?=2E?= Message-ID: <3WldLT54trzPS9@mail.python.org> http://hg.python.org/cpython/rev/1d3155750808 changeset: 78321:1d3155750808 branch: 3.2 parent: 78318:8a02a93c803a user: Antoine Pitrou date: Mon Jul 30 00:01:06 2012 +0200 summary: Issue #15489: Add a __sizeof__ implementation for BytesIO objects. Patch by Serhiy Storchaka. files: Lib/test/test_memoryio.py | 11 +++++++++++ Misc/NEWS | 3 +++ Modules/_io/bytesio.c | 12 ++++++++++++ 3 files changed, 26 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_memoryio.py b/Lib/test/test_memoryio.py --- a/Lib/test/test_memoryio.py +++ b/Lib/test/test_memoryio.py @@ -654,6 +654,17 @@ memio.close() self.assertRaises(ValueError, memio.__setstate__, (b"closed", 0, None)) + check_sizeof = support.check_sizeof + + @support.cpython_only + def test_sizeof(self): + basesize = support.calcobjsize('P2PP2PP') + check = self.check_sizeof + self.assertEqual(object.__sizeof__(io.BytesIO()), basesize) + check(io.BytesIO(), basesize ) + check(io.BytesIO(b'a'), basesize + 1 + 1 ) + check(io.BytesIO(b'a' * 1000), basesize + 1000 + 1 ) + class CStringIOTest(PyStringIOTest): ioclass = io.StringIO diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -98,6 +98,9 @@ Library ------- +- Issue #15489: Add a __sizeof__ implementation for BytesIO objects. + Patch by Serhiy Storchaka. + - Issue #15487: Add a __sizeof__ implementation for buffered I/O objects. Patch by Serhiy Storchaka. diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -834,6 +834,17 @@ return 0; } +static PyObject * +bytesio_sizeof(bytesio *self, void *unused) +{ + Py_ssize_t res; + + res = sizeof(bytesio); + if (self->buf) + res += self->buf_size; + return PyLong_FromSsize_t(res); +} + static int bytesio_traverse(bytesio *self, visitproc visit, void *arg) { @@ -876,6 +887,7 @@ {"truncate", (PyCFunction)bytesio_truncate, METH_VARARGS, truncate_doc}, {"__getstate__", (PyCFunction)bytesio_getstate, METH_NOARGS, NULL}, {"__setstate__", (PyCFunction)bytesio_setstate, METH_O, NULL}, + {"__sizeof__", (PyCFunction)bytesio_sizeof, METH_NOARGS, NULL}, {NULL, NULL} /* sentinel */ }; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 30 00:07:15 2012 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 30 Jul 2012 00:07:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2315489=3A_Add_a_=5F=5Fsizeof=5F=5F_implementatio?= =?utf-8?q?n_for_BytesIO_objects=2E?= Message-ID: <3WldLW3M8xzPVM@mail.python.org> http://hg.python.org/cpython/rev/917295aaad76 changeset: 78322:917295aaad76 parent: 78319:1d811e1097ed parent: 78321:1d3155750808 user: Antoine Pitrou date: Mon Jul 30 00:01:44 2012 +0200 summary: Issue #15489: Add a __sizeof__ implementation for BytesIO objects. Patch by Serhiy Storchaka. files: Lib/test/test_memoryio.py | 11 +++++++++++ Misc/NEWS | 3 +++ Modules/_io/bytesio.c | 12 ++++++++++++ 3 files changed, 26 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_memoryio.py b/Lib/test/test_memoryio.py --- a/Lib/test/test_memoryio.py +++ b/Lib/test/test_memoryio.py @@ -654,6 +654,17 @@ memio.close() self.assertRaises(ValueError, memio.__setstate__, (b"closed", 0, None)) + check_sizeof = support.check_sizeof + + @support.cpython_only + def test_sizeof(self): + basesize = support.calcobjsize('P2PP2PP') + check = self.check_sizeof + self.assertEqual(object.__sizeof__(io.BytesIO()), basesize) + check(io.BytesIO(), basesize ) + check(io.BytesIO(b'a'), basesize + 1 + 1 ) + check(io.BytesIO(b'a' * 1000), basesize + 1000 + 1 ) + class CStringIOTest(PyStringIOTest): ioclass = io.StringIO diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -334,6 +334,9 @@ Library ------- +- Issue #15489: Add a __sizeof__ implementation for BytesIO objects. + Patch by Serhiy Storchaka. + - Issue #15487: Add a __sizeof__ implementation for buffered I/O objects. Patch by Serhiy Storchaka. diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -834,6 +834,17 @@ return 0; } +static PyObject * +bytesio_sizeof(bytesio *self, void *unused) +{ + Py_ssize_t res; + + res = sizeof(bytesio); + if (self->buf) + res += self->buf_size; + return PyLong_FromSsize_t(res); +} + static int bytesio_traverse(bytesio *self, visitproc visit, void *arg) { @@ -876,6 +887,7 @@ {"truncate", (PyCFunction)bytesio_truncate, METH_VARARGS, truncate_doc}, {"__getstate__", (PyCFunction)bytesio_getstate, METH_NOARGS, NULL}, {"__setstate__", (PyCFunction)bytesio_setstate, METH_O, NULL}, + {"__sizeof__", (PyCFunction)bytesio_sizeof, METH_NOARGS, NULL}, {NULL, NULL} /* sentinel */ }; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 30 00:07:16 2012 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 30 Jul 2012 00:07:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE1NDg5?= =?utf-8?q?=3A_Add_a_=5F=5Fsizeof=5F=5F_implementation_for_BytesIO_objects?= =?utf-8?q?=2E?= Message-ID: <3WldLX6dCZzPYq@mail.python.org> http://hg.python.org/cpython/rev/e8851809ae83 changeset: 78323:e8851809ae83 branch: 2.7 parent: 78320:1102e86b8739 user: Antoine Pitrou date: Mon Jul 30 00:01:06 2012 +0200 summary: Issue #15489: Add a __sizeof__ implementation for BytesIO objects. Patch by Serhiy Storchaka. files: Lib/test/test_memoryio.py | 11 +++++++++++ Misc/NEWS | 3 +++ Modules/_io/bytesio.c | 12 ++++++++++++ 3 files changed, 26 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_memoryio.py b/Lib/test/test_memoryio.py --- a/Lib/test/test_memoryio.py +++ b/Lib/test/test_memoryio.py @@ -638,6 +638,17 @@ memio.close() self.assertRaises(ValueError, memio.__setstate__, (b"closed", 0, None)) + check_sizeof = support.check_sizeof + + @support.cpython_only + def test_sizeof(self): + basesize = support.calcobjsize(b'P2PP2P') + check = self.check_sizeof + self.assertEqual(object.__sizeof__(io.BytesIO()), basesize) + check(io.BytesIO(), basesize ) + check(io.BytesIO(b'a'), basesize + 1 + 1 ) + check(io.BytesIO(b'a' * 1000), basesize + 1000 + 1 ) + class CStringIOTest(PyStringIOTest): ioclass = io.StringIO diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -92,6 +92,9 @@ Library ------- +- Issue #15489: Add a __sizeof__ implementation for BytesIO objects. + Patch by Serhiy Storchaka. + - Issue #15487: Add a __sizeof__ implementation for buffered I/O objects. Patch by Serhiy Storchaka. diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -794,6 +794,17 @@ return 0; } +static PyObject * +bytesio_sizeof(bytesio *self, void *unused) +{ + Py_ssize_t res; + + res = sizeof(bytesio); + if (self->buf) + res += self->buf_size; + return PyLong_FromSsize_t(res); +} + static int bytesio_traverse(bytesio *self, visitproc visit, void *arg) { @@ -835,6 +846,7 @@ {"truncate", (PyCFunction)bytesio_truncate, METH_VARARGS, truncate_doc}, {"__getstate__", (PyCFunction)bytesio_getstate, METH_NOARGS, NULL}, {"__setstate__", (PyCFunction)bytesio_setstate, METH_O, NULL}, + {"__sizeof__", (PyCFunction)bytesio_sizeof, METH_NOARGS, NULL}, {NULL, NULL} /* sentinel */ }; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 30 00:10:16 2012 From: python-checkins at python.org (ezio.melotti) Date: Mon, 30 Jul 2012 00:10:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devguide=3A_=2315491=3A_link_to_the_f?= =?utf-8?q?ile_list_of_the_=22default=22_branch=2E?= Message-ID: <3WldQ04VSpzPNr@mail.python.org> http://hg.python.org/devguide/rev/0529e2062ec7 changeset: 533:0529e2062ec7 user: Ezio Melotti date: Mon Jul 30 00:10:06 2012 +0200 summary: #15491: link to the file list of the "default" branch. files: index.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -163,7 +163,7 @@ * `Firefox search engine plug-in`_ * `Buildbot status`_ * Source code - * `Browse online `_ + * `Browse online `_ * `Snapshot of py3k `_ * `Daily OS X installer `_ * Tool support -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Mon Jul 30 00:23:15 2012 From: python-checkins at python.org (ezio.melotti) Date: Mon, 30 Jul 2012 00:23:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devguide=3A_=2315491=3A_change_a_coup?= =?utf-8?q?le_more_links_to_point_to_the_=22default=22_branch=2E?= Message-ID: <3Wldhz2thfzPRd@mail.python.org> http://hg.python.org/devguide/rev/54ec1b493006 changeset: 534:54ec1b493006 user: Ezio Melotti date: Mon Jul 30 00:23:03 2012 +0200 summary: #15491: change a couple more links to point to the "default" branch. files: index.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -164,7 +164,7 @@ * `Buildbot status`_ * Source code * `Browse online `_ - * `Snapshot of py3k `_ + * `Snapshot of py3k `_ * `Daily OS X installer `_ * Tool support * :doc:`emacs` @@ -182,7 +182,7 @@ .. _Buildbot status: http://python.org/dev/buildbot/ .. _Firefox search engine plug-in: http://www.python.org/dev/searchplugin/ -.. _Misc directory: http://hg.python.org/cpython/file/tip/Misc +.. _Misc directory: http://hg.python.org/cpython/file/default/Misc .. _PEPs: http://www.python.org/dev/peps .. _python.org maintenance: http://python.org/dev/pydotorg/ .. _Python Mentors: http://pythonmentors.com/ -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Mon Jul 30 01:03:14 2012 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 30 Jul 2012 01:03:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devguide=3A_Closes_=2315493=3A_fix_li?= =?utf-8?q?nk_to_daily_DMG_installer?= Message-ID: <3Wlfb66lQpzPWR@mail.python.org> http://hg.python.org/devguide/rev/89d9874dfd13 changeset: 535:89d9874dfd13 user: Antoine Pitrou date: Mon Jul 30 01:00:52 2012 +0200 summary: Closes #15493: fix link to daily DMG installer files: index.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -165,7 +165,7 @@ * Source code * `Browse online `_ * `Snapshot of py3k `_ - * `Daily OS X installer `_ + * `Daily OS X installer `_ * Tool support * :doc:`emacs` * :doc:`gdb` -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Mon Jul 30 03:10:53 2012 From: python-checkins at python.org (alex.gaynor) Date: Mon, 30 Jul 2012 03:10:53 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Update_PEP-0424_with_respect_?= =?utf-8?q?to_feedback_received=2E?= Message-ID: <3WljQP1gshzPXX@mail.python.org> http://hg.python.org/peps/rev/055f717ee69a changeset: 4492:055f717ee69a parent: 4490:d4e77ba5329d user: Alex Gaynor date: Mon Jul 16 20:00:55 2012 -0700 summary: Update PEP-0424 with respect to feedback received. files: pep-0424.txt | 43 ++++++++++++++++++++++++++++++++++----- 1 files changed, 37 insertions(+), 6 deletions(-) diff --git a/pep-0424.txt b/pep-0424.txt --- a/pep-0424.txt +++ b/pep-0424.txt @@ -15,7 +15,7 @@ CPython currently defines an ``__length_hint__`` method on several types, such as various iterators. This method is then used by various other functions (such -as ``map``) to presize lists based on the estimated returned by +as ``list``) to presize lists based on the estimated returned by ``__length_hint__``. Types can then define ``__length_hint__`` which are not sized, and thus should not define ``__len__``, but can estimate or compute a size (such as many iterators). @@ -26,11 +26,42 @@ This PEP proposes formally documenting ``__length_hint__`` for other interpreter and non-standard library Python to implement. -``__length_hint__`` must return an integer (else a TypeError is raised), and is -not required to be accurate. It may return a value that is either larger or -smaller than the actual size ofthe container. It may raise a ``TypeError`` if a -specific instance cannot have its length estimated. It may not return a -negative value (else a ValueError is raised). +``__length_hint__`` must return an integer (else a TypeError is raised) or +``NotImplemented, and is not required to be accurate. It may return a value +that is either larger or smaller than the actual size ofthe container. A return value of ``NotImplemented`` indicates that there is no finite length estimate. +It may not return a negative value (else a ValueError is raised). + +In addition, a new function ``operator.length`` hint is added, having the +follow semantics (which define how ``__length_hint__`` should be used:: + + def length_hint(obj, default): + """ + Return an estimate of the number of items in obj. This is + useful for presizing containers when building from an iterable. + + If the object supports len(), the result will be exact. Otherwise, it + may over or underestimate by an arbitrary amount. The result will be an + integer >= 0. + """ + try: + return len(obj) + except TypeError: + try: + get_hint = obj.__length_hint__ + except AttributeError: + return default + hint = get_hint() + if hint is NotImplemented: + return default + if not isinstance(hint, int): + raise TypeError("Length hint must be an integer, not %r" % type(hint)) + if hint < 0: + raise ValueError("Length hint (%r) must be >= 0" % hint) + return hint + +Callers are required to provide a default value, because there is no sane +return value for objects which do not provide a length or length hint. + Rationale ========= -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Jul 30 03:10:54 2012 From: python-checkins at python.org (alex.gaynor) Date: Mon, 30 Jul 2012 03:10:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps_=28merge_default_-=3E_default=29?= =?utf-8?q?=3A_Merged_upstream=2E?= Message-ID: <3WljQQ6VyhzPYJ@mail.python.org> http://hg.python.org/peps/rev/bd9ac2ef37a1 changeset: 4493:bd9ac2ef37a1 parent: 4492:055f717ee69a parent: 4491:7838a83c3ad1 user: Alex Gaynor date: Sun Jul 29 18:08:14 2012 -0700 summary: Merged upstream. files: pep-0398.txt | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pep-0398.txt b/pep-0398.txt --- a/pep-0398.txt +++ b/pep-0398.txt @@ -17,7 +17,7 @@ Python 3.3. The schedule primarily concerns itself with PEP-sized items. Small features may be added up to and including the first beta release. Bugs may be fixed until the final release, which is planned -for August 2012. +for September 2012. Release Manager and Crew @@ -42,10 +42,10 @@ (No new features beyond this point.) -- 3.3.0 beta 2: July 14, 2012 -- 3.3.0 candidate 1: July 28, 2012 -- 3.3.0 candidate 2: August 11, 2012 -- 3.3.0 final: August 25, 2012 +- 3.3.0 beta 2: July 21, 2012 +- 3.3.0 candidate 1: August 4, 2012 +- 3.3.0 candidate 2: August 18, 2012 +- 3.3.0 final: September 1, 2012 .. don't forget to update final date above as well -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Jul 30 03:10:56 2012 From: python-checkins at python.org (alex.gaynor) Date: Mon, 30 Jul 2012 03:10:56 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Whitespace_and_spelling_fixes?= =?utf-8?q?=2E?= Message-ID: <3WljQS2PHwzPZ4@mail.python.org> http://hg.python.org/peps/rev/7fd8d7c91bb0 changeset: 4494:7fd8d7c91bb0 user: Alex Gaynor date: Sun Jul 29 18:10:33 2012 -0700 summary: Whitespace and spelling fixes. files: pep-0424.txt | 8 +++++--- 1 files changed, 5 insertions(+), 3 deletions(-) diff --git a/pep-0424.txt b/pep-0424.txt --- a/pep-0424.txt +++ b/pep-0424.txt @@ -28,8 +28,9 @@ ``__length_hint__`` must return an integer (else a TypeError is raised) or ``NotImplemented, and is not required to be accurate. It may return a value -that is either larger or smaller than the actual size ofthe container. A return value of ``NotImplemented`` indicates that there is no finite length estimate. -It may not return a negative value (else a ValueError is raised). +that is either larger or smaller than the actual size of the container. A +return value of ``NotImplemented`` indicates that there is no finite length +estimate. It may not return a negative value (else a ValueError is raised). In addition, a new function ``operator.length`` hint is added, having the follow semantics (which define how ``__length_hint__`` should be used:: @@ -66,7 +67,8 @@ Rationale ========= -Being able to pre-allocate lists based on the expected size, as estimated by ``__length_hint__``, can be a significant optimization. CPython has been +Being able to pre-allocate lists based on the expected size, as estimated by +``__length_hint__``, can be a significant optimization. CPython has been observed to run some code faster than PyPy, purely because of this optimization being present. -- Repository URL: http://hg.python.org/peps From solipsis at pitrou.net Mon Jul 30 06:00:12 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 30 Jul 2012 06:00:12 +0200 Subject: [Python-checkins] Daily reference leaks (917295aaad76): sum=0 Message-ID: results for 917295aaad76 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogmAjmmW', '-x'] From andrew.svetlov at gmail.com Mon Jul 30 11:23:51 2012 From: andrew.svetlov at gmail.com (Andrew Svetlov) Date: Mon, 30 Jul 2012 12:23:51 +0300 Subject: [Python-checkins] peps: Update PEP-0424 with respect to feedback received. In-Reply-To: <3WljQP1gshzPXX@mail.python.org> References: <3WljQP1gshzPXX@mail.python.org> Message-ID: On Mon, Jul 30, 2012 at 4:10 AM, alex.gaynor wrote: > +In addition, a new function ``operator.length`` hint is added ``operator.length`` or ``operator.length_hint``? > + def length_hint(obj, default): Is there default value for `default` parameter? For example: def length_hint(obj, default=0): pass or something like that? -- Thanks, Andrew Svetlov From python-checkins at python.org Mon Jul 30 11:37:38 2012 From: python-checkins at python.org (ned.deily) Date: Mon, 30 Jul 2012 11:37:38 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_invalid_UTF-8_encoding?= =?utf-8?q?_in_commit_message=2E?= Message-ID: <3Wlwg664wBzP8p@mail.python.org> http://hg.python.org/cpython/rev/457195ddf172 changeset: 78324:457195ddf172 parent: 78322:917295aaad76 user: Ned Deily date: Mon Jul 30 02:34:03 2012 -0700 summary: Fix invalid UTF-8 encoding in commit message. files: Misc/NEWS | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -265,7 +265,7 @@ ----- - Issue #15431: Add _freeze_importlib project to regenerate importlib.h - on Windows. Patch by Kristj?n Valur J?nsson. + on Windows. Patch by Kristj??n Valur J??nsson. - Issue #14197: For OS X framework builds, ensure links to the shared library are created with the proper ABI suffix. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 30 11:37:40 2012 From: python-checkins at python.org (ned.deily) Date: Mon, 30 Jul 2012 11:37:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2314018=3A_Fix_OS_X?= =?utf-8?q?_Tcl/Tk_framework_checking_when_using_OS_X_SDKs=2E?= Message-ID: <3Wlwg86FQ5zPTC@mail.python.org> http://hg.python.org/cpython/rev/f96579debefa changeset: 78325:f96579debefa user: Ned Deily date: Mon Jul 30 02:35:58 2012 -0700 summary: Issue #14018: Fix OS X Tcl/Tk framework checking when using OS X SDKs. Also add tests in the OS X installer build to ensure that the desired dynamic linking with an optional newer Tcl/Tk in /Library actually happens. files: Mac/BuildScript/build-installer.py | 57 ++++++++++++++--- Misc/NEWS | 2 + setup.py | 4 +- 3 files changed, 50 insertions(+), 13 deletions(-) diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -161,6 +161,13 @@ --universal-archs=x universal architectures (options: %(UNIVERSALOPTS)r, default: %(UNIVERSALARCHS)r) """)% globals() +# Dict of object file names with shared library names to check after building. +# This is to ensure that we ended up dynamically linking with the shared +# library paths and versions we expected. For example: +# EXPECTED_SHARED_LIBS['_tkinter.so'] = [ +# '/Library/Frameworks/Tcl.framework/Versions/8.5/Tcl', +# '/Library/Frameworks/Tk.framework/Versions/8.5/Tk'] +EXPECTED_SHARED_LIBS = {} # Instructions for building libraries that are necessary for building a # batteries included python. @@ -460,27 +467,40 @@ # Because we only support dynamic load of only one major/minor version of # Tcl/Tk, ensure: # 1. there are no user-installed frameworks of Tcl/Tk with version - # higher than the Apple-supplied system version - # 2. there is a user-installed framework in /Library/Frameworks with the - # same version as the system version. This allows users to choose - # to install a newer patch level. + # higher than the Apple-supplied system version in + # SDKROOT/System/Library/Frameworks + # 2. there is a user-installed framework (usually ActiveTcl) in (or linked + # in) SDKROOT/Library/Frameworks with the same version as the system + # version. This allows users to choose to install a newer patch level. + frameworks = {} for framework in ['Tcl', 'Tk']: - #fw = dict(lower=framework.lower(), - # upper=framework.upper(), - # cap=framework.capitalize()) - #fwpth = "Library/Frameworks/%(cap)s.framework/%(lower)sConfig.sh" % fw - fwpth = 'Library/Frameworks/Tcl.framework/Versions/Current' + fwpth = 'Library/Frameworks/%s.framework/Versions/Current' % framework sysfw = os.path.join(SDKPATH, 'System', fwpth) - libfw = os.path.join('/', fwpth) + libfw = os.path.join(SDKPATH, fwpth) usrfw = os.path.join(os.getenv('HOME'), fwpth) - #version = "%(upper)s_VERSION" % fw + frameworks[framework] = os.readlink(sysfw) + if not os.path.exists(libfw): + fatal("Please install a link to a current %s %s as %s so " + "the user can override the system framework." + % (framework, frameworks[framework], libfw)) if os.readlink(libfw) != os.readlink(sysfw): fatal("Version of %s must match %s" % (libfw, sysfw) ) if os.path.exists(usrfw): fatal("Please rename %s to avoid possible dynamic load issues." % usrfw) + if frameworks['Tcl'] != frameworks['Tk']: + fatal("The Tcl and Tk frameworks are not the same version.") + + # add files to check after build + EXPECTED_SHARED_LIBS['_tkinter.so'] = [ + "/Library/Frameworks/Tcl.framework/Versions/%s/Tcl" + % frameworks['Tcl'], + "/Library/Frameworks/Tk.framework/Versions/%s/Tk" + % frameworks['Tk'], + ] + # Remove inherited environment variables which might influence build environ_var_prefixes = ['CPATH', 'C_INCLUDE_', 'DYLD_', 'LANG', 'LC_', 'LD_', 'LIBRARY_', 'PATH', 'PYTHON'] @@ -861,12 +881,12 @@ frmDir = os.path.join(rootDir, 'Library', 'Frameworks', 'Python.framework') gid = grp.getgrnam('admin').gr_gid + shared_lib_error = False for dirpath, dirnames, filenames in os.walk(frmDir): for dn in dirnames: os.chmod(os.path.join(dirpath, dn), STAT_0o775) os.chown(os.path.join(dirpath, dn), -1, gid) - for fn in filenames: if os.path.islink(fn): continue @@ -877,6 +897,19 @@ os.chmod(p, stat.S_IMODE(st.st_mode) | stat.S_IWGRP) os.chown(p, -1, gid) + if fn in EXPECTED_SHARED_LIBS: + # check to see that this file was linked with the + # expected library path and version + data = captureCommand("otool -L %s" % shellQuote(p)) + for sl in EXPECTED_SHARED_LIBS[fn]: + if ("\t%s " % sl) not in data: + print("Expected shared lib %s was not linked with %s" + % (sl, p)) + shared_lib_error = True + + if shared_lib_error: + fatal("Unexpected shared library errors.") + if PYTHON_3: LDVERSION=None VERSION=None diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -264,6 +264,8 @@ Build ----- +- Issue #14018: Fix OS X Tcl/Tk framework checking when using OS X SDKs. + - Issue #15431: Add _freeze_importlib project to regenerate importlib.h on Windows. Patch by Kristj?n Valur J?nsson. diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -69,7 +69,9 @@ """ Returns True if 'path' can be located in an OSX SDK """ - return (path.startswith('/usr/') and not path.startswith('/usr/local')) or path.startswith('/System/') + return ( (path.startswith('/usr/') and not path.startswith('/usr/local')) + or path.startswith('/System/') + or path.startswith('/Library/') ) def find_file(filename, std_dirs, paths): """Searches for the directory where a given file is located, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 30 12:38:49 2012 From: python-checkins at python.org (ned.deily) Date: Mon, 30 Jul 2012 12:38:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE0MDE4?= =?utf-8?q?=3A_Update_the_OS_X_IDLE_Tcl/Tk_warning_check_to_include?= Message-ID: <3Wly1j5lL1zPYw@mail.python.org> http://hg.python.org/cpython/rev/7232d544c811 changeset: 78326:7232d544c811 branch: 2.7 parent: 78323:e8851809ae83 user: Ned Deily date: Mon Jul 30 03:28:22 2012 -0700 summary: Issue #14018: Update the OS X IDLE Tcl/Tk warning check to include the Apple-supplied Tck/Tk versions shipped with OS X 10.7 and 10.8. They are not as buggy as the 10.6 version but can still easily crash. files: Lib/idlelib/NEWS.txt | 3 +++ Lib/idlelib/macosxSupport.py | 16 ++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -12,6 +12,9 @@ - Issue 14876: use user-selected font for highlight configuration. +- Issue #14018: Update checks for unstable system Tcl/Tk versions on OS X + to include versions shipped with OS X 10.7 and 10.8 in addition to 10.6. + What's New in IDLE 2.7.3? ========================= diff --git a/Lib/idlelib/macosxSupport.py b/Lib/idlelib/macosxSupport.py --- a/Lib/idlelib/macosxSupport.py +++ b/Lib/idlelib/macosxSupport.py @@ -37,17 +37,21 @@ def tkVersionWarning(root): """ Returns a string warning message if the Tk version in use appears to - be one known to cause problems with IDLE. The Apple Cocoa-based Tk 8.5 - that was shipped with Mac OS X 10.6. + be one known to cause problems with IDLE. + 1. Apple Cocoa-based Tk 8.5.7 shipped with Mac OS X 10.6 is unusable. + 2. Apple Cocoa-based Tk 8.5.9 in OS X 10.7 and 10.8 is better but + can still crash unexpectedly. """ if (runningAsOSXApp() and - ('AppKit' in root.tk.call('winfo', 'server', '.')) and - (root.tk.call('info', 'patchlevel') == '8.5.7') ): - return (r"WARNING: The version of Tcl/Tk (8.5.7) in use may" + ('AppKit' in root.tk.call('winfo', 'server', '.')) ): + patchlevel = root.tk.call('info', 'patchlevel') + if patchlevel not in ('8.5.7', '8.5.9'): + return False + return (r"WARNING: The version of Tcl/Tk ({0}) in use may" r" be unstable.\n" r"Visit http://www.python.org/download/mac/tcltk/" - r" for current information.") + r" for current information.".format(patchlevel)) else: return False -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 30 12:38:51 2012 From: python-checkins at python.org (ned.deily) Date: Mon, 30 Jul 2012 12:38:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE0MDE4?= =?utf-8?q?=3A_Update_the_OS_X_IDLE_Tcl/Tk_warning_check_to_include?= Message-ID: <3Wly1l1cvDzPYw@mail.python.org> http://hg.python.org/cpython/rev/17ddc0c34d9d changeset: 78327:17ddc0c34d9d branch: 3.2 parent: 78321:1d3155750808 user: Ned Deily date: Mon Jul 30 03:31:21 2012 -0700 summary: Issue #14018: Update the OS X IDLE Tcl/Tk warning check to include the Apple-supplied Tck/Tk versions shipped with OS X 10.7 and 10.8. They are not as buggy as the 10.6 version but can still easily crash. files: Lib/idlelib/NEWS.txt | 4 ++++ Lib/idlelib/macosxSupport.py | 16 ++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -18,6 +18,10 @@ - Issue #14937: Perform auto-completion of filenames in strings even for non-ASCII filenames. Likewise for identifiers. +- Issue #14018: Update checks for unstable system Tcl/Tk versions on OS X + to include versions shipped with OS X 10.7 and 10.8 in addition to 10.6. + + What's New in IDLE 3.2.3? ========================= diff --git a/Lib/idlelib/macosxSupport.py b/Lib/idlelib/macosxSupport.py --- a/Lib/idlelib/macosxSupport.py +++ b/Lib/idlelib/macosxSupport.py @@ -37,17 +37,21 @@ def tkVersionWarning(root): """ Returns a string warning message if the Tk version in use appears to - be one known to cause problems with IDLE. The Apple Cocoa-based Tk 8.5 - that was shipped with Mac OS X 10.6. + be one known to cause problems with IDLE. + 1. Apple Cocoa-based Tk 8.5.7 shipped with Mac OS X 10.6 is unusable. + 2. Apple Cocoa-based Tk 8.5.9 in OS X 10.7 and 10.8 is better but + can still crash unexpectedly. """ if (runningAsOSXApp() and - ('AppKit' in root.tk.call('winfo', 'server', '.')) and - (root.tk.call('info', 'patchlevel') == '8.5.7') ): - return (r"WARNING: The version of Tcl/Tk (8.5.7) in use may" + ('AppKit' in root.tk.call('winfo', 'server', '.')) ): + patchlevel = root.tk.call('info', 'patchlevel') + if patchlevel not in ('8.5.7', '8.5.9'): + return False + return (r"WARNING: The version of Tcl/Tk ({0}) in use may" r" be unstable.\n" r"Visit http://www.python.org/download/mac/tcltk/" - r" for current information.") + r" for current information.".format(patchlevel)) else: return False -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 30 12:38:52 2012 From: python-checkins at python.org (ned.deily) Date: Mon, 30 Jul 2012 12:38:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2314018=3A_merge?= Message-ID: <3Wly1m4V6WzPY2@mail.python.org> http://hg.python.org/cpython/rev/28cb0bcaa22e changeset: 78328:28cb0bcaa22e parent: 78325:f96579debefa parent: 78327:17ddc0c34d9d user: Ned Deily date: Mon Jul 30 03:38:02 2012 -0700 summary: Issue #14018: merge files: Lib/idlelib/NEWS.txt | 3 +++ Lib/idlelib/macosxSupport.py | 16 ++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -34,6 +34,9 @@ - Issue #3573: IDLE hangs when passing invalid command line args (directory(ies) instead of file(s)). +- Issue #14018: Update checks for unstable system Tcl/Tk versions on OS X + to include versions shipped with OS X 10.7 and 10.8 in addition to 10.6. + What's New in IDLE 3.2.1? ========================= diff --git a/Lib/idlelib/macosxSupport.py b/Lib/idlelib/macosxSupport.py --- a/Lib/idlelib/macosxSupport.py +++ b/Lib/idlelib/macosxSupport.py @@ -37,17 +37,21 @@ def tkVersionWarning(root): """ Returns a string warning message if the Tk version in use appears to - be one known to cause problems with IDLE. The Apple Cocoa-based Tk 8.5 - that was shipped with Mac OS X 10.6. + be one known to cause problems with IDLE. + 1. Apple Cocoa-based Tk 8.5.7 shipped with Mac OS X 10.6 is unusable. + 2. Apple Cocoa-based Tk 8.5.9 in OS X 10.7 and 10.8 is better but + can still crash unexpectedly. """ if (runningAsOSXApp() and - ('AppKit' in root.tk.call('winfo', 'server', '.')) and - (root.tk.call('info', 'patchlevel') == '8.5.7') ): - return (r"WARNING: The version of Tcl/Tk (8.5.7) in use may" + ('AppKit' in root.tk.call('winfo', 'server', '.')) ): + patchlevel = root.tk.call('info', 'patchlevel') + if patchlevel not in ('8.5.7', '8.5.9'): + return False + return (r"WARNING: The version of Tcl/Tk ({0}) in use may" r" be unstable.\n" r"Visit http://www.python.org/download/mac/tcltk/" - r" for current information.") + r" for current information.".format(patchlevel)) else: return False -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 30 13:08:40 2012 From: python-checkins at python.org (victor.stinner) Date: Mon, 30 Jul 2012 13:08:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315463=3A_the_faul?= =?utf-8?q?thandler_module_truncates_strings_to_500_characters=2C?= Message-ID: <3Wlyh86gnhzPZ7@mail.python.org> http://hg.python.org/cpython/rev/ff7fc6a91212 changeset: 78329:ff7fc6a91212 user: Victor Stinner date: Mon Jul 30 13:08:58 2012 +0200 summary: Issue #15463: the faulthandler module truncates strings to 500 characters, instead of 100, to be able to display long file paths files: Misc/NEWS | 3 +++ Python/traceback.c | 2 +- 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -68,6 +68,9 @@ Library ------- +- Issue #15463: the faulthandler module truncates strings to 500 characters, + instead of 100, to be able to display long file paths + - Issue #6056: Make multiprocessing use setblocking(True) on the sockets it uses. Original patch by J Derek Wilson. diff --git a/Python/traceback.c b/Python/traceback.c --- a/Python/traceback.c +++ b/Python/traceback.c @@ -14,7 +14,7 @@ #define OFF(x) offsetof(PyTracebackObject, x) #define PUTS(fd, str) write(fd, str, strlen(str)) -#define MAX_STRING_LENGTH 100 +#define MAX_STRING_LENGTH 500 #define MAX_FRAME_DEPTH 100 #define MAX_NTHREADS 100 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 30 13:21:42 2012 From: python-checkins at python.org (ned.deily) Date: Mon, 30 Jul 2012 13:21:42 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE0MDE4?= =?utf-8?q?=3A_Fix_OS_X_Tcl/Tk_framework_checking_when_using_OS_X_SDKs=2E?= Message-ID: <3WlyzB4wDfzPYt@mail.python.org> http://hg.python.org/cpython/rev/e0eb7dea245f changeset: 78330:e0eb7dea245f branch: 2.7 parent: 78326:7232d544c811 user: Ned Deily date: Mon Jul 30 04:07:49 2012 -0700 summary: Issue #14018: Fix OS X Tcl/Tk framework checking when using OS X SDKs. files: Misc/NEWS | 2 ++ setup.py | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -309,6 +309,8 @@ Build ----- +- Issue #14018: Fix OS X Tcl/Tk framework checking when using OS X SDKs. + - Issue #8767: Restore building with --disable-unicode. Patch by Stefano Taschini. diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -48,6 +48,9 @@ Returns True if 'path' can be located in an OSX SDK """ return (path.startswith('/usr/') and not path.startswith('/usr/local')) or path.startswith('/System/') + return ( (path.startswith('/usr/') and not path.startswith('/usr/local')) + or path.startswith('/System/') + or path.startswith('/Library/') ) def find_file(filename, std_dirs, paths): """Searches for the directory where a given file is located, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 30 13:21:44 2012 From: python-checkins at python.org (ned.deily) Date: Mon, 30 Jul 2012 13:21:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE0MDE4?= =?utf-8?q?=3A_Fix_OS_X_Tcl/Tk_framework_checking_when_using_OS_X_SDKs=2E?= Message-ID: <3WlyzD1K7YzPYt@mail.python.org> http://hg.python.org/cpython/rev/eb0af7f6ea6d changeset: 78331:eb0af7f6ea6d branch: 3.2 parent: 78327:17ddc0c34d9d user: Ned Deily date: Mon Jul 30 04:09:32 2012 -0700 summary: Issue #14018: Fix OS X Tcl/Tk framework checking when using OS X SDKs. files: Misc/NEWS | 2 ++ setup.py | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -435,6 +435,8 @@ - Issue #14359: Only use O_CLOEXEC in _posixmodule.c if it is defined. Based on patch from Herv? Coatanhay. +- Issue #14018: Fix OS X Tcl/Tk framework checking when using OS X SDKs. + Documentation ------------- diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -60,6 +60,9 @@ Returns True if 'path' can be located in an OSX SDK """ return (path.startswith('/usr/') and not path.startswith('/usr/local')) or path.startswith('/System/') + return ( (path.startswith('/usr/') and not path.startswith('/usr/local')) + or path.startswith('/System/') + or path.startswith('/Library/') ) def find_file(filename, std_dirs, paths): """Searches for the directory where a given file is located, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 30 13:21:45 2012 From: python-checkins at python.org (ned.deily) Date: Mon, 30 Jul 2012 13:21:45 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_null_merge?= Message-ID: <3WlyzF4QGXzPZR@mail.python.org> http://hg.python.org/cpython/rev/1462e1652f5d changeset: 78332:1462e1652f5d parent: 78328:28cb0bcaa22e parent: 78331:eb0af7f6ea6d user: Ned Deily date: Mon Jul 30 04:14:18 2012 -0700 summary: null merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 30 13:21:47 2012 From: python-checkins at python.org (ned.deily) Date: Mon, 30 Jul 2012 13:21:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3WlyzH0LzRzPZw@mail.python.org> http://hg.python.org/cpython/rev/8dfbe120e4e9 changeset: 78333:8dfbe120e4e9 parent: 78332:1462e1652f5d parent: 78329:ff7fc6a91212 user: Ned Deily date: Mon Jul 30 04:20:51 2012 -0700 summary: merge files: Misc/NEWS | 3 +++ Python/traceback.c | 2 +- 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -68,6 +68,9 @@ Library ------- +- Issue #15463: the faulthandler module truncates strings to 500 characters, + instead of 100, to be able to display long file paths + - Issue #6056: Make multiprocessing use setblocking(True) on the sockets it uses. Original patch by J Derek Wilson. diff --git a/Python/traceback.c b/Python/traceback.c --- a/Python/traceback.c +++ b/Python/traceback.c @@ -14,7 +14,7 @@ #define OFF(x) offsetof(PyTracebackObject, x) #define PUTS(fd, str) write(fd, str, strlen(str)) -#define MAX_STRING_LENGTH 100 +#define MAX_STRING_LENGTH 500 #define MAX_FRAME_DEPTH 100 #define MAX_NTHREADS 100 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 30 14:01:13 2012 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 30 Jul 2012 14:01:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Better_test_for_BytesIO=2E?= =?utf-8?q?=5F=5Fsizeof=5F=5F=2C_now_that_the_struct_module_supports?= Message-ID: <3Wlzrn19NZzPYt@mail.python.org> http://hg.python.org/cpython/rev/e77c117ab024 changeset: 78334:e77c117ab024 user: Antoine Pitrou date: Mon Jul 30 13:58:42 2012 +0200 summary: Better test for BytesIO.__sizeof__, now that the struct module supports (s)size_t. Followup to issue #15489. files: Lib/test/test_memoryio.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_memoryio.py b/Lib/test/test_memoryio.py --- a/Lib/test/test_memoryio.py +++ b/Lib/test/test_memoryio.py @@ -658,7 +658,7 @@ @support.cpython_only def test_sizeof(self): - basesize = support.calcobjsize('P2PP2PP') + basesize = support.calcobjsize('P2nN2Pn') check = self.check_sizeof self.assertEqual(object.__sizeof__(io.BytesIO()), basesize) check(io.BytesIO(), basesize ) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 30 19:05:20 2012 From: python-checkins at python.org (andrew.svetlov) Date: Mon, 30 Jul 2012 19:05:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzEyMjg4?= =?utf-8?q?=3A_Consider_=270=27_and_=270=2E0=27_as_valid_initialvalue_for_?= =?utf-8?q?tkinter?= Message-ID: <3Wm6bh4LF4zPTp@mail.python.org> http://hg.python.org/cpython/rev/fd5166fdb978 changeset: 78335:fd5166fdb978 branch: 3.2 parent: 78331:eb0af7f6ea6d user: Andrew Svetlov date: Mon Jul 30 19:59:53 2012 +0300 summary: Issue #12288: Consider '0' and '0.0' as valid initialvalue for tkinter SimpleDialog. files: Lib/tkinter/simpledialog.py | 2 +- Misc/ACKS | 1 + Misc/NEWS | 3 +++ 3 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Lib/tkinter/simpledialog.py b/Lib/tkinter/simpledialog.py --- a/Lib/tkinter/simpledialog.py +++ b/Lib/tkinter/simpledialog.py @@ -282,7 +282,7 @@ self.entry = Entry(master, name="entry") self.entry.grid(row=1, padx=5, sticky=W+E) - if self.initialvalue: + if self.initialvalue is not None: self.entry.insert(0, self.initialvalue) self.entry.select_range(0, END) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -633,6 +633,7 @@ Mike Meyer Steven Miale Trent Mick +Tom Middleton Stan Mihai Stefan Mihaila Aristotelis Mikropoulos diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -98,6 +98,9 @@ Library ------- +- Issue #12288: Consider '0' and '0.0' as valid initialvalue + for tkinter SimpleDialog. + - Issue #15489: Add a __sizeof__ implementation for BytesIO objects. Patch by Serhiy Storchaka. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 30 19:05:23 2012 From: python-checkins at python.org (andrew.svetlov) Date: Mon, 30 Jul 2012 19:05:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?b?KTogSXNzdWUgIzEyMjg4OiBDb25zaWRlciAnMCcgYW5kICcwLjAnIGFzIHZh?= =?utf-8?q?lid_initialvalue_for_tkinter?= Message-ID: <3Wm6bl1zdKzPZX@mail.python.org> http://hg.python.org/cpython/rev/2f3ccf4ec193 changeset: 78336:2f3ccf4ec193 parent: 78334:e77c117ab024 parent: 78335:fd5166fdb978 user: Andrew Svetlov date: Mon Jul 30 20:01:13 2012 +0300 summary: Issue #12288: Consider '0' and '0.0' as valid initialvalue for tkinter SimpleDialog. files: Lib/tkinter/simpledialog.py | 2 +- Misc/ACKS | 1 + Misc/NEWS | 3 +++ 3 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Lib/tkinter/simpledialog.py b/Lib/tkinter/simpledialog.py --- a/Lib/tkinter/simpledialog.py +++ b/Lib/tkinter/simpledialog.py @@ -282,7 +282,7 @@ self.entry = Entry(master, name="entry") self.entry.grid(row=1, padx=5, sticky=W+E) - if self.initialvalue: + if self.initialvalue is not None: self.entry.insert(0, self.initialvalue) self.entry.select_range(0, END) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -700,6 +700,7 @@ Alexis M?taireau Steven Miale Trent Mick +Tom Middleton Stan Mihai Stefan Mihaila Aristotelis Mikropoulos diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -339,6 +339,9 @@ Library ------- +- Issue #12288: Consider '0' and '0.0' as valid initialvalue + for tkinter SimpleDialog. + - Issue #15489: Add a __sizeof__ implementation for BytesIO objects. Patch by Serhiy Storchaka. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 30 19:05:24 2012 From: python-checkins at python.org (andrew.svetlov) Date: Mon, 30 Jul 2012 19:05:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzEyMjg4?= =?utf-8?q?=3A_Consider_=270=27_and_=270=2E0=27_as_valid_initialvalue_for_?= =?utf-8?q?tkinter?= Message-ID: <3Wm6bm52KzzPW7@mail.python.org> http://hg.python.org/cpython/rev/f98e2944cb40 changeset: 78337:f98e2944cb40 branch: 2.7 parent: 78330:e0eb7dea245f user: Andrew Svetlov date: Mon Jul 30 20:04:53 2012 +0300 summary: Issue #12288: Consider '0' and '0.0' as valid initialvalue for tkinter SimpleDialog. files: Lib/lib-tk/tkSimpleDialog.py | 2 +- Misc/ACKS | 1 + Misc/NEWS | 3 +++ 3 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Lib/lib-tk/tkSimpleDialog.py b/Lib/lib-tk/tkSimpleDialog.py --- a/Lib/lib-tk/tkSimpleDialog.py +++ b/Lib/lib-tk/tkSimpleDialog.py @@ -200,7 +200,7 @@ self.entry = Entry(master, name="entry") self.entry.grid(row=1, padx=5, sticky=W+E) - if self.initialvalue: + if self.initialvalue is not None: self.entry.insert(0, self.initialvalue) self.entry.select_range(0, END) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -576,6 +576,7 @@ Mike Meyer Steven Miale Trent Mick +Tom Middleton Stan Mihai Aristotelis Mikropoulos Damien Miller diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -92,6 +92,9 @@ Library ------- +- Issue #12288: Consider '0' and '0.0' as valid initialvalue + for tkinter SimpleDialog. + - Issue #15489: Add a __sizeof__ implementation for BytesIO objects. Patch by Serhiy Storchaka. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jul 30 19:12:27 2012 From: python-checkins at python.org (guido.van.rossum) Date: Mon, 30 Jul 2012 19:12:27 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Improve_and_accept_PEP_424_?= =?utf-8?b?KF9fbGVuZ3RoX2hpbnRfXyku?= Message-ID: <3Wm6lv4xC9zPZ4@mail.python.org> http://hg.python.org/peps/rev/fa104e5c1abe changeset: 4495:fa104e5c1abe user: Guido van Rossum date: Mon Jul 30 10:12:18 2012 -0700 summary: Improve and accept PEP 424 (__length_hint__). files: pep-0424.txt | 66 ++++++++++++++++++++++----------------- 1 files changed, 37 insertions(+), 29 deletions(-) diff --git a/pep-0424.txt b/pep-0424.txt --- a/pep-0424.txt +++ b/pep-0424.txt @@ -3,7 +3,7 @@ Version: $Revision$ Last-Modified: $Date Author: Alex Gaynor -Status: Draft +Status: Accepted Type: Standards Track Content-Type: text/x-rst Created: 14-July-2012 @@ -13,18 +13,19 @@ Abstract ======== -CPython currently defines an ``__length_hint__`` method on several types, such -as various iterators. This method is then used by various other functions (such -as ``list``) to presize lists based on the estimated returned by -``__length_hint__``. Types can then define ``__length_hint__`` which are not -sized, and thus should not define ``__len__``, but can estimate or compute a -size (such as many iterators). +CPython currently defines a ``__length_hint__`` method on several +types, such as various iterators. This method is then used by various +other functions (such as ``list``) to presize lists based on the +estimate returned by ``__length_hint__``. Types which are not sized, +and thus should not define ``__len__``, can then define +``__length_hint__``, to allow estimating or computing a size (such as +many iterators). -Proposal -======== +Specification +============= -This PEP proposes formally documenting ``__length_hint__`` for other -interpreter and non-standard library Python to implement. +This PEP formally documents ``__length_hint__`` for other +interpreters and non-standard-library Python modules to implement. ``__length_hint__`` must return an integer (else a TypeError is raised) or ``NotImplemented, and is not required to be accurate. It may return a value @@ -32,21 +33,23 @@ return value of ``NotImplemented`` indicates that there is no finite length estimate. It may not return a negative value (else a ValueError is raised). -In addition, a new function ``operator.length`` hint is added, having the -follow semantics (which define how ``__length_hint__`` should be used:: +In addition, a new function ``operator.length_hint`` hint is added, +with the follow semantics (which define how ``__length_hint__`` should +be used):: - def length_hint(obj, default): + def length_hint(obj, default=0): + """Return an estimate of the number of items in obj. + + This is useful for presizing containers when building from an + iterable. + + If the object supports len(), the result will be + exact. Otherwise, it may over- or under-estimate by an + arbitrary amount. The result will be an integer >= 0. """ - Return an estimate of the number of items in obj. This is - useful for presizing containers when building from an iterable. - - If the object supports len(), the result will be exact. Otherwise, it - may over or underestimate by an arbitrary amount. The result will be an - integer >= 0. - """ - try: + if : return len(obj) - except TypeError: + else: try: get_hint = obj.__length_hint__ except AttributeError: @@ -55,13 +58,18 @@ if hint is NotImplemented: return default if not isinstance(hint, int): - raise TypeError("Length hint must be an integer, not %r" % type(hint)) - if hint < 0: - raise ValueError("Length hint (%r) must be >= 0" % hint) - return hint + raise TypeError("Length hint must be an integer, not %r" % + type(hint)) + return max(hint, 0) -Callers are required to provide a default value, because there is no sane -return value for objects which do not provide a length or length hint. +Note: there is no good way to spell "obj has a __len__ method" in pure +Python. In CPython, this comes down to checking for a ``sq_length`` +slot. Other implementations presumably have their own way of +checking. Calling ``len(obj)`` and catching TypeError is not quite +correct (as it would assume no __len__ method exists when in fact one +exists but calling it raises TypeError); checking ``hasattr(obj, +'__len__')`` likewise is incorrect if obj is a class defining a +``__len__`` method for its instances. Rationale -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Jul 30 20:38:03 2012 From: python-checkins at python.org (brett.cannon) Date: Mon, 30 Jul 2012 20:38:03 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Grammar_fix=2E?= Message-ID: <3Wm8fg74rHzPYb@mail.python.org> http://hg.python.org/peps/rev/2cf5fd8a64ee changeset: 4496:2cf5fd8a64ee user: Brett Cannon date: Mon Jul 30 14:37:57 2012 -0400 summary: Grammar fix. files: pep-0424.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0424.txt b/pep-0424.txt --- a/pep-0424.txt +++ b/pep-0424.txt @@ -34,7 +34,7 @@ estimate. It may not return a negative value (else a ValueError is raised). In addition, a new function ``operator.length_hint`` hint is added, -with the follow semantics (which define how ``__length_hint__`` should +with the following semantics (which define how ``__length_hint__`` should be used):: def length_hint(obj, default=0): -- Repository URL: http://hg.python.org/peps From andrew.svetlov at gmail.com Mon Jul 30 20:58:59 2012 From: andrew.svetlov at gmail.com (Andrew Svetlov) Date: Mon, 30 Jul 2012 21:58:59 +0300 Subject: [Python-checkins] [Python-Dev] peps: Update PEP-0424 with respect to feedback received. In-Reply-To: References: <3WljQP1gshzPXX@mail.python.org> Message-ID: Sure, GvR covered my question in much more clean way in http://code.activestate.com/lists/python-dev/117152/ On Mon, Jul 30, 2012 at 9:49 PM, Ifthikhan Nazeem wrote: > The question is not very clear. Are you asking whether function arguments > can have default parameters? > > -- > Thanks > Iftikhan Nazeem > LinkedIn : http://ae.linkedin.com/in/ifthikhan > > > On Mon, Jul 30, 2012 at 11:23 AM, Andrew Svetlov > wrote: >> >> On Mon, Jul 30, 2012 at 4:10 AM, alex.gaynor >> wrote: >> >> > +In addition, a new function ``operator.length`` hint is added >> >> ``operator.length`` or ``operator.length_hint``? >> >> > + def length_hint(obj, default): >> Is there default value for `default` parameter? >> For example: >> >> def length_hint(obj, default=0): >> pass >> >> or something like that? >> >> -- >> Thanks, >> Andrew Svetlov >> _______________________________________________ >> Python-Dev mailing list >> Python-Dev at python.org >> http://mail.python.org/mailman/listinfo/python-dev >> Unsubscribe: >> http://mail.python.org/mailman/options/python-dev/iftecan2000%40gmail.com > > -- Thanks, Andrew Svetlov From python-checkins at python.org Mon Jul 30 23:46:03 2012 From: python-checkins at python.org (brett.cannon) Date: Mon, 30 Jul 2012 23:46:03 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315508=3A_Fix_the_?= =?utf-8?q?docstring_for_=5F=5Fimport=5F=5F_to_not_mention_negative?= Message-ID: <3WmDqb5LzCzPX1@mail.python.org> http://hg.python.org/cpython/rev/2a4ca86cc2b7 changeset: 78338:2a4ca86cc2b7 parent: 78336:2f3ccf4ec193 user: Brett Cannon date: Mon Jul 30 17:45:54 2012 -0400 summary: Issue #15508: Fix the docstring for __import__ to not mention negative 'level' values and set its document default value to 0. Thanks to Arfrever Frehtes Taifersar Arahesis for filing the bug. files: Misc/NEWS | 4 ++++ Python/bltinmodule.c | 5 ++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #15508: Fix the docstring for __import__ to have the proper default + value of 0 for 'level' and to not mention negative levels since they are + not supported. + - Issue #15425: Eliminated traceback noise from more situations involving importlib diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -195,7 +195,7 @@ } PyDoc_STRVAR(import_doc, -"__import__(name, globals={}, locals={}, fromlist=[], level=-1) -> module\n\ +"__import__(name, globals={}, locals={}, fromlist=[], level=0) -> module\n\ \n\ Import a module. Because this function is meant for use by the Python\n\ interpreter and not for general use it is better to use\n\ @@ -208,8 +208,7 @@ When importing a module from a package, note that __import__('A.B', ...)\n\ returns package A when fromlist is empty, but its submodule B when\n\ fromlist is not empty. Level is used to determine whether to perform \n\ -absolute or relative imports. -1 is the original strategy of attempting\n\ -both absolute and relative imports, 0 is absolute, a positive number\n\ +absolute or relative imports. 0 is absolute while a positive number\n\ is the number of parent directories to search relative to the current module."); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 31 00:35:24 2012 From: python-checkins at python.org (brett.cannon) Date: Tue, 31 Jul 2012 00:35:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Add_a_versionchanged_menti?= =?utf-8?q?on_to_=5F=5Fimport=5F=5F_in_regards_to_negative_level_values=2E?= Message-ID: <3WmFwX0MdPzPZX@mail.python.org> http://hg.python.org/cpython/rev/231d98a38eec changeset: 78339:231d98a38eec user: Brett Cannon date: Mon Jul 30 18:35:17 2012 -0400 summary: Add a versionchanged mention to __import__ in regards to negative level values. files: Doc/library/functions.rst | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1506,6 +1506,9 @@ If you simply want to import a module (potentially within a package) by name, use :func:`importlib.import_module`. + .. versionchanged:: 3.3 + Negative values for 'level' are no longer supported. + .. rubric:: Footnotes -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 31 01:31:07 2012 From: python-checkins at python.org (brett.cannon) Date: Tue, 31 Jul 2012 01:31:07 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Minor_markup_tweak=2E?= Message-ID: <3WmH8q2Wr7zPVM@mail.python.org> http://hg.python.org/cpython/rev/d56b647f325a changeset: 78340:d56b647f325a user: Brett Cannon date: Mon Jul 30 19:31:00 2012 -0400 summary: Minor markup tweak. files: Doc/library/functions.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1507,7 +1507,7 @@ use :func:`importlib.import_module`. .. versionchanged:: 3.3 - Negative values for 'level' are no longer supported. + Negative values for *level* are no longer supported. .. rubric:: Footnotes -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 31 03:00:42 2012 From: python-checkins at python.org (victor.stinner) Date: Tue, 31 Jul 2012 03:00:42 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_initialization_of_the_?= =?utf-8?q?faulthandler_module?= Message-ID: <3WmK8B3qWxzPV0@mail.python.org> http://hg.python.org/cpython/rev/2f1494d243ad changeset: 78341:2f1494d243ad user: Victor Stinner date: Tue Jul 31 02:55:49 2012 +0200 summary: Fix initialization of the faulthandler module faulthandler requires the importlib if "-X faulthandler" option is present on the command line, so initialize faulthandler after importlib. Add also an unit test. files: Lib/test/test_faulthandler.py | 15 +++++++++++++++ Python/pythonrun.c | 8 ++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -7,6 +7,7 @@ import subprocess import sys from test import support, script_helper +from test.script_helper import assert_python_ok import tempfile import unittest @@ -256,6 +257,20 @@ finally: sys.stderr = orig_stderr + def test_disabled_by_default(self): + # By default, the module should be disabled + code = "import faulthandler; print(faulthandler.is_enabled())" + rc, stdout, stderr = assert_python_ok("-c", code) + stdout = (stdout + stderr).strip() + self.assertEqual(stdout, b"False") + + def test_sys_xoptions(self): + # Test python -X faulthandler + code = "import faulthandler; print(faulthandler.is_enabled())" + rc, stdout, stderr = assert_python_ok("-X", "faulthandler", "-c", code) + stdout = (stdout + stderr).strip() + self.assertEqual(stdout, b"True") + def check_dump_traceback(self, filename): """ Explicitly call dump_traceback() function and check its output. diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -356,10 +356,6 @@ _PyImportHooks_Init(); - /* initialize the faulthandler module */ - if (_PyFaulthandler_Init()) - Py_FatalError("Py_Initialize: can't initialize faulthandler"); - /* Initialize _warnings. */ _PyWarnings_Init(); @@ -368,6 +364,10 @@ import_init(interp, sysmod); + /* initialize the faulthandler module */ + if (_PyFaulthandler_Init()) + Py_FatalError("Py_Initialize: can't initialize faulthandler"); + _PyTime_Init(); if (initfsencoding(interp) < 0) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 31 03:29:35 2012 From: python-checkins at python.org (victor.stinner) Date: Tue, 31 Jul 2012 03:29:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Update_the_string_limit_in?= =?utf-8?q?_the_faulthandler_documentations?= Message-ID: <3WmKnW3d3FzPTd@mail.python.org> http://hg.python.org/cpython/rev/dc9402c3db92 changeset: 78342:dc9402c3db92 user: Victor Stinner date: Tue Jul 31 03:25:28 2012 +0200 summary: Update the string limit in the faulthandler documentations files: Doc/library/faulthandler.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/faulthandler.rst b/Doc/library/faulthandler.rst --- a/Doc/library/faulthandler.rst +++ b/Doc/library/faulthandler.rst @@ -23,7 +23,7 @@ * Only ASCII is supported. The ``backslashreplace`` error handler is used on encoding. -* Each string is limited to 100 characters. +* Each string is limited to 500 characters. * Only the filename, the function name and the line number are displayed. (no source code) * It is limited to 100 frames and 100 threads. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 31 05:15:19 2012 From: python-checkins at python.org (eli.bendersky) Date: Tue, 31 Jul 2012 05:15:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315231=3A_rephrase?= =?utf-8?q?_the_last_paragraph_slightly?= Message-ID: <3WmN7W3Gp6zPbY@mail.python.org> http://hg.python.org/cpython/rev/3a08d766eee3 changeset: 78343:3a08d766eee3 user: Eli Bendersky date: Tue Jul 31 06:14:59 2012 +0300 summary: Issue #15231: rephrase the last paragraph slightly files: Doc/distutils/uploading.rst | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Doc/distutils/uploading.rst b/Doc/distutils/uploading.rst --- a/Doc/distutils/uploading.rst +++ b/Doc/distutils/uploading.rst @@ -74,5 +74,7 @@ :mod:`docutils` will display a warning if there's something wrong with your syntax. Because PyPI applies additional checks (e.g. by passing ``--no-raw`` -to ``rst2html.py`` in the command above), running the command above without -warnings is not sufficient for PyPI to convert the content successfully. +to ``rst2html.py`` in the command above), being able to run the command above +without warnings does not guarantee that PyPI will convert the content +successfully. + -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Tue Jul 31 05:54:31 2012 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 31 Jul 2012 05:54:31 +0200 Subject: [Python-checkins] Daily reference leaks (dc9402c3db92): sum=0 Message-ID: results for dc9402c3db92 on branch "default" -------------------------------------------- test_support leaked [-1, 1, 0] references, sum=0 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogb0l4qQ', '-x'] From python-checkins at python.org Tue Jul 31 13:14:33 2012 From: python-checkins at python.org (nick.coghlan) Date: Tue, 31 Jul 2012 13:14:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Close_=2315486=3A_Simplify?= =?utf-8?q?_the_mechanism_used_to_remove_importlib_frames_from?= Message-ID: <3WmZmT466dzPbV@mail.python.org> http://hg.python.org/cpython/rev/62033490ca0f changeset: 78344:62033490ca0f user: Nick Coghlan date: Tue Jul 31 21:14:18 2012 +1000 summary: Close #15486: Simplify the mechanism used to remove importlib frames from tracebacks when they just introduce irrelevant noise files: Lib/importlib/_bootstrap.py | 65 +- Lib/test/test_import.py | 6 +- Python/import.c | 28 +- Python/importlib.h | 7034 +++++++++++----------- 4 files changed, 3510 insertions(+), 3623 deletions(-) diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -297,8 +297,20 @@ else: lock.release() +# Frame stripping magic ############################################### -# Finder/loader utility code ################################################## +def _call_with_frames_removed(f, *args, **kwds): + """remove_importlib_frames in import.c will always remove sequences + of importlib frames that end with a call to this function + + Use it instead of a normal call in places where including the importlib + frames introduces unwanted noise into the traceback (e.g. when executing + module code) + """ + return f(*args, **kwds) + + +# Finder/loader utility code ############################################### """Magic word to reject .pyc files generated by other Python versions. It should change for each incompatible change to the bytecode. @@ -629,20 +641,13 @@ """Load a built-in module.""" is_reload = fullname in sys.modules try: - return cls._exec_module(fullname) + return _call_with_frames_removed(_imp.init_builtin, fullname) except: if not is_reload and fullname in sys.modules: del sys.modules[fullname] raise @classmethod - def _exec_module(cls, fullname): - """Helper for load_module, allowing to isolate easily (when - looking at a traceback) whether an error comes from executing - an imported module's code.""" - return _imp.init_builtin(fullname) - - @classmethod @_requires_builtin def get_code(cls, fullname): """Return None as built-in modules do not have code objects.""" @@ -687,7 +692,7 @@ """Load a frozen module.""" is_reload = fullname in sys.modules try: - m = cls._exec_module(fullname) + m = _call_with_frames_removed(_imp.init_frozen, fullname) # Let our own module_repr() method produce a suitable repr. del m.__file__ return m @@ -714,13 +719,6 @@ """Return if the frozen module is a package.""" return _imp.is_frozen_package(fullname) - @classmethod - def _exec_module(cls, fullname): - """Helper for load_module, allowing to isolate easily (when - looking at a traceback) whether an error comes from executing - an imported module's code.""" - return _imp.init_frozen(fullname) - class WindowsRegistryImporter: @@ -850,15 +848,9 @@ else: module.__package__ = module.__package__.rpartition('.')[0] module.__loader__ = self - self._exec_module(code_object, module.__dict__) + _call_with_frames_removed(exec, code_object, module.__dict__) return module - def _exec_module(self, code_object, module_dict): - """Helper for _load_module, allowing to isolate easily (when - looking at a traceback) whether an error comes from executing - an imported module's code.""" - exec(code_object, module_dict) - class SourceLoader(_LoaderBasics): @@ -956,8 +948,9 @@ raise ImportError(msg.format(bytecode_path), name=fullname, path=bytecode_path) source_bytes = self.get_data(source_path) - code_object = compile(source_bytes, source_path, 'exec', - dont_inherit=True) + code_object = _call_with_frames_removed(compile, + source_bytes, source_path, 'exec', + dont_inherit=True) _verbose_message('code object from {}', source_path) if (not sys.dont_write_bytecode and bytecode_path is not None and source_mtime is not None): @@ -1093,7 +1086,8 @@ """Load an extension module.""" is_reload = fullname in sys.modules try: - module = self._exec_module(fullname, self.path) + module = _call_with_frames_removed(_imp.load_dynamic, + fullname, self.path) _verbose_message('extension module loaded from {!r}', self.path) return module except: @@ -1113,12 +1107,6 @@ """Return None as extension modules have no source code.""" return None - def _exec_module(self, fullname, path): - """Helper for load_module, allowing to isolate easily (when - looking at a traceback) whether an error comes from executing - an imported module's code.""" - return _imp.load_dynamic(fullname, path) - class _NamespacePath: """Represents a namespace package's path. It uses the module name @@ -1472,7 +1460,7 @@ parent = name.rpartition('.')[0] if parent: if parent not in sys.modules: - _recursive_import(import_, parent) + _call_with_frames_removed(import_, parent) # Crazy side-effects! if name in sys.modules: return sys.modules[name] @@ -1550,13 +1538,6 @@ _lock_unlock_module(name) return module -def _recursive_import(import_, name): - """Common exit point for recursive calls to the import machinery - - This simplifies the process of stripping importlib from tracebacks - """ - return import_(name) - def _handle_fromlist(module, fromlist, import_): """Figure out what __import__ should return. @@ -1575,7 +1556,7 @@ fromlist.extend(module.__all__) for x in fromlist: if not hasattr(module, x): - _recursive_import(import_, + _call_with_frames_removed(import_, '{}.{}'.format(module.__name__, x)) return module diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -785,11 +785,13 @@ sys.path[:] = self.old_path rmtree(TESTFN) - def create_module(self, mod, contents): - with open(os.path.join(TESTFN, mod + ".py"), "w") as f: + def create_module(self, mod, contents, ext=".py"): + fname = os.path.join(TESTFN, mod + ext) + with open(fname, "w") as f: f.write(contents) self.addCleanup(unload, mod) importlib.invalidate_caches() + return fname def assert_traceback(self, tb, files): deduped_files = [] diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -1153,9 +1153,7 @@ remove_importlib_frames(void) { const char *importlib_filename = ""; - const char *exec_funcname = "_exec_module"; - const char *get_code_funcname = "get_code"; - const char *recursive_import = "_recursive_import"; + const char *remove_frames = "_call_with_frames_removed"; int always_trim = 0; int trim_get_code = 0; int in_importlib = 0; @@ -1163,18 +1161,8 @@ PyObject **prev_link, **outer_link = NULL; /* Synopsis: if it's an ImportError, we trim all importlib chunks - from the traceback. If it's a SyntaxError, we trim any chunks that - end with a call to "get_code", We always trim chunks - which end with a call to "_exec_module". */ - - /* Thanks to issue 15425, we also strip any chunk ending with - * _recursive_import. This is used when making a recursive call to the - * full import machinery which means the inner stack gets stripped early - * and the normal heuristics won't fire properly for outer frames. A - * more elegant mechanism would be nice, as this one can misfire if - * builtins.__import__ has been replaced with a custom implementation. - * However, the current approach at least gets the job done. - */ + from the traceback. We always trim chunks + which end with a call to "_call_with_frames_removed". */ PyErr_Fetch(&exception, &value, &base_tb); if (!exception || Py_VerboseFlag) @@ -1207,14 +1195,8 @@ if (in_importlib && (always_trim || - (PyUnicode_CompareWithASCIIString(code->co_name, - exec_funcname) == 0) || - (PyUnicode_CompareWithASCIIString(code->co_name, - recursive_import) == 0) || - (trim_get_code && - PyUnicode_CompareWithASCIIString(code->co_name, - get_code_funcname) == 0) - )) { + PyUnicode_CompareWithASCIIString(code->co_name, + remove_frames) == 0)) { PyObject *tmp = *outer_link; *outer_link = next; Py_XINCREF(next); diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 31 13:39:58 2012 From: python-checkins at python.org (nick.coghlan) Date: Tue, 31 Jul 2012 13:39:58 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315425=3A_Don=27t_?= =?utf-8?q?rely_on_the_assumption_that_the_current_working_directory?= Message-ID: <3WmbKp1g5RzNbw@mail.python.org> http://hg.python.org/cpython/rev/8a0eb395e725 changeset: 78345:8a0eb395e725 user: Nick Coghlan date: Tue Jul 31 21:39:42 2012 +1000 summary: Issue #15425: Don't rely on the assumption that the current working directory is on sys.path (this will hopefully appease the XP buildbots) files: Lib/test/test_import.py | 12 +++++------- 1 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -859,16 +859,14 @@ def _setup_broken_package(self, parent, child): pkg_name = "_parent_foo" - def cleanup(): - rmtree(pkg_name) - unload(pkg_name) - os.mkdir(pkg_name) - self.addCleanup(cleanup) + self.addCleanup(unload, pkg_name) + pkg_path = os.path.join(TESTFN, pkg_name) + os.mkdir(pkg_path) # Touch the __init__.py - init_path = os.path.join(pkg_name, '__init__.py') + init_path = os.path.join(pkg_path, '__init__.py') with open(init_path, 'w') as f: f.write(parent) - bar_path = os.path.join(pkg_name, 'bar.py') + bar_path = os.path.join(pkg_path, 'bar.py') with open(bar_path, 'w') as f: f.write(child) importlib.invalidate_caches() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 31 16:23:34 2012 From: python-checkins at python.org (eli.bendersky) Date: Tue, 31 Jul 2012 16:23:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2314814=3A_reorgani?= =?utf-8?q?ze_ipaddress_documentation_and_document_all_attributes_of?= Message-ID: <3WmfyZ576NzPQf@mail.python.org> http://hg.python.org/cpython/rev/586eb57e06ba changeset: 78346:586eb57e06ba user: Eli Bendersky date: Tue Jul 31 17:23:11 2012 +0300 summary: Issue #14814: reorganize ipaddress documentation and document all attributes of IPv[46]Address objects files: Doc/library/ipaddress.rst | 248 ++++++++++++++++++++----- 1 files changed, 192 insertions(+), 56 deletions(-) diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst --- a/Doc/library/ipaddress.rst +++ b/Doc/library/ipaddress.rst @@ -22,19 +22,18 @@ IP address or network definition. -Defining IP Addresses and Interfaces ------------------------------------- +Convenience factory functions +----------------------------- -The :mod:`ipaddress` module provides factory functions to define IP addresses -and networks: +The :mod:`ipaddress` module provides factory functions to conveniently create +IP addresses, networks and interfaces: .. function:: ip_address(address) Return an :class:`IPv4Address` or :class:`IPv6Address` object depending on - the IP address passed as argument. *address* is a string or integer - representing the IP address. Either IPv4 or IPv6 addresses may be supplied; - integers less than 2**32 will be considered to be IPv4 by default. A - :exc:`ValueError` is raised if the *address* passed is neither an IPv4 nor + the IP address passed as argument. Either IPv4 or IPv6 addresses may be + supplied; integers less than 2**32 will be considered to be IPv4 by default. + A :exc:`ValueError` is raised if *address* does not represent a valid IPv4 or IPv6 address. >>> ipaddress.ip_address('192.168.0.1') @@ -50,8 +49,8 @@ representing the IP network. Either IPv4 or IPv6 networks may be supplied; integers less than 2**32 will be considered to be IPv4 by default. *strict* is passed to :class:`IPv4Network` or :class:`IPv6Network` constructor. A - :exc:`ValueError` is raised if the string passed isn't either an IPv4 or IPv6 - address, or if the network has host bits set. + :exc:`ValueError` is raised if *address* does not represent a valid IPv4 or + IPv6 address, or if the network has host bits set. >>> ipaddress.ip_network('192.168.0.0/28') IPv4Network('192.168.0.0/28') @@ -62,45 +61,174 @@ Return an :class:`IPv4Interface` or :class:`IPv6Interface` object depending on the IP address passed as argument. *address* is a string or integer representing the IP address. Either IPv4 or IPv6 addresses may be supplied; - integers less than 2**32 will be considered to be IPv4 by default.. A - :exc:`ValueError` is raised if the *address* passed isn't either an IPv4 or + integers less than 2**32 will be considered to be IPv4 by default. A + :exc:`ValueError` is raised if *address* does not represent a valid IPv4 or IPv6 address. -Representing IP Addresses and Networks --------------------------------------- +Address objects +--------------- -The module defines the following and classes to represent IP addresses -and networks: - -.. todo: list the properties and methods +The :class:`IPv4Address` and :class:`IPv6Address` objects share a lot of common +attributes. Some attributes that are only meaningful for IPv6 addresses are +also implemented by :class:`IPv4Address` objects, in order to make it easier to +write code that handles both IP versions correctly. To avoid duplication, all +common attributes will only be documented for :class:`IPv4Address`. .. class:: IPv4Address(address) - Construct an IPv4 address. *address* is a string or integer representing the - IP address. An :exc:`AddressValueError` is raised if *address* is not a - valid IPv4 address. + Construct an IPv4 address. An :exc:`AddressValueError` is raised if + *address* is not a valid IPv4 address. + + The following constitutes a valid IPv4 address: + + 1. A string in decimal-dot notation, consisting of four decimal integers in + the inclusive range 0-255, separated by dots (e.g. ``192.168.0.1``). Each + integer represents an octet (byte) in the address, big-endian. + 2. An integer that fits into 32 bits. + 3. An integer packed into a :class:`bytes` object of length 4, big-endian. >>> ipaddress.IPv4Address('192.168.0.1') IPv4Address('192.168.0.1') >>> ipaddress.IPv4Address('192.0.2.1') == ipaddress.IPv4Address(3221225985) True + .. attribute:: exploded -.. class:: IPv4Interface(address) + The longhand version of the address as a string. Note: the + exploded/compressed distinction is meaningful only for IPv6 addresses. + For IPv4 addresses it is the same. - Construct an IPv4 interface. *address* is a string or integer representing - the IP interface. An :exc:`AddressValueError` is raised if *address* is not - a valid IPv4 address. + .. attribute:: compressed - The network address for the interface is determined by calling - ``IPv4Network(address, strict=False)``. + The shorthand version of the address as a string. - >>> ipaddress.IPv4Interface('192.168.0.0/24') - IPv4Interface('192.168.0.0/24') - >>> ipaddress.IPv4Interface('192.168.0.0/24').network - IPv4Network('192.168.0.0/24') + .. attribute:: packed + The binary representation of this address - a :class:`bytes` object. + + .. attribute:: version + + A numeric version number. + + .. attribute:: max_prefixlen + + Maximal length of the prefix (in bits). The prefix defines the number of + leading bits in an address that are compared to determine whether or not an + address is part of a network. + + .. attribute:: is_multicast + + ``True`` if the address is reserved for multicast use. See :RFC:`3171` (for + IPv4) or :RFC:`2373` (for IPv6). + + .. attribute:: is_private + + ``True`` if the address is allocated for private networks. See :RFC:`1918` + (for IPv4) or :RFC:`4193` (for IPv6). + + .. attribute:: is_unspecified + + ``True`` if the address is unspecified. See :RFC:`5375` (for IPv4) or + :RFC:`2373` (for IPv6). + + .. attribute:: is_reserved + + ``True`` if the address is otherwise IETF reserved. + + .. attribute:: is_loopback + + ``True`` if this is a loopback address. See :RFC:`3330` (for IPv4) or + :RFC:`2373` (for IPv6). + + .. attribute:: is_link_local + + ``True`` if the address is reserved for link-local. See :RFC:`3927`. + +.. class:: IPv6Address(address) + + Construct an IPv6 address. An :exc:`AddressValueError` is raised if + *address* is not a valid IPv6 address. + + The following constitutes a valid IPv6 address: + + 1. A string consisting of eight groups of four hexadecimal digits, each + group representing 16 bits. The groups are separated by colons. + This describes an *exploded* (longhand) notation. The string can + also be *compressed* (shorthand notation) by various means. See + :RFC:`4291` for details. For example, + ``"0000:0000:0000:0000:0000:0abc:0007:0def"`` can be compressed to + ``"::abc:7:def"``. + 2. An integer that fits into 128 bits. + 3. An integer packed into a :class:`bytes` object of length 16, big-endian. + + >>> ipaddress.IPv6Address('2001:db8::1000') + IPv6Address('2001:db8::1000') + + All the attributes exposed by :class:`IPv4Address` are supported. In + addition, the following attributs are exposed only by :class:`IPv6Address`. + + .. attribute:: is_site_local + + ``True`` if the address is reserved for site-local. Note that the site-local + address space has been deprecated by :RFC:`3879`. Use + :attr:`~IPv4Address.is_private` to test if this address is in the space of + unique local addresses as defined by :RFC:`4193`. + + .. attribute:: ipv4_mapped + + If this address represents a IPv4 mapped address, return the IPv4 mapped + address. Otherwise return ``None``. + + .. attribute:: teredo + + If this address appears to be a teredo address (starts with ``2001::/32``), + return a tuple of embedded teredo IPs ``(server, client)`` pairs. Otherwise + return ``None``. + + .. attribute:: sixtofour + + If this address appears to contain a 6to4 embedded address, return the + embedded IPv4 address. Otherwise return ``None``. + + +Operators +^^^^^^^^^ + +Address objects support some operators. Unless stated otherwise, operators can +only be applied between compatible objects (i.e. IPv4 with IPv4, IPv6 with +IPv6). + +Logical operators +""""""""""""""""" + +Address objects can be compared with the usual set of logical operators. Some +examples:: + + >>> IPv4Address('127.0.0.2') > IPv4Address('127.0.0.1') + True + >>> IPv4Address('127.0.0.2') == IPv4Address('127.0.0.1') + False + >>> IPv4Address('127.0.0.2') != IPv4Address('127.0.0.1') + True + +Arithmetic operators +"""""""""""""""""""" + +Integers can be added to or subtracted from address objects. Some examples:: + + >>> IPv4Address('127.0.0.2') + 3 + IPv4Address('127.0.0.5') + >>> IPv4Address('127.0.0.2') - 3 + IPv4Address('126.255.255.255') + >>> IPv4Address('255.255.255.255') + 1 + Traceback (most recent call last): + File "", line 1, in + ipaddress.AddressValueError: 4294967296 (>= 2**32) is not permitted as an IPv4 address + + +Network objects +--------------- .. class:: IPv4Network(address, strict=True) @@ -121,31 +249,6 @@ IPv4Network('192.0.2.0/27') -.. class:: IPv6Address(address) - - Construct an IPv6 address. *address* is a string or integer representing the - IP address. An :exc:`AddressValueError` is raised if *address* is not a - valid IPv6 address. - - >>> ipaddress.IPv6Address('2001:db8::1000') - IPv6Address('2001:db8::1000') - - -.. class:: IPv6Interface(address) - - Construct an IPv6 interface. *address* is a string or integer representing - the IP interface. An :exc:`AddressValueError` is raised if *address* is not - a valid IPv6 address. - - The network address for the interface is determined by calling - ``IPv6Network(address, strict=False)``. - - >>> ipaddress.IPv6Interface('2001:db8::1000/96') - IPv6Interface('2001:db8::1000/96') - >>> ipaddress.IPv6Interface('2001:db8::1000/96').network - IPv6Network('2001:db8::/96') - - .. class:: IPv6Network(address, strict=True) Construct an IPv6 network. *address* is a string or integer representing the @@ -165,6 +268,39 @@ IPv6Network('2001:db8::/96') +Interface objects +----------------- + +.. class:: IPv4Interface(address) + + Construct an IPv4 interface. *address* is a string or integer representing + the IP interface. An :exc:`AddressValueError` is raised if *address* is not + a valid IPv4 address. + + The network address for the interface is determined by calling + ``IPv4Network(address, strict=False)``. + + >>> ipaddress.IPv4Interface('192.168.0.0/24') + IPv4Interface('192.168.0.0/24') + >>> ipaddress.IPv4Interface('192.168.0.0/24').network + IPv4Network('192.168.0.0/24') + + +.. class:: IPv6Interface(address) + + Construct an IPv6 interface. *address* is a string or integer representing + the IP interface. An :exc:`AddressValueError` is raised if *address* is not + a valid IPv6 address. + + The network address for the interface is determined by calling + ``IPv6Network(address, strict=False)``. + + >>> ipaddress.IPv6Interface('2001:db8::1000/96') + IPv6Interface('2001:db8::1000/96') + >>> ipaddress.IPv6Interface('2001:db8::1000/96').network + IPv6Network('2001:db8::/96') + + Other Module Level Functions ---------------------------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 31 16:25:53 2012 From: python-checkins at python.org (eli.bendersky) Date: Tue, 31 Jul 2012 16:25:53 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2314814=3A_fix_some?= =?utf-8?q?_typos_in_howto/ipaddress=2Erst?= Message-ID: <3Wmg1F372QzPXx@mail.python.org> http://hg.python.org/cpython/rev/07ddf5ecaafa changeset: 78347:07ddf5ecaafa user: Eli Bendersky date: Tue Jul 31 17:25:33 2012 +0300 summary: Issue #14814: fix some typos in howto/ipaddress.rst files: Doc/howto/ipaddress.rst | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/howto/ipaddress.rst b/Doc/howto/ipaddress.rst --- a/Doc/howto/ipaddress.rst +++ b/Doc/howto/ipaddress.rst @@ -19,7 +19,7 @@ Creating Address/Network/Interface objects ========================================== -Since :mod:`ipaddress` is a module for inspecting and manipulating IP address, +Since :mod:`ipaddress` is a module for inspecting and manipulating IP addresses, the first thing you'll want to do is create some objects. You can use :mod:`ipaddress` to create objects from strings and integers. @@ -183,10 +183,10 @@ >>> net6.numhosts 4294967296 -Iterating through the 'usable' addresses on a network:: +Iterating through the "usable" addresses on a network:: >>> net4 = ipaddress.ip_network('192.0.2.0/24') - >>> for x in net4.iterhosts(): + >>> for x in net4.hosts(): print(x) 192.0.2.1 192.0.2.2 @@ -294,7 +294,7 @@ When creating address/network/interface objects using the version-agnostic factory functions, any errors will be reported as :exc:`ValueError` with a generic error message that simply says the passed in value was not -recognised as an object of that type. The lack of a specific error is +recognized as an object of that type. The lack of a specific error is because it's necessary to know whether the value is *supposed* to be IPv4 or IPv6 in order to provide more detail on why it has been rejected. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 31 18:52:49 2012 From: python-checkins at python.org (andrew.svetlov) Date: Tue, 31 Jul 2012 18:52:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzk4MDM6?= =?utf-8?q?_Don=27t_close_IDLE_on_saving_if_breakpoint_is_open=2E?= Message-ID: <3WmkGn5ZnjzPc9@mail.python.org> http://hg.python.org/cpython/rev/47536beb7453 changeset: 78348:47536beb7453 branch: 3.2 parent: 78335:fd5166fdb978 user: Andrew Svetlov date: Tue Jul 31 19:48:00 2012 +0300 summary: Issue #9803: Don't close IDLE on saving if breakpoint is open. Patch by Roger Serwy. files: Lib/idlelib/PyShell.py | 4 ++-- Misc/NEWS | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -248,8 +248,8 @@ def ranges_to_linenumbers(self, ranges): lines = [] for index in range(0, len(ranges), 2): - lineno = int(float(ranges[index])) - end = int(float(ranges[index+1])) + lineno = int(float(ranges[index].string)) + end = int(float(ranges[index+1].string)) while lineno < end: lines.append(lineno) lineno += 1 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -98,6 +98,9 @@ Library ------- +- Issue #9803: Don't close IDLE on saving if breakpoint is open. + Patch by Roger Serwy. + - Issue #12288: Consider '0' and '0.0' as valid initialvalue for tkinter SimpleDialog. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 31 18:52:52 2012 From: python-checkins at python.org (andrew.svetlov) Date: Tue, 31 Jul 2012 18:52:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E2_-=3E_default?= =?utf-8?q?=29=3A_Issue_=239803=3A_Don=27t_close_IDLE_on_saving_if_breakpo?= =?utf-8?q?int_is_open=2E?= Message-ID: <3WmkGr0BtXzPcC@mail.python.org> http://hg.python.org/cpython/rev/28c935ded243 changeset: 78349:28c935ded243 parent: 78347:07ddf5ecaafa parent: 78348:47536beb7453 user: Andrew Svetlov date: Tue Jul 31 19:49:38 2012 +0300 summary: Issue #9803: Don't close IDLE on saving if breakpoint is open. Patch by Roger Serwy. files: Lib/idlelib/PyShell.py | 4 ++-- Misc/NEWS | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -248,8 +248,8 @@ def ranges_to_linenumbers(self, ranges): lines = [] for index in range(0, len(ranges), 2): - lineno = int(float(ranges[index])) - end = int(float(ranges[index+1])) + lineno = int(float(ranges[index].string)) + end = int(float(ranges[index+1].string)) while lineno < end: lines.append(lineno) lineno += 1 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -343,6 +343,9 @@ Library ------- +- Issue #9803: Don't close IDLE on saving if breakpoint is open. + Patch by Roger Serwy. + - Issue #12288: Consider '0' and '0.0' as valid initialvalue for tkinter SimpleDialog. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 31 18:52:53 2012 From: python-checkins at python.org (andrew.svetlov) Date: Tue, 31 Jul 2012 18:52:53 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzk4MDM6?= =?utf-8?q?_Don=27t_close_IDLE_on_saving_if_breakpoint_is_open=2E?= Message-ID: <3WmkGs4cFnzPd3@mail.python.org> http://hg.python.org/cpython/rev/8f1a8e80f330 changeset: 78350:8f1a8e80f330 branch: 2.7 parent: 78337:f98e2944cb40 user: Andrew Svetlov date: Tue Jul 31 19:51:27 2012 +0300 summary: Issue #9803: Don't close IDLE on saving if breakpoint is open. Patch by Roger Serwy. files: Lib/idlelib/PyShell.py | 4 ++-- Misc/NEWS | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -252,8 +252,8 @@ def ranges_to_linenumbers(self, ranges): lines = [] for index in range(0, len(ranges), 2): - lineno = int(float(ranges[index])) - end = int(float(ranges[index+1])) + lineno = int(float(ranges[index].string)) + end = int(float(ranges[index+1].string)) while lineno < end: lines.append(lineno) lineno += 1 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -92,6 +92,9 @@ Library ------- +- Issue #9803: Don't close IDLE on saving if breakpoint is open. + Patch by Roger Serwy. + - Issue #12288: Consider '0' and '0.0' as valid initialvalue for tkinter SimpleDialog. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 31 22:10:22 2012 From: python-checkins at python.org (barry.warsaw) Date: Tue, 31 Jul 2012 22:10:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Integration_of_importdocs_?= =?utf-8?q?from_the_features/pep-420_repo=2E?= Message-ID: <3Wmpfk0hR3zPcd@mail.python.org> http://hg.python.org/cpython/rev/d64f84bd1a02 changeset: 78351:d64f84bd1a02 parent: 78307:fe29a657bde9 user: Barry Warsaw date: Sun Jul 29 16:36:17 2012 -0400 summary: Integration of importdocs from the features/pep-420 repo. files: Doc/glossary.rst | 70 +- Doc/library/importlib.rst | 27 +- Doc/reference/datamodel.rst | 29 +- Doc/reference/import_machinery.rst | 547 +++++++++++++++++ Doc/reference/index.rst | 1 + Doc/reference/simple_stmts.rst | 172 +---- Lib/importlib/abc.py | 19 +- 7 files changed, 693 insertions(+), 172 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -209,9 +209,9 @@ finder An object that tries to find the :term:`loader` for a module. It must - implement a method named :meth:`find_module`. See :pep:`302` for - details and :class:`importlib.abc.Finder` for an - :term:`abstract base class`. + implement either a method named :meth:`find_loader` or a method named + :meth:`find_module`. See :pep:`302` and :pep:`420` for details and + :class:`importlib.abc.Finder` for an :term:`abstract base class`. floor division Mathematical division that rounds down to nearest integer. The floor @@ -315,6 +315,10 @@ role in places where a constant hash value is needed, for example as a key in a dictionary. + importing + The process by which Python code in one module is made available to + Python code in another module. + importer An object that both finds and loads a module; both a :term:`finder` and :term:`loader` object. @@ -440,6 +444,11 @@ include :class:`dict`, :class:`collections.defaultdict`, :class:`collections.OrderedDict` and :class:`collections.Counter`. + meta path finder + A finder returned by a search of :data:`sys.meta_path`. Meta path + finders are related to, but different from :term:`sys path finders `. + metaclass The class of a class. Class definitions create a class name, a class dictionary, and a list of base classes. The metaclass is responsible for @@ -464,6 +473,11 @@ for a member during lookup. See `The Python 2.3 Method Resolution Order `_. + module + An object that serves as an organizational unit of Python code. Modules + have a namespace contain arbitrary Python objects. Modules are loaded + into Python by the process of :term:`importing`. + MRO See :term:`method resolution order`. @@ -496,6 +510,12 @@ functions are implemented by the :mod:`random` and :mod:`itertools` modules, respectively. + namespace package + A :pep:`420` :term:`package` which serves only as a container for + subpackages. Namespace packages may have no physical representation, + and specifically are not like a :term:`regular package` because they + have no ``__init__.py`` file. + nested scope The ability to refer to a variable in an enclosing definition. For instance, a function defined inside another function can refer to @@ -516,6 +536,19 @@ (methods). Also the ultimate base class of any :term:`new-style class`. + package + A Python module which can contain submodules or recursively, + subpackages. Technically, a package is a Python module with an + ``__path__`` attribute. + + path importer + A built-in :term:`finder` / :term:`loader` that knows how to find and + load modules from the file system. + + portion + A set of files in a single directory (possibly stored in a zip file) + that contribute to a namespace package, as defined in :pep:`420`. + positional argument The arguments assigned to local names inside a function or method, determined by the order in which they were given in the call. ``*`` is @@ -524,8 +557,8 @@ :term:`argument`. provisional package - A provisional package is one which has been deliberately excluded from the - standard library's backwards compatibility guarantees. While major + A provisional package is one which has been deliberately excluded from + the standard library's backwards compatibility guarantees. While major changes to such packages are not expected, as long as they are marked provisional, backwards incompatible changes (up to and including removal of the package) may occur if deemed necessary by core developers. Such @@ -533,13 +566,13 @@ flaws are uncovered that were missed prior to the inclusion of the package. - This process allows the standard library to continue to evolve over time, - without locking in problematic design errors for extended periods of time. - See :pep:`411` for more details. + This process allows the standard library to continue to evolve over + time, without locking in problematic design errors for extended periods + of time. See :pep:`411` for more details. Python 3000 - Nickname for the Python 3.x release line (coined long ago when the release - of version 3 was something in the distant future.) This is also + Nickname for the Python 3.x release line (coined long ago when the + release of version 3 was something in the distant future.) This is also abbreviated "Py3k". Pythonic @@ -576,6 +609,14 @@ >>> C.D.meth.__qualname__ 'C.D.meth' + When used to refer to modules, the *fully qualified name* means the + entire dotted path to the module, including any parent packages, + e.g. ``email.mime.text``:: + + >>> import email.mime.text + >>> email.mime.text.__name__ + 'email.mime.text' + reference count The number of references to an object. When the reference count of an object drops to zero, it is deallocated. Reference counting is @@ -584,6 +625,10 @@ :func:`~sys.getrefcount` function that programmers can call to return the reference count for a particular object. + regular package + A traditional :term:`package`, such as a directory containing an + ``__init__.py`` file. + __slots__ A declaration inside a class that saves memory by pre-declaring space for instance attributes and eliminating instance dictionaries. Though @@ -626,6 +671,11 @@ :meth:`~collections.somenamedtuple._asdict`. Examples of struct sequences include :data:`sys.float_info` and the return value of :func:`os.stat`. + sys path finder + A finder returned by a search of :data:`sys.path` by the :term:`path + importer`. Sys path finders are related to, but different from + :term:`meta path finders `. + triple-quoted string A string which is bound by three instances of either a quotation mark (") or an apostrophe ('). While they don't provide any functionality diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -128,6 +128,16 @@ An abstract base class representing a :term:`finder`. See :pep:`302` for the exact definition for a finder. + .. method:: find_loader(self, fullname): + + An abstract method for finding a :term:`loader` for the specified + module. Returns a 2-tuple of ``(loader, portion)`` where portion is a + sequence of file system locations contributing to part of a namespace + package. The sequence may be empty. When present, `find_loader()` is + preferred over `find_module()`. + + .. versionadded: 3.3 + .. method:: find_module(fullname, path=None) An abstract method for finding a :term:`loader` for the specified @@ -190,6 +200,13 @@ (This is not set by the built-in import machinery, but it should be set whenever a :term:`loader` is used.) + .. method:: module_repr(module) + + An abstract method which when implemented calculates and returns the + given module's repr, as a string. + + .. versionadded: 3.3 + .. class:: ResourceLoader @@ -270,14 +287,13 @@ Path to the file of the module. - .. method:: load_module(fullname=None) + .. method:: load_module(fullname) - Calls - ``super().load_module(fullname if fullname is not None else self.name)``. + Calls super's ``load_module()``. .. method:: get_filename(fullname) - Returns :attr:`path` when ``fullname`` equals :attr:`name` or ``None``. + Returns :attr:`path`. .. method:: get_data(path) @@ -538,7 +554,6 @@ .. versionadded:: 3.3 - .. function:: all_suffixes() Returns a combined list of strings representing all file suffixes for @@ -727,7 +742,7 @@ Path to the extension module. - .. method:: load_module(fullname=None) + .. method:: load_module(fullname) Loads the extension module if and only if *fullname* is the same as :attr:`name` or is ``None``. diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -651,17 +651,19 @@ statement: import object: module - Modules are imported by the :keyword:`import` statement (see section - :ref:`import`). A module object has a - namespace implemented by a dictionary object (this is the dictionary referenced - by the __globals__ attribute of functions defined in the module). Attribute + Modules are a basic organizational unit of Python code, and are created by + the :ref:`importmachinery` as invoked either by the :keyword:`import` + statement (see section :ref:`import`) or by calling the built in + :func:`__import__` function. A module object has a namespace implemented + by a dictionary object (this is the dictionary referenced by the + ``__globals__`` attribute of functions defined in the module). Attribute references are translated to lookups in this dictionary, e.g., ``m.x`` is - equivalent to ``m.__dict__["x"]``. A module object does not contain the code - object used to initialize the module (since it isn't needed once the + equivalent to ``m.__dict__["x"]``. A module object does not contain the + code object used to initialize the module (since it isn't needed once the initialization is done). - Attribute assignment updates the module's namespace dictionary, e.g., ``m.x = - 1`` is equivalent to ``m.__dict__["x"] = 1``. + Attribute assignment updates the module's namespace dictionary, e.g., + ``m.x = 1`` is equivalent to ``m.__dict__["x"] = 1``. .. index:: single: __dict__ (module attribute) @@ -683,11 +685,12 @@ Predefined (writable) attributes: :attr:`__name__` is the module's name; :attr:`__doc__` is the module's documentation string, or ``None`` if - unavailable; :attr:`__file__` is the pathname of the file from which the module - was loaded, if it was loaded from a file. The :attr:`__file__` attribute is not - present for C modules that are statically linked into the interpreter; for - extension modules loaded dynamically from a shared library, it is the pathname - of the shared library file. + unavailable; :attr:`__file__` is the pathname of the file from which the + module was loaded, if it was loaded from a file. The :attr:`__file__` + attribute may be missing for certain types of modules, such as C modules + that are statically linked into the interpreter; for extension modules + loaded dynamically from a shared library, it is the pathname of the shared + library file. Custom classes Custom class types are typically created by class definitions (see section diff --git a/Doc/reference/import_machinery.rst b/Doc/reference/import_machinery.rst new file mode 100644 --- /dev/null +++ b/Doc/reference/import_machinery.rst @@ -0,0 +1,547 @@ + +.. _importmachinery: + +**************** +Import machinery +**************** + +.. index:: single: import machinery + +Python code in one :term:`module` gains access to the code in another module +by the process of :term:`importing` it. Most commonly, the :keyword:`import` +statement is used to invoke the import machinery, but it can also be invoked +by calling the built-in :func:`__import__` function. + +The :keyword:`import` statement combines two operations; it searches for the +named module, then it binds the results of that search to a name in the local +scope. The search operation of the :keyword:`import` statement is defined as +a call to the :func:`__import__` function, with the appropriate arguments. +The return value of :func:`__import__` is used to perform the name binding +operation of the :keyword:`import` statement. See the :keyword:`import` +statement for the exact details of that name binding operation. + +A direct call to :func:`__import__` performs only the search for the module. +The function's return value is used like any other function call in Python; +there is no special side-effects (e.g. name binding) associated with +:func:`__import__`. + +When a module is first imported, Python searches for the module and if found, +it creates a module object, initializing it. If the named module cannot be +found, an :exc:`ImportError` is raised. Python implements various strategies +to search for the named module when the import machinery is invoked. These +strategies can be modified and extended by using various hooks described in +the sections below. The entire import machinery itself can be overridden by +replacing built-in :func:`__import__`. + + +Packages +======== + +.. index:: + single: package + +Python has only one type of module object, and all modules are of this type, +regardless of whether the module is implemented in Python, C, or something +else. To help organize modules and provide a naming hierarchy, Python has a +concept of :term:`packages `. It's important to keep in mind that +all packages are modules, but not all modules are packages. Or put another +way, packages are just a special kind of module. Although usually +unnecessary, introspection of various module object attributes can determine +whether a module is a package or not. + +Packages can contain other packages and modules, while modules generally do +not contain other modules or packages. You can think of packages as the +directories on a file system and modules as files within directories, but +don't take this analogy too literally since packages and modules need not +originate from the file system. For the purposes of this documentation, we'll +use this convenient analogy of directories and files. + +All modules have a name. Packages also have names, and subpackages can be +nested arbitrarily deeply. Subpackage names are separated from their parent +package by dots, akin to Python's standard attribute access syntax. Thus you +might have a module called :mod:`sys` and a package called :mod:`email`, which +in turn has a subpackage called :mod:`email.mime` and a module within that +subpackage called :mod:`email.mime.text`. + + +Regular packages +---------------- + +.. index:: + pair: package; regular + +Python defines two types of packages, :term:`regular packages ` and :term:`namespace packages `. Regular +packages are traditional packages as they existed in Python 3.2 and earlier. +A regular package is typically implemented as a directory containing an +``__init__.py`` file. When a regular package is imported, this +``__init__.py`` file is implicitly imported, and the objects it defines are +bound to names in the package's namespace. The ``__init__.py`` file can +contain the same Python code that any other module can contain, and Python +will add some additional attributes to the module when it is imported. + + +Namespace packages +------------------ + +.. index:: + pair:: package; namespace + pair:: package; portion + +A namespace package is a composite of various :term:`portions `, +where each portion contributes a subpackage to the parent package. Portions +may reside in different locations on the file system. Portions may also be +found in zip files, on the network, or anywhere else that Python searches +during import. Namespace packages may or may not correspond directly to +objects on the file system; they may be virtual modules that have no concrete +representation. + +For example, the following file system layout defines a top level ``parent`` +package with three subpackages:: + + parent/ + __init__.py + one/ + __init__.py + two/ + __init__.py + three/ + __init__.py + +Importing ``parent.one`` will implicitly import ``parent/__init__.py`` and +``parent/one/__init__.py``. Subsequent imports of ``parent.two`` or +``parent.three`` will import ``parent/two/__init__.py`` and +``parent/three/__init__.py`` respectively. + +With namespace packages, there is no ``parent/__init__.py`` file. In fact, +there may be multiple ``parent`` directories found during import search, where +each one is provided by a separate vendor installed container, and none of +them contain an ``__init__.py`` file. Thus ``parent/one`` may not be +physically located next to ``parent/two``. In this case, Python will create a +namespace package for the top-level ``parent`` package whenever it or one of +its subpackages is imported. + + +Searching +========= + +To begin the search, Python needs the :term:`fully qualified ` +name of the module (or package, but for the purposes of this discussion, the +difference is immaterial) being imported. This name may come from various +arguments to the :keyword:`import` statement, or from the parameters to the +:func:`__import__` function. + +This name will be used in various phases of the import search, and it may be +the dotted path to a submodule, e.g. ``foo.bar.baz``. In this case, Python +first tries to import ``foo``, then ``foo.bar``, and finally ``foo.bar.baz``. +If any of the intermediate imports fail, an :exc:`ImportError` is raised. + + +The module cache +---------------- + +.. index:: + single: sys.modules + +The first place checked during import search is :data:`sys.modules`. This +mapping serves as a cache of all modules that have been previously imported, +including the intermediate paths. So if ``foo.bar.baz`` was previously +imported, :data:`sys.modules` will contain entries for ``foo``, ``foo.bar``, +and ``foo.bar.baz``. Each key will have as its value the corresponding module +object. + +During import, the module name is looked up in :data:`sys.modules` and if +present, the associated value is the module satisfying the import, and the +process completes. However, if the value is ``None``, then an +:exc:`ImportError` is raised. If the module name is missing, Python will +continue searching for the module. + +:data:`sys.modules` is writable. Deleting a key will generally not destroy +the associated module, but it will invalidate the cache entry for the named +module, causing Python to search anew for the named module upon its next +import. Beware though, because if you keep a reference to the module object, +invalidate its cache entry in :data:`sys.modules`, and then re-import the +named module, the two module objects will *not* be the same. The key can also +be assigned to ``None``, forcing the next import of the module to result in an +:exc:`ImportError`. + + +Finders and loaders +------------------- + +.. index:: + single: finder + single: loader + +If the named module is not found in :data:`sys.modules` then Python's import +protocol is invoked to find and load the module. As this implies, the import +protocol consists of two conceptual objects, :term:`finders ` and +:term:`loaders `. A finder's job is to determine whether it can find +the named module using whatever strategy it knows about. For example, there +is a file system finder which know how to search the file system for the named +module. Other finders may know how to search a zip file, a web page, or a +database to find the named module. The import machinery is extensible, so new +finders can be added to extend the range and scope of module searching. + +Finders do not actually load modules. If they can find the named module, they +return a loader, which the import machinery later invokes to load the module +and create the corresponding module object. + +There are actually two types of finders, and two different but related APIs +for finders, depending on whether it is a :term:`meta path finder` or a +:term:`sys path finder`. Meta path processing occurs at the beginning of +import processing, while sys path processing happens later, by the :term:`path +importer`. + +The following sections describe the protocol for finders and loaders in more +detail, including how you can create and register new ones to extend the +import machinery. + + +Import hooks +------------ + +.. index:: + single: import hooks + single: meta hooks + single: path hooks + pair: hooks; import + pair: hooks; meta + pair: hooks; path + +The import machinery is designed to be extensible; the primary mechanism for +this are the *import hooks*. There are two types of import hooks: *meta +hooks* and *path hooks*. + +Meta hooks are called at the start of import processing, before any other +import processing has occurred. This allows meta hooks to override +:data:`sys.path` processing, frozen modules, or even built-in modules. Meta +hooks are registered by adding new finder objects to :data:`sys.meta_path`, as +described below. + +Path hooks are called as part of :data:`sys.path` (or ``package.__path__``) +processing, at the point where their associated path item is encountered. +Path hooks are registered by adding new callables to :data:`sys.path_hooks` as +described below. + + +The meta path +------------- + +.. index:: + single: sys.meta_path + pair: finder; find_module + pair: finder; find_loader + +When the named module is not found in :data:`sys.modules`, Python next +searches :data:`sys.meta_path`, which contains a list of meta path finder +objects. These finders are queried in order to see if they know how to handle +the named module. Meta path finders must implement a method called +:meth:`find_module()` which takes two arguments, a name and a path. The meta +path finder can use any strategy it wants to determine whether it can handle +the named module or not. + +If the meta path finder knows how to handle the named module, it returns a +loader object. If it cannot handle the named module, it returns ``None``. If +:data:`sys.meta_path` processing reaches the end of its list without returning +a loader, then an :exc:`ImportError` is raised. Any other exceptions raised +are simply propagated up, aborting the import process. + +The :meth:`find_module()` method of meta path finders is called with two +arguments. The first is the fully qualified name of the module being +imported, for example ``foo.bar.baz``. The second argument is the relative +path for the module search. For top-level modules, the second argument is +``None``, but for submodules or subpackages, the second argument is the value +of the parent package's ``__path__`` attribute, which must exist or an +:exc:`ImportError` is raised. + +Python's default :data:`sys.meta_path` has three meta path finders, one that +knows how to import built-in modules, one that knows how to import frozen +modules, and one that knows how to import modules from the file system +(i.e. the :term:`path importer`). + + +Meta path loaders +----------------- + +Once a loader is found via a meta path finder, the loader's +:meth:`load_module()` method is called, with a single argument, the fully +qualified name of the module being imported. This method has several +responsibilities, and should return the module object it has loaded [#fn1]_. +If it cannot load the module, it should raise an :exc:`ImportError`, although +any other exception raised during :meth:`load_module()` will be propagated. + +In many cases, the meta path finder and loader can be the same object, +e.g. :meth:`finder.find_module()` would just return ``self``. + +Loaders must satisfy the following requirements: + + * If there is an existing module object with the given name in + :data:`sys.modules`, the loader must use that existing module. (Otherwise, + the :func:`reload()` builtin will not work correctly.) If the named module + does not exist in :data:`sys.modules`, the loader must create a new module + object and add it to :data:`sys.modules`. + + Note that the module *must* exist in :data:`sys.modules` before the loader + executes the module code. This is crucial because the module code may + (directly or indirectly) import itself; adding it to :data:`sys.modules` + beforehand prevents unbounded recursion in the worst case and multiple + loading in the best. + + If the load fails, the loader needs to remove any modules it may have + inserted into ``sys.modules``. If the module was already in + ``sys.modules`` then the loader should leave it alone. + + * The loader may set the ``__file__`` attribute of the module. If set, this + attribute's value must be a string. The loader may opt to leave + ``__file__`` unset if it has no semantic meaning (e.g. a module loaded from + a database). + + * The loader may set the ``__name__`` attribute of the module. While not + required, setting this attribute is highly recommended so that the + :meth:`repr()` of the module is more informative. + + * If module is a package (either regular or namespace), the loader must set + the module object's ``__path__`` attribute. The value must be a list, but + may be empty if ``__path__`` has no further significance to the importer. + More details on the semantics of ``__path__`` are given below. + + * The ``__loader__`` attribute must be set to the loader object that loaded + the module. This is mostly for introspection and reloading, but can be + used for additional importer-specific functionality, for example getting + data associated with an importer. + + * The module's ``__package__`` attribute should be set. Its value must be a + string, but it can be the same value as its ``__name__``. This is the + recommendation when the module is a package. When the module is not a + package, ``__package__`` should be set to the parent package's name. + + This attribute is used instead of ``__name__`` to calculate explicit + relative imports for main modules, as defined in :pep:`366`. + + * If the module is a Python module (as opposed to a built-in module or a + dynamically loaded extension), it should execute the module's code in the + module's global name space (``module.__dict__``). + + +Module reprs +------------ + +By default, all modules have a usable repr, however depending on the +attributes set above, and hooks in the loader, you can more tightly control +the repr of module objects. + +Loaders may implement a :meth:`module_repr()` method which takes a single +argument, the module object. When ``repr(module)`` is called for a module +with a loader supporting this protocol, whatever is returned from +``loader.module_repr(module)`` is returned as the module's repr without +further processing. This return value must be a string. + +If the module has no ``__loader__`` attribute, or the loader has no +:meth:`module_repr()` method, then the module object implementation itself +will craft a default repr using whatever information is available. It will +try to use the ``module.__name__``, ``module.__file__``, and +``module.__loader__`` as input into the repr, with defaults for whatever +information is missing. + +Here are the exact rules used: + + * If the module has an ``__loader__`` and that loader has a + :meth:`module_repr()` method, call it with a single argument, which is the + module object. The value returned is used as the module's repr. + + * If an exception occurs in :meth:`module_repr()`, the exception is caught + and discarded, and the calculation of the module's repr continues as if + :meth:`module_repr()` did not exist. + + * If the module has an ``__file__`` attribute, this is used as part of the + module's repr. + + * If the module has no ``__file__`` but does have an ``__loader__``, then the + loader's repr is used as part of the module's repr. + + * Otherwise, just use the module's ``__name__`` in the repr. + +This example, from :pep:`420` shows how a loader can craft its own module +repr:: + + class NamespaceLoader: + @classmethod + def module_repr(cls, module): + return "".format(module.__name__) + + +module.__path__ +--------------- + +By definition, if a module has an ``__path__`` attribute, it is a package, +regardless of its value. + +A package's ``__path__`` attribute is used during imports of its subpackages. +Within the import machinery, it functions much the same as :data:`sys.path`, +i.e. providing a list of locations to search for modules during import. +However, ``__path__`` is typically much more constrained than +:data:`sys.path`. + +``__path__`` must be a list, but it may be empty. The same rules used for +:data:`sys.path` also apply to a package's ``__path__``, and +:data:`sys.path_hooks` (described below) are consulted when traversing a +package's ``__path__``. + +A package's ``__init__.py`` file may set or alter the package's ``__path__`` +attribute, and this was typically the way namespace packages were implemented +prior to :pep:`420`. With the adoption of :pep:`420`, namespace packages no +longer need to supply ``__init__.py`` files containing only ``__path__`` +manipulation code; the namespace loader automatically sets ``__path__`` +correctly for the namespace package. + + +The Path Importer +================= + +.. index:: + single: path importer + +As mentioned previously, Python comes with several default meta path finders. +One of these, called the :term:`path importer`, knows how to provide +traditional file system imports. It implements all the semantics for finding +modules on the file system, handling special file types such as Python source +code (``.py`` files), Python byte code (``.pyc`` and ``.pyo`` files) and +shared libraries (e.g. ``.so`` files). + +In addition to being able to find such modules, there is built-in support for +loading these modules. To accomplish these two related tasks, additional +hooks and protocols are provided so that you can extend and customize the path +importer semantics. + +A word of warning: this section and the previous both use the term *finder*, +distinguishing between them by using the terms :term:`meta path finder` and +:term:`sys path finder`. Meta path finders and sys path finders are very +similar, support similar protocols, and function in similar ways during the +import process, but it's important to keep in mind that they are subtly +different. In particular, meta path finders operate at the beginning of the +import process, as keyed off the :data:`sys.meta_path` traversal. + +On the other hand, sys path finders are in a sense an implementation detail of +the path importer, and in fact, if the path importer were to be removed from +:data:`sys.meta_path`, none of the sys path finder semantics would be invoked. + + +sys path finders +---------------- + +.. index:: + single: sys.path + single: sys.path_hooks + single: sys.path_importer_cache + single: PYTHONPATH + +The path importer is responsible for finding and loading Python modules and +packages from the file system. As a meta path finder, it implements the +:meth:`find_module()` protocol previously described, however it exposes +additional hooks that can be used to customize how modules are found and +loaded from the file system. + +Three variables are used during file system import, :data:`sys.path`, +:data:`sys.path_hooks` and :data:`sys.path_importer_cache`. These provide +additional ways that the import machinery can be customized, in this case +specifically during file system path import. + +:data:`sys.path` contains a list of strings providing search locations for +modules and packages. It is initialized from the :data:`PYTHONPATH` +environment variable and various other installation- and +implementation-specific defaults. Entries in :data:`sys.path` can name +directories on the file system, zip files, and potentially other "locations" +that should be searched for modules. + +The path importer is a meta path finder, so the import machinery begins file +system search by calling the path importer's :meth:`find_module()` method as +described previously. When the ``path`` argument to :meth:`find_module()` is +given, it will be a list of string paths to traverse. If not, +:data:`sys.path` is used. + +The path importer iterates over every entry in the search path, and for each +of these, searches for an appropriate sys path finder for the path entry. +Because this can be an expensive operation (e.g. there are `stat()` call +overheads for this search), the path importer maintains a cache mapping path +entries to sys path finders. This cache is maintained in +:data:`sys.path_importer_cache`. In this way, the expensive search for a +particular path location's sys path finder need only be done once. User code +is free to remove cache entries from :data:`sys.path_importer_cache` forcing +the path importer to perform the path search again. + +If the path entry is not present in the cache, the path importer iterates over +every callable in :data:`sys.path_hooks`. Each entry in this list is called +with a single argument, the path entry being searched. This callable may +either return a sys path finder that can handle the path entry, or it may +raise :exc:`ImportError`. An :exc:`ImportError` is used by the path importer +to signal that the hook cannot find a sys path finder for that path entry. +The exception is ignored and :data:`sys.path_hooks` iteration continues. + +If :data:`sys.path_hooks` iteration ends with no sys path finder being +returned then the path importer's :meth:`find_module()` method will return +``None`` and an :exc:`ImportError` will be raised. + +If a sys path finder *is* returned by one of the callables on +:data:`sys.path_hooks`, then the following protocol is used to ask the sys +path finder for a module loader. If a loader results from this step, it is +used to load the module as previously described (i.e. its +:meth:`load_module()` method is called). + + +sys path finder protocol +------------------------ + +sys path finders support the same, traditional :meth:`find_module()` method +that meta path finders support, however sys path finder :meth:`find_module()` +methods are never called with a ``path`` argument. + +The :meth:`find_module()` method on sys path finders is deprecated though, and +instead sys path finders should implement the :meth:`find_loader()` method. +If it exists on the sys path finder, :meth:`find_loader()` will always be +called instead of :meth:`find_module()`. + +:meth:`find_loader()` takes one argument, the fully qualified name of the +module being imported. :meth:`find_loader()` returns a 2-tuple where the +first item is the loader and the second item is a namespace :term:`portion`. +When the first item (i.e. the loader) is ``None``, this means that while the +sys path finder does not have a loader for the named module, it knows that the +path entry contributes to a namespace portion for the named module. This will +almost always be the case where Python is asked to import a namespace package +that has no physical presence on the file system. When a sys path finder +returns ``None`` for the loader, the second item of the 2-tuple return value +must be a sequence, although it can be empty. + +If :meth:`find_loader()` returns a non-``None`` loader value, the portion is +ignored and the loader is returned from the path importer, terminating the +:data:`sys.path` search. + + +Open issues +=========== + +XXX What to say about `imp.NullImporter` when it's found in +:data:`sys.path_importer_cache`? + +XXX It would be really nice to have a diagram. + +.. [#fn1] The importlib implementation appears not to use the return value + directly. Instead, it gets the module object by looking the module name up + in ``sys.modules``.) + + +References +========== + +The import machinery has evolved considerably since Python's early days. The +original `specification for packages +`_ is still available to read, +although some details have changed since the writing of that document. + +The original specification for :data:`sys.meta_path` was :pep:`302`, with +subsequent extension in :pep:`420`, which also introduced namespace packages +without ``__init__.py`` files in Python 3.3. :pep:`420` also introduced the +:meth:`find_loader` protocol as an alternative to :meth:`find_module`. + +:pep:`366` describes the addition of the ``__package__`` attribute for +explicit relative imports in main modules. diff --git a/Doc/reference/index.rst b/Doc/reference/index.rst --- a/Doc/reference/index.rst +++ b/Doc/reference/index.rst @@ -24,6 +24,7 @@ lexical_analysis.rst datamodel.rst executionmodel.rst + import_machinery.rst expressions.rst simple_stmts.rst compound_stmts.rst diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -660,162 +660,50 @@ relative_module: "."* `module` | "."+ name: `identifier` -Import statements are executed in two steps: (1) find a module, and initialize -it if necessary; (2) define a name or names in the local namespace (of the scope -where the :keyword:`import` statement occurs). The statement comes in two -forms differing on whether it uses the :keyword:`from` keyword. The first form -(without :keyword:`from`) repeats these steps for each identifier in the list. -The form with :keyword:`from` performs step (1) once, and then performs step -(2) repeatedly. For a reference implementation of step (1), see the -:mod:`importlib` module. +Import statements are executed in two steps: (1) find a module, loading and +initializing it if necessary; (2) define a name or names in the local +namespace (of the scope where the :keyword:`import` statement occurs). The +statement comes in two forms differing on whether it uses the :keyword:`from` +keyword. The first form (without :keyword:`from`) repeats these steps for each +identifier in the list. The form with :keyword:`from` performs step (1) once, +and then performs step (2) repeatedly. -.. index:: - single: package - -To understand how step (1) occurs, one must first understand how Python handles -hierarchical naming of modules. To help organize modules and provide a -hierarchy in naming, Python has a concept of packages. A package can contain -other packages and modules while modules cannot contain other modules or -packages. From a file system perspective, packages are directories and modules -are files. The original `specification for packages -`_ is still available to read, -although minor details have changed since the writing of that document. - -.. index:: - single: sys.modules - -Once the name of the module is known (unless otherwise specified, the term -"module" will refer to both packages and modules), searching -for the module or package can begin. The first place checked is -:data:`sys.modules`, the cache of all modules that have been imported -previously. If the module is found there then it is used in step (2) of import -unless ``None`` is found in :data:`sys.modules`, in which case -:exc:`ImportError` is raised. - -.. index:: - single: sys.meta_path - single: finder - pair: finder; find_module - single: __path__ - -If the module is not found in the cache, then :data:`sys.meta_path` is searched -(the specification for :data:`sys.meta_path` can be found in :pep:`302`). -The object is a list of :term:`finder` objects which are queried in order as to -whether they know how to load the module by calling their :meth:`find_module` -method with the name of the module. If the module happens to be contained -within a package (as denoted by the existence of a dot in the name), then a -second argument to :meth:`find_module` is given as the value of the -:attr:`__path__` attribute from the parent package (everything up to the last -dot in the name of the module being imported). If a finder can find the module -it returns a :term:`loader` (discussed later) or returns ``None``. - -.. index:: - single: sys.path_hooks - single: sys.path_importer_cache - single: sys.path - -If none of the finders on :data:`sys.meta_path` are able to find the module -then some implicitly defined finders are queried. Implementations of Python -vary in what implicit meta path finders are defined. The one they all do -define, though, is one that handles :data:`sys.path_hooks`, -:data:`sys.path_importer_cache`, and :data:`sys.path`. - -The implicit finder searches for the requested module in the "paths" specified -in one of two places ("paths" do not have to be file system paths). If the -module being imported is supposed to be contained within a package then the -second argument passed to :meth:`find_module`, :attr:`__path__` on the parent -package, is used as the source of paths. If the module is not contained in a -package then :data:`sys.path` is used as the source of paths. - -Once the source of paths is chosen it is iterated over to find a finder that -can handle that path. The dict at :data:`sys.path_importer_cache` caches -finders for paths and is checked for a finder. If the path does not have a -finder cached then :data:`sys.path_hooks` is searched by calling each object in -the list with a single argument of the path, returning a finder or raises -:exc:`ImportError`. If a finder is returned then it is cached in -:data:`sys.path_importer_cache` and then used for that path entry. If no finder -can be found but the path exists then a value of ``None`` is -stored in :data:`sys.path_importer_cache` to signify that an implicit, -file-based finder that handles modules stored as individual files should be -used for that path. If the path does not exist then a finder which always -returns ``None`` is placed in the cache for the path. - -.. index:: - single: loader - pair: loader; load_module - exception: ImportError - -If no finder can find the module then :exc:`ImportError` is raised. Otherwise -some finder returned a loader whose :meth:`load_module` method is called with -the name of the module to load (see :pep:`302` for the original definition of -loaders). A loader has several responsibilities to perform on a module it -loads. First, if the module already exists in :data:`sys.modules` (a -possibility if the loader is called outside of the import machinery) then it -is to use that module for initialization and not a new module. But if the -module does not exist in :data:`sys.modules` then it is to be added to that -dict before initialization begins. If an error occurs during loading of the -module and it was added to :data:`sys.modules` it is to be removed from the -dict. If an error occurs but the module was already in :data:`sys.modules` it -is left in the dict. - -.. index:: - single: __name__ - single: __file__ - single: __path__ - single: __package__ - single: __loader__ - -The loader must set several attributes on the module. :data:`__name__` is to be -set to the name of the module. :data:`__file__` is to be the "path" to the file -unless the module is built-in (and thus listed in -:data:`sys.builtin_module_names`) in which case the attribute is not set. -If what is being imported is a package then :data:`__path__` is to be set to a -list of paths to be searched when looking for modules and packages contained -within the package being imported. :data:`__package__` is optional but should -be set to the name of package that contains the module or package (the empty -string is used for module not contained in a package). :data:`__loader__` is -also optional but should be set to the loader object that is loading the -module. While loaders are required to return the module they loaded, import -itself always retrieves any modules it returns from :data:`sys.modules`. - -.. index:: - exception: ImportError - -If an error occurs during loading then the loader raises :exc:`ImportError` if -some other exception is not already being propagated. Otherwise the loader -returns the module that was loaded and initialized. +The details of step (1), finding and loading modules is described in greater +detail in the section on the :ref:`import machinery `, which +also describes the various types of packages and modules that can be imported, +as well as all the hooks that can be used to customize Python's import. When step (1) finishes without raising an exception, step (2) can begin. -The first form of :keyword:`import` statement binds the module name in the local -namespace to the module object, and then goes on to import the next identifier, -if any. If the module name is followed by :keyword:`as`, the name following -:keyword:`as` is used as the local name for the module. +The first form of :keyword:`import` statement binds the module name in the +local namespace to the module object, and then goes on to import the next +identifier, if any. If the module name is followed by :keyword:`as`, the name +following :keyword:`as` is used as the local name for the module. .. index:: pair: name; binding exception: ImportError -The :keyword:`from` form does not bind the module name: it goes through the list -of identifiers, looks each one of them up in the module found in step (1), and -binds the name in the local namespace to the object thus found. As with the -first form of :keyword:`import`, an alternate local name can be supplied by -specifying ":keyword:`as` localname". If a name is not found, -:exc:`ImportError` is raised. If the list of identifiers is replaced by a star -(``'*'``), all public names defined in the module are bound in the local +The :keyword:`from` form does not bind the module name: it goes through the +list of identifiers, looks each one of them up in the module found in step +(1), and binds the name in the local namespace to the object thus found. As +with the first form of :keyword:`import`, an alternate local name can be +supplied by specifying ":keyword:`as` localname". If a name is not found, +:exc:`ImportError` is raised. If the list of identifiers is replaced by a +star (``'*'``), all public names defined in the module are bound in the local namespace of the :keyword:`import` statement. .. index:: single: __all__ (optional module attribute) The *public names* defined by a module are determined by checking the module's -namespace for a variable named ``__all__``; if defined, it must be a sequence of -strings which are names defined or imported by that module. The names given in -``__all__`` are all considered public and are required to exist. If ``__all__`` -is not defined, the set of public names includes all names found in the module's -namespace which do not begin with an underscore character (``'_'``). -``__all__`` should contain the entire public API. It is intended to avoid -accidentally exporting items that are not part of the API (such as library -modules which were imported and used within the module). +namespace for a variable named ``__all__``; if defined, it must be a sequence +of strings which are names defined or imported by that module. The names +given in ``__all__`` are all considered public and are required to exist. If +``__all__`` is not defined, the set of public names includes all names found +in the module's namespace which do not begin with an underscore character +(``'_'``). ``__all__`` should contain the entire public API. It is intended +to avoid accidentally exporting items that are not part of the API (such as +library modules which were imported and used within the module). The :keyword:`from` form with ``*`` may only occur in a module scope. The wild card form of import --- ``import *`` --- is only allowed at the module level. diff --git a/Lib/importlib/abc.py b/Lib/importlib/abc.py --- a/Lib/importlib/abc.py +++ b/Lib/importlib/abc.py @@ -33,16 +33,33 @@ The fullname is a str.""" raise NotImplementedError + @abs.abstractmethod + def module_repr(self, module): + """Abstract method which when implemented calculates and returns the + given module's repr.""" + raise NotImplementedError + class Finder(metaclass=abc.ABCMeta): """Abstract base class for import finders.""" + @abs.abstractmethod + def find_loader(self, fullname): + """Abstract method which when implemented returns a module loader. + The fullname is a str. Returns a 2-tuple of (Loader, portion) where + portion is a sequence of file system locations contributing to part of + a namespace package. The sequence may be empty. When present, + `find_loader()` is preferred over `find_module()`. + """ + raise NotImplementedError + @abc.abstractmethod def find_module(self, fullname, path=None): """Abstract method which when implemented should find a module. The fullname is a str and the optional path is a str or None. - Returns a Loader object. + Returns a Loader object. This method is only called if + `find_loader()` is not present. """ raise NotImplementedError -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 31 22:10:24 2012 From: python-checkins at python.org (barry.warsaw) Date: Tue, 31 Jul 2012 22:10:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Add_NEWS?= Message-ID: <3Wmpfm0q1fzPct@mail.python.org> http://hg.python.org/cpython/rev/a391185ab5b2 changeset: 78352:a391185ab5b2 user: Barry Warsaw date: Sun Jul 29 16:37:33 2012 -0400 summary: Add NEWS files: Misc/NEWS | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -213,6 +213,9 @@ Documentation ------------- +- Issue #15295: Reorganize and rewrite the documentation on the import + machinery. + - Issue #15230: Clearly document some of the limitations of the runpy module and nudge readers towards importlib when appropriate. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 31 22:10:26 2012 From: python-checkins at python.org (barry.warsaw) Date: Tue, 31 Jul 2012 22:10:26 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?b?KTogbWVyZ2Vk?= Message-ID: <3Wmpfp1nypzPdq@mail.python.org> http://hg.python.org/cpython/rev/d406e1392bbc changeset: 78353:d406e1392bbc parent: 78352:a391185ab5b2 parent: 78319:1d811e1097ed user: Barry Warsaw date: Sun Jul 29 16:40:04 2012 -0400 summary: merged files: Lib/importlib/_bootstrap.py | 89 +- Lib/test/support.py | 28 + Lib/test/test_import.py | 68 + Lib/test/test_io.py | 20 +- Lib/test/test_struct.py | 33 +- Lib/test/test_sys.py | 214 +- Lib/test/test_xml_etree_c.py | 24 +- Misc/NEWS | 11 + Modules/_freeze_importlib.c | 11 +- Modules/_io/bufferedio.c | 14 + Modules/_struct.c | 8 +- PCbuild/pcbuild.sln | 6 - Python/import.c | 30 +- Python/importlib.h | 8060 +++++++++++---------- 14 files changed, 4511 insertions(+), 4105 deletions(-) diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -722,6 +722,56 @@ return _imp.init_frozen(fullname) +class WindowsRegistryImporter: + + """Meta path import for modules declared in the Windows registry. + """ + + REGISTRY_KEY = ( + "Software\\Python\\PythonCore\\{sys_version}" + "\\Modules\\{fullname}") + REGISTRY_KEY_DEBUG = ( + "Software\\Python\\PythonCore\\{sys_version}" + "\\Modules\\{fullname}\\Debug") + DEBUG_BUILD = False # Changed in _setup() + + @classmethod + def _open_registry(cls, key): + try: + return _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, key) + except WindowsError: + return _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, key) + + @classmethod + def _search_registry(cls, fullname): + if cls.DEBUG_BUILD: + registry_key = cls.REGISTRY_KEY_DEBUG + else: + registry_key = cls.REGISTRY_KEY + key = registry_key.format(fullname=fullname, + sys_version=sys.version[:3]) + try: + with cls._open_registry(key) as hkey: + filepath = _winreg.QueryValue(hkey, "") + except WindowsError: + return None + return filepath + + @classmethod + def find_module(cls, fullname, path=None): + """Find module named in the registry.""" + filepath = cls._search_registry(fullname) + if filepath is None: + return None + try: + _os.stat(filepath) + except OSError: + return None + for loader, suffixes, _ in _get_supported_file_loaders(): + if filepath.endswith(tuple(suffixes)): + return loader(fullname, filepath) + + class _LoaderBasics: """Base class of common code needed by both SourceLoader and @@ -1422,7 +1472,7 @@ parent = name.rpartition('.')[0] if parent: if parent not in sys.modules: - import_(parent) + _recursive_import(import_, parent) # Crazy side-effects! if name in sys.modules: return sys.modules[name] @@ -1500,6 +1550,12 @@ _lock_unlock_module(name) return module +def _recursive_import(import_, name): + """Common exit point for recursive calls to the import machinery + + This simplifies the process of stripping importlib from tracebacks + """ + return import_(name) def _handle_fromlist(module, fromlist, import_): """Figure out what __import__ should return. @@ -1519,7 +1575,8 @@ fromlist.extend(module.__all__) for x in fromlist: if not hasattr(module, x): - import_('{}.{}'.format(module.__name__, x)) + _recursive_import(import_, + '{}.{}'.format(module.__name__, x)) return module @@ -1538,6 +1595,17 @@ return package +def _get_supported_file_loaders(): + """Returns a list of file-based module loaders. + + Each item is a tuple (loader, suffixes, allow_packages). + """ + extensions = ExtensionFileLoader, _imp.extension_suffixes(), False + source = SourceFileLoader, SOURCE_SUFFIXES, True + bytecode = SourcelessFileLoader, BYTECODE_SUFFIXES, True + return [extensions, source, bytecode] + + def __import__(name, globals={}, locals={}, fromlist=[], level=0): """Import a module. @@ -1620,6 +1688,10 @@ thread_module = None weakref_module = BuiltinImporter.load_module('_weakref') + if builtin_os == 'nt': + winreg_module = BuiltinImporter.load_module('winreg') + setattr(self_module, '_winreg', winreg_module) + setattr(self_module, '_os', os_module) setattr(self_module, '_thread', thread_module) setattr(self_module, '_weakref', weakref_module) @@ -1629,14 +1701,17 @@ setattr(self_module, '_relax_case', _make_relax_case()) if builtin_os == 'nt': SOURCE_SUFFIXES.append('.pyw') + if '_d.pyd' in _imp.extension_suffixes(): + WindowsRegistryImporter.DEBUG_BUILD = True def _install(sys_module, _imp_module): """Install importlib as the implementation of import.""" _setup(sys_module, _imp_module) - extensions = ExtensionFileLoader, _imp_module.extension_suffixes(), False - source = SourceFileLoader, SOURCE_SUFFIXES, True - bytecode = SourcelessFileLoader, BYTECODE_SUFFIXES, True - supported_loaders = [extensions, source, bytecode] + supported_loaders = _get_supported_file_loaders() sys.path_hooks.extend([FileFinder.path_hook(*supported_loaders)]) - sys.meta_path.extend([BuiltinImporter, FrozenImporter, PathFinder]) + sys.meta_path.append(BuiltinImporter) + sys.meta_path.append(FrozenImporter) + if _os.__name__ == 'nt': + sys.meta_path.append(WindowsRegistryImporter) + sys.meta_path.append(PathFinder) diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -25,6 +25,7 @@ import logging.handlers import struct import tempfile +import _testcapi try: import _thread, threading @@ -1082,6 +1083,33 @@ return final_opt != '' and final_opt != '-O0' +_header = 'nP' +_align = '0n' +if hasattr(sys, "gettotalrefcount"): + _header = '2P' + _header + _align = '0P' +_vheader = _header + 'n' + +def calcobjsize(fmt): + return struct.calcsize(_header + fmt + _align) + +def calcvobjsize(fmt): + return struct.calcsize(_vheader + fmt + _align) + + +_TPFLAGS_HAVE_GC = 1<<14 +_TPFLAGS_HEAPTYPE = 1<<9 + +def check_sizeof(test, o, size): + result = sys.getsizeof(o) + # add GC header size + if ((type(o) == type) and (o.__flags__ & _TPFLAGS_HEAPTYPE) or\ + ((type(o) != type) and (type(o).__flags__ & _TPFLAGS_HAVE_GC))): + size += _testcapi.SIZEOF_PYGC_HEAD + msg = 'wrong size for %s: got %d, expected %d' \ + % (type(o), result, size) + test.assertEqual(result, size, msg) + #======================================================================= # Decorator for running a function in a different locale, correctly resetting # it afterwards. diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -844,6 +844,74 @@ self.fail("ZeroDivisionError should have been raised") self.assert_traceback(tb, [__file__, 'foo.py', 'bar.py']) + # A few more examples from issue #15425 + def test_syntax_error(self): + self.create_module("foo", "invalid syntax is invalid") + try: + import foo + except SyntaxError as e: + tb = e.__traceback__ + else: + self.fail("SyntaxError should have been raised") + self.assert_traceback(tb, [__file__]) + + def _setup_broken_package(self, parent, child): + pkg_name = "_parent_foo" + def cleanup(): + rmtree(pkg_name) + unload(pkg_name) + os.mkdir(pkg_name) + self.addCleanup(cleanup) + # Touch the __init__.py + init_path = os.path.join(pkg_name, '__init__.py') + with open(init_path, 'w') as f: + f.write(parent) + bar_path = os.path.join(pkg_name, 'bar.py') + with open(bar_path, 'w') as f: + f.write(child) + importlib.invalidate_caches() + return init_path, bar_path + + def test_broken_submodule(self): + init_path, bar_path = self._setup_broken_package("", "1/0") + try: + import _parent_foo.bar + except ZeroDivisionError as e: + tb = e.__traceback__ + else: + self.fail("ZeroDivisionError should have been raised") + self.assert_traceback(tb, [__file__, bar_path]) + + def test_broken_from(self): + init_path, bar_path = self._setup_broken_package("", "1/0") + try: + from _parent_foo import bar + except ZeroDivisionError as e: + tb = e.__traceback__ + else: + self.fail("ImportError should have been raised") + self.assert_traceback(tb, [__file__, bar_path]) + + def test_broken_parent(self): + init_path, bar_path = self._setup_broken_package("1/0", "") + try: + import _parent_foo.bar + except ZeroDivisionError as e: + tb = e.__traceback__ + else: + self.fail("ZeroDivisionError should have been raised") + self.assert_traceback(tb, [__file__, init_path]) + + def test_broken_parent_from(self): + init_path, bar_path = self._setup_broken_package("1/0", "") + try: + from _parent_foo import bar + except ZeroDivisionError as e: + tb = e.__traceback__ + else: + self.fail("ZeroDivisionError should have been raised") + self.assert_traceback(tb, [__file__, init_path]) + @cpython_only def test_import_bug(self): # We simulate a bug in importlib and check that it's not stripped diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -802,6 +802,20 @@ buf.raw = x +class SizeofTest: + + @support.cpython_only + def test_sizeof(self): + bufsize1 = 4096 + bufsize2 = 8192 + rawio = self.MockRawIO() + bufio = self.tp(rawio, buffer_size=bufsize1) + size = sys.getsizeof(bufio) - bufsize1 + rawio = self.MockRawIO() + bufio = self.tp(rawio, buffer_size=bufsize2) + self.assertEqual(sys.getsizeof(bufio), size + bufsize2) + + class BufferedReaderTest(unittest.TestCase, CommonBufferedTests): read_mode = "rb" @@ -999,7 +1013,7 @@ "failed for {}: {} != 0".format(n, rawio._extraneous_reads)) -class CBufferedReaderTest(BufferedReaderTest): +class CBufferedReaderTest(BufferedReaderTest, SizeofTest): tp = io.BufferedReader def test_constructor(self): @@ -1260,7 +1274,7 @@ self.tp(self.MockRawIO(), 8, 12) -class CBufferedWriterTest(BufferedWriterTest): +class CBufferedWriterTest(BufferedWriterTest, SizeofTest): tp = io.BufferedWriter def test_constructor(self): @@ -1650,7 +1664,7 @@ # You can't construct a BufferedRandom over a non-seekable stream. test_unseekable = None -class CBufferedRandomTest(BufferedRandomTest): +class CBufferedRandomTest(BufferedRandomTest, SizeofTest): tp = io.BufferedRandom def test_constructor(self): diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -3,7 +3,7 @@ import struct import sys -from test.support import run_unittest +from test import support ISBIGENDIAN = sys.byteorder == "big" IS32BIT = sys.maxsize == 0x7fffffff @@ -572,18 +572,29 @@ s = struct.Struct('i') s.__init__('ii') - def test_sizeof(self): - self.assertGreater(sys.getsizeof(struct.Struct('BHILfdspP')), - sys.getsizeof(struct.Struct('B'))) - self.assertGreater(sys.getsizeof(struct.Struct('123B')), - sys.getsizeof(struct.Struct('B'))) - self.assertGreater(sys.getsizeof(struct.Struct('B' * 1234)), - sys.getsizeof(struct.Struct('123B'))) - self.assertGreater(sys.getsizeof(struct.Struct('1234B')), - sys.getsizeof(struct.Struct('123B'))) + def check_sizeof(self, format_str, number_of_codes): + # The size of 'PyStructObject' + totalsize = support.calcobjsize('2n3P') + # The size taken up by the 'formatcode' dynamic array + totalsize += struct.calcsize('P2n0P') * (number_of_codes + 1) + support.check_sizeof(self, struct.Struct(format_str), totalsize) + + @support.cpython_only + def test__sizeof__(self): + for code in integer_codes: + self.check_sizeof(code, 1) + self.check_sizeof('BHILfdspP', 9) + self.check_sizeof('B' * 1234, 1234) + self.check_sizeof('fd', 2) + self.check_sizeof('xxxxxxxxxxxxxx', 0) + self.check_sizeof('100H', 100) + self.check_sizeof('187s', 1) + self.check_sizeof('20p', 1) + self.check_sizeof('0s', 1) + self.check_sizeof('0c', 0) def test_main(): - run_unittest(StructTest) + support.run_unittest(StructTest) if __name__ == '__main__': test_main() diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -612,22 +612,8 @@ class SizeofTest(unittest.TestCase): - TPFLAGS_HAVE_GC = 1<<14 - TPFLAGS_HEAPTYPE = 1<<9 - def setUp(self): - self.c = len(struct.pack('c', b' ')) - self.H = len(struct.pack('H', 0)) - self.i = len(struct.pack('i', 0)) - self.l = len(struct.pack('l', 0)) - self.P = len(struct.pack('P', 0)) - # due to missing size_t information from struct, it is assumed that - # sizeof(Py_ssize_t) = sizeof(void*) - self.header = 'PP' - self.vheader = self.header + 'P' - if hasattr(sys, "gettotalrefcount"): - self.header += '2P' - self.vheader += '2P' + self.P = struct.calcsize('P') self.longdigit = sys.int_info.sizeof_digit import _testcapi self.gc_headsize = _testcapi.SIZEOF_PYGC_HEAD @@ -637,129 +623,108 @@ self.file.close() test.support.unlink(test.support.TESTFN) - def check_sizeof(self, o, size): - result = sys.getsizeof(o) - # add GC header size - if ((type(o) == type) and (o.__flags__ & self.TPFLAGS_HEAPTYPE) or\ - ((type(o) != type) and (type(o).__flags__ & self.TPFLAGS_HAVE_GC))): - size += self.gc_headsize - msg = 'wrong size for %s: got %d, expected %d' \ - % (type(o), result, size) - self.assertEqual(result, size, msg) - - def calcsize(self, fmt): - """Wrapper around struct.calcsize which enforces the alignment of the - end of a structure to the alignment requirement of pointer. - - Note: This wrapper should only be used if a pointer member is included - and no member with a size larger than a pointer exists. - """ - return struct.calcsize(fmt + '0P') + check_sizeof = test.support.check_sizeof def test_gc_head_size(self): # Check that the gc header size is added to objects tracked by the gc. - h = self.header - vh = self.vheader - size = self.calcsize + vsize = test.support.calcvobjsize gc_header_size = self.gc_headsize # bool objects are not gc tracked - self.assertEqual(sys.getsizeof(True), size(vh) + self.longdigit) + self.assertEqual(sys.getsizeof(True), vsize('') + self.longdigit) # but lists are - self.assertEqual(sys.getsizeof([]), size(vh + 'PP') + gc_header_size) + self.assertEqual(sys.getsizeof([]), vsize('Pn') + gc_header_size) def test_default(self): - h = self.header - vh = self.vheader - size = self.calcsize - self.assertEqual(sys.getsizeof(True), size(vh) + self.longdigit) - self.assertEqual(sys.getsizeof(True, -1), size(vh) + self.longdigit) + size = test.support.calcvobjsize + self.assertEqual(sys.getsizeof(True), size('') + self.longdigit) + self.assertEqual(sys.getsizeof(True, -1), size('') + self.longdigit) def test_objecttypes(self): # check all types defined in Objects/ - h = self.header - vh = self.vheader - size = self.calcsize + size = test.support.calcobjsize + vsize = test.support.calcvobjsize check = self.check_sizeof # bool - check(True, size(vh) + self.longdigit) + check(True, vsize('') + self.longdigit) # buffer # XXX # builtin_function_or_method - check(len, size(h + '3P')) + check(len, size('3P')) # XXX check layout # bytearray samples = [b'', b'u'*100000] for sample in samples: x = bytearray(sample) - check(x, size(vh + 'iPP') + x.__alloc__() * self.c) + check(x, vsize('inP') + x.__alloc__()) # bytearray_iterator - check(iter(bytearray()), size(h + 'PP')) + check(iter(bytearray()), size('nP')) # cell def get_cell(): x = 42 def inner(): return x return inner - check(get_cell().__closure__[0], size(h + 'P')) + check(get_cell().__closure__[0], size('P')) # code - check(get_cell().__code__, size(h + '5i9Pi3P')) - check(get_cell.__code__, size(h + '5i9Pi3P')) + check(get_cell().__code__, size('5i9Pi3P')) + check(get_cell.__code__, size('5i9Pi3P')) def get_cell2(x): def inner(): return x return inner - check(get_cell2.__code__, size(h + '5i9Pi3P') + 1) + check(get_cell2.__code__, size('5i9Pi3P') + 1) # complex - check(complex(0,1), size(h + '2d')) + check(complex(0,1), size('2d')) # method_descriptor (descriptor object) - check(str.lower, size(h + '3PP')) + check(str.lower, size('3PP')) # classmethod_descriptor (descriptor object) # XXX # member_descriptor (descriptor object) import datetime - check(datetime.timedelta.days, size(h + '3PP')) + check(datetime.timedelta.days, size('3PP')) # getset_descriptor (descriptor object) import collections - check(collections.defaultdict.default_factory, size(h + '3PP')) + check(collections.defaultdict.default_factory, size('3PP')) # wrapper_descriptor (descriptor object) - check(int.__add__, size(h + '3P2P')) + check(int.__add__, size('3P2P')) # method-wrapper (descriptor object) - check({}.__iter__, size(h + '2P')) + check({}.__iter__, size('2P')) # dict - check({}, size(h + '3P' + '4P' + 8*'P2P')) + check({}, size('n2P' + '2nPn' + 8*'n2P')) longdict = {1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8} - check(longdict, size(h + '3P' + '4P') + 16*size('P2P')) + check(longdict, size('n2P' + '2nPn') + 16*struct.calcsize('n2P')) # dictionary-keyiterator - check({}.keys(), size(h + 'P')) + check({}.keys(), size('P')) # dictionary-valueiterator - check({}.values(), size(h + 'P')) + check({}.values(), size('P')) # dictionary-itemiterator - check({}.items(), size(h + 'P')) + check({}.items(), size('P')) + # dictionary iterator + check(iter({}), size('P2nPn')) # dictproxy class C(object): pass - check(C.__dict__, size(h + 'P')) + check(C.__dict__, size('P')) # BaseException - check(BaseException(), size(h + '5Pi')) + check(BaseException(), size('5Pi')) # UnicodeEncodeError - check(UnicodeEncodeError("", "", 0, 0, ""), size(h + '5Pi 2P2PP')) + check(UnicodeEncodeError("", "", 0, 0, ""), size('5Pi 2P2nP')) # UnicodeDecodeError - # XXX -# check(UnicodeDecodeError("", "", 0, 0, ""), size(h + '5P2PP')) + check(UnicodeDecodeError("", b"", 0, 0, ""), size('5Pi 2P2nP')) # UnicodeTranslateError - check(UnicodeTranslateError("", 0, 1, ""), size(h + '5Pi 2P2PP')) + check(UnicodeTranslateError("", 0, 1, ""), size('5Pi 2P2nP')) # ellipses - check(Ellipsis, size(h + '')) + check(Ellipsis, size('')) # EncodingMap import codecs, encodings.iso8859_3 x = codecs.charmap_build(encodings.iso8859_3.decoding_table) - check(x, size(h + '32B2iB')) + check(x, size('32B2iB')) # enumerate - check(enumerate([]), size(h + 'l3P')) + check(enumerate([]), size('n3P')) # reverse - check(reversed(''), size(h + 'PP')) + check(reversed(''), size('nP')) # float - check(float(0), size(h + 'd')) + check(float(0), size('d')) # sys.floatinfo - check(sys.float_info, size(vh) + self.P * len(sys.float_info)) + check(sys.float_info, vsize('') + self.P * len(sys.float_info)) # frame import inspect CO_MAXBLOCKS = 20 @@ -768,10 +733,10 @@ nfrees = len(x.f_code.co_freevars) extras = x.f_code.co_stacksize + x.f_code.co_nlocals +\ ncells + nfrees - 1 - check(x, size(vh + '12P3i' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P')) + check(x, vsize('12P3i' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P')) # function def func(): pass - check(func, size(h + '12P')) + check(func, size('12P')) class c(): @staticmethod def foo(): @@ -780,68 +745,68 @@ def bar(cls): pass # staticmethod - check(foo, size(h + 'PP')) + check(foo, size('PP')) # classmethod - check(bar, size(h + 'PP')) + check(bar, size('PP')) # generator def get_gen(): yield 1 - check(get_gen(), size(h + 'Pi2P')) + check(get_gen(), size('Pb2P')) # iterator - check(iter('abc'), size(h + 'lP')) + check(iter('abc'), size('lP')) # callable-iterator import re - check(re.finditer('',''), size(h + '2P')) + check(re.finditer('',''), size('2P')) # list samples = [[], [1,2,3], ['1', '2', '3']] for sample in samples: - check(sample, size(vh + 'PP') + len(sample)*self.P) + check(sample, vsize('Pn') + len(sample)*self.P) # sortwrapper (list) # XXX # cmpwrapper (list) # XXX # listiterator (list) - check(iter([]), size(h + 'lP')) + check(iter([]), size('lP')) # listreverseiterator (list) - check(reversed([]), size(h + 'lP')) + check(reversed([]), size('nP')) # long - check(0, size(vh)) - check(1, size(vh) + self.longdigit) - check(-1, size(vh) + self.longdigit) + check(0, vsize('')) + check(1, vsize('') + self.longdigit) + check(-1, vsize('') + self.longdigit) PyLong_BASE = 2**sys.int_info.bits_per_digit - check(int(PyLong_BASE), size(vh) + 2*self.longdigit) - check(int(PyLong_BASE**2-1), size(vh) + 2*self.longdigit) - check(int(PyLong_BASE**2), size(vh) + 3*self.longdigit) + check(int(PyLong_BASE), vsize('') + 2*self.longdigit) + check(int(PyLong_BASE**2-1), vsize('') + 2*self.longdigit) + check(int(PyLong_BASE**2), vsize('') + 3*self.longdigit) # memoryview - check(memoryview(b''), size(h + 'PPiP4P2i5P3c2P')) + check(memoryview(b''), size('Pnin 2P2n2i5P 3cPn')) # module - check(unittest, size(h + '3P')) + check(unittest, size('PnP')) # None - check(None, size(h + '')) + check(None, size('')) # NotImplementedType - check(NotImplemented, size(h)) + check(NotImplemented, size('')) # object - check(object(), size(h + '')) + check(object(), size('')) # property (descriptor object) class C(object): def getx(self): return self.__x def setx(self, value): self.__x = value def delx(self): del self.__x x = property(getx, setx, delx, "") - check(x, size(h + '4Pi')) + check(x, size('4Pi')) # PyCapsule # XXX # rangeiterator - check(iter(range(1)), size(h + '4l')) + check(iter(range(1)), size('4l')) # reverse - check(reversed(''), size(h + 'PP')) + check(reversed(''), size('nP')) # range - check(range(1), size(h + '4P')) - check(range(66000), size(h + '4P')) + check(range(1), size('4P')) + check(range(66000), size('4P')) # set # frozenset PySet_MINSIZE = 8 samples = [[], range(10), range(50)] - s = size(h + '3P2P' + PySet_MINSIZE*'lP' + 'lP') + s = size('3n2P' + PySet_MINSIZE*'nP' + 'nP') for sample in samples: minused = len(sample) if minused == 0: tmp = 1 @@ -855,31 +820,31 @@ check(set(sample), s) check(frozenset(sample), s) else: - check(set(sample), s + newsize*struct.calcsize('lP')) - check(frozenset(sample), s + newsize*struct.calcsize('lP')) + check(set(sample), s + newsize*struct.calcsize('nP')) + check(frozenset(sample), s + newsize*struct.calcsize('nP')) # setiterator - check(iter(set()), size(h + 'P3P')) + check(iter(set()), size('P3n')) # slice - check(slice(0), size(h + '3P')) + check(slice(0), size('3P')) # super - check(super(int), size(h + '3P')) + check(super(int), size('3P')) # tuple - check((), size(vh)) - check((1,2,3), size(vh) + 3*self.P) + check((), vsize('')) + check((1,2,3), vsize('') + 3*self.P) # type # static type: PyTypeObject - s = size(vh + 'P2P15Pl4PP9PP11PI') + s = vsize('P2n15Pl4Pn9Pn11PI') check(int, s) # (PyTypeObject + PyNumberMethods + PyMappingMethods + # PySequenceMethods + PyBufferProcs + 4P) - s = size(vh + 'P2P15Pl4PP9PP11PI') + size('34P 3P 10P 2P 4P') + s = vsize('P2n15Pl4Pn9Pn11PI') + struct.calcsize('34P 3P 10P 2P 4P') # Separate block for PyDictKeysObject with 4 entries - s += size("PPPP") + 4*size("PPP") + s += struct.calcsize("2nPn") + 4*struct.calcsize("n2P") # class class newstyleclass(object): pass check(newstyleclass, s) # dict with shared keys - check(newstyleclass().__dict__, size(h+"PPP4P")) + check(newstyleclass().__dict__, size('n2P' + '2nPn')) # unicode # each tuple contains a string and its expected character size # don't put any static strings here, as they may contain @@ -887,8 +852,8 @@ samples = ['1'*100, '\xff'*50, '\u0100'*40, '\uffff'*100, '\U00010000'*30, '\U0010ffff'*100] - asciifields = h + "PPiP" - compactfields = asciifields + "PPP" + asciifields = "nniP" + compactfields = asciifields + "nPn" unicodefields = compactfields + "P" for s in samples: maxchar = ord(max(s)) @@ -912,32 +877,31 @@ # TODO: add check that forces layout of unicodefields # weakref import weakref - check(weakref.ref(int), size(h + '2Pl2P')) + check(weakref.ref(int), size('2Pn2P')) # weakproxy # XXX # weakcallableproxy - check(weakref.proxy(int), size(h + '2Pl2P')) + check(weakref.proxy(int), size('2Pn2P')) def test_pythontypes(self): # check all types defined in Python/ - h = self.header - vh = self.vheader - size = self.calcsize + size = test.support.calcobjsize + vsize = test.support.calcvobjsize check = self.check_sizeof # _ast.AST import _ast - check(_ast.AST(), size(h + 'P')) + check(_ast.AST(), size('P')) try: raise TypeError except TypeError: tb = sys.exc_info()[2] # traceback if tb != None: - check(tb, size(h + '2P2i')) + check(tb, size('2P2i')) # symtable entry # XXX # sys.flags - check(sys.flags, size(vh) + self.P * len(sys.flags)) + check(sys.flags, vsize('') + self.P * len(sys.flags)) def test_main(): diff --git a/Lib/test/test_xml_etree_c.py b/Lib/test/test_xml_etree_c.py --- a/Lib/test/test_xml_etree_c.py +++ b/Lib/test/test_xml_etree_c.py @@ -41,38 +41,30 @@ @unittest.skipUnless(cET, 'requires _elementtree') + at support.cpython_only class SizeofTest(unittest.TestCase): def setUp(self): - import _testcapi - gc_headsize = _testcapi.SIZEOF_PYGC_HEAD - # object header - header = 'PP' - if hasattr(sys, "gettotalrefcount"): - # debug header - header = 'PP' + header - # fields - element = header + '5P' - self.elementsize = gc_headsize + struct.calcsize(element) + self.elementsize = support.calcobjsize('5P') # extra self.extra = struct.calcsize('PiiP4P') + check_sizeof = support.check_sizeof + def test_element(self): e = cET.Element('a') - self.assertEqual(sys.getsizeof(e), self.elementsize) + self.check_sizeof(e, self.elementsize) def test_element_with_attrib(self): e = cET.Element('a', href='about:') - self.assertEqual(sys.getsizeof(e), - self.elementsize + self.extra) + self.check_sizeof(e, self.elementsize + self.extra) def test_element_with_children(self): e = cET.Element('a') for i in range(5): cET.SubElement(e, 'span') # should have space for 8 children now - self.assertEqual(sys.getsizeof(e), - self.elementsize + self.extra + - struct.calcsize('8P')) + self.check_sizeof(e, self.elementsize + self.extra + + struct.calcsize('8P')) def test_main(): from test import test_xml_etree, test_xml_etree_c diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,11 @@ Core and Builtins ----------------- +- Issue #15425: Eliminated traceback noise from more situations involving + importlib + +- Issue #14578: Support modules registered in the Windows registry again. + - Issue #15466: Stop using TYPE_INT64 in marshal, to make importlib.h (and other byte code files) equal between 32-bit and 64-bit systems. @@ -236,6 +241,9 @@ Tests ----- +- Issue #15467: Move helpers for __sizeof__ tests into test_support. + Patch by Serhiy Storchaka. + - Issue #15320: Make iterating the list of tests thread-safe when running tests in multiprocess mode. Patch by Chris Jerdonek. @@ -329,6 +337,9 @@ Library ------- +- Issue #15487: Add a __sizeof__ implementation for buffered I/O objects. + Patch by Serhiy Storchaka. + - Issue #15187: Bugfix: remove temporary directories test_shutil was leaving behind. diff --git a/Modules/_freeze_importlib.c b/Modules/_freeze_importlib.c --- a/Modules/_freeze_importlib.c +++ b/Modules/_freeze_importlib.c @@ -21,6 +21,13 @@ {0, 0, 0} /* sentinel */ }; +#ifndef MS_WINDOWS +/* On Windows, this links with the regular pythonXY.dll, so this variable comes + from frozen.obj. In the Makefile, frozen.o is not linked into this executable, + so we define the variable here. */ +struct _frozen *PyImport_FrozenModules; +#endif + const char header[] = "/* Auto-generated by Modules/_freeze_importlib.c */"; int @@ -91,8 +98,8 @@ data_size = PyBytes_GET_SIZE(marshalled); /* Open the file in text mode. The hg checkout should be using the eol extension, - which in turn should cause the existing file to use CRLF */ - outfile = fopen(outpath, "wt"); + which in turn should cause the EOL style match the C library's text mode */ + outfile = fopen(outpath, "w"); if (outfile == NULL) { fprintf(stderr, "cannot open '%s' for writing\n", outpath); return 1; diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -398,6 +398,17 @@ Py_TYPE(self)->tp_free((PyObject *)self); } +static PyObject * +buffered_sizeof(buffered *self, void *unused) +{ + Py_ssize_t res; + + res = sizeof(buffered); + if (self->buffer) + res += self->buffer_size; + return PyLong_FromSsize_t(res); +} + static int buffered_traverse(buffered *self, visitproc visit, void *arg) { @@ -1699,6 +1710,7 @@ {"seek", (PyCFunction)buffered_seek, METH_VARARGS}, {"tell", (PyCFunction)buffered_tell, METH_NOARGS}, {"truncate", (PyCFunction)buffered_truncate, METH_VARARGS}, + {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, {NULL, NULL} }; @@ -2079,6 +2091,7 @@ {"flush", (PyCFunction)buffered_flush, METH_NOARGS}, {"seek", (PyCFunction)buffered_seek, METH_VARARGS}, {"tell", (PyCFunction)buffered_tell, METH_NOARGS}, + {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, {NULL, NULL} }; @@ -2470,6 +2483,7 @@ {"readline", (PyCFunction)buffered_readline, METH_VARARGS}, {"peek", (PyCFunction)buffered_peek, METH_VARARGS}, {"write", (PyCFunction)bufferedwriter_write, METH_VARARGS}, + {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, {NULL, NULL} }; diff --git a/Modules/_struct.c b/Modules/_struct.c --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -1756,15 +1756,11 @@ "S.__sizeof__() -> size of S in memory, in bytes"); static PyObject * -s_sizeof(PyStructObject *self) +s_sizeof(PyStructObject *self, void *unused) { Py_ssize_t size; - formatcode *code; - size = sizeof(PyStructObject) + sizeof(formatcode); - for (code = self->s_codes; code->fmtdef != NULL; code++) { - size += sizeof(formatcode); - } + size = sizeof(PyStructObject) + sizeof(formatcode) * (self->s_len + 1); return PyLong_FromSsize_t(size); } diff --git a/PCbuild/pcbuild.sln b/PCbuild/pcbuild.sln --- a/PCbuild/pcbuild.sln +++ b/PCbuild/pcbuild.sln @@ -603,19 +603,13 @@ {1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Release|x64.ActiveCfg = Release|Win32 {1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Release|x64.Build.0 = Release|Win32 {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Debug|Win32.ActiveCfg = Debug|Win32 - {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Debug|Win32.Build.0 = Debug|Win32 {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Debug|x64.ActiveCfg = Debug|x64 - {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Debug|x64.Build.0 = Debug|x64 {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGInstrument|Win32.ActiveCfg = Release|Win32 - {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGInstrument|Win32.Build.0 = Release|Win32 {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGInstrument|x64.ActiveCfg = Release|Win32 {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGUpdate|Win32.ActiveCfg = Release|Win32 - {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGUpdate|Win32.Build.0 = Release|Win32 {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGUpdate|x64.ActiveCfg = Release|Win32 {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Release|Win32.ActiveCfg = Release|Win32 - {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Release|Win32.Build.0 = Release|Win32 {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Release|x64.ActiveCfg = Release|x64 - {19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -1154,14 +1154,27 @@ { const char *importlib_filename = ""; const char *exec_funcname = "_exec_module"; + const char *get_code_funcname = "get_code"; + const char *recursive_import = "_recursive_import"; int always_trim = 0; + int trim_get_code = 0; int in_importlib = 0; PyObject *exception, *value, *base_tb, *tb; PyObject **prev_link, **outer_link = NULL; /* Synopsis: if it's an ImportError, we trim all importlib chunks - from the traceback. Otherwise, we trim only those chunks which - end with a call to "_exec_module". */ + from the traceback. If it's a SyntaxError, we trim any chunks that + end with a call to "get_code", We always trim chunks + which end with a call to "_exec_module". */ + + /* Thanks to issue 15425, we also strip any chunk ending with + * _recursive_import. This is used when making a recursive call to the + * full import machinery which means the inner stack gets stripped early + * and the normal heuristics won't fire properly for outer frames. A + * more elegant mechanism would be nice, as this one can misfire if + * builtins.__import__ has been replaced with a custom implementation. + * However, the current approach at least gets the job done. + */ PyErr_Fetch(&exception, &value, &base_tb); if (!exception || Py_VerboseFlag) @@ -1169,6 +1182,9 @@ if (PyType_IsSubtype((PyTypeObject *) exception, (PyTypeObject *) PyExc_ImportError)) always_trim = 1; + if (PyType_IsSubtype((PyTypeObject *) exception, + (PyTypeObject *) PyExc_SyntaxError)) + trim_get_code = 1; prev_link = &base_tb; tb = base_tb; @@ -1191,8 +1207,14 @@ if (in_importlib && (always_trim || - PyUnicode_CompareWithASCIIString(code->co_name, - exec_funcname) == 0)) { + (PyUnicode_CompareWithASCIIString(code->co_name, + exec_funcname) == 0) || + (PyUnicode_CompareWithASCIIString(code->co_name, + recursive_import) == 0) || + (trim_get_code && + PyUnicode_CompareWithASCIIString(code->co_name, + get_code_funcname) == 0) + )) { PyObject *tmp = *outer_link; *outer_link = next; Py_XINCREF(next); diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 31 22:10:28 2012 From: python-checkins at python.org (barry.warsaw) Date: Tue, 31 Jul 2012 22:10:28 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3Wmpfr0yLvzPf7@mail.python.org> http://hg.python.org/cpython/rev/deed2a674a1c changeset: 78354:deed2a674a1c parent: 78353:d406e1392bbc parent: 78336:2f3ccf4ec193 user: Barry Warsaw date: Mon Jul 30 14:34:43 2012 -0400 summary: merge files: Lib/idlelib/NEWS.txt | 3 + Lib/idlelib/macosxSupport.py | 16 +++- Lib/test/test_memoryio.py | 11 +++ Lib/tkinter/simpledialog.py | 2 +- Mac/BuildScript/build-installer.py | 57 ++++++++++++++--- Misc/ACKS | 1 + Misc/NEWS | 13 +++- Modules/_io/bytesio.c | 12 +++ Python/traceback.c | 2 +- setup.py | 4 +- 10 files changed, 99 insertions(+), 22 deletions(-) diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -34,6 +34,9 @@ - Issue #3573: IDLE hangs when passing invalid command line args (directory(ies) instead of file(s)). +- Issue #14018: Update checks for unstable system Tcl/Tk versions on OS X + to include versions shipped with OS X 10.7 and 10.8 in addition to 10.6. + What's New in IDLE 3.2.1? ========================= diff --git a/Lib/idlelib/macosxSupport.py b/Lib/idlelib/macosxSupport.py --- a/Lib/idlelib/macosxSupport.py +++ b/Lib/idlelib/macosxSupport.py @@ -37,17 +37,21 @@ def tkVersionWarning(root): """ Returns a string warning message if the Tk version in use appears to - be one known to cause problems with IDLE. The Apple Cocoa-based Tk 8.5 - that was shipped with Mac OS X 10.6. + be one known to cause problems with IDLE. + 1. Apple Cocoa-based Tk 8.5.7 shipped with Mac OS X 10.6 is unusable. + 2. Apple Cocoa-based Tk 8.5.9 in OS X 10.7 and 10.8 is better but + can still crash unexpectedly. """ if (runningAsOSXApp() and - ('AppKit' in root.tk.call('winfo', 'server', '.')) and - (root.tk.call('info', 'patchlevel') == '8.5.7') ): - return (r"WARNING: The version of Tcl/Tk (8.5.7) in use may" + ('AppKit' in root.tk.call('winfo', 'server', '.')) ): + patchlevel = root.tk.call('info', 'patchlevel') + if patchlevel not in ('8.5.7', '8.5.9'): + return False + return (r"WARNING: The version of Tcl/Tk ({0}) in use may" r" be unstable.\n" r"Visit http://www.python.org/download/mac/tcltk/" - r" for current information.") + r" for current information.".format(patchlevel)) else: return False diff --git a/Lib/test/test_memoryio.py b/Lib/test/test_memoryio.py --- a/Lib/test/test_memoryio.py +++ b/Lib/test/test_memoryio.py @@ -654,6 +654,17 @@ memio.close() self.assertRaises(ValueError, memio.__setstate__, (b"closed", 0, None)) + check_sizeof = support.check_sizeof + + @support.cpython_only + def test_sizeof(self): + basesize = support.calcobjsize('P2nN2Pn') + check = self.check_sizeof + self.assertEqual(object.__sizeof__(io.BytesIO()), basesize) + check(io.BytesIO(), basesize ) + check(io.BytesIO(b'a'), basesize + 1 + 1 ) + check(io.BytesIO(b'a' * 1000), basesize + 1000 + 1 ) + class CStringIOTest(PyStringIOTest): ioclass = io.StringIO diff --git a/Lib/tkinter/simpledialog.py b/Lib/tkinter/simpledialog.py --- a/Lib/tkinter/simpledialog.py +++ b/Lib/tkinter/simpledialog.py @@ -282,7 +282,7 @@ self.entry = Entry(master, name="entry") self.entry.grid(row=1, padx=5, sticky=W+E) - if self.initialvalue: + if self.initialvalue is not None: self.entry.insert(0, self.initialvalue) self.entry.select_range(0, END) diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -161,6 +161,13 @@ --universal-archs=x universal architectures (options: %(UNIVERSALOPTS)r, default: %(UNIVERSALARCHS)r) """)% globals() +# Dict of object file names with shared library names to check after building. +# This is to ensure that we ended up dynamically linking with the shared +# library paths and versions we expected. For example: +# EXPECTED_SHARED_LIBS['_tkinter.so'] = [ +# '/Library/Frameworks/Tcl.framework/Versions/8.5/Tcl', +# '/Library/Frameworks/Tk.framework/Versions/8.5/Tk'] +EXPECTED_SHARED_LIBS = {} # Instructions for building libraries that are necessary for building a # batteries included python. @@ -460,27 +467,40 @@ # Because we only support dynamic load of only one major/minor version of # Tcl/Tk, ensure: # 1. there are no user-installed frameworks of Tcl/Tk with version - # higher than the Apple-supplied system version - # 2. there is a user-installed framework in /Library/Frameworks with the - # same version as the system version. This allows users to choose - # to install a newer patch level. + # higher than the Apple-supplied system version in + # SDKROOT/System/Library/Frameworks + # 2. there is a user-installed framework (usually ActiveTcl) in (or linked + # in) SDKROOT/Library/Frameworks with the same version as the system + # version. This allows users to choose to install a newer patch level. + frameworks = {} for framework in ['Tcl', 'Tk']: - #fw = dict(lower=framework.lower(), - # upper=framework.upper(), - # cap=framework.capitalize()) - #fwpth = "Library/Frameworks/%(cap)s.framework/%(lower)sConfig.sh" % fw - fwpth = 'Library/Frameworks/Tcl.framework/Versions/Current' + fwpth = 'Library/Frameworks/%s.framework/Versions/Current' % framework sysfw = os.path.join(SDKPATH, 'System', fwpth) - libfw = os.path.join('/', fwpth) + libfw = os.path.join(SDKPATH, fwpth) usrfw = os.path.join(os.getenv('HOME'), fwpth) - #version = "%(upper)s_VERSION" % fw + frameworks[framework] = os.readlink(sysfw) + if not os.path.exists(libfw): + fatal("Please install a link to a current %s %s as %s so " + "the user can override the system framework." + % (framework, frameworks[framework], libfw)) if os.readlink(libfw) != os.readlink(sysfw): fatal("Version of %s must match %s" % (libfw, sysfw) ) if os.path.exists(usrfw): fatal("Please rename %s to avoid possible dynamic load issues." % usrfw) + if frameworks['Tcl'] != frameworks['Tk']: + fatal("The Tcl and Tk frameworks are not the same version.") + + # add files to check after build + EXPECTED_SHARED_LIBS['_tkinter.so'] = [ + "/Library/Frameworks/Tcl.framework/Versions/%s/Tcl" + % frameworks['Tcl'], + "/Library/Frameworks/Tk.framework/Versions/%s/Tk" + % frameworks['Tk'], + ] + # Remove inherited environment variables which might influence build environ_var_prefixes = ['CPATH', 'C_INCLUDE_', 'DYLD_', 'LANG', 'LC_', 'LD_', 'LIBRARY_', 'PATH', 'PYTHON'] @@ -861,12 +881,12 @@ frmDir = os.path.join(rootDir, 'Library', 'Frameworks', 'Python.framework') gid = grp.getgrnam('admin').gr_gid + shared_lib_error = False for dirpath, dirnames, filenames in os.walk(frmDir): for dn in dirnames: os.chmod(os.path.join(dirpath, dn), STAT_0o775) os.chown(os.path.join(dirpath, dn), -1, gid) - for fn in filenames: if os.path.islink(fn): continue @@ -877,6 +897,19 @@ os.chmod(p, stat.S_IMODE(st.st_mode) | stat.S_IWGRP) os.chown(p, -1, gid) + if fn in EXPECTED_SHARED_LIBS: + # check to see that this file was linked with the + # expected library path and version + data = captureCommand("otool -L %s" % shellQuote(p)) + for sl in EXPECTED_SHARED_LIBS[fn]: + if ("\t%s " % sl) not in data: + print("Expected shared lib %s was not linked with %s" + % (sl, p)) + shared_lib_error = True + + if shared_lib_error: + fatal("Unexpected shared library errors.") + if PYTHON_3: LDVERSION=None VERSION=None diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -700,6 +700,7 @@ Alexis M??taireau Steven Miale Trent Mick +Tom Middleton Stan Mihai Stefan Mihaila Aristotelis Mikropoulos diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -68,6 +68,9 @@ Library ------- +- Issue #15463: the faulthandler module truncates strings to 500 characters, + instead of 100, to be able to display long file paths + - Issue #6056: Make multiprocessing use setblocking(True) on the sockets it uses. Original patch by J Derek Wilson. @@ -267,8 +270,10 @@ Build ----- +- Issue #14018: Fix OS X Tcl/Tk framework checking when using OS X SDKs. + - Issue #15431: Add _freeze_importlib project to regenerate importlib.h - on Windows. Patch by Kristj?n Valur J?nsson. + on Windows. Patch by Kristj??n Valur J??nsson. - Issue #14197: For OS X framework builds, ensure links to the shared library are created with the proper ABI suffix. @@ -337,6 +342,12 @@ Library ------- +- Issue #12288: Consider '0' and '0.0' as valid initialvalue + for tkinter SimpleDialog. + +- Issue #15489: Add a __sizeof__ implementation for BytesIO objects. + Patch by Serhiy Storchaka. + - Issue #15487: Add a __sizeof__ implementation for buffered I/O objects. Patch by Serhiy Storchaka. diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -834,6 +834,17 @@ return 0; } +static PyObject * +bytesio_sizeof(bytesio *self, void *unused) +{ + Py_ssize_t res; + + res = sizeof(bytesio); + if (self->buf) + res += self->buf_size; + return PyLong_FromSsize_t(res); +} + static int bytesio_traverse(bytesio *self, visitproc visit, void *arg) { @@ -876,6 +887,7 @@ {"truncate", (PyCFunction)bytesio_truncate, METH_VARARGS, truncate_doc}, {"__getstate__", (PyCFunction)bytesio_getstate, METH_NOARGS, NULL}, {"__setstate__", (PyCFunction)bytesio_setstate, METH_O, NULL}, + {"__sizeof__", (PyCFunction)bytesio_sizeof, METH_NOARGS, NULL}, {NULL, NULL} /* sentinel */ }; diff --git a/Python/traceback.c b/Python/traceback.c --- a/Python/traceback.c +++ b/Python/traceback.c @@ -14,7 +14,7 @@ #define OFF(x) offsetof(PyTracebackObject, x) #define PUTS(fd, str) write(fd, str, strlen(str)) -#define MAX_STRING_LENGTH 100 +#define MAX_STRING_LENGTH 500 #define MAX_FRAME_DEPTH 100 #define MAX_NTHREADS 100 diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -69,7 +69,9 @@ """ Returns True if 'path' can be located in an OSX SDK """ - return (path.startswith('/usr/') and not path.startswith('/usr/local')) or path.startswith('/System/') + return ( (path.startswith('/usr/') and not path.startswith('/usr/local')) + or path.startswith('/System/') + or path.startswith('/Library/') ) def find_file(filename, std_dirs, paths): """Searches for the directory where a given file is located, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 31 22:10:29 2012 From: python-checkins at python.org (barry.warsaw) Date: Tue, 31 Jul 2012 22:10:29 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Address_substantially_all_?= =?utf-8?q?of_Eric_Snow=27s_comments_in_issue_=2315295=2C_except_for?= Message-ID: <3Wmpfs75mjzPdl@mail.python.org> http://hg.python.org/cpython/rev/c933ec7cafcf changeset: 78355:c933ec7cafcf user: Barry Warsaw date: Mon Jul 30 16:24:12 2012 -0400 summary: Address substantially all of Eric Snow's comments in issue #15295, except for those which now have additional XXX's here. I'll get to those later. :) files: Doc/glossary.rst | 2 +- Doc/reference/import_machinery.rst | 210 ++++++++++------ Doc/whatsnew/3.3.rst | 2 + 3 files changed, 134 insertions(+), 80 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -475,7 +475,7 @@ module An object that serves as an organizational unit of Python code. Modules - have a namespace contain arbitrary Python objects. Modules are loaded + have a namespace containing arbitrary Python objects. Modules are loaded into Python by the process of :term:`importing`. MRO diff --git a/Doc/reference/import_machinery.rst b/Doc/reference/import_machinery.rst --- a/Doc/reference/import_machinery.rst +++ b/Doc/reference/import_machinery.rst @@ -8,30 +8,44 @@ .. index:: single: import machinery Python code in one :term:`module` gains access to the code in another module -by the process of :term:`importing` it. Most commonly, the :keyword:`import` -statement is used to invoke the import machinery, but it can also be invoked -by calling the built-in :func:`__import__` function. +by the process of :term:`importing` it. The :keyword:`import` statement is +the most common way of invoking the import machinery, but it is not the only +way. Functions such as :func:`importlib.import_module` and built-in +:func:`__import__` can also be used to invoke the import machinery. The :keyword:`import` statement combines two operations; it searches for the named module, then it binds the results of that search to a name in the local scope. The search operation of the :keyword:`import` statement is defined as -a call to the :func:`__import__` function, with the appropriate arguments. -The return value of :func:`__import__` is used to perform the name binding -operation of the :keyword:`import` statement. See the :keyword:`import` -statement for the exact details of that name binding operation. +a call to the built-in :func:`__import__` function, with the appropriate +arguments. The return value of :func:`__import__` is used to perform the name +binding operation of the :keyword:`import` statement. See the +:keyword:`import` statement for the exact details of that name binding +operation. -A direct call to :func:`__import__` performs only the search for the module. -The function's return value is used like any other function call in Python; -there is no special side-effects (e.g. name binding) associated with -:func:`__import__`. +A direct call to :func:`__import__` performs only the module search and, if +found, the module creation operation. While certain side-effects may occur, +such as the importing of parent packages, and the updating of various caches +(including :data:`sys.modules`), only the :keyword:`import` statement performs +a name binding operation. When a module is first imported, Python searches for the module and if found, -it creates a module object, initializing it. If the named module cannot be -found, an :exc:`ImportError` is raised. Python implements various strategies -to search for the named module when the import machinery is invoked. These -strategies can be modified and extended by using various hooks described in -the sections below. The entire import machinery itself can be overridden by -replacing built-in :func:`__import__`. +it creates a module object [#fnmo]_, initializing it. If the named module +cannot be found, an :exc:`ImportError` is raised. Python implements various +strategies to search for the named module when the import machinery is +invoked. These strategies can be modified and extended by using various hooks +described in the sections below. The entire import machinery itself can be +overridden by replacing built-in :func:`__import__`. + + +:mod:`importlib` +================ + +The :mod:`importlib` module provides a rich API for interacting with the +import system. For example :func:`importlib.import_module` provides a +recommended, simpler API than built-in :func:`__import__` for invoking the +import machinery. Refer to the :mod:`importlib` library documentation for +additional detail. + Packages @@ -43,25 +57,26 @@ Python has only one type of module object, and all modules are of this type, regardless of whether the module is implemented in Python, C, or something else. To help organize modules and provide a naming hierarchy, Python has a -concept of :term:`packages `. It's important to keep in mind that -all packages are modules, but not all modules are packages. Or put another -way, packages are just a special kind of module. Although usually -unnecessary, introspection of various module object attributes can determine -whether a module is a package or not. +concept of :term:`packages `. -Packages can contain other packages and modules, while modules generally do -not contain other modules or packages. You can think of packages as the -directories on a file system and modules as files within directories, but -don't take this analogy too literally since packages and modules need not -originate from the file system. For the purposes of this documentation, we'll -use this convenient analogy of directories and files. +You can think of packages as the directories on a file system and modules as +files within directories, but don't take this analogy too literally since +packages and modules need not originate from the file system. For the +purposes of this documentation, we'll use this convenient analogy of +directories and files. Like file system directories, packages are organized +hierarchically, and packages may themselves contain subpackages, as well as +regular modules. -All modules have a name. Packages also have names, and subpackages can be -nested arbitrarily deeply. Subpackage names are separated from their parent -package by dots, akin to Python's standard attribute access syntax. Thus you -might have a module called :mod:`sys` and a package called :mod:`email`, which -in turn has a subpackage called :mod:`email.mime` and a module within that -subpackage called :mod:`email.mime.text`. +It's important to keep in mind that all packages are modules, but not all +modules are packages. Or put another way, packages are just a special kind of +module. Specifically, any module that contains an ``__path__`` attribute is +considered a package. + +All modules have a name. Subpackage names are separated from their parent +package name by dots, akin to Python's standard attribute access syntax. Thus +you might have a module called :mod:`sys` and a package called :mod:`email`, +which in turn has a subpackage called :mod:`email.mime` and a module within +that subpackage called :mod:`email.mime.text`. Regular packages @@ -80,22 +95,6 @@ contain the same Python code that any other module can contain, and Python will add some additional attributes to the module when it is imported. - -Namespace packages ------------------- - -.. index:: - pair:: package; namespace - pair:: package; portion - -A namespace package is a composite of various :term:`portions `, -where each portion contributes a subpackage to the parent package. Portions -may reside in different locations on the file system. Portions may also be -found in zip files, on the network, or anywhere else that Python searches -during import. Namespace packages may or may not correspond directly to -objects on the file system; they may be virtual modules that have no concrete -representation. - For example, the following file system layout defines a top level ``parent`` package with three subpackages:: @@ -113,14 +112,31 @@ ``parent.three`` will import ``parent/two/__init__.py`` and ``parent/three/__init__.py`` respectively. + +Namespace packages +------------------ + +.. index:: + pair:: package; namespace + pair:: package; portion + +A namespace package is a composite of various :term:`portions `, +where each portion contributes a subpackage to the parent package. Portions +may reside in different locations on the file system. Portions may also be +found in zip files, on the network, or anywhere else that Python searches +during import. Namespace packages may or may not correspond directly to +objects on the file system; they may be virtual modules that have no concrete +representation. + With namespace packages, there is no ``parent/__init__.py`` file. In fact, there may be multiple ``parent`` directories found during import search, where -each one is provided by a separate vendor installed container, and none of -them contain an ``__init__.py`` file. Thus ``parent/one`` may not be +each one is provided by a different portion. Thus ``parent/one`` may not be physically located next to ``parent/two``. In this case, Python will create a namespace package for the top-level ``parent`` package whenever it or one of its subpackages is imported. +See also :pep:`420` for the namespace package specification. + Searching ========= @@ -129,7 +145,7 @@ name of the module (or package, but for the purposes of this discussion, the difference is immaterial) being imported. This name may come from various arguments to the :keyword:`import` statement, or from the parameters to the -:func:`__import__` function. +:func:`importlib.import_module` or :func:`__import__` functions. This name will be used in various phases of the import search, and it may be the dotted path to a submodule, e.g. ``foo.bar.baz``. In this case, Python @@ -156,8 +172,8 @@ :exc:`ImportError` is raised. If the module name is missing, Python will continue searching for the module. -:data:`sys.modules` is writable. Deleting a key will generally not destroy -the associated module, but it will invalidate the cache entry for the named +:data:`sys.modules` is writable. Deleting a key will not destroy the +associated module, but it will invalidate the cache entry for the named module, causing Python to search anew for the named module upon its next import. Beware though, because if you keep a reference to the module object, invalidate its cache entry in :data:`sys.modules`, and then re-import the @@ -265,11 +281,12 @@ ----------------- Once a loader is found via a meta path finder, the loader's -:meth:`load_module()` method is called, with a single argument, the fully -qualified name of the module being imported. This method has several -responsibilities, and should return the module object it has loaded [#fn1]_. -If it cannot load the module, it should raise an :exc:`ImportError`, although -any other exception raised during :meth:`load_module()` will be propagated. +:meth:`~importlib.abc.Loader.load_module` method is called, with a single +argument, the fully qualified name of the module being imported. This method +has several responsibilities, and should return the module object it has +loaded [#fnlo]_. If it cannot load the module, it should raise an +:exc:`ImportError`, although any other exception raised during +:meth:`load_module()` will be propagated. In many cases, the meta path finder and loader can be the same object, e.g. :meth:`finder.find_module()` would just return ``self``. @@ -278,8 +295,8 @@ * If there is an existing module object with the given name in :data:`sys.modules`, the loader must use that existing module. (Otherwise, - the :func:`reload()` builtin will not work correctly.) If the named module - does not exist in :data:`sys.modules`, the loader must create a new module + the :func:`imp.reload` will not work correctly.) If the named module does + not exist in :data:`sys.modules`, the loader must create a new module object and add it to :data:`sys.modules`. Note that the module *must* exist in :data:`sys.modules` before the loader @@ -314,28 +331,29 @@ * The module's ``__package__`` attribute should be set. Its value must be a string, but it can be the same value as its ``__name__``. This is the recommendation when the module is a package. When the module is not a - package, ``__package__`` should be set to the parent package's name. + package, ``__package__`` should be set to the parent package's + name [#fnpk]_. This attribute is used instead of ``__name__`` to calculate explicit relative imports for main modules, as defined in :pep:`366`. * If the module is a Python module (as opposed to a built-in module or a - dynamically loaded extension), it should execute the module's code in the - module's global name space (``module.__dict__``). + dynamically loaded extension), the loader should execute the module's code + in the module's global name space (``module.__dict__``). Module reprs ------------ By default, all modules have a usable repr, however depending on the -attributes set above, and hooks in the loader, you can more tightly control +attributes set above, and hooks in the loader, you can more explicitly control the repr of module objects. Loaders may implement a :meth:`module_repr()` method which takes a single argument, the module object. When ``repr(module)`` is called for a module with a loader supporting this protocol, whatever is returned from -``loader.module_repr(module)`` is returned as the module's repr without -further processing. This return value must be a string. +``module.__loader__.module_repr(module)`` is returned as the module's repr +without further processing. This return value must be a string. If the module has no ``__loader__`` attribute, or the loader has no :meth:`module_repr()` method, then the module object implementation itself @@ -385,7 +403,7 @@ ``__path__`` must be a list, but it may be empty. The same rules used for :data:`sys.path` also apply to a package's ``__path__``, and -:data:`sys.path_hooks` (described below) are consulted when traversing a +:data:`sys.path_hooks` (described below) is consulted when traversing a package's ``__path__``. A package's ``__init__.py`` file may set or alter the package's ``__path__`` @@ -452,7 +470,7 @@ environment variable and various other installation- and implementation-specific defaults. Entries in :data:`sys.path` can name directories on the file system, zip files, and potentially other "locations" -that should be searched for modules. +(see the :mod:`site` module) that should be searched for modules. The path importer is a meta path finder, so the import machinery begins file system search by calling the path importer's :meth:`find_module()` method as @@ -468,7 +486,7 @@ :data:`sys.path_importer_cache`. In this way, the expensive search for a particular path location's sys path finder need only be done once. User code is free to remove cache entries from :data:`sys.path_importer_cache` forcing -the path importer to perform the path search again. +the path importer to perform the path search again [#fnpic]_. If the path entry is not present in the cache, the path importer iterates over every callable in :data:`sys.path_hooks`. Each entry in this list is called @@ -484,9 +502,8 @@ If a sys path finder *is* returned by one of the callables on :data:`sys.path_hooks`, then the following protocol is used to ask the sys -path finder for a module loader. If a loader results from this step, it is -used to load the module as previously described (i.e. its -:meth:`load_module()` method is called). +path finder for a module loader, which is then used to load the module as +previously described (i.e. its :meth:`load_module()` method is called). sys path finder protocol @@ -520,14 +537,24 @@ Open issues =========== -XXX What to say about `imp.NullImporter` when it's found in -:data:`sys.path_importer_cache`? +XXX Find a better term than "path importer" for class PathFinder and update +the glossary. XXX It would be really nice to have a diagram. -.. [#fn1] The importlib implementation appears not to use the return value - directly. Instead, it gets the module object by looking the module name up - in ``sys.modules``.) +XXX * (import_machinery.rst) how about a section devoted just to the +attributes of modules and packages, perhaps expanding upon or supplanting the +related entries in the data model reference page? + +XXX * (import_machinery.rst) Meta path loaders, end of paragraph 2: "The +finder could also be a classmethod that returns an instance of the class." + +XXX * (import_machinery.rst) Meta path loaders: "If the load fails, the loader +needs to remove any modules..." is a pretty exceptional case, since the +modules is not in charge of its parent or children, nor of import statements +executed for it. Is this a new requirement? + +XXX Module reprs: how does module.__qualname__ fit in? References @@ -545,3 +572,28 @@ :pep:`366` describes the addition of the ``__package__`` attribute for explicit relative imports in main modules. + + +Footnotes +========= + +.. [#fnmo] See :class:`types.ModuleType`. + +.. [#fnlo] The importlib implementation appears not to use the return value + directly. Instead, it gets the module object by looking the module name up + in :data:`sys.modules`.) The indirect effect of this is that an imported + module may replace itself in :data:`sys.modules`. This is + implementation-specific behavior that is not guaranteed to work in other + Python implementations. + +.. [#fnpk] In practice, within CPython there is little consistency in the + values of ``__package__`` for top-level modules. In some, such as in the + :mod:`email` package, both the ``__name__`` and ``__package__`` are set to + "email". In other top-level modules (non-packages), ``__package__`` may be + set to ``None`` or the empty string. The recommendation for top-level + non-package modules is to set ``__package__`` to the empty string. + +.. [#fnpic] In legacy code, it is possible to find instances of + :class:`imp.NullImporter` in the :data:`sys.path_importer_cache`. It + recommended that code be changed to use ``None`` instead. See + :ref:`portingpythoncode` for more details. diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -1677,6 +1677,8 @@ This section lists previously described changes and other bugfixes that may require changes to your code. +.. _portingpythoncode: + Porting Python code ------------------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 31 22:10:31 2012 From: python-checkins at python.org (barry.warsaw) Date: Tue, 31 Jul 2012 22:10:31 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Another_XXX=2E?= Message-ID: <3Wmpfv3TMCzPdf@mail.python.org> http://hg.python.org/cpython/rev/9adcc021cbc2 changeset: 78356:9adcc021cbc2 user: Barry Warsaw date: Mon Jul 30 16:57:20 2012 -0400 summary: Another XXX. files: Doc/reference/import_machinery.rst | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Doc/reference/import_machinery.rst b/Doc/reference/import_machinery.rst --- a/Doc/reference/import_machinery.rst +++ b/Doc/reference/import_machinery.rst @@ -540,6 +540,11 @@ XXX Find a better term than "path importer" for class PathFinder and update the glossary. +XXX In the glossary, "though I'd change ":term:`finder` / :term:`loader`" to +"metapath importer". + +XXX Find a better term than "sys path finder". + XXX It would be really nice to have a diagram. XXX * (import_machinery.rst) how about a section devoted just to the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 31 22:10:33 2012 From: python-checkins at python.org (barry.warsaw) Date: Tue, 31 Jul 2012 22:10:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Finally=2C_a_coherent_set_?= =?utf-8?q?of_terminology_for_all_the_lil=27_beasties_involved=2E?= Message-ID: <3Wmpfx2ZGLzPf7@mail.python.org> http://hg.python.org/cpython/rev/1cf1df6f62f5 changeset: 78357:1cf1df6f62f5 user: Barry Warsaw date: Tue Jul 31 16:03:09 2012 -0400 summary: Finally, a coherent set of terminology for all the lil' beasties involved. files: Doc/glossary.rst | 34 +- Doc/reference/datamodel.rst | 19 +- Doc/reference/import_machinery.rst | 307 ++++++++-------- Doc/reference/index.rst | 2 +- Doc/reference/simple_stmts.rst | 15 +- 5 files changed, 205 insertions(+), 172 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -315,6 +315,13 @@ role in places where a constant hash value is needed, for example as a key in a dictionary. + import path + A list of locations (or :term:`path entries `) that are + searched by the :term:`path importer` for modules to import. During + import, this list of locations usually comes from :data:`sys.path`, but + for subpackages it may also come from the parent package's ``__path__`` + attribute. + importing The process by which Python code in one module is made available to Python code in another module. @@ -446,8 +453,8 @@ meta path finder A finder returned by a search of :data:`sys.meta_path`. Meta path - finders are related to, but different from :term:`sys path finders `. + finders are related to, but different from :term:`path entry finders + `. metaclass The class of a class. Class definitions create a class name, a class @@ -541,9 +548,23 @@ subpackages. Technically, a package is a Python module with an ``__path__`` attribute. + path entry + A single location on the :term:`import path` which the :term:`path + importer` consults to find modules for importing. + + path entry finder + A :term:`finder` returned by a callable on :data:`sys.path_hooks` + (i.e. a :term:`path entry hook`) which knows how to locate modules given + a :term:`path entry`. + + path entry hook + A callable on the :data:`sys.path_hook` list which returns a :term:`path + entry finder` if it knows how to find modules on a specific :term:`path + entry`. + path importer - A built-in :term:`finder` / :term:`loader` that knows how to find and - load modules from the file system. + One of the default :term:`meta path finders ` which + searches an :term:`import path` for modules. portion A set of files in a single directory (possibly stored in a zip file) @@ -671,11 +692,6 @@ :meth:`~collections.somenamedtuple._asdict`. Examples of struct sequences include :data:`sys.float_info` and the return value of :func:`os.stat`. - sys path finder - A finder returned by a search of :data:`sys.path` by the :term:`path - importer`. Sys path finders are related to, but different from - :term:`meta path finders `. - triple-quoted string A string which is bound by three instances of either a quotation mark (") or an apostrophe ('). While they don't provide any functionality diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -652,15 +652,16 @@ object: module Modules are a basic organizational unit of Python code, and are created by - the :ref:`importmachinery` as invoked either by the :keyword:`import` - statement (see section :ref:`import`) or by calling the built in - :func:`__import__` function. A module object has a namespace implemented - by a dictionary object (this is the dictionary referenced by the - ``__globals__`` attribute of functions defined in the module). Attribute - references are translated to lookups in this dictionary, e.g., ``m.x`` is - equivalent to ``m.__dict__["x"]``. A module object does not contain the - code object used to initialize the module (since it isn't needed once the - initialization is done). + the :ref:`import system ` as invoked either by the + :keyword:`import` statement (see :keyword:`import`), or by calling + functions such as :func:`importlib.import_module` and built-in + :func:`__import__`. A module object has a namespace implemented by a + dictionary object (this is the dictionary referenced by the ``__globals__`` + attribute of functions defined in the module). Attribute references are + translated to lookups in this dictionary, e.g., ``m.x`` is equivalent to + ``m.__dict__["x"]``. A module object does not contain the code object used + to initialize the module (since it isn't needed once the initialization is + done). Attribute assignment updates the module's namespace dictionary, e.g., ``m.x = 1`` is equivalent to ``m.__dict__["x"] = 1``. diff --git a/Doc/reference/import_machinery.rst b/Doc/reference/import.rst rename from Doc/reference/import_machinery.rst rename to Doc/reference/import.rst --- a/Doc/reference/import_machinery.rst +++ b/Doc/reference/import.rst @@ -1,9 +1,9 @@ -.. _importmachinery: +.. _importsystem: -**************** -Import machinery -**************** +***************** +The import system +***************** .. index:: single: import machinery @@ -33,8 +33,8 @@ cannot be found, an :exc:`ImportError` is raised. Python implements various strategies to search for the named module when the import machinery is invoked. These strategies can be modified and extended by using various hooks -described in the sections below. The entire import machinery itself can be -overridden by replacing built-in :func:`__import__`. +described in the sections below. More coarse-grained overriding of the import +system can be accomplished by replacing built-in :func:`__import__`. :mod:`importlib` @@ -189,25 +189,25 @@ single: finder single: loader -If the named module is not found in :data:`sys.modules` then Python's import -protocol is invoked to find and load the module. As this implies, the import -protocol consists of two conceptual objects, :term:`finders ` and -:term:`loaders `. A finder's job is to determine whether it can find -the named module using whatever strategy it knows about. For example, there -is a file system finder which know how to search the file system for the named -module. Other finders may know how to search a zip file, a web page, or a -database to find the named module. The import machinery is extensible, so new -finders can be added to extend the range and scope of module searching. +If the named module is not found in :data:`sys.modules`, then Python's import +protocol is invoked to find and load the module. This protocol consists of +two conceptual objects, :term:`finders ` and :term:`loaders `. +A finder's job is to determine whether it can find the named module using +whatever strategy it knows about. + +By default, Python comes with several default finders. One knows how to +locate frozen modules, and another knows how to locate built-in modules. A +third default finder searches an :term:`import path` for modules. The +:term:`import path` is a list of locations that may name file system paths or +zip files. It can also be extended to search for any locatable resource, such +as those identified by URLs. + +The import machinery is extensible, so new finders can be added to extend the +range and scope of module searching. Finders do not actually load modules. If they can find the named module, they -return a loader, which the import machinery later invokes to load the module -and create the corresponding module object. - -There are actually two types of finders, and two different but related APIs -for finders, depending on whether it is a :term:`meta path finder` or a -:term:`sys path finder`. Meta path processing occurs at the beginning of -import processing, while sys path processing happens later, by the :term:`path -importer`. +return a :term:`loader`, which the import machinery then invokes to load the +module and create the corresponding module object. The following sections describe the protocol for finders and loaders in more detail, including how you can create and register new ones to extend the @@ -227,18 +227,18 @@ The import machinery is designed to be extensible; the primary mechanism for this are the *import hooks*. There are two types of import hooks: *meta -hooks* and *path hooks*. +hooks* and *import path hooks*. Meta hooks are called at the start of import processing, before any other -import processing has occurred. This allows meta hooks to override -:data:`sys.path` processing, frozen modules, or even built-in modules. Meta -hooks are registered by adding new finder objects to :data:`sys.meta_path`, as -described below. +import processing has occurred, other than :data:`sys.modules` cache look up. +This allows meta hooks to override :data:`sys.path` processing, frozen +modules, or even built-in modules. Meta hooks are registered by adding new +finder objects to :data:`sys.meta_path`, as described below. -Path hooks are called as part of :data:`sys.path` (or ``package.__path__``) -processing, at the point where their associated path item is encountered. -Path hooks are registered by adding new callables to :data:`sys.path_hooks` as -described below. +Import path hooks are called as part of :data:`sys.path` (or +``package.__path__``) processing, at the point where their associated path +item is encountered. Import path hooks are registered by adding new callables +to :data:`sys.path_hooks` as described below. The meta path @@ -253,9 +253,9 @@ searches :data:`sys.meta_path`, which contains a list of meta path finder objects. These finders are queried in order to see if they know how to handle the named module. Meta path finders must implement a method called -:meth:`find_module()` which takes two arguments, a name and a path. The meta -path finder can use any strategy it wants to determine whether it can handle -the named module or not. +:meth:`find_module()` which takes two arguments, a name and an import path. +The meta path finder can use any strategy it wants to determine whether it can +handle the named module or not. If the meta path finder knows how to handle the named module, it returns a loader object. If it cannot handle the named module, it returns ``None``. If @@ -266,21 +266,21 @@ The :meth:`find_module()` method of meta path finders is called with two arguments. The first is the fully qualified name of the module being imported, for example ``foo.bar.baz``. The second argument is the relative -path for the module search. For top-level modules, the second argument is -``None``, but for submodules or subpackages, the second argument is the value -of the parent package's ``__path__`` attribute, which must exist or an -:exc:`ImportError` is raised. +import path for the module search. For top-level modules, this second +argument will always be ``None``, but for submodules or subpackages, the +second argument is the value of the parent package's ``__path__`` attribute, +which must exist on the parent module or an :exc:`ImportError` is raised. Python's default :data:`sys.meta_path` has three meta path finders, one that knows how to import built-in modules, one that knows how to import frozen -modules, and one that knows how to import modules from the file system +modules, and one that knows how to import modules from an :term:`import path` (i.e. the :term:`path importer`). -Meta path loaders ------------------ +Loaders +======= -Once a loader is found via a meta path finder, the loader's +If and when a module loader is found its :meth:`~importlib.abc.Loader.load_module` method is called, with a single argument, the fully qualified name of the module being imported. This method has several responsibilities, and should return the module object it has @@ -288,8 +288,8 @@ :exc:`ImportError`, although any other exception raised during :meth:`load_module()` will be propagated. -In many cases, the meta path finder and loader can be the same object, -e.g. :meth:`finder.find_module()` would just return ``self``. +In many cases, the finder and loader can be the same object; in such cases the +:meth:`finder.find_module()` would just return ``self``. Loaders must satisfy the following requirements: @@ -305,9 +305,11 @@ beforehand prevents unbounded recursion in the worst case and multiple loading in the best. - If the load fails, the loader needs to remove any modules it may have - inserted into ``sys.modules``. If the module was already in - ``sys.modules`` then the loader should leave it alone. + If loading fails, the loader must remove any modules it has inserted into + :data:`sys.modules`, but it must remove **only** the failing module, and + only if the loader itself has loaded it explicitly. Any module already in + the :data:`sys.modules` cache, and any module that was successfully loaded + as a side-effect, must remain in the cache. * The loader may set the ``__file__`` attribute of the module. If set, this attribute's value must be a string. The loader may opt to leave @@ -329,10 +331,13 @@ data associated with an importer. * The module's ``__package__`` attribute should be set. Its value must be a - string, but it can be the same value as its ``__name__``. This is the - recommendation when the module is a package. When the module is not a - package, ``__package__`` should be set to the parent package's - name [#fnpk]_. + string, but it can be the same value as its ``__name__``. If the attribute + is set to ``None`` or is missing, the import system will fill it in with a + more appropriate value. When the module is a package, its ``__package__`` + value should be set to its ``__name__``. When the module is not a package, + ``__package__`` should be set to the empty string for top-level modules, or + for submodules, to the parent package's name. See :pep:`366` for further + details. This attribute is used instead of ``__name__`` to calculate explicit relative imports for main modules, as defined in :pep:`366`. @@ -421,32 +426,44 @@ single: path importer As mentioned previously, Python comes with several default meta path finders. -One of these, called the :term:`path importer`, knows how to provide -traditional file system imports. It implements all the semantics for finding -modules on the file system, handling special file types such as Python source -code (``.py`` files), Python byte code (``.pyc`` and ``.pyo`` files) and -shared libraries (e.g. ``.so`` files). +One of these, called the :term:`path importer`, searches an :term:`import +path`, which contains a list of :term:`path entries `. Each path +entry names a location to search for modules. -In addition to being able to find such modules, there is built-in support for -loading these modules. To accomplish these two related tasks, additional -hooks and protocols are provided so that you can extend and customize the path -importer semantics. +Path entries may name file system locations, and by default the :term:`path +importer` knows how to provide traditional file system imports. It implements +all the semantics for finding modules on the file system, handling special +file types such as Python source code (``.py`` files), Python byte code +(``.pyc`` and ``.pyo`` files) and shared libraries (e.g. ``.so`` files). + +Path entries need not be limited to file system locations. They can refer to +the contents of zip files, URLs, database queries, or any other location that +can be specified as a string. + +The :term:`path importer` provides additional hooks and protocols so that you +can extend and customize the types of searchable path entries. For example, +if you wanted to support path entries as network URLs, you could write a hook +that implements HTTP semantics to find modules on the web. This hook (a +callable) would return a :term:`path entry finder` supporting the protocol +described below, which was then used to get a loader for the module from the +web. A word of warning: this section and the previous both use the term *finder*, distinguishing between them by using the terms :term:`meta path finder` and -:term:`sys path finder`. Meta path finders and sys path finders are very -similar, support similar protocols, and function in similar ways during the -import process, but it's important to keep in mind that they are subtly -different. In particular, meta path finders operate at the beginning of the -import process, as keyed off the :data:`sys.meta_path` traversal. +:term:`path entry finder`. These two types of finders are very similar, +support similar protocols, and function in similar ways during the import +process, but it's important to keep in mind that they are subtly different. +In particular, meta path finders operate at the beginning of the import +process, as keyed off the :data:`sys.meta_path` traversal. -On the other hand, sys path finders are in a sense an implementation detail of -the path importer, and in fact, if the path importer were to be removed from -:data:`sys.meta_path`, none of the sys path finder semantics would be invoked. +On the other hand, path entry finders are in a sense an implementation detail +of the :term:`path importer`, and in fact, if the path importer were to be +removed from :data:`sys.meta_path`, none of the path entry finder semantics +would be invoked. -sys path finders ----------------- +Path entry finders +------------------ .. index:: single: sys.path @@ -454,112 +471,107 @@ single: sys.path_importer_cache single: PYTHONPATH -The path importer is responsible for finding and loading Python modules and -packages from the file system. As a meta path finder, it implements the +The :term:`path importer` is responsible for finding and loading Python +modules and packages whose location is specified with a string :term:`path +entry`. Most path entries name locations in the file system, but they need +not be limited to this. + +As a meta path finder, the :term:`path importer` implements the :meth:`find_module()` protocol previously described, however it exposes additional hooks that can be used to customize how modules are found and -loaded from the file system. +loaded from the :term:`import path`. -Three variables are used during file system import, :data:`sys.path`, -:data:`sys.path_hooks` and :data:`sys.path_importer_cache`. These provide -additional ways that the import machinery can be customized, in this case -specifically during file system path import. +Three variables are used by the :term:`path importer`, :data:`sys.path`, +:data:`sys.path_hooks` and :data:`sys.path_importer_cache`. The ``__path__`` +attribute on package objects is also used. These provide additional ways that +the import machinery can be customized. :data:`sys.path` contains a list of strings providing search locations for modules and packages. It is initialized from the :data:`PYTHONPATH` environment variable and various other installation- and implementation-specific defaults. Entries in :data:`sys.path` can name directories on the file system, zip files, and potentially other "locations" -(see the :mod:`site` module) that should be searched for modules. +(see the :mod:`site` module) that should be searched for modules, such as +URLs, or database queries. -The path importer is a meta path finder, so the import machinery begins file -system search by calling the path importer's :meth:`find_module()` method as -described previously. When the ``path`` argument to :meth:`find_module()` is -given, it will be a list of string paths to traverse. If not, +The :term:`path importer` is a :term:`meta path finder`, so the import +machinery begins :term:`import path` search by calling the path importer's +:meth:`find_module()` method as described previously. When the ``path`` +argument to :meth:`find_module()` is given, it will be a list of string paths +to traverse. If the ``path`` argument is not given or is ``None``, :data:`sys.path` is used. -The path importer iterates over every entry in the search path, and for each -of these, searches for an appropriate sys path finder for the path entry. -Because this can be an expensive operation (e.g. there are `stat()` call -overheads for this search), the path importer maintains a cache mapping path -entries to sys path finders. This cache is maintained in -:data:`sys.path_importer_cache`. In this way, the expensive search for a -particular path location's sys path finder need only be done once. User code -is free to remove cache entries from :data:`sys.path_importer_cache` forcing -the path importer to perform the path search again [#fnpic]_. +The :term:`path importer` iterates over every entry in the search path, and +for each of these, looks for an appropriate :term:`path entry finder` for the +path entry. Because this can be an expensive operation (e.g. there may be +`stat()` call overheads for this search), the :term:`path importer` maintains +a cache mapping path entries to path entry finders. This cache is maintained +in :data:`sys.path_importer_cache`. In this way, the expensive search for a +particular :term:`path entry` location's :term:`path entry finder` need only +be done once. User code is free to remove cache entries from +:data:`sys.path_importer_cache` forcing the :term:`path importer` to perform +the path entry search again [#fnpic]_. If the path entry is not present in the cache, the path importer iterates over -every callable in :data:`sys.path_hooks`. Each entry in this list is called -with a single argument, the path entry being searched. This callable may -either return a sys path finder that can handle the path entry, or it may -raise :exc:`ImportError`. An :exc:`ImportError` is used by the path importer -to signal that the hook cannot find a sys path finder for that path entry. -The exception is ignored and :data:`sys.path_hooks` iteration continues. +every callable in :data:`sys.path_hooks`. Each of the :term:`path entry hooks +` in this list is called with a single argument, the path +entry being searched. This callable may either return a :term:`path entry +finder` that can handle the path entry, or it may raise :exc:`ImportError`. +An :exc:`ImportError` is used by the path importer to signal that the hook +cannot find a :term:`path entry finder` for that :term:`path entry`. The +exception is ignored and :term:`import path` iteration continues. -If :data:`sys.path_hooks` iteration ends with no sys path finder being -returned then the path importer's :meth:`find_module()` method will return -``None`` and an :exc:`ImportError` will be raised. +If :data:`sys.path_hooks` iteration ends with no :term:`path entry finder` +being returned, then the path importer's :meth:`find_module()` method will +return ``None``, indicating that this :term:`meta path finder` could not find +the module. -If a sys path finder *is* returned by one of the callables on -:data:`sys.path_hooks`, then the following protocol is used to ask the sys -path finder for a module loader, which is then used to load the module as -previously described (i.e. its :meth:`load_module()` method is called). +If a :term:`path entry finder` *is* returned by one of the :term:`path entry +hook` callables on :data:`sys.path_hooks`, then the following protocol is used +to ask the finder for a module loader, which is then used to load the module. -sys path finder protocol ------------------------- +Path entry finder protocol +-------------------------- -sys path finders support the same, traditional :meth:`find_module()` method -that meta path finders support, however sys path finder :meth:`find_module()` +Path entry finders support the same :meth:`find_module()` method that meta +path finders support, however path entry finder's :meth:`find_module()` methods are never called with a ``path`` argument. -The :meth:`find_module()` method on sys path finders is deprecated though, and -instead sys path finders should implement the :meth:`find_loader()` method. -If it exists on the sys path finder, :meth:`find_loader()` will always be -called instead of :meth:`find_module()`. +The :meth:`find_module()` method on path entry finders is deprecated though, +and instead path entry finders should implement the :meth:`find_loader()` +method. If it exists on the path entry finder, :meth:`find_loader()` will +always be called instead of :meth:`find_module()`. :meth:`find_loader()` takes one argument, the fully qualified name of the module being imported. :meth:`find_loader()` returns a 2-tuple where the first item is the loader and the second item is a namespace :term:`portion`. When the first item (i.e. the loader) is ``None``, this means that while the -sys path finder does not have a loader for the named module, it knows that the -path entry contributes to a namespace portion for the named module. This will -almost always be the case where Python is asked to import a namespace package -that has no physical presence on the file system. When a sys path finder -returns ``None`` for the loader, the second item of the 2-tuple return value -must be a sequence, although it can be empty. +path entry finder does not have a loader for the named module, it knows that +the :term:`path entry` contributes to a namespace portion for the named +module. This will almost always be the case where Python is asked to import a +:term:`namespace package` that has no physical presence on the file system. +When a path entry finder returns ``None`` for the loader, the second item of +the 2-tuple return value must be a sequence, although it can be empty. If :meth:`find_loader()` returns a non-``None`` loader value, the portion is -ignored and the loader is returned from the path importer, terminating the -:data:`sys.path` search. +ignored and the loader is returned from the :term:`path importer`, terminating +the :term:`import path` search. Open issues =========== -XXX Find a better term than "path importer" for class PathFinder and update -the glossary. - -XXX In the glossary, "though I'd change ":term:`finder` / :term:`loader`" to -"metapath importer". - -XXX Find a better term than "sys path finder". - XXX It would be really nice to have a diagram. XXX * (import_machinery.rst) how about a section devoted just to the attributes of modules and packages, perhaps expanding upon or supplanting the related entries in the data model reference page? -XXX * (import_machinery.rst) Meta path loaders, end of paragraph 2: "The -finder could also be a classmethod that returns an instance of the class." +XXX Module reprs: how does module.__qualname__ fit in? -XXX * (import_machinery.rst) Meta path loaders: "If the load fails, the loader -needs to remove any modules..." is a pretty exceptional case, since the -modules is not in charge of its parent or children, nor of import statements -executed for it. Is this a new requirement? - -XXX Module reprs: how does module.__qualname__ fit in? +XXX runpy, pkgutil, et al in the library manual should all get "See Also" +links at the top pointing to the new import system section. References @@ -571,13 +583,21 @@ although some details have changed since the writing of that document. The original specification for :data:`sys.meta_path` was :pep:`302`, with -subsequent extension in :pep:`420`, which also introduced namespace packages -without ``__init__.py`` files in Python 3.3. :pep:`420` also introduced the -:meth:`find_loader` protocol as an alternative to :meth:`find_module`. +subsequent extension in :pep:`420`. + +:pep:`420` introduced :term:`namespace packages ` for +Python 3.3. :pep:`420` also introduced the :meth:`find_loader` protocol as an +alternative to :meth:`find_module`. :pep:`366` describes the addition of the ``__package__`` attribute for explicit relative imports in main modules. +:pep:`328` introduced absolute and relative imports and initially proposed +``__name__`` for semantics :pep:`366` would eventually specify for +``__package__``. + +:pep:`338` defines executing modules as scripts. + Footnotes ========= @@ -591,13 +611,6 @@ implementation-specific behavior that is not guaranteed to work in other Python implementations. -.. [#fnpk] In practice, within CPython there is little consistency in the - values of ``__package__`` for top-level modules. In some, such as in the - :mod:`email` package, both the ``__name__`` and ``__package__`` are set to - "email". In other top-level modules (non-packages), ``__package__`` may be - set to ``None`` or the empty string. The recommendation for top-level - non-package modules is to set ``__package__`` to the empty string. - .. [#fnpic] In legacy code, it is possible to find instances of :class:`imp.NullImporter` in the :data:`sys.path_importer_cache`. It recommended that code be changed to use ``None`` instead. See diff --git a/Doc/reference/index.rst b/Doc/reference/index.rst --- a/Doc/reference/index.rst +++ b/Doc/reference/index.rst @@ -24,7 +24,7 @@ lexical_analysis.rst datamodel.rst executionmodel.rst - import_machinery.rst + import.rst expressions.rst simple_stmts.rst compound_stmts.rst diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -662,14 +662,17 @@ Import statements are executed in two steps: (1) find a module, loading and initializing it if necessary; (2) define a name or names in the local -namespace (of the scope where the :keyword:`import` statement occurs). The -statement comes in two forms differing on whether it uses the :keyword:`from` -keyword. The first form (without :keyword:`from`) repeats these steps for each -identifier in the list. The form with :keyword:`from` performs step (1) once, -and then performs step (2) repeatedly. +namespace (of the scope where the :keyword:`import` statement occurs). +Step (1) may be performed recursively if the named module is a submodule or +subpackage of a parent package. + +The :keyword:`import` statement comes in two forms differing on whether it +uses the :keyword:`from` keyword. The first form (without :keyword:`from`) +repeats these steps for each identifier in the list. The form with +:keyword:`from` performs step (1), and then performs step (2) repeatedly. The details of step (1), finding and loading modules is described in greater -detail in the section on the :ref:`import machinery `, which +detail in the section on the :ref:`import system `, which also describes the various types of packages and modules that can be imported, as well as all the hooks that can be used to customize Python's import. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 31 22:10:35 2012 From: python-checkins at python.org (barry.warsaw) Date: Tue, 31 Jul 2012 22:10:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3Wmpfz2cwxzPct@mail.python.org> http://hg.python.org/cpython/rev/8c0745ffbef5 changeset: 78358:8c0745ffbef5 parent: 78357:1cf1df6f62f5 parent: 78349:28c935ded243 user: Barry Warsaw date: Tue Jul 31 16:03:25 2012 -0400 summary: merge files: Doc/distutils/uploading.rst | 6 +- Doc/howto/ipaddress.rst | 8 +- Doc/library/faulthandler.rst | 2 +- Doc/library/functions.rst | 3 + Doc/library/ipaddress.rst | 248 +- Lib/idlelib/PyShell.py | 4 +- Lib/importlib/_bootstrap.py | 65 +- Lib/test/test_faulthandler.py | 15 + Lib/test/test_import.py | 18 +- Misc/NEWS | 7 + Python/bltinmodule.c | 5 +- Python/import.c | 28 +- Python/importlib.h | 7034 ++++++++++---------- Python/pythonrun.c | 8 +- 14 files changed, 3749 insertions(+), 3702 deletions(-) diff --git a/Doc/distutils/uploading.rst b/Doc/distutils/uploading.rst --- a/Doc/distutils/uploading.rst +++ b/Doc/distutils/uploading.rst @@ -74,5 +74,7 @@ :mod:`docutils` will display a warning if there's something wrong with your syntax. Because PyPI applies additional checks (e.g. by passing ``--no-raw`` -to ``rst2html.py`` in the command above), running the command above without -warnings is not sufficient for PyPI to convert the content successfully. +to ``rst2html.py`` in the command above), being able to run the command above +without warnings does not guarantee that PyPI will convert the content +successfully. + diff --git a/Doc/howto/ipaddress.rst b/Doc/howto/ipaddress.rst --- a/Doc/howto/ipaddress.rst +++ b/Doc/howto/ipaddress.rst @@ -19,7 +19,7 @@ Creating Address/Network/Interface objects ========================================== -Since :mod:`ipaddress` is a module for inspecting and manipulating IP address, +Since :mod:`ipaddress` is a module for inspecting and manipulating IP addresses, the first thing you'll want to do is create some objects. You can use :mod:`ipaddress` to create objects from strings and integers. @@ -183,10 +183,10 @@ >>> net6.numhosts 4294967296 -Iterating through the 'usable' addresses on a network:: +Iterating through the "usable" addresses on a network:: >>> net4 = ipaddress.ip_network('192.0.2.0/24') - >>> for x in net4.iterhosts(): + >>> for x in net4.hosts(): print(x) 192.0.2.1 192.0.2.2 @@ -294,7 +294,7 @@ When creating address/network/interface objects using the version-agnostic factory functions, any errors will be reported as :exc:`ValueError` with a generic error message that simply says the passed in value was not -recognised as an object of that type. The lack of a specific error is +recognized as an object of that type. The lack of a specific error is because it's necessary to know whether the value is *supposed* to be IPv4 or IPv6 in order to provide more detail on why it has been rejected. diff --git a/Doc/library/faulthandler.rst b/Doc/library/faulthandler.rst --- a/Doc/library/faulthandler.rst +++ b/Doc/library/faulthandler.rst @@ -23,7 +23,7 @@ * Only ASCII is supported. The ``backslashreplace`` error handler is used on encoding. -* Each string is limited to 100 characters. +* Each string is limited to 500 characters. * Only the filename, the function name and the line number are displayed. (no source code) * It is limited to 100 frames and 100 threads. diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1506,6 +1506,9 @@ If you simply want to import a module (potentially within a package) by name, use :func:`importlib.import_module`. + .. versionchanged:: 3.3 + Negative values for *level* are no longer supported. + .. rubric:: Footnotes diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst --- a/Doc/library/ipaddress.rst +++ b/Doc/library/ipaddress.rst @@ -22,19 +22,18 @@ IP address or network definition. -Defining IP Addresses and Interfaces ------------------------------------- +Convenience factory functions +----------------------------- -The :mod:`ipaddress` module provides factory functions to define IP addresses -and networks: +The :mod:`ipaddress` module provides factory functions to conveniently create +IP addresses, networks and interfaces: .. function:: ip_address(address) Return an :class:`IPv4Address` or :class:`IPv6Address` object depending on - the IP address passed as argument. *address* is a string or integer - representing the IP address. Either IPv4 or IPv6 addresses may be supplied; - integers less than 2**32 will be considered to be IPv4 by default. A - :exc:`ValueError` is raised if the *address* passed is neither an IPv4 nor + the IP address passed as argument. Either IPv4 or IPv6 addresses may be + supplied; integers less than 2**32 will be considered to be IPv4 by default. + A :exc:`ValueError` is raised if *address* does not represent a valid IPv4 or IPv6 address. >>> ipaddress.ip_address('192.168.0.1') @@ -50,8 +49,8 @@ representing the IP network. Either IPv4 or IPv6 networks may be supplied; integers less than 2**32 will be considered to be IPv4 by default. *strict* is passed to :class:`IPv4Network` or :class:`IPv6Network` constructor. A - :exc:`ValueError` is raised if the string passed isn't either an IPv4 or IPv6 - address, or if the network has host bits set. + :exc:`ValueError` is raised if *address* does not represent a valid IPv4 or + IPv6 address, or if the network has host bits set. >>> ipaddress.ip_network('192.168.0.0/28') IPv4Network('192.168.0.0/28') @@ -62,45 +61,174 @@ Return an :class:`IPv4Interface` or :class:`IPv6Interface` object depending on the IP address passed as argument. *address* is a string or integer representing the IP address. Either IPv4 or IPv6 addresses may be supplied; - integers less than 2**32 will be considered to be IPv4 by default.. A - :exc:`ValueError` is raised if the *address* passed isn't either an IPv4 or + integers less than 2**32 will be considered to be IPv4 by default. A + :exc:`ValueError` is raised if *address* does not represent a valid IPv4 or IPv6 address. -Representing IP Addresses and Networks --------------------------------------- +Address objects +--------------- -The module defines the following and classes to represent IP addresses -and networks: - -.. todo: list the properties and methods +The :class:`IPv4Address` and :class:`IPv6Address` objects share a lot of common +attributes. Some attributes that are only meaningful for IPv6 addresses are +also implemented by :class:`IPv4Address` objects, in order to make it easier to +write code that handles both IP versions correctly. To avoid duplication, all +common attributes will only be documented for :class:`IPv4Address`. .. class:: IPv4Address(address) - Construct an IPv4 address. *address* is a string or integer representing the - IP address. An :exc:`AddressValueError` is raised if *address* is not a - valid IPv4 address. + Construct an IPv4 address. An :exc:`AddressValueError` is raised if + *address* is not a valid IPv4 address. + + The following constitutes a valid IPv4 address: + + 1. A string in decimal-dot notation, consisting of four decimal integers in + the inclusive range 0-255, separated by dots (e.g. ``192.168.0.1``). Each + integer represents an octet (byte) in the address, big-endian. + 2. An integer that fits into 32 bits. + 3. An integer packed into a :class:`bytes` object of length 4, big-endian. >>> ipaddress.IPv4Address('192.168.0.1') IPv4Address('192.168.0.1') >>> ipaddress.IPv4Address('192.0.2.1') == ipaddress.IPv4Address(3221225985) True + .. attribute:: exploded -.. class:: IPv4Interface(address) + The longhand version of the address as a string. Note: the + exploded/compressed distinction is meaningful only for IPv6 addresses. + For IPv4 addresses it is the same. - Construct an IPv4 interface. *address* is a string or integer representing - the IP interface. An :exc:`AddressValueError` is raised if *address* is not - a valid IPv4 address. + .. attribute:: compressed - The network address for the interface is determined by calling - ``IPv4Network(address, strict=False)``. + The shorthand version of the address as a string. - >>> ipaddress.IPv4Interface('192.168.0.0/24') - IPv4Interface('192.168.0.0/24') - >>> ipaddress.IPv4Interface('192.168.0.0/24').network - IPv4Network('192.168.0.0/24') + .. attribute:: packed + The binary representation of this address - a :class:`bytes` object. + + .. attribute:: version + + A numeric version number. + + .. attribute:: max_prefixlen + + Maximal length of the prefix (in bits). The prefix defines the number of + leading bits in an address that are compared to determine whether or not an + address is part of a network. + + .. attribute:: is_multicast + + ``True`` if the address is reserved for multicast use. See :RFC:`3171` (for + IPv4) or :RFC:`2373` (for IPv6). + + .. attribute:: is_private + + ``True`` if the address is allocated for private networks. See :RFC:`1918` + (for IPv4) or :RFC:`4193` (for IPv6). + + .. attribute:: is_unspecified + + ``True`` if the address is unspecified. See :RFC:`5375` (for IPv4) or + :RFC:`2373` (for IPv6). + + .. attribute:: is_reserved + + ``True`` if the address is otherwise IETF reserved. + + .. attribute:: is_loopback + + ``True`` if this is a loopback address. See :RFC:`3330` (for IPv4) or + :RFC:`2373` (for IPv6). + + .. attribute:: is_link_local + + ``True`` if the address is reserved for link-local. See :RFC:`3927`. + +.. class:: IPv6Address(address) + + Construct an IPv6 address. An :exc:`AddressValueError` is raised if + *address* is not a valid IPv6 address. + + The following constitutes a valid IPv6 address: + + 1. A string consisting of eight groups of four hexadecimal digits, each + group representing 16 bits. The groups are separated by colons. + This describes an *exploded* (longhand) notation. The string can + also be *compressed* (shorthand notation) by various means. See + :RFC:`4291` for details. For example, + ``"0000:0000:0000:0000:0000:0abc:0007:0def"`` can be compressed to + ``"::abc:7:def"``. + 2. An integer that fits into 128 bits. + 3. An integer packed into a :class:`bytes` object of length 16, big-endian. + + >>> ipaddress.IPv6Address('2001:db8::1000') + IPv6Address('2001:db8::1000') + + All the attributes exposed by :class:`IPv4Address` are supported. In + addition, the following attributs are exposed only by :class:`IPv6Address`. + + .. attribute:: is_site_local + + ``True`` if the address is reserved for site-local. Note that the site-local + address space has been deprecated by :RFC:`3879`. Use + :attr:`~IPv4Address.is_private` to test if this address is in the space of + unique local addresses as defined by :RFC:`4193`. + + .. attribute:: ipv4_mapped + + If this address represents a IPv4 mapped address, return the IPv4 mapped + address. Otherwise return ``None``. + + .. attribute:: teredo + + If this address appears to be a teredo address (starts with ``2001::/32``), + return a tuple of embedded teredo IPs ``(server, client)`` pairs. Otherwise + return ``None``. + + .. attribute:: sixtofour + + If this address appears to contain a 6to4 embedded address, return the + embedded IPv4 address. Otherwise return ``None``. + + +Operators +^^^^^^^^^ + +Address objects support some operators. Unless stated otherwise, operators can +only be applied between compatible objects (i.e. IPv4 with IPv4, IPv6 with +IPv6). + +Logical operators +""""""""""""""""" + +Address objects can be compared with the usual set of logical operators. Some +examples:: + + >>> IPv4Address('127.0.0.2') > IPv4Address('127.0.0.1') + True + >>> IPv4Address('127.0.0.2') == IPv4Address('127.0.0.1') + False + >>> IPv4Address('127.0.0.2') != IPv4Address('127.0.0.1') + True + +Arithmetic operators +"""""""""""""""""""" + +Integers can be added to or subtracted from address objects. Some examples:: + + >>> IPv4Address('127.0.0.2') + 3 + IPv4Address('127.0.0.5') + >>> IPv4Address('127.0.0.2') - 3 + IPv4Address('126.255.255.255') + >>> IPv4Address('255.255.255.255') + 1 + Traceback (most recent call last): + File "", line 1, in + ipaddress.AddressValueError: 4294967296 (>= 2**32) is not permitted as an IPv4 address + + +Network objects +--------------- .. class:: IPv4Network(address, strict=True) @@ -121,31 +249,6 @@ IPv4Network('192.0.2.0/27') -.. class:: IPv6Address(address) - - Construct an IPv6 address. *address* is a string or integer representing the - IP address. An :exc:`AddressValueError` is raised if *address* is not a - valid IPv6 address. - - >>> ipaddress.IPv6Address('2001:db8::1000') - IPv6Address('2001:db8::1000') - - -.. class:: IPv6Interface(address) - - Construct an IPv6 interface. *address* is a string or integer representing - the IP interface. An :exc:`AddressValueError` is raised if *address* is not - a valid IPv6 address. - - The network address for the interface is determined by calling - ``IPv6Network(address, strict=False)``. - - >>> ipaddress.IPv6Interface('2001:db8::1000/96') - IPv6Interface('2001:db8::1000/96') - >>> ipaddress.IPv6Interface('2001:db8::1000/96').network - IPv6Network('2001:db8::/96') - - .. class:: IPv6Network(address, strict=True) Construct an IPv6 network. *address* is a string or integer representing the @@ -165,6 +268,39 @@ IPv6Network('2001:db8::/96') +Interface objects +----------------- + +.. class:: IPv4Interface(address) + + Construct an IPv4 interface. *address* is a string or integer representing + the IP interface. An :exc:`AddressValueError` is raised if *address* is not + a valid IPv4 address. + + The network address for the interface is determined by calling + ``IPv4Network(address, strict=False)``. + + >>> ipaddress.IPv4Interface('192.168.0.0/24') + IPv4Interface('192.168.0.0/24') + >>> ipaddress.IPv4Interface('192.168.0.0/24').network + IPv4Network('192.168.0.0/24') + + +.. class:: IPv6Interface(address) + + Construct an IPv6 interface. *address* is a string or integer representing + the IP interface. An :exc:`AddressValueError` is raised if *address* is not + a valid IPv6 address. + + The network address for the interface is determined by calling + ``IPv6Network(address, strict=False)``. + + >>> ipaddress.IPv6Interface('2001:db8::1000/96') + IPv6Interface('2001:db8::1000/96') + >>> ipaddress.IPv6Interface('2001:db8::1000/96').network + IPv6Network('2001:db8::/96') + + Other Module Level Functions ---------------------------- diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -248,8 +248,8 @@ def ranges_to_linenumbers(self, ranges): lines = [] for index in range(0, len(ranges), 2): - lineno = int(float(ranges[index])) - end = int(float(ranges[index+1])) + lineno = int(float(ranges[index].string)) + end = int(float(ranges[index+1].string)) while lineno < end: lines.append(lineno) lineno += 1 diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -297,8 +297,20 @@ else: lock.release() +# Frame stripping magic ############################################### -# Finder/loader utility code ################################################## +def _call_with_frames_removed(f, *args, **kwds): + """remove_importlib_frames in import.c will always remove sequences + of importlib frames that end with a call to this function + + Use it instead of a normal call in places where including the importlib + frames introduces unwanted noise into the traceback (e.g. when executing + module code) + """ + return f(*args, **kwds) + + +# Finder/loader utility code ############################################### """Magic word to reject .pyc files generated by other Python versions. It should change for each incompatible change to the bytecode. @@ -629,20 +641,13 @@ """Load a built-in module.""" is_reload = fullname in sys.modules try: - return cls._exec_module(fullname) + return _call_with_frames_removed(_imp.init_builtin, fullname) except: if not is_reload and fullname in sys.modules: del sys.modules[fullname] raise @classmethod - def _exec_module(cls, fullname): - """Helper for load_module, allowing to isolate easily (when - looking at a traceback) whether an error comes from executing - an imported module's code.""" - return _imp.init_builtin(fullname) - - @classmethod @_requires_builtin def get_code(cls, fullname): """Return None as built-in modules do not have code objects.""" @@ -687,7 +692,7 @@ """Load a frozen module.""" is_reload = fullname in sys.modules try: - m = cls._exec_module(fullname) + m = _call_with_frames_removed(_imp.init_frozen, fullname) # Let our own module_repr() method produce a suitable repr. del m.__file__ return m @@ -714,13 +719,6 @@ """Return if the frozen module is a package.""" return _imp.is_frozen_package(fullname) - @classmethod - def _exec_module(cls, fullname): - """Helper for load_module, allowing to isolate easily (when - looking at a traceback) whether an error comes from executing - an imported module's code.""" - return _imp.init_frozen(fullname) - class WindowsRegistryImporter: @@ -850,15 +848,9 @@ else: module.__package__ = module.__package__.rpartition('.')[0] module.__loader__ = self - self._exec_module(code_object, module.__dict__) + _call_with_frames_removed(exec, code_object, module.__dict__) return module - def _exec_module(self, code_object, module_dict): - """Helper for _load_module, allowing to isolate easily (when - looking at a traceback) whether an error comes from executing - an imported module's code.""" - exec(code_object, module_dict) - class SourceLoader(_LoaderBasics): @@ -956,8 +948,9 @@ raise ImportError(msg.format(bytecode_path), name=fullname, path=bytecode_path) source_bytes = self.get_data(source_path) - code_object = compile(source_bytes, source_path, 'exec', - dont_inherit=True) + code_object = _call_with_frames_removed(compile, + source_bytes, source_path, 'exec', + dont_inherit=True) _verbose_message('code object from {}', source_path) if (not sys.dont_write_bytecode and bytecode_path is not None and source_mtime is not None): @@ -1093,7 +1086,8 @@ """Load an extension module.""" is_reload = fullname in sys.modules try: - module = self._exec_module(fullname, self.path) + module = _call_with_frames_removed(_imp.load_dynamic, + fullname, self.path) _verbose_message('extension module loaded from {!r}', self.path) return module except: @@ -1113,12 +1107,6 @@ """Return None as extension modules have no source code.""" return None - def _exec_module(self, fullname, path): - """Helper for load_module, allowing to isolate easily (when - looking at a traceback) whether an error comes from executing - an imported module's code.""" - return _imp.load_dynamic(fullname, path) - class _NamespacePath: """Represents a namespace package's path. It uses the module name @@ -1472,7 +1460,7 @@ parent = name.rpartition('.')[0] if parent: if parent not in sys.modules: - _recursive_import(import_, parent) + _call_with_frames_removed(import_, parent) # Crazy side-effects! if name in sys.modules: return sys.modules[name] @@ -1550,13 +1538,6 @@ _lock_unlock_module(name) return module -def _recursive_import(import_, name): - """Common exit point for recursive calls to the import machinery - - This simplifies the process of stripping importlib from tracebacks - """ - return import_(name) - def _handle_fromlist(module, fromlist, import_): """Figure out what __import__ should return. @@ -1575,7 +1556,7 @@ fromlist.extend(module.__all__) for x in fromlist: if not hasattr(module, x): - _recursive_import(import_, + _call_with_frames_removed(import_, '{}.{}'.format(module.__name__, x)) return module diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -7,6 +7,7 @@ import subprocess import sys from test import support, script_helper +from test.script_helper import assert_python_ok import tempfile import unittest @@ -256,6 +257,20 @@ finally: sys.stderr = orig_stderr + def test_disabled_by_default(self): + # By default, the module should be disabled + code = "import faulthandler; print(faulthandler.is_enabled())" + rc, stdout, stderr = assert_python_ok("-c", code) + stdout = (stdout + stderr).strip() + self.assertEqual(stdout, b"False") + + def test_sys_xoptions(self): + # Test python -X faulthandler + code = "import faulthandler; print(faulthandler.is_enabled())" + rc, stdout, stderr = assert_python_ok("-X", "faulthandler", "-c", code) + stdout = (stdout + stderr).strip() + self.assertEqual(stdout, b"True") + def check_dump_traceback(self, filename): """ Explicitly call dump_traceback() function and check its output. diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -785,11 +785,13 @@ sys.path[:] = self.old_path rmtree(TESTFN) - def create_module(self, mod, contents): - with open(os.path.join(TESTFN, mod + ".py"), "w") as f: + def create_module(self, mod, contents, ext=".py"): + fname = os.path.join(TESTFN, mod + ext) + with open(fname, "w") as f: f.write(contents) self.addCleanup(unload, mod) importlib.invalidate_caches() + return fname def assert_traceback(self, tb, files): deduped_files = [] @@ -857,16 +859,14 @@ def _setup_broken_package(self, parent, child): pkg_name = "_parent_foo" - def cleanup(): - rmtree(pkg_name) - unload(pkg_name) - os.mkdir(pkg_name) - self.addCleanup(cleanup) + self.addCleanup(unload, pkg_name) + pkg_path = os.path.join(TESTFN, pkg_name) + os.mkdir(pkg_path) # Touch the __init__.py - init_path = os.path.join(pkg_name, '__init__.py') + init_path = os.path.join(pkg_path, '__init__.py') with open(init_path, 'w') as f: f.write(parent) - bar_path = os.path.join(pkg_name, 'bar.py') + bar_path = os.path.join(pkg_path, 'bar.py') with open(bar_path, 'w') as f: f.write(child) importlib.invalidate_caches() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #15508: Fix the docstring for __import__ to have the proper default + value of 0 for 'level' and to not mention negative levels since they are + not supported. + - Issue #15425: Eliminated traceback noise from more situations involving importlib @@ -342,6 +346,9 @@ Library ------- +- Issue #9803: Don't close IDLE on saving if breakpoint is open. + Patch by Roger Serwy. + - Issue #12288: Consider '0' and '0.0' as valid initialvalue for tkinter SimpleDialog. diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -195,7 +195,7 @@ } PyDoc_STRVAR(import_doc, -"__import__(name, globals={}, locals={}, fromlist=[], level=-1) -> module\n\ +"__import__(name, globals={}, locals={}, fromlist=[], level=0) -> module\n\ \n\ Import a module. Because this function is meant for use by the Python\n\ interpreter and not for general use it is better to use\n\ @@ -208,8 +208,7 @@ When importing a module from a package, note that __import__('A.B', ...)\n\ returns package A when fromlist is empty, but its submodule B when\n\ fromlist is not empty. Level is used to determine whether to perform \n\ -absolute or relative imports. -1 is the original strategy of attempting\n\ -both absolute and relative imports, 0 is absolute, a positive number\n\ +absolute or relative imports. 0 is absolute while a positive number\n\ is the number of parent directories to search relative to the current module."); diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -1153,9 +1153,7 @@ remove_importlib_frames(void) { const char *importlib_filename = ""; - const char *exec_funcname = "_exec_module"; - const char *get_code_funcname = "get_code"; - const char *recursive_import = "_recursive_import"; + const char *remove_frames = "_call_with_frames_removed"; int always_trim = 0; int trim_get_code = 0; int in_importlib = 0; @@ -1163,18 +1161,8 @@ PyObject **prev_link, **outer_link = NULL; /* Synopsis: if it's an ImportError, we trim all importlib chunks - from the traceback. If it's a SyntaxError, we trim any chunks that - end with a call to "get_code", We always trim chunks - which end with a call to "_exec_module". */ - - /* Thanks to issue 15425, we also strip any chunk ending with - * _recursive_import. This is used when making a recursive call to the - * full import machinery which means the inner stack gets stripped early - * and the normal heuristics won't fire properly for outer frames. A - * more elegant mechanism would be nice, as this one can misfire if - * builtins.__import__ has been replaced with a custom implementation. - * However, the current approach at least gets the job done. - */ + from the traceback. We always trim chunks + which end with a call to "_call_with_frames_removed". */ PyErr_Fetch(&exception, &value, &base_tb); if (!exception || Py_VerboseFlag) @@ -1207,14 +1195,8 @@ if (in_importlib && (always_trim || - (PyUnicode_CompareWithASCIIString(code->co_name, - exec_funcname) == 0) || - (PyUnicode_CompareWithASCIIString(code->co_name, - recursive_import) == 0) || - (trim_get_code && - PyUnicode_CompareWithASCIIString(code->co_name, - get_code_funcname) == 0) - )) { + PyUnicode_CompareWithASCIIString(code->co_name, + remove_frames) == 0)) { PyObject *tmp = *outer_link; *outer_link = next; Py_XINCREF(next); diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -356,10 +356,6 @@ _PyImportHooks_Init(); - /* initialize the faulthandler module */ - if (_PyFaulthandler_Init()) - Py_FatalError("Py_Initialize: can't initialize faulthandler"); - /* Initialize _warnings. */ _PyWarnings_Init(); @@ -368,6 +364,10 @@ import_init(interp, sysmod); + /* initialize the faulthandler module */ + if (_PyFaulthandler_Init()) + Py_FatalError("Py_Initialize: can't initialize faulthandler"); + _PyTime_Init(); if (initfsencoding(interp) < 0) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 31 22:10:36 2012 From: python-checkins at python.org (barry.warsaw) Date: Tue, 31 Jul 2012 22:10:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_-_Issue_=2315295=3A_Reorga?= =?utf-8?q?nize_and_rewrite_the_documentation_on_the_import_system=2E?= Message-ID: <3Wmpg06NbLzPdx@mail.python.org> http://hg.python.org/cpython/rev/d5317b8f455a changeset: 78359:d5317b8f455a user: Barry Warsaw date: Tue Jul 31 16:10:12 2012 -0400 summary: - Issue #15295: Reorganize and rewrite the documentation on the import system. files: Misc/NEWS | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -225,8 +225,7 @@ Documentation ------------- -- Issue #15295: Reorganize and rewrite the documentation on the import - machinery. +- Issue #15295: Reorganize and rewrite the documentation on the import system. - Issue #15230: Clearly document some of the limitations of the runpy module and nudge readers towards importlib when appropriate. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 31 22:39:47 2012 From: python-checkins at python.org (barry.warsaw) Date: Tue, 31 Jul 2012 22:39:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Typo=2E?= Message-ID: <3WmqJg2rDCzPc3@mail.python.org> http://hg.python.org/cpython/rev/564c2a8c975b changeset: 78360:564c2a8c975b user: Barry Warsaw date: Tue Jul 31 16:39:43 2012 -0400 summary: Typo. files: Lib/importlib/abc.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/importlib/abc.py b/Lib/importlib/abc.py --- a/Lib/importlib/abc.py +++ b/Lib/importlib/abc.py @@ -33,7 +33,7 @@ The fullname is a str.""" raise NotImplementedError - @abs.abstractmethod + @abc.abstractmethod def module_repr(self, module): """Abstract method which when implemented calculates and returns the given module's repr.""" @@ -44,7 +44,7 @@ """Abstract base class for import finders.""" - @abs.abstractmethod + @abc.abstractmethod def find_loader(self, fullname): """Abstract method which when implemented returns a module loader. The fullname is a str. Returns a 2-tuple of (Loader, portion) where -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jul 31 23:52:38 2012 From: python-checkins at python.org (barry.warsaw) Date: Tue, 31 Jul 2012 23:52:38 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_abc_fixes=2E?= Message-ID: <3Wmrwk6JWFzPcP@mail.python.org> http://hg.python.org/cpython/rev/b213894e0859 changeset: 78361:b213894e0859 user: Barry Warsaw date: Tue Jul 31 17:52:32 2012 -0400 summary: abc fixes. files: Lib/test/test_importlib/source/test_abc_loader.py | 11 ++++++++++ Lib/test/test_importlib/source/test_file_loader.py | 2 + 2 files changed, 13 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_importlib/source/test_abc_loader.py b/Lib/test/test_importlib/source/test_abc_loader.py --- a/Lib/test/test_importlib/source/test_abc_loader.py +++ b/Lib/test/test_importlib/source/test_abc_loader.py @@ -32,6 +32,9 @@ def get_filename(self, fullname): return self.path + def module_repr(self, module): + return '' + class SourceLoaderMock(SourceOnlyLoaderMock): @@ -107,6 +110,9 @@ assert issubclass(w[0].category, DeprecationWarning) return path + def module_repr(self): + return '' + class PyLoaderCompatMock(PyLoaderMock): @@ -779,11 +785,16 @@ class Loader(abc.Loader): def load_module(self, fullname): super().load_module(fullname) + def module_repr(self, module): + super().module_repr(module) class Finder(abc.Finder): def find_module(self, _): super().find_module(_) + def find_loader(self, _): + super().find_loader(_) + class ResourceLoader(Loader, abc.ResourceLoader): def get_data(self, _): super().get_data(_) diff --git a/Lib/test/test_importlib/source/test_file_loader.py b/Lib/test/test_importlib/source/test_file_loader.py --- a/Lib/test/test_importlib/source/test_file_loader.py +++ b/Lib/test/test_importlib/source/test_file_loader.py @@ -29,6 +29,7 @@ # If fullname is not specified that assume self.name is desired. class TesterMixin(importlib.abc.Loader): def load_module(self, fullname): return fullname + def module_repr(self, module): return '' class Tester(importlib.abc.FileLoader, TesterMixin): def get_code(self, _): pass @@ -49,6 +50,7 @@ def get_code(self, _): pass def get_source(self, _): pass def is_package(self, _): pass + def module_repr(self, _): pass path = 'some_path' name = 'some_name' -- Repository URL: http://hg.python.org/cpython