[pypy-svn] r48968 - pypy/branch/windows48396/pypy/translator/goal

tismer at codespeak.net tismer at codespeak.net
Fri Nov 23 00:52:55 CET 2007

Author: tismer
Date: Fri Nov 23 00:52:55 2007
New Revision: 48968

partial solution to the os import problem.
The next version will avoid importing os, altogether.
I think of producing these functions using the gateway.

Modified: pypy/branch/windows48396/pypy/translator/goal/app_main.py
--- pypy/branch/windows48396/pypy/translator/goal/app_main.py	(original)
+++ pypy/branch/windows48396/pypy/translator/goal/app_main.py	Fri Nov 23 00:52:55 2007
@@ -146,8 +146,8 @@
 # faking os, until we really are able to import it from source
-Why fake_os ?
+Why reload_os ?
 When pypy is starting, the builtin modules are there, but os.path
 is a Python module. The current startup code depends on os.py,
@@ -156,36 +156,16 @@
 Os.py is a wrapper for system specific built-in modules and tries
 to unify the interface. One problem is os.environ which looks
 very differently per os.
-Due to the way os.py initializes its environ variable on Windows,
-it s hard to get a correct os.getenv that uses the actual environment
-variables. In order to fix that without modifying os.py, we need to
-re-import it several times, before and after compilation.
-When compiling the source, we first create a fake_os class instance.
-fake_os contains all of os, when compiling.reduction seems to be not
-appropriate, since lots of other modules are sucked in, at the same time.
-A complete reduction is possible, but would require much more work.
-In the course of creating fake_os, we import the real os. We keep a record
-of which modules were imported, before.
-During start of the entry_point, we call os.setup().
-This repeats an import of the specific parts in os.name.
-Depending of the underlying os, this might or might not
-cause a redefinition of certain os variables, but this happens
-exactly like in os.py's initialization.
-We then capture the variable environ, which may or may not come from the
-specific os.
-After that, we re-initialize our dict to what is expected in standard
-os. The effect of all this magic is that we have captured the environ
-cariable, again, and we now can redefine os.getenv to use this fresh
-variable, being accurate and not frozen.
-At this point, we finally can compute the location of our import.
-As a side effect, the involved modules are re-imported, although they had
-been compiled in, so PyPy behaves really conformant, making all .py
-modules changeable, again.
+Access to os.environ is not possible on Windows, due to caching
+problems. We solve that by passing the PATH envirnment setting
+in from a low-level interface.
+As an intermediate hack, the os.path functions are used until
+os.py can be imported. The module is then re-imported. This
+intermediate, since it will still leave os.environ unusable.
+(the last version solved that by hairy import tricks)
+The next version will avoid early import of os, alltogether.
 def we_are_translated():
@@ -195,51 +175,23 @@
     # which I did.
     return hasattr(sys, 'pypy_translation_info')
-class fake_os:
+class reload_os:
     def __init__(self):
-        import sys
         self.pre_import = sys.modules.keys()
-        import os
-        self.os = os
-        # make ourselves a clone of os
-        self.__dict__.update(self.os.__dict__)
-    def setup(self):
-        # we now repeat the os-specific initialization, which
-        # must be done before importing os, since os hides
-        # variables after initialization.
-        specifics = __import__(self.os.name)
-        self.__dict__.update(specifics.__dict__)
-        # depending on the os, we now might or might not have
-        # a new environ variable. However, we can now
-        # repeat the environ initialisation from os.py
-        environ = self.os._Environ(self.environ)
-        # to be safe, reset our dict to be like os
-        self.__dict__.update(self.os.__dict__)
-        # but now we insert the fresh environ
-        self.environ = environ
-        del self.getenv
-        # use our method, instead of the os's one's
-        assert self.getenv
-    def teardown(self):
+    def reload(self):
         # re-load modules instead of using the pre-compiled ones
         # note that this gives trouble if we are not translated,
         # since some exithandler in threading.py complains
-        # XXX check if this is a bug to be fixed for cpython
         if we_are_translated():
             for mod in sys.modules.keys():
                 if mod not in self.pre_import:
                     del sys.modules[mod]
         global os
         import os
-    def getenv(self, key, default=None):
-        """Get an environment variable, return None if it doesn't exist.
-        The optional second argument can specify an alternate default."""
-        return self.environ.get(key, default)
-os = fake_os()
+reload_os = reload_os()
+import os
 AUTOSUBPATH = 'share' + os.sep + 'pypy-%d.%d'
@@ -249,16 +201,16 @@
     IS_WINDOWS = False
-def entry_point(executable, argv):
+def entry_point(executable, argv, path):
     # find the full path to the executable, assuming that if there is no '/'
     # in the provided one then we must look along the $PATH
-    os.setup() # this is the faked one
     if we_are_translated() and IS_WINDOWS and not executable.lower().endswith('.exe'):
         executable += '.exe'
     if os.sep in executable or (IS_WINDOWS and DRIVE_LETTER_SEP in executable):
         pass    # the path is already more than just an executable name
-        path = os.getenv('PATH')
+        # path = os.getenv('PATH')
+        # we avoid getenv
         if path:
             for dir in path.split(os.pathsep):
                 fn = os.path.join(dir, executable)
@@ -286,7 +238,7 @@
         sys.path = newpath      # found!
-    os.teardown() # from now on this is the real one
+    reload_os.reload() # from now on use a fresh import
     go_interactive = False
     run_command = False
@@ -507,5 +459,5 @@
     from pypy.module.sys.version import PYPY_VERSION
     sys.pypy_version_info = PYPY_VERSION
     sys.pypy_initial_path = pypy_initial_path
-    sys.exit(entry_point(sys.argv[0], sys.argv[1:]))
+    sys.exit(entry_point(sys.argv[0], sys.argv[1:], os.getenv("PATH")))
     #sys.exit(entry_point('app_main.py', sys.argv[1:]))

Modified: pypy/branch/windows48396/pypy/translator/goal/targetpypystandalone.py
--- pypy/branch/windows48396/pypy/translator/goal/targetpypystandalone.py	(original)
+++ pypy/branch/windows48396/pypy/translator/goal/targetpypystandalone.py	Fri Nov 23 00:52:55 2007
@@ -43,7 +43,9 @@
                 space.call_function(w_run_toplevel, w_call_startup_gateway)
                 w_executable = space.wrap(argv[0])
                 w_argv = space.newlist([space.wrap(s) for s in argv[1:]])
-                w_exitcode = space.call_function(w_entry_point, w_executable, w_argv)
+                # we avoid using app-level environ due to the weird initialization of os
+                w_path = space.wrap(os.environ.get("PATH"))
+                w_exitcode = space.call_function(w_entry_point, w_executable, w_argv, w_path)
                 exitcode = space.int_w(w_exitcode)
                 # try to pull it all in
             ##    from pypy.interpreter import main, interactive, error

More information about the Pypy-commit mailing list