[pypy-commit] pypy app_main-refactor: copy the logic to find the stdlib from app_main into sys.initpath, and make it rpython. Also, add tests for it, which is always good :-)

antocuni noreply at buildbot.pypy.org
Fri Jun 8 17:33:14 CEST 2012


Author: Antonio Cuni <anto.cuni at gmail.com>
Branch: app_main-refactor
Changeset: r55509:203459fe802c
Date: 2012-06-08 16:11 +0200
http://bitbucket.org/pypy/pypy/changeset/203459fe802c/

Log:	copy the logic to find the stdlib from app_main into sys.initpath,
	and make it rpython. Also, add tests for it, which is always good
	:-)

diff --git a/pypy/module/sys/__init__.py b/pypy/module/sys/__init__.py
--- a/pypy/module/sys/__init__.py
+++ b/pypy/module/sys/__init__.py
@@ -44,7 +44,7 @@
         'warnoptions'           : 'state.get(space).w_warnoptions', 
         'builtin_module_names'  : 'space.w_None',
         'pypy_getudir'          : 'state.pypy_getudir',    # not translated
-        'pypy_initial_path'     : 'initpath.pypy_initial_path',
+        'pypy_find_stdlib'      : 'initpath.pypy_find_stdlib',
         'pypy_find_executable'  : 'initpath.pypy_find_executable',
 
         '_getframe'             : 'vm._getframe', 
diff --git a/pypy/module/sys/initpath.py b/pypy/module/sys/initpath.py
--- a/pypy/module/sys/initpath.py
+++ b/pypy/module/sys/initpath.py
@@ -9,11 +9,16 @@
 from pypy.rlib import rpath
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.interpreter.gateway import unwrap_spec
+from pypy.module.sys.state import get_state
 
 platform = sys.platform
 IS_WINDOWS = sys.platform == 'win32'
 
 def find_executable(executable):
+    """
+    Return the absolute path of the executable, by looking into PATH and the
+    current directory.  If it cannot be found, return ''.
+    """
     if we_are_translated() and IS_WINDOWS and not executable.lower().endswith('.exe'):
         executable += '.exe'
     if os.sep in executable or (IS_WINDOWS and ':' in executable):
@@ -35,15 +40,57 @@
     return executable
 
 
+def readlink_maybe(filename):
+    if hasattr(os, 'readlink'):
+        return os.readlink(filename)
+    raise NotImplementedError
+
+def resolvedirof(filename):
+    try:
+        filename = rpath.rabspath(filename)
+    except OSError:
+        pass
+    dirname = rpath.rabspath(os.path.join(filename, '..'))
+    if os.path.islink(filename):
+        try:
+            link = readlink_maybe(filename)
+        except OSError:
+            pass
+        else:
+            return resolvedirof(os.path.join(dirname, link))
+    return dirname
+
+def find_stdlib(state, executable):
+    """
+    Find and compute the stdlib path, starting from the directory where
+    ``executable`` is and going one level up until we find it.  Return a tuple
+    (path, prefix), where ``prefix`` is the root directory which contains the
+    stdlib.
+    If it cannot be found, return (None, None).
+    """
+    search = executable
+    while True:
+        dirname = resolvedirof(search)
+        if dirname == search:
+            return None, None # not found :-(
+        newpath = compute_stdlib_path_maybe(state, dirname)
+        if newpath is not None:
+            return newpath, dirname
+        search = dirname    # walk to the parent directory
+
+
 
 def checkdir(path):
     st = os.stat(path)
     if not stat.S_ISDIR(st[0]):
         raise OSError(errno.ENOTDIR, path)
 
-
-
 def compute_stdlib_path(state, prefix):
+    """
+    Compute the paths for the stdlib rooted at ``prefix``. ``prefix`` must at
+    least contain a directory called ``lib-python/X.Y`` and another one called
+    ``lib_pypy``. If they cannot be found, it raises OSError.
+    """
     from pypy.module.sys.version import CPYTHON_VERSION
     dirname = '%d.%d' % (CPYTHON_VERSION[0],
                          CPYTHON_VERSION[1])
@@ -77,23 +124,28 @@
     #
     return importlist
 
+def compute_stdlib_path_maybe(state, prefix):
+    """
+    Return the stdlib path rooted at ``prefix``, or None if it cannot be
+    found.
+    """
+    try:
+        return compute_stdlib_path(state, prefix)
+    except OSError:
+        return None
 
 @unwrap_spec(executable='str0')
 def pypy_find_executable(space, executable):
     return space.wrap(find_executable(executable))
 
-
 @unwrap_spec(srcdir='str0')
-def pypy_initial_path(space, srcdir):
-    try:
-        path = compute_stdlib_path(get(space), srcdir)
-    except OSError:
+def pypy_find_stdlib(space, executable):
+    path, prefix = find_stdlib(get_state(space), executable)
+    if path is None:
         return space.w_None
     else:
         space.setitem(space.sys.w_dict, space.wrap('prefix'),
-                                        space.wrap(srcdir))
+                                        space.wrap(prefix))
         space.setitem(space.sys.w_dict, space.wrap('exec_prefix'),
-                                        space.wrap(srcdir))
+                                        space.wrap(prefix))
         return space.newlist([space.wrap(p) for p in path])
-
-
diff --git a/pypy/module/sys/state.py b/pypy/module/sys/state.py
--- a/pypy/module/sys/state.py
+++ b/pypy/module/sys/state.py
@@ -3,7 +3,6 @@
 """
 import os
 import pypy
-from pypy.module.sys.initpath import compute_stdlib_path
 
 # ____________________________________________________________
 #
@@ -18,7 +17,8 @@
         self.w_argv = space.newlist([])
         self.setinitialpath(space) 
 
-    def setinitialpath(self, space): 
+    def setinitialpath(self, space):
+        from pypy.module.sys.initpath import compute_stdlib_path
         # Initialize the default path
         pypydir = os.path.dirname(os.path.abspath(pypy.__file__))
         srcdir = os.path.dirname(pypydir)
@@ -26,7 +26,7 @@
         self.w_path = space.newlist([space.wrap(p) for p in path])
 
 
-def get(space):
+def get_state(space):
     return space.fromcache(State)
 
 class IOState:
diff --git a/pypy/module/sys/test/test_initpath.py b/pypy/module/sys/test/test_initpath.py
--- a/pypy/module/sys/test/test_initpath.py
+++ b/pypy/module/sys/test/test_initpath.py
@@ -1,6 +1,6 @@
 import py
 import os.path
-from pypy.module.sys.initpath import compute_stdlib_path, find_executable
+from pypy.module.sys.initpath import compute_stdlib_path, find_executable, find_stdlib
 from pypy.module.sys.version import PYPY_VERSION, CPYTHON_VERSION
 
 def build_hierarchy(prefix):
@@ -9,8 +9,25 @@
     b = prefix.join('lib-python', dirname).ensure(dir=1)
     return a, b
 
+def test_find_stdlib(tmpdir):
+    bin_dir = tmpdir.join('bin').ensure(dir=True)
+    pypy = bin_dir.join('pypy').ensure(file=True)
+    build_hierarchy(tmpdir)
+    path, prefix = find_stdlib(None, str(pypy))
+    assert prefix == tmpdir
 
-def test_stdlib_in_prefix(tmpdir):
+ at py.test.mark.skipif('not hasattr(os, "symlink")')
+def test_find_stdlib_follow_symlink(tmpdir):
+    pypydir = tmpdir.join('opt', 'pypy-xxx')
+    pypy = pypydir.join('bin', 'pypy').ensure(file=True)
+    build_hierarchy(pypydir)
+    pypy_sym = tmpdir.join('pypy_sym')
+    os.symlink(str(pypy), str(pypy_sym))
+    path, prefix = find_stdlib(None, str(pypy_sym))
+    assert prefix == pypydir
+
+
+def test_compute_stdlib_path(tmpdir):
     dirs = build_hierarchy(tmpdir)
     path = compute_stdlib_path(None, str(tmpdir))
     # we get at least 'dirs', and maybe more (e.g. plat-linux2)
diff --git a/pypy/rlib/rpath.py b/pypy/rlib/rpath.py
--- a/pypy/rlib/rpath.py
+++ b/pypy/rlib/rpath.py
@@ -18,4 +18,3 @@
             return path
 else:
     raise ImportError('Unsupported os: %s' % os.name)
-


More information about the pypy-commit mailing list