Commits

Philip Jenvey committed 60f1685

use wide environ APIs on windows

Comments (0)

Files changed (2)

pypy/module/posix/interp_posix.py

 
 _WIN32 = sys.platform == 'win32'
 if _WIN32:
-    from rpython.rlib.rwin32 import _MAX_ENV
+    from rpython.rlib import rwin32
 
 c_int = "c_int"
 
         self.w_environ = space.newdict()
         self.random_context = rurandom.init_urandom()
     def startup(self, space):
+        space.call_method(self.w_environ, 'clear')
         _convertenviron(space, self.w_environ)
     def _freeze_(self):
         # don't capture the environment in the translated pypy
 def get(space):
     return space.fromcache(State)
 
-def _convertenviron(space, w_env):
-    space.call_method(w_env, 'clear')
-    for key, value in os.environ.items():
-        space.setitem(w_env, space.wrapbytes(key), space.wrapbytes(value))
+if _WIN32:
+    def _convertenviron(space, w_env):
+        # _wenviron must be initialized in this way if the program is
+        # started through main() instead of wmain()
+        rwin32._wgetenv(u"")
+        for key, value in rwin32._wenviron_items():
+            space.setitem(w_env, space.wrap(key), space.wrap(value))
 
-def putenv(space, w_name, w_value):
-    """Change or add an environment variable."""
-    if _WIN32 and len(name) > _MAX_ENV:
-        raise OperationError(space.w_ValueError, space.wrap(
-                "the environment variable is longer than %d bytes" % _MAX_ENV))
-    try:
-        dispatch_filename_2(rposix.putenv)(space, w_name, w_value)
-    except OSError, e:
-        raise wrap_oserror(space, e)
+    @unwrap_spec(name=unicode, value=unicode)
+    def putenv(space, name, value):
+        """Change or add an environment variable."""
+        # len includes space for '=' and a trailing NUL
+        if len(name) + len(value) + 2 > rwin32._MAX_ENV:
+            msg = ("the environment variable is longer than %d characters" %
+                   rwin32._MAX_ENV)
+            raise OperationError(space.w_ValueError, space.wrap(msg))
+        try:
+            rwin32._wputenv(name, value)
+        except OSError, e:
+            raise wrap_oserror(space, e)
+else:
+    def _convertenviron(space, w_env):
+        for key, value in os.environ.items():
+            space.setitem(w_env, space.wrapbytes(key), space.wrapbytes(value))
 
-def unsetenv(space, w_name):
-    """Delete an environment variable."""
-    try:
-        dispatch_filename(rposix.unsetenv)(space, w_name)
-    except KeyError:
-        pass
-    except OSError, e:
-        raise wrap_oserror(space, e)
+    def putenv(space, w_name, w_value):
+        """Change or add an environment variable."""
+        try:
+            dispatch_filename_2(rposix.putenv)(space, w_name, w_value)
+        except OSError, e:
+            raise wrap_oserror(space, e)
+
+    def unsetenv(space, w_name):
+        """Delete an environment variable."""
+        try:
+            dispatch_filename(rposix.unsetenv)(space, w_name)
+        except KeyError:
+            pass
+        except OSError, e:
+            raise wrap_oserror(space, e)
 
 
 @unwrap_spec(w_dirname=WrappedDefault(u"."))

pypy/module/posix/test/test_posix2.py

         cls.w_path = space.wrap(str(path))
 
     def test_environ(self):
-        posix = self.posix
+        import sys
+        environ = self.posix.environ
+        item_type = str if sys.platform.startswith('win') else bytes
+        for k, v in environ.items():
+            assert type(k) is item_type
+            assert type(v) is item_type
+        name = next(iter(environ))
+        assert environ[name] is not None
+        del environ[name]
+        raises(KeyError, lambda: environ[name])
+
+    @py.test.mark.dont_track_allocations('putenv intentionally keeps strings alive')
+    def test_environ_nonascii(self):
         os = self.os
-        assert posix.environ[b'PATH']
-        del posix.environ[b'PATH']
-        def fn(): posix.environ[b'PATH']
-        raises(KeyError, fn)
+        name, value = 'PYPY_TEST_日本', 'foobar日本'
+        os.environ[name] = value
+        assert os.environ[name] == value
+        assert os.getenv(name) == value
+        del os.environ[name]
+        assert os.environ.get(name) is None
+        assert os.getenv(name) is None
 
     if hasattr(__import__(os.name), "unsetenv"):
         def test_unsetenv_nonexisting(self):
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.