Rev 6358: (gz) Add get_environ_unicode for accessing variables without mbcs mangling in file:///srv/pqm.bazaar-vcs.org/archives/thelove/bzr/%2Btrunk/
Patch Queue Manager
pqm at pqm.ubuntu.com
Mon Dec 12 13:31:09 UTC 2011
At file:///srv/pqm.bazaar-vcs.org/archives/thelove/bzr/%2Btrunk/
------------------------------------------------------------
revno: 6358 [merge]
revision-id: pqm at pqm.ubuntu.com-20111212133108-m0wtlolqdsh1u9bj
parent: pqm at pqm.ubuntu.com-20111212130524-l9s3fwxxy1pujx7t
parent: martin.packman at canonical.com-20111212121522-iact2d3w4l2ga5tk
committer: Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Mon 2011-12-12 13:31:08 +0000
message:
(gz) Add get_environ_unicode for accessing variables without mbcs mangling
on windows (Martin Packman)
modified:
bzrlib/tests/test_win32utils.py test_win32utils.py-20070713181630-8xsrjymd3e8mgw23-108
bzrlib/win32utils.py win32console.py-20051021033308-123c6c929d04973d
=== modified file 'bzrlib/tests/test_win32utils.py'
--- a/bzrlib/tests/test_win32utils.py 2011-06-14 01:26:41 +0000
+++ b/bzrlib/tests/test_win32utils.py 2011-12-05 12:50:21 +0000
@@ -328,3 +328,56 @@
self.assertCommandLine([u"rm", u"x*"], "-m pdb rm x*", ["rm", u"x*"])
self.assertCommandLine([u"add", u"d/f1", u"d/f2"], "-m pdb add d/*",
["add", u"d/*"])
+
+
+class TestGetEnvironUnicode(tests.TestCase):
+ """Tests for accessing the environment via the windows wide api"""
+
+ _test_needs_features = [CtypesFeature, features.win32_feature]
+
+ def setUp(self):
+ super(TestGetEnvironUnicode, self).setUp()
+ self.overrideEnv("TEST", "1")
+
+ def test_get(self):
+ """In the normal case behaves the same as os.environ access"""
+ self.assertEqual("1", win32utils.get_environ_unicode("TEST"))
+
+ def test_unset(self):
+ """A variable not present in the environment gives None by default"""
+ del os.environ["TEST"]
+ self.assertIs(None, win32utils.get_environ_unicode("TEST"))
+
+ def test_unset_default(self):
+ """A variable not present in the environment gives passed default"""
+ del os.environ["TEST"]
+ self.assertIs("a", win32utils.get_environ_unicode("TEST", "a"))
+
+ def test_unicode(self):
+ """A non-ascii variable is returned as unicode"""
+ unicode_val = u"\xa7" # non-ascii character present in many encodings
+ try:
+ bytes_val = unicode_val.encode(osutils.get_user_encoding())
+ except UnicodeEncodeError:
+ self.skip("Couldn't encode non-ascii string to place in environ")
+ os.environ["TEST"] = bytes_val
+ self.assertEqual(unicode_val, win32utils.get_environ_unicode("TEST"))
+
+ def test_long(self):
+ """A variable bigger than heuristic buffer size is still accessible"""
+ big_val = "x" * (2<<10)
+ os.environ["TEST"] = big_val
+ self.assertEqual(big_val, win32utils.get_environ_unicode("TEST"))
+
+ def test_unexpected_error(self):
+ """An error from the underlying platform function is propogated"""
+ ERROR_INVALID_PARAMETER = 87
+ SetLastError = win32utils.ctypes.windll.kernel32.SetLastError
+ def failer(*args, **kwargs):
+ SetLastError(ERROR_INVALID_PARAMETER)
+ return 0
+ self.overrideAttr(win32utils.get_environ_unicode, "_c_function",
+ failer)
+ e = self.assertRaises(WindowsError,
+ win32utils.get_environ_unicode, "TEST")
+ self.assertEqual(e.winerror, ERROR_INVALID_PARAMETER)
=== modified file 'bzrlib/win32utils.py'
--- a/bzrlib/win32utils.py 2011-12-05 11:06:16 +0000
+++ b/bzrlib/win32utils.py 2011-12-12 13:31:08 +0000
@@ -569,7 +569,7 @@
return args
-if has_ctypes and winver != 'Windows 98':
+if has_ctypes and winver == 'Windows NT':
def get_unicode_argv():
prototype = ctypes.WINFUNCTYPE(ctypes.c_wchar_p)
GetCommandLineW = prototype(("GetCommandLineW",
@@ -580,8 +580,36 @@
# Skip the first argument, since we only care about parameters
argv = _command_line_to_argv(command_line, sys.argv)[1:]
return argv
+
+
+ def get_environ_unicode(key, default=None):
+ """Get `key` from environment as unicode or `default` if unset
+
+ A large enough buffer will be allocated to retrieve the value, though
+ it may take two calls to the underlying library function.
+
+ This needs ctypes because pywin32 does not expose the wide version.
+ """
+ cfunc = getattr(get_environ_unicode, "_c_function", None)
+ if cfunc is None:
+ from ctypes.wintypes import DWORD, LPCWSTR, LPWSTR
+ cfunc = ctypes.WINFUNCTYPE(DWORD, LPCWSTR, LPWSTR, DWORD)(
+ ("GetEnvironmentVariableW", ctypes.windll.kernel32))
+ get_environ_unicode._c_function = cfunc
+ buffer_size = 256 # heuristic, 256 characters often enough
+ while True:
+ buffer = ctypes.create_unicode_buffer(buffer_size)
+ length = cfunc(key, buffer, buffer_size)
+ if not length:
+ code = ctypes.GetLastError()
+ if code == 203: # ERROR_ENVVAR_NOT_FOUND
+ return default
+ raise ctypes.WinError(code)
+ if buffer_size > length:
+ return buffer[:length]
+ buffer_size = length
else:
- get_unicode_argv = None
+ get_unicode_argv = get_environ_unicode = None
if has_win32api:
More information about the bazaar-commits
mailing list