D10998: windows: replicate the normalizing behavior of os.environ

Alphare (Raphaël Gomès) phabricator at mercurial-scm.org
Wed Jul 7 13:14:29 UTC 2021


Alphare created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  On Windows, `os.environ` normalizes environment variables to uppercase. Our
  current bytes-based environ substitution object is a simple dict, so we add
  the normalization behavior.
  
  This changed needed `upper` to be defined higher, I moved `upper` and `lower`
  together.
  
  This fixes test-http-peer.t on Windows.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D10998

AFFECTED FILES
  mercurial/encoding.py

CHANGE DETAILS

diff --git a/mercurial/encoding.py b/mercurial/encoding.py
--- a/mercurial/encoding.py
+++ b/mercurial/encoding.py
@@ -284,13 +284,73 @@
 
     strmethod = pycompat.identity
 
+
+def lower(s):
+    # type: (bytes) -> bytes
+    """best-effort encoding-aware case-folding of local string s"""
+    try:
+        return asciilower(s)
+    except UnicodeDecodeError:
+        pass
+    try:
+        if isinstance(s, localstr):
+            u = s._utf8.decode("utf-8")
+        else:
+            u = s.decode(_sysstr(encoding), _sysstr(encodingmode))
+
+        lu = u.lower()
+        if u == lu:
+            return s  # preserve localstring
+        return lu.encode(_sysstr(encoding))
+    except UnicodeError:
+        return s.lower()  # we don't know how to fold this except in ASCII
+    except LookupError as k:
+        raise error.Abort(k, hint=b"please check your locale settings")
+
+
+def upper(s):
+    # type: (bytes) -> bytes
+    """best-effort encoding-aware case-folding of local string s"""
+    try:
+        return asciiupper(s)
+    except UnicodeDecodeError:
+        return upperfallback(s)
+
+
+def upperfallback(s):
+    # type: (Any) -> Any
+    try:
+        if isinstance(s, localstr):
+            u = s._utf8.decode("utf-8")
+        else:
+            u = s.decode(_sysstr(encoding), _sysstr(encodingmode))
+
+        uu = u.upper()
+        if u == uu:
+            return s  # preserve localstring
+        return uu.encode(_sysstr(encoding))
+    except UnicodeError:
+        return s.upper()  # we don't know how to fold this except in ASCII
+    except LookupError as k:
+        raise error.Abort(k, hint=b"please check your locale settings")
+
+
 if not _nativeenviron:
     # now encoding and helper functions are available, recreate the environ
     # dict to be exported to other modules
-    environ = {
-        tolocal(k.encode('utf-8')): tolocal(v.encode('utf-8'))
-        for k, v in os.environ.items()  # re-exports
-    }
+    if pycompat.iswindows and pycompat.ispy3:
+
+        class WindowsEnviron(dict):
+            """`os.environ` normalizes environment variables to uppercase on windows"""
+
+            def get(self, key, default=None):
+                return super().get(upper(key), default)
+
+        environ = WindowsEnviron()
+
+    for k, v in os.environ.items():  # re-exports
+        environ[tolocal(k.encode('utf-8'))] = tolocal(v.encode('utf-8'))
+
 
 if pycompat.ispy3:
     # os.getcwd() on Python 3 returns string, but it has os.getcwdb() which
@@ -441,56 +501,6 @@
     return ellipsis  # no enough room for multi-column characters
 
 
-def lower(s):
-    # type: (bytes) -> bytes
-    """best-effort encoding-aware case-folding of local string s"""
-    try:
-        return asciilower(s)
-    except UnicodeDecodeError:
-        pass
-    try:
-        if isinstance(s, localstr):
-            u = s._utf8.decode("utf-8")
-        else:
-            u = s.decode(_sysstr(encoding), _sysstr(encodingmode))
-
-        lu = u.lower()
-        if u == lu:
-            return s  # preserve localstring
-        return lu.encode(_sysstr(encoding))
-    except UnicodeError:
-        return s.lower()  # we don't know how to fold this except in ASCII
-    except LookupError as k:
-        raise error.Abort(k, hint=b"please check your locale settings")
-
-
-def upper(s):
-    # type: (bytes) -> bytes
-    """best-effort encoding-aware case-folding of local string s"""
-    try:
-        return asciiupper(s)
-    except UnicodeDecodeError:
-        return upperfallback(s)
-
-
-def upperfallback(s):
-    # type: (Any) -> Any
-    try:
-        if isinstance(s, localstr):
-            u = s._utf8.decode("utf-8")
-        else:
-            u = s.decode(_sysstr(encoding), _sysstr(encodingmode))
-
-        uu = u.upper()
-        if u == uu:
-            return s  # preserve localstring
-        return uu.encode(_sysstr(encoding))
-    except UnicodeError:
-        return s.upper()  # we don't know how to fold this except in ASCII
-    except LookupError as k:
-        raise error.Abort(k, hint=b"please check your locale settings")
-
-
 class normcasespecs(object):
     """what a platform's normcase does to ASCII strings
 



To: Alphare, #hg-reviewers
Cc: mercurial-patches, mercurial-devel


More information about the Mercurial-devel mailing list