[Python-checkins] r59957 - in sandbox/trunk/pep370: Include/pydebug.h Lib/distutils/command/install.py Lib/site.py Lib/test/test_site.py Modules/main.c Python/pythonrun.c Python/sysmodule.c

christian.heimes python-checkins at python.org
Mon Jan 14 22:11:23 CET 2008


Author: christian.heimes
Date: Mon Jan 14 22:11:23 2008
New Revision: 59957

Modified:
   sandbox/trunk/pep370/Include/pydebug.h
   sandbox/trunk/pep370/Lib/distutils/command/install.py
   sandbox/trunk/pep370/Lib/site.py
   sandbox/trunk/pep370/Lib/test/test_site.py
   sandbox/trunk/pep370/Modules/main.c
   sandbox/trunk/pep370/Python/pythonrun.c
   sandbox/trunk/pep370/Python/sysmodule.c
Log:
Applied latest patch for PEP 370.
By the way I wasn't able to run Python until I've changed the subversion code in Python/sysmodule.c. The code doesn't like sandbox urls.

Modified: sandbox/trunk/pep370/Include/pydebug.h
==============================================================================
--- sandbox/trunk/pep370/Include/pydebug.h	(original)
+++ sandbox/trunk/pep370/Include/pydebug.h	Mon Jan 14 22:11:23 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;
 /* _XXX Py_QnewFlag should go away in 3.0.  It's true iff -Qnew is passed,
   on the command line, and is used in 2.2 by ceval.c to make all "/" divisions
   true divisions (which they will be in 3.0). */

Modified: sandbox/trunk/pep370/Lib/distutils/command/install.py
==============================================================================
--- sandbox/trunk/pep370/Lib/distutils/command/install.py	(original)
+++ sandbox/trunk/pep370/Lib/distutils/command/install.py	Mon Jan 14 22:11:23 2008
@@ -18,6 +18,8 @@
 from distutils.util import convert_path, subst_vars, change_root
 from distutils.errors import DistutilsOptionError
 from glob import glob
+from site import USER_BASE
+from site import USER_SITE
 
 if sys.version < "2.2":
     WINDOWS_SCHEME = {
@@ -51,7 +53,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',
@@ -59,13 +75,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
@@ -86,6 +116,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,
@@ -137,7 +169,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'}
 
 
@@ -148,6 +180,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
@@ -166,6 +199,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
@@ -241,6 +276,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:
@@ -276,10 +316,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()
 
@@ -301,6 +344,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
@@ -315,7 +362,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
@@ -376,7 +424,10 @@
                       "installation scheme is incomplete")
             return
 
-        if self.home is not None:
+        if self.user:
+            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:
@@ -401,7 +452,10 @@
 
     def finalize_other (self):          # Windows and Mac OS for now
 
-        if self.home is not None:
+        if self.user:
+            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:
@@ -431,7 +485,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)
@@ -496,6 +550,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', 0700)" % path)
+                os.makedirs(path, 0700)
 
     # -- Command execution methods -------------------------------------
 

Modified: sandbox/trunk/pep370/Lib/site.py
==============================================================================
--- sandbox/trunk/pep370/Lib/site.py	(original)
+++ sandbox/trunk/pep370/Lib/site.py	Mon Jan 14 22:11:23 2008
@@ -62,11 +62,21 @@
 import os
 import __builtin__
 
+# 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 sys.modules.values():
@@ -77,6 +87,7 @@
         except AttributeError:
             continue
 
+
 def removeduppaths():
     """ Remove duplicate entries from sys.path along with making them
     absolute"""
@@ -105,6 +116,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()
@@ -117,6 +129,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
@@ -132,11 +145,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()
@@ -144,12 +157,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'"""
@@ -165,48 +177,112 @@
         names = os.listdir(sitedir)
     except os.error:
         return
-    names.sort()
-    for name in names:
-        if name.endswith(os.extsep + "pth"):
-            addpackage(sitedir, name, known_paths)
+    dotpth = os.extsep + "pth"
+    names = [name for name in names if name.endswith(dotpth)]
+    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 equal to effective uid.
+
+    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
+
+    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. _global_userdirs contains (basedir, user site-packages)
+    although the directories may not exist.
+
+    basedir is the root directory for all Python versions, userdir is the
+    user specific site-packages directory. userdir/.. can be used for
+    configuration data.
+    """
+    global USER_BASE, USER_SITE
+    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 sys.platform == "darwin":
+        USER_BASE = joinuser("~", "Library", "Python")
+        USER_SITE = os.path.join(USER_BASE, sys.version[:3],
+                                 "site-packages")
+    elif os.name == "nt":
+        base = os.environ.get("APPDATA") or "~"
+        USER_BASE = joinuser(base, "Python")
+        USER_SITE = os.path.join(USER_BASE,
+                                 "Python" + sys.version[0] + sys.version[2],
+                                 "site-packages")
+    else:
+        USER_BASE = joinuser("~", ".local")
+        USER_SITE =  os.path.join(USER_BASE, "lib",
+                                  "python" + sys.version[:3],
+                                  "site-packages")
+
+    if 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 in ('os2emx', 'riscos'):
-                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():
@@ -393,13 +469,27 @@
         pass
 
 
+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()
+    if ENABLE_USER_SITE:
+        known_paths = addusersitepackages(known_paths)
+    known_paths = addsitepackages(known_paths)
     if sys.platform == 'os2emx':
         setBEGINLIBPATH()
     setquit()
@@ -408,6 +498,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.

Modified: sandbox/trunk/pep370/Lib/test/test_site.py
==============================================================================
--- sandbox/trunk/pep370/Lib/test/test_site.py	(original)
+++ sandbox/trunk/pep370/Lib/test/test_site.py	Mon Jan 14 22:11:23 2008
@@ -11,6 +11,7 @@
 import sys
 import encodings
 import tempfile
+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.
@@ -31,7 +32,7 @@
         """Save a copy of sys.path"""
         self.sys_path = sys.path[:]
 
-    def tearDown(self):
+
         """Restore sys.path"""
         sys.path = self.sys_path
 
@@ -91,6 +92,16 @@
         finally:
             pth_file.cleanup()
 
+    def test_s_option(self):
+        usersite = site.USER_SITE
+        self.assert_(usersite in sys.path)
+        cmd = [sys.executable, "-c",
+               "\"import sys; sys.exit('%s' in sys.path)\"" % usersite
+              ]
+        p = subprocess.Popen(cmd)
+        self.assertEqual(p.wait(), 0)
+
+
 class PthFile(object):
     """Helper class for handling testing of .pth files"""
 

Modified: sandbox/trunk/pep370/Modules/main.c
==============================================================================
--- sandbox/trunk/pep370/Modules/main.c	(original)
+++ sandbox/trunk/pep370/Modules/main.c	Mon Jan 14 22:11:23 2008
@@ -40,7 +40,7 @@
 static int  orig_argc;
 
 /* command line options */
-#define BASE_OPTS "3Bc:dEhim:OQ:StuUvVW:xX?"
+#define BASE_OPTS "3Bc:dEhim:OQ:sStuUvVW:xX?"
 
 #ifndef RISCOS
 #define PROGRAM_OPTS BASE_OPTS
@@ -72,6 +72,7 @@
 -O     : optimize generated bytecode slightly; also PYTHONOPTIMIZE=x\n\
 -OO    : remove doc-strings in addition to the -O optimizations\n\
 -Q arg : division options: -Qold (default), -Qwarn, -Qwarnall, -Qnew\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\
 ";
@@ -345,6 +346,10 @@
 			Py_DontWriteBytecodeFlag++;
 			break;
 
+		case 's':
+			Py_NoUserSiteDirectory++;
+			break;
+
 		case 'S':
 			Py_NoSiteFlag++;
 			break;
@@ -415,6 +420,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 &&
 	    strcmp(argv[_PyOS_optind], "-") != 0)
 	{

Modified: sandbox/trunk/pep370/Python/pythonrun.c
==============================================================================
--- sandbox/trunk/pep370/Python/pythonrun.c	(original)
+++ sandbox/trunk/pep370/Python/pythonrun.c	Mon Jan 14 22:11:23 2008
@@ -81,6 +81,7 @@
   on the command line, and is used in 2.2 by ceval.c to make all "/" divisions
   true divisions (which they will be in 2.3). */
 int _Py_QnewFlag = 0;
+int Py_NoUserSiteDirectory = 0; /* for -s and site.py */
 
 /* Reference to 'warnings' module, to avoid importing it
    on the fly when the import lock may be held.  See 683658/771097

Modified: sandbox/trunk/pep370/Python/sysmodule.c
==============================================================================
--- sandbox/trunk/pep370/Python/sysmodule.c	(original)
+++ sandbox/trunk/pep370/Python/sysmodule.c	Mon Jan 14 22:11:23 2008
@@ -979,6 +979,12 @@
 		return;
 
 	python = strstr(headurl, "/python/");
+	if (python) {
+		br_start = python + 8;
+	}
+	else if ((python = strstr(headurl, "/sandbox/")) != NULL) {
+		br_start = python + 9;
+	}
 	if (!python)
 		Py_FatalError("subversion keywords missing");
 
@@ -1006,8 +1012,10 @@
 		shortbranch[len] = '\0';
 	}
 	else {
-		Py_FatalError("bad HeadURL");
-		return;
+		/* Py_FatalError("bad HeadURL"); 
+		return; */
+		*branch = '\0';
+		*shortbranch = '\0';
 	}
 
 
@@ -1063,7 +1071,7 @@
 	{"interactive",		"-i"},
 	{"optimize",		"-O or -OO"},
 	{"dont_write_bytecode",	"-B"},
-	/* {"no_user_site",	"-s"}, */
+	{"no_user_site",	"-s"},
 	{"no_site",		"-S"},
 	{"ingnore_environment",	"-E"},
 	{"tabcheck",		"-t or -tt"},
@@ -1082,9 +1090,9 @@
 	flags__doc__,	/* doc */
 	flags_fields,	/* fields */
 #ifdef RISCOS
-	14
+	15
 #else
-	13
+	14
 #endif
 };
 
@@ -1109,7 +1117,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-checkins mailing list