[Python-3000-checkins] r62801 - in python/branches/py3k: Doc/library/site.rst Doc/library/stdtypes.rst Doc/using/cmdline.rst Include/pydebug.h Lib/distutils/command/install.py Lib/site.py Lib/test/test_site.py Lib/test/test_warnings.py Lib/warnings.py Modules/main.c Python/_warnings.c Python/pythonrun.c Python/sysmodule.c

christian.heimes python-3000-checkins at python.org
Wed May 7 01:45:47 CEST 2008


Author: christian.heimes
Date: Wed May  7 01:45:46 2008
New Revision: 62801

Log:
Merged revisions 62774-62775,62785,62787-62788 via svnmerge from 
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r62774 | georg.brandl | 2008-05-06 19:11:42 +0200 (Tue, 06 May 2008) | 2 lines
  
  #2773: fix description of 'g' and 'G' formatting spec.
........
  r62775 | georg.brandl | 2008-05-06 19:20:54 +0200 (Tue, 06 May 2008) | 2 lines
  
  > != (!<).
........
  r62785 | benjamin.peterson | 2008-05-07 00:18:11 +0200 (Wed, 07 May 2008) | 2 lines
  
  Fix logic error in Python/_warnings.c and add a test to verify
........
  r62787 | benjamin.peterson | 2008-05-07 00:31:52 +0200 (Wed, 07 May 2008) | 2 lines
  
  Make the Python implementation of warnings compatible with the C implementation regarding non-callable showwarning
........
  r62788 | christian.heimes | 2008-05-07 00:41:46 +0200 (Wed, 07 May 2008) | 1 line
  
  Implemented PEP 370
........


Modified:
   python/branches/py3k/   (props changed)
   python/branches/py3k/Doc/library/site.rst
   python/branches/py3k/Doc/library/stdtypes.rst
   python/branches/py3k/Doc/using/cmdline.rst
   python/branches/py3k/Include/pydebug.h
   python/branches/py3k/Lib/distutils/command/install.py
   python/branches/py3k/Lib/site.py
   python/branches/py3k/Lib/test/test_site.py
   python/branches/py3k/Lib/test/test_warnings.py
   python/branches/py3k/Lib/warnings.py
   python/branches/py3k/Modules/main.c
   python/branches/py3k/Python/_warnings.c
   python/branches/py3k/Python/pythonrun.c
   python/branches/py3k/Python/sysmodule.c

Modified: python/branches/py3k/Doc/library/site.rst
==============================================================================
--- python/branches/py3k/Doc/library/site.rst	(original)
+++ python/branches/py3k/Doc/library/site.rst	Wed May  7 01:45:46 2008
@@ -82,3 +82,51 @@
 empty, and the path manipulations are skipped; however the import of
 :mod:`sitecustomize` is still attempted.
 
+
+.. data:: PREFIXES
+
+   A list of prefixes for site package directories
+
+   .. versionadded:: 2.6
+
+
+.. data:: ENABLE_USER_SITE
+
+   Flag showing the status of the user site directory. True means the
+   user site directory is enabled and added to sys.path. When the flag
+   is None the user site directory is disabled for security reasons.
+
+   .. versionadded:: 2.6
+
+
+.. data:: USER_SITE
+
+   Path to the user site directory for the current Python version or None
+
+   .. versionadded:: 2.6
+
+
+.. data:: USER_BASE
+
+   Path to the base directory for user site directories
+
+   .. versionadded:: 2.6
+
+
+.. envvar:: PYTHONNOUSERSITE
+
+   .. versionadded:: 2.6
+
+
+.. envvar:: PYTHONUSERBASE
+
+   .. versionadded:: 2.6
+
+
+.. function:: addsitedir(sitedir, known_paths=None)
+
+   Adds a directory to sys.path and processes its pth files.
+
+
+XXX Update documentation
+XXX document python -m site --user-base --user-site

Modified: python/branches/py3k/Doc/library/stdtypes.rst
==============================================================================
--- python/branches/py3k/Doc/library/stdtypes.rst	(original)
+++ python/branches/py3k/Doc/library/stdtypes.rst	Wed May  7 01:45:46 2008
@@ -1141,13 +1141,13 @@
 +------------+-----------------------------------------------------+-------+
 | ``'F'``    | Floating point decimal format.                      | \(3)  |
 +------------+-----------------------------------------------------+-------+
-| ``'g'``    | Floating point format. Uses exponential format if   | \(4)  |
-|            | exponent is greater than -4 or less than precision, |       |
-|            | decimal format otherwise.                           |       |
+| ``'g'``    | Floating point format. Uses lowercase exponential   | \(4)  |
+|            | format if exponent is less than -4 or not less than |       |
+|            | precision, decimal format otherwise.                |       |
 +------------+-----------------------------------------------------+-------+
-| ``'G'``    | Floating point format. Uses exponential format if   | \(4)  |
-|            | exponent is greater than -4 or less than precision, |       |
-|            | decimal format otherwise.                           |       |
+| ``'G'``    | Floating point format. Uses uppercase exponential   | \(4)  |
+|            | format if exponent is less than -4 or not less than |       |
+|            | precision, decimal format otherwise.                |       |
 +------------+-----------------------------------------------------+-------+
 | ``'c'``    | Single character (accepts integer or single         |       |
 |            | character string).                                  |       |

Modified: python/branches/py3k/Doc/using/cmdline.rst
==============================================================================
--- python/branches/py3k/Doc/using/cmdline.rst	(original)
+++ python/branches/py3k/Doc/using/cmdline.rst	Wed May  7 01:45:46 2008
@@ -21,7 +21,7 @@
 
 When invoking Python, you may specify any of these options::
 
-    python [-bdEiOStuUvxX?] [-c command | -m module-name | script | - ] [args]
+    python [-bdEiOsStuUvxX?] [-c command | -m module-name | script | - ] [args]
 
 The most common use case is, of course, a simple invocation of a script::
 
@@ -214,6 +214,29 @@
 
 
 
+<<<<<<< .working
+=======
+   .. seealso::
+      :file:`Tools/scripts/fixdiv.py`
+         for a use of ``warnall``
+
+      :pep:`238` -- Changing the division operator
+
+
+.. cmdoption:: -s
+
+   Don't add user site directory to sys.path
+
+   .. versionadded:: 2.6
+
+   .. seealso::
+
+      :pep:`370` -- Per user site-packages directory
+
+
+.. cmdoption:: -S
+
+>>>>>>> .merge-right.r62788
    Disable the import of the module :mod:`site` and the site-dependent
    manipulations of :data:`sys.path` that it entails.
 
@@ -424,6 +447,24 @@
    .. versionadded:: 2.6
 
 
+.. envvar:: PYTHONNOUSERSITE
+
+   If this is set, Python won't add the user site directory to sys.path
+
+   .. seealso::
+
+      :pep:`370` -- Per user site-packages directory
+
+
+.. envvar:: PYTHONUSERBASE
+
+   Sets the base directory for the user site directory
+
+   .. seealso::
+
+      :pep:`370` -- Per user site-packages directory
+
+
 .. envvar:: PYTHONEXECUTABLE
 
    If this environment variable is set, ``sys.argv[0]`` will be set to its

Modified: python/branches/py3k/Include/pydebug.h
==============================================================================
--- python/branches/py3k/Include/pydebug.h	(original)
+++ python/branches/py3k/Include/pydebug.h	Wed May  7 01:45:46 2008
@@ -18,6 +18,7 @@
 PyAPI_DATA(int) Py_IgnoreEnvironmentFlag;
 PyAPI_DATA(int) Py_DivisionWarningFlag;
 PyAPI_DATA(int) Py_DontWriteBytecodeFlag;
+PyAPI_DATA(int) Py_NoUserSiteDirectory;
 
 /* this is a wrapper around getenv() that pays attention to
    Py_IgnoreEnvironmentFlag.  It should be used for getting variables like

Modified: python/branches/py3k/Lib/distutils/command/install.py
==============================================================================
--- python/branches/py3k/Lib/distutils/command/install.py	(original)
+++ python/branches/py3k/Lib/distutils/command/install.py	Wed May  7 01:45:46 2008
@@ -15,6 +15,9 @@
 from distutils.util import convert_path, subst_vars, change_root
 from distutils.util import get_platform
 from distutils.errors import DistutilsOptionError
+from site import USER_BASE
+from site import USER_SITE
+
 
 if sys.version < "2.2":
     WINDOWS_SCHEME = {
@@ -48,7 +51,21 @@
         'scripts': '$base/bin',
         'data'   : '$base',
         },
+    'unix_user': {
+        'purelib': '$usersite',
+        'platlib': '$usersite',
+        'headers': '$userbase/include/python$py_version_short/$dist_name',
+        'scripts': '$userbase/bin',
+        'data'   : '$userbase',
+        },
     'nt': WINDOWS_SCHEME,
+    'nt_user': {
+        'purelib': '$usersite',
+        'platlib': '$usersite',
+        'headers': '$userbase/Python$py_version_nodot/Include/$dist_name',
+        'scripts': '$userbase/Scripts',
+        'data'   : '$userbase',
+        },
     'mac': {
         'purelib': '$base/Lib/site-packages',
         'platlib': '$base/Lib/site-packages',
@@ -56,13 +73,27 @@
         'scripts': '$base/Scripts',
         'data'   : '$base',
         },
+    'mac_user': {
+        'purelib': '$usersite',
+        'platlib': '$usersite',
+        'headers': '$userbase/$py_version_short/include/$dist_name',
+        'scripts': '$userbase/bin',
+        'data'   : '$userbase',
+        },
     'os2': {
         'purelib': '$base/Lib/site-packages',
         'platlib': '$base/Lib/site-packages',
         'headers': '$base/Include/$dist_name',
         'scripts': '$base/Scripts',
         'data'   : '$base',
-        }
+        },
+    'os2_home': {
+        'purelib': '$usersite',
+        'platlib': '$usersite',
+        'headers': '$userbase/include/python$py_version_short/$dist_name',
+        'scripts': '$userbase/bin',
+        'data'   : '$userbase',
+        },
     }
 
 # The keys to an installation scheme; if any new types of files are to be
@@ -83,6 +114,8 @@
          "(Unix only) prefix for platform-specific files"),
         ('home=', None,
          "(Unix only) home directory to install under"),
+        ('user', None,
+         "install in user site-package '%s'" % USER_SITE),
 
         # Or, just set the base director(y|ies)
         ('install-base=', None,
@@ -134,7 +167,7 @@
          "filename in which to record list of installed files"),
         ]
 
-    boolean_options = ['compile', 'force', 'skip-build']
+    boolean_options = ['compile', 'force', 'skip-build', 'user']
     negative_opt = {'no-compile' : 'compile'}
 
 
@@ -145,6 +178,7 @@
         self.prefix = None
         self.exec_prefix = None
         self.home = None
+        self.user = 0
 
         # These select only the installation base; it's up to the user to
         # specify the installation scheme (currently, that means supplying
@@ -163,6 +197,8 @@
         self.install_lib = None         # set to either purelib or platlib
         self.install_scripts = None
         self.install_data = None
+        self.install_userbase = USER_BASE
+        self.install_usersite = USER_SITE
 
         self.compile = None
         self.optimize = None
@@ -238,6 +274,11 @@
             raise DistutilsOptionError(
                   "must supply either home or prefix/exec-prefix -- not both")
 
+        if self.user and (self.prefix or self.exec_prefix or self.home or
+                self.install_base or self.install_platbase):
+            raise DistutilsOptionError("can't combine user with with prefix/"
+                                       "exec_prefix/home or install_(plat)base")
+
         # Next, stuff that's wrong (or dubious) only on certain platforms.
         if os.name != "posix":
             if self.exec_prefix:
@@ -273,10 +314,13 @@
                             'dist_fullname': self.distribution.get_fullname(),
                             'py_version': py_version,
                             'py_version_short': py_version[0:3],
+                            'py_version_nodot': py_version[0] + py_version[2],
                             'sys_prefix': prefix,
                             'prefix': prefix,
                             'sys_exec_prefix': exec_prefix,
                             'exec_prefix': exec_prefix,
+                            'userbase': self.install_userbase,
+                            'usersite': self.install_usersite,
                            }
         self.expand_basedirs()
 
@@ -298,6 +342,10 @@
 
         self.dump_dirs("post-expand_dirs()")
 
+        # Create directories in the home dir:
+        if self.user:
+            self.create_home_path()
+
         # Pick the actual directory to install all modules to: either
         # install_purelib or install_platlib, depending on whether this
         # module distribution is pure or not.  Of course, if the user
@@ -312,7 +360,8 @@
         # Convert directories from Unix /-separated syntax to the local
         # convention.
         self.convert_paths('lib', 'purelib', 'platlib',
-                           'scripts', 'data', 'headers')
+                           'scripts', 'data', 'headers',
+                           'userbase', 'usersite')
 
         # Well, we're not actually fully completely finalized yet: we still
         # have to deal with 'extra_path', which is the hack for allowing
@@ -369,7 +418,13 @@
                       "installation scheme is incomplete")
             return
 
-        if self.home is not None:
+        if self.user:
+            if self.install_userbase is None:
+                raise DistutilsPlatformError(
+                    "User base directory is not specified")
+            self.install_base = self.install_platbase = self.install_userbase
+            self.select_scheme("unix_user")
+        elif self.home is not None:
             self.install_base = self.install_platbase = self.home
             self.select_scheme("unix_home")
         else:
@@ -391,7 +446,13 @@
 
 
     def finalize_other(self):          # Windows and Mac OS for now
-        if self.home is not None:
+        if self.user:
+            if self.install_userbase is None:
+                raise DistutilsPlatformError(
+                    "User base directory is not specified")
+            self.install_base = self.install_platbase = self.install_userbase
+            self.select_scheme(os.name + "_user")
+        elif self.home is not None:
             self.install_base = self.install_platbase = self.home
             self.select_scheme("unix_home")
         else:
@@ -419,7 +480,7 @@
         for attr in attrs:
             val = getattr(self, attr)
             if val is not None:
-                if os.name == 'posix':
+                if os.name == 'posix' or os.name == 'nt':
                     val = os.path.expanduser(val)
                 val = subst_vars(val, self.config_vars)
                 setattr(self, attr, val)
@@ -479,6 +540,16 @@
             attr = "install_" + name
             setattr(self, attr, change_root(self.root, getattr(self, attr)))
 
+    def create_home_path(self):
+        """Create directories under ~
+        """
+        if not self.user:
+            return
+        home = convert_path(os.path.expanduser("~"))
+        for name, path in self.config_vars.iteritems():
+            if path.startswith(home) and not os.path.isdir(path):
+                self.debug_print("os.makedirs('%s', 0o700)" % path)
+                os.makedirs(path, 0o700)
 
     # -- Command execution methods -------------------------------------
 

Modified: python/branches/py3k/Lib/site.py
==============================================================================
--- python/branches/py3k/Lib/site.py	(original)
+++ python/branches/py3k/Lib/site.py	Wed May  7 01:45:46 2008
@@ -56,11 +56,21 @@
 import os
 import builtins
 
+# Prefixes for site-packages; add additional prefixes like /usr/local here
+PREFIXES = [sys.prefix, sys.exec_prefix]
+# Enable per user site-packages directory
+# set it to False to disable the feature or True to force the feature
+ENABLE_USER_SITE = None
+# for distutils.commands.install
+USER_SITE = None
+USER_BASE = None
+
 
 def makepath(*paths):
     dir = os.path.abspath(os.path.join(*paths))
     return dir, os.path.normcase(dir)
 
+
 def abs__file__():
     """Set all module' __file__ attribute to an absolute path"""
     for m in set(sys.modules.values()):
@@ -71,6 +81,7 @@
         except AttributeError:
             continue
 
+
 def removeduppaths():
     """ Remove duplicate entries from sys.path along with making them
     absolute"""
@@ -101,6 +112,7 @@
     s = os.path.join(os.path.dirname(sys.path[-1]), s)
     sys.path.append(s)
 
+
 def _init_pathinfo():
     """Return a set containing all existing directory entries from sys.path"""
     d = set()
@@ -113,6 +125,7 @@
             continue
     return d
 
+
 def addpackage(sitedir, name, known_paths):
     """Process a .pth file within the site-packages directory:
        For each line in the file, either combine it with sitedir to a path
@@ -128,11 +141,11 @@
         f = open(fullname, "rU")
     except IOError:
         return
-    try:
+    with f:
         for line in f:
             if line.startswith("#"):
                 continue
-            if line.startswith("import ") or line.startswith("import\t"):
+            if line.startswith(("import ", "import\t")):
                 exec(line)
                 continue
             line = line.rstrip()
@@ -140,12 +153,11 @@
             if not dircase in known_paths and os.path.exists(dir):
                 sys.path.append(dir)
                 known_paths.add(dircase)
-    finally:
-        f.close()
     if reset:
         known_paths = None
     return known_paths
 
+
 def addsitedir(sitedir, known_paths=None):
     """Add 'sitedir' argument to sys.path if missing and handle .pth files in
     'sitedir'"""
@@ -161,48 +173,114 @@
         names = os.listdir(sitedir)
     except os.error:
         return
-    names.sort()
-    for name in names:
-        if name.endswith(".pth"):
-            addpackage(sitedir, name, known_paths)
+    names = [name for name in names if name.endswith(".pth")]
+    for name in sorted(names):
+        addpackage(sitedir, name, known_paths)
     if reset:
         known_paths = None
     return known_paths
 
+
+def check_enableusersite():
+    """Check if user site directory is safe for inclusion
+
+    The functions tests for the command line flag (including environment var),
+    process uid/gid equal to effective uid/gid.
+
+    None: Disabled for security reasons
+    False: Disabled by user (command line option)
+    True: Safe and enabled
+    """
+    if sys.flags.no_user_site:
+        return False
+
+    if hasattr(os, "getuid") and hasattr(os, "geteuid"):
+        # check process uid == effective uid
+        if os.geteuid() != os.getuid():
+            return None
+    if hasattr(os, "getgid") and hasattr(os, "getegid"):
+        # check process gid == effective gid
+        if os.getegid() != os.getgid():
+            return None
+
+    return True
+
+
+def addusersitepackages(known_paths):
+    """Add a per user site-package to sys.path
+
+    Each user has its own python directory with site-packages in the
+    home directory.
+
+    USER_BASE is the root directory for all Python versions
+
+    USER_SITE is the user specific site-packages directory
+
+    USER_SITE/.. can be used for data.
+    """
+    global USER_BASE, USER_SITE, ENABLE_USER_SITE
+    env_base = os.environ.get("PYTHONUSERBASE", None)
+
+    def joinuser(*args):
+        return os.path.expanduser(os.path.join(*args))
+
+    #if sys.platform in ('os2emx', 'riscos'):
+    #    # Don't know what to put here
+    #    USER_BASE = ''
+    #    USER_SITE = ''
+    if os.name == "nt":
+        base = os.environ.get("APPDATA") or "~"
+        USER_BASE = env_base if env_base else joinuser(base, "Python")
+        USER_SITE = os.path.join(USER_BASE,
+                                 "Python" + sys.version[0] + sys.version[2],
+                                 "site-packages")
+    else:
+        USER_BASE = env_base if env_base else joinuser("~", ".local")
+        USER_SITE = os.path.join(USER_BASE, "lib",
+                                 "python" + sys.version[:3],
+                                 "site-packages")
+
+    if ENABLE_USER_SITE and os.path.isdir(USER_SITE):
+        addsitedir(USER_SITE, known_paths)
+    return known_paths
+
+
 def addsitepackages(known_paths):
     """Add site-packages (and possibly site-python) to sys.path"""
-    prefixes = [sys.prefix]
-    if sys.exec_prefix != sys.prefix:
-        prefixes.append(sys.exec_prefix)
-    for prefix in prefixes:
-        if prefix:
-            if sys.platform == 'os2emx':
-                sitedirs = [os.path.join(prefix, "Lib", "site-packages")]
-            elif os.sep == '/':
-                sitedirs = [os.path.join(prefix,
-                                         "lib",
-                                         "python" + sys.version[:3],
-                                         "site-packages"),
-                            os.path.join(prefix, "lib", "site-python")]
-            else:
-                sitedirs = [prefix, os.path.join(prefix, "lib", "site-packages")]
-            if sys.platform == 'darwin':
-                # for framework builds *only* we add the standard Apple
-                # locations. Currently only per-user, but /Library and
-                # /Network/Library could be added too
-                if 'Python.framework' in prefix:
-                    home = os.environ.get('HOME')
-                    if home:
-                        sitedirs.append(
-                            os.path.join(home,
-                                         'Library',
-                                         'Python',
-                                         sys.version[:3],
-                                         'site-packages'))
-            for sitedir in sitedirs:
-                if os.path.isdir(sitedir):
-                    addsitedir(sitedir, known_paths)
-    return None
+    sitedirs = []
+    seen = []
+
+    for prefix in PREFIXES:
+        if not prefix or prefix in seen:
+            continue
+        seen.append(prefix)
+
+        if sys.platform in ('os2emx', 'riscos'):
+            sitedirs.append(os.path.join(prefix, "Lib", "site-packages"))
+        elif os.sep == '/':
+            sitedirs.append(os.path.join(prefix, "lib",
+                                        "python" + sys.version[:3],
+                                        "site-packages"))
+            sitedirs.append(os.path.join(prefix, "lib", "site-python"))
+        else:
+            sitedirs.append(prefix)
+            sitedirs.append(os.path.join(prefix, "lib", "site-packages"))
+
+        if sys.platform == "darwin":
+            # for framework builds *only* we add the standard Apple
+            # locations. Currently only per-user, but /Library and
+            # /Network/Library could be added too
+            if 'Python.framework' in prefix:
+                sitedirs.append(
+                    os.path.expanduser(
+                        os.path.join("~", "Library", "Python",
+                                     sys.version[:3], "site-packages")))
+
+    for sitedir in sitedirs:
+        if os.path.isdir(sitedir):
+            addsitedir(sitedir, known_paths)
+
+    return known_paths
 
 
 def setBEGINLIBPATH():
@@ -401,13 +479,26 @@
             (err.__class__.__name__, err))
 
 
+def execusercustomize():
+    """Run custom user specific code, if available."""
+    try:
+        import usercustomize
+    except ImportError:
+        pass
+
+
 def main():
+    global ENABLE_USER_SITE
+
     abs__file__()
-    paths_in_sys = removeduppaths()
+    known_paths = removeduppaths()
     if (os.name == "posix" and sys.path and
         os.path.basename(sys.path[-1]) == "Modules"):
         addbuilddir()
-    paths_in_sys = addsitepackages(paths_in_sys)
+    if ENABLE_USER_SITE is None:
+        ENABLE_USER_SITE = check_enableusersite()
+    known_paths = addusersitepackages(known_paths)
+    known_paths = addsitepackages(known_paths)
     if sys.platform == 'os2emx':
         setBEGINLIBPATH()
     setquit()
@@ -416,6 +507,8 @@
     aliasmbcs()
     setencoding()
     execsitecustomize()
+    if ENABLE_USER_SITE:
+        execusercustomize()
     # Remove sys.setdefaultencoding() so that users cannot change the
     # encoding after initialization.  The test for presence is needed when
     # this module is run as a script, because this code is executed twice.
@@ -424,11 +517,54 @@
 
 main()
 
-def _test():
-    print("sys.path = [")
-    for dir in sys.path:
-        print("    %r," % (dir,))
-    print("]")
+def _script():
+    help = """\
+    %s [--user-base] [--user-site]
+
+    Without arguments print some useful information
+    With arguments print the value of USER_BASE and/or USER_SITE separated
+    by '%s'.
+
+    Exit codes with --user-base or --user-site:
+      0 - user site directory is enabled
+      1 - user site diretory is disabled by user
+      2 - uses site directory is disabled by super user
+          or for security reasons
+     >2 - unknown error
+    """
+    args = sys.argv[1:]
+    if not args:
+        print("sys.path = [")
+        for dir in sys.path:
+            print("    %r," % (dir,))
+        print("]")
+        print("USER_BASE: %r (%s)" % (USER_BASE,
+            "exists" if os.path.isdir(USER_BASE) else "doesn't exist"))
+        print("USER_SITE: %r (%s)" % (USER_SITE,
+            "exists" if os.path.isdir(USER_SITE) else "doesn't exist"))
+        print("ENABLE_USER_SITE: %r" %  ENABLE_USER_SITE)
+        sys.exit(0)
+
+    buffer = []
+    if '--user-base' in args:
+        buffer.append(USER_BASE)
+    if '--user-site' in args:
+        buffer.append(USER_SITE)
+
+    if buffer:
+        print(os.pathsep.join(buffer))
+        if ENABLE_USER_SITE:
+            sys.exit(0)
+        elif ENABLE_USER_SITE is False:
+            sys.exit(1)
+        elif ENABLE_USER_SITE is None:
+            sys.exit(2)
+        else:
+            sys.exit(3)
+    else:
+        import textwrap
+        print(textwrap.dedent(help % (sys.argv[0], os.pathsep)))
+        sys.exit(10)
 
 if __name__ == '__main__':
-    _test()
+    _script()

Modified: python/branches/py3k/Lib/test/test_site.py
==============================================================================
--- python/branches/py3k/Lib/test/test_site.py	(original)
+++ python/branches/py3k/Lib/test/test_site.py	Wed May  7 01:45:46 2008
@@ -10,6 +10,7 @@
 import os
 import sys
 import encodings
+import subprocess
 # Need to make sure to not import 'site' if someone specified ``-S`` at the
 # command-line.  Detect this by just making sure 'site' has not been imported
 # already.
@@ -18,6 +19,11 @@
 else:
     raise TestSkipped("importation of site.py suppressed")
 
+if not os.path.isdir(site.USER_SITE):
+    # need to add user site directory for tests
+    os.makedirs(site.USER_SITE)
+    site.addsitedir(site.USER_SITE)
+
 class HelperFunctionsTests(unittest.TestCase):
     """Tests for helper functions.
 
@@ -30,7 +36,7 @@
         """Save a copy of sys.path"""
         self.sys_path = sys.path[:]
 
-    def tearDown(self):
+
         """Restore sys.path"""
         sys.path = self.sys_path
 
@@ -90,6 +96,33 @@
         finally:
             pth_file.cleanup()
 
+    def test_s_option(self):
+        usersite = site.USER_SITE
+        self.assert_(usersite in sys.path)
+
+        rc = subprocess.call([sys.executable, '-c',
+            'import sys; sys.exit("%s" in sys.path)' % usersite])
+        self.assertEqual(rc, 1)
+
+        rc = subprocess.call([sys.executable, '-s', '-c',
+            'import sys; sys.exit("%s" in sys.path)' % usersite])
+        self.assertEqual(rc, 0)
+
+        env = os.environ.copy()
+        env["PYTHONNOUSERSITE"] = "1"
+        rc = subprocess.call([sys.executable, '-c',
+            'import sys; sys.exit("%s" in sys.path)' % usersite],
+            env=env)
+        self.assertEqual(rc, 0)
+
+        env = os.environ.copy()
+        env["PYTHONUSERBASE"] = "/tmp"
+        rc = subprocess.call([sys.executable, '-c',
+            'import sys, site; sys.exit(site.USER_BASE.startswith("/tmp"))'],
+            env=env)
+        self.assertEqual(rc, 1)
+
+
 class PthFile(object):
     """Helper class for handling testing of .pth files"""
 

Modified: python/branches/py3k/Lib/test/test_warnings.py
==============================================================================
--- python/branches/py3k/Lib/test/test_warnings.py	(original)
+++ python/branches/py3k/Lib/test/test_warnings.py	Wed May  7 01:45:46 2008
@@ -388,6 +388,15 @@
                 result = stream.getvalue()
         self.failUnless(text in result)
 
+    def test_showwarning_not_callable(self):
+        self.module.filterwarnings("always", category=UserWarning)
+        old_showwarning = self.module.showwarning
+        self.module.showwarning = 23
+        try:
+            self.assertRaises(TypeError, self.module.warn, "Warning!")
+        finally:
+            self.module.showwarning = old_showwarning
+
     def test_show_warning_output(self):
         # With showarning() missing, make sure that output is okay.
         text = 'test show_warning'

Modified: python/branches/py3k/Lib/warnings.py
==============================================================================
--- python/branches/py3k/Lib/warnings.py	(original)
+++ python/branches/py3k/Lib/warnings.py	Wed May  7 01:45:46 2008
@@ -247,6 +247,9 @@
         raise RuntimeError(
               "Unrecognized action (%r) in warnings.filters:\n %s" %
               (action, item))
+    if not hasattr(showwarning, "__call__"):
+        raise TypeError("warnings.showwarning() must be set to a "
+                        "function or method")
     # Print message and context
     showwarning(message, category, filename, lineno)
 

Modified: python/branches/py3k/Modules/main.c
==============================================================================
--- python/branches/py3k/Modules/main.c	(original)
+++ python/branches/py3k/Modules/main.c	Wed May  7 01:45:46 2008
@@ -45,7 +45,7 @@
 static int  orig_argc;
 
 /* command line options */
-#define BASE_OPTS L"bBc:dEhiJm:OStuvVW:xX?"
+#define BASE_OPTS L"bBc:dEhiJm:OsStuvVW:xX?"
 
 #define PROGRAM_OPTS BASE_OPTS
 
@@ -70,6 +70,7 @@
 -m mod : run library module as a script (terminates option list)\n\
 -O     : optimize generated bytecode slightly; also PYTHONOPTIMIZE=x\n\
 -OO    : remove doc-strings in addition to the -O optimizations\n\
+-s     : don't add user site directory to sys.path; also PYTHONNOUSERSITE\n\
 -S     : don't imply 'import site' on initialization\n\
 -t     : issue warnings about inconsistent tab usage (-tt: issue errors)\n\
 ";
@@ -355,6 +356,10 @@
 			Py_DontWriteBytecodeFlag++;
 			break;
 
+		case 's':
+			Py_NoUserSiteDirectory++;
+			break;
+
 		case 'S':
 			Py_NoSiteFlag++;
 			break;
@@ -419,6 +424,10 @@
 	    (p = Py_GETENV("PYTHONUNBUFFERED")) && *p != '\0')
 		unbuffered = 1;
 
+	if (!Py_NoUserSiteDirectory &&
+	    (p = Py_GETENV("PYTHONNOUSERSITE")) && *p != '\0')
+		Py_NoUserSiteDirectory = 1;
+
 	if (command == NULL && module == NULL && _PyOS_optind < argc &&
 	    wcscmp(argv[_PyOS_optind], L"-") != 0)
 	{

Modified: python/branches/py3k/Python/_warnings.c
==============================================================================
--- python/branches/py3k/Python/_warnings.c	(original)
+++ python/branches/py3k/Python/_warnings.c	Wed May  7 01:45:46 2008
@@ -378,15 +378,47 @@
             show_warning(filename, lineno, text, category, sourceline);
         }
         else {
-            PyObject *res;
-            
-            res = PyObject_CallFunctionObjArgs(show_fxn, message, category,
+            const char *msg = "functions overriding warnings.showwarning() "
+                                "must support the 'line' argument";
+            const char *text_char = PyUnicode_AsString(text);
+
+            if (strcmp(msg, text_char) == 0) {
+                /* Prevent infinite recursion by using built-in implementation
+                   of showwarning(). */
+                show_warning(filename, lineno, text, category, sourceline);
+            }
+            else {
+                PyObject *check_fxn;
+                PyObject *defaults;
+                PyObject *res;
+
+                if (PyMethod_Check(show_fxn))
+                    check_fxn = PyMethod_Function(show_fxn);
+                else if (PyFunction_Check(show_fxn))
+                    check_fxn = show_fxn;
+                else {
+                    PyErr_SetString(PyExc_TypeError,
+                                    "warnings.showwarning() must be set to a "
+                                    "function or method");
+                    Py_DECREF(show_fxn);
+                    goto cleanup;
+                }
+
+                defaults = PyFunction_GetDefaults(check_fxn);
+                /* A proper implementation of warnings.showwarning() should
+                    have at least two default arguments. */
+                if ((defaults == NULL) || (PyTuple_Size(defaults) < 2)) {
+                    if (PyErr_WarnEx(PyExc_DeprecationWarning, msg, 1) < 0)
+                        goto cleanup;
+                }
+                res = PyObject_CallFunctionObjArgs(show_fxn, message, category,
                                                     filename, lineno_obj,
                                                     NULL);
-            Py_DECREF(show_fxn);
-            Py_XDECREF(res);
-            if (res == NULL)
-                goto cleanup;
+                Py_DECREF(show_fxn);
+                Py_XDECREF(res);
+                if (res == NULL)
+                    goto cleanup;
+            }
         }
     }
     else /* if (rc == -1) */

Modified: python/branches/py3k/Python/pythonrun.c
==============================================================================
--- python/branches/py3k/Python/pythonrun.c	(original)
+++ python/branches/py3k/Python/pythonrun.c	Wed May  7 01:45:46 2008
@@ -83,6 +83,7 @@
 int Py_UseClassExceptionsFlag = 1; /* Needed by bltinmodule.c: deprecated */
 int Py_FrozenFlag; /* Needed by getpath.c */
 int Py_IgnoreEnvironmentFlag; /* e.g. PYTHONPATH, PYTHONHOME */
+int Py_NoUserSiteDirectory = 0; /* for -s and site.py */
 
 /* PyModule_GetWarningsModule is no longer necessary as of 2.6
 since _warnings is builtin.  This API should not be used. */

Modified: python/branches/py3k/Python/sysmodule.c
==============================================================================
--- python/branches/py3k/Python/sysmodule.c	(original)
+++ python/branches/py3k/Python/sysmodule.c	Wed May  7 01:45:46 2008
@@ -1097,7 +1097,7 @@
 	{"interactive",		"-i"},
 	{"optimize",		"-O or -OO"},
 	{"dont_write_bytecode",	"-B"},
-	/* {"no_user_site",	"-s"}, */
+	{"no_user_site",	"-s"},
 	{"no_site",		"-S"},
 	{"ignore_environment",	"-E"},
 	{"tabcheck",		"-t or -tt"},
@@ -1116,9 +1116,9 @@
 	flags__doc__,	/* doc */
 	flags_fields,	/* fields */
 #ifdef RISCOS
-	11
+	12
 #else
-	10
+	11
 #endif
 };
 
@@ -1141,7 +1141,7 @@
 	SetFlag(Py_InteractiveFlag);
 	SetFlag(Py_OptimizeFlag);
 	SetFlag(Py_DontWriteBytecodeFlag);
-	/* SetFlag(Py_NoUserSiteDirectory); */
+	SetFlag(Py_NoUserSiteDirectory);
 	SetFlag(Py_NoSiteFlag);
 	SetFlag(Py_IgnoreEnvironmentFlag);
 	SetFlag(Py_TabcheckFlag);


More information about the Python-3000-checkins mailing list