Skip to content

Commit

Permalink
Add environ and environb
Browse files Browse the repository at this point in the history
  • Loading branch information
abadger committed Nov 14, 2018
1 parent e114efc commit 277c50d
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 1 deletion.
4 changes: 4 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ Development version
- Pull request #204: Add `six.ensure_binary`, `six.ensure_text`, and
`six.ensure_str`.

- Add `six.supports_bytes_environ`, `six.environ`, and `six.environb` (when
`six.supports_bytes_environ` is True) which operate similar to the
Python-3.2+ `os.supports_bytes_environ`, `os.environ`, and `os.environb`.

1.11.0
------

Expand Down
84 changes: 83 additions & 1 deletion six.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import functools
import itertools
import operator
import os
import sys
import types

Expand Down Expand Up @@ -621,6 +622,88 @@ def iterlists(d, **kw):
"Return an iterator over the (key, [values]) pairs of a dictionary.")


if PY3:
environ = os.environ
if sys.version_info >= (3, 2):
# We can simply reuse what Python 3.2+ provides
supports_bytes_environ = os.supports_bytes_environ
if supports_bytes_environ:
environb = os.environb
else:
# There is no os.environb on Python 3.0 and 3.1
supports_bytes_environ = False
else:
# Python 2's environ is bytes-oriented
supports_bytes_environ = True
environb = os.environ
if sys.version_info >= (2, 6):
# Python 2.6 and Python 2.7 have MutableMapping
from collections import MutableMapping as DictBaseClass
else:
# Python 2.5 and below do not have MutableMapping
from UserDict import DictMixin as DictBaseClass

class _TextEnviron(DictBaseClass):
"""
Utility class to return text strings from the environment instead of byte strings
Mimics the behaviour of os.environ on Python3
"""
# Mimic Python3's os.environ by using sys.getfilesystemencoding()
def __init__(self, env=None, encoding=sys.getfilesystemencoding()):
if env is None:
env = os.environ
self._raw_environ = env
self._value_cache = {}
self.encoding = encoding

def __delitem__(self, key):
del self._raw_environ[key]

def __getitem__(self, key):
# Note: For undecodable strings, Python3 will use surrogateescape. We don't have that
# on Python2 so we throw a ValueError instead
value = self._raw_environ[key]

# Cache keys off of the undecoded values to handle any environment variables which
# change during a run
if value not in self._value_cache:
try:
self._value_cache[value] = ensure_text(value, encoding=self.encoding)
except UnicodeError:
raise ValueError('environ string for %s is undecodable in the'
' filesystemencoding. Use six.environb and manually convert'
' the value to text instead' % value)
return self._value_cache[value]

def __setitem__(self, key, value):
if not isinstance(value, text_type):
raise TypeError("str expected, not %s" % type(value).__name__)

try:
self._raw_environ[key] = ensure_binary(value, encoding=self.encoding)
except UnicodeError:
raise ValueError('The value, %s, is unencodable in the filesystemencoding.'
' Use six.environb and manually convert the value to bytes'
' instead' % value)

def __iter__(self):
return self._raw_environ.__iter__()

def __len__(self):
return len(self._raw_environ)

# Needed for the DictMixin-based subclass but not for MutableMapping-based subclass
if sys.version_info < (2, 6):
def keys(self):
return self._raw_environ.keys()

def copy(self):
return self._raw_environ.copy()

environ = _TextEnviron()


if PY3:
def b(s):
return s.encode("latin-1")
Expand Down Expand Up @@ -908,7 +991,6 @@ def ensure_text(s, encoding='utf-8', errors='strict'):
raise TypeError("not expecting type '%s'" % type(s))



def python_2_unicode_compatible(klass):
"""
A decorator that defines __unicode__ and __str__ methods under Python 2.
Expand Down

0 comments on commit 277c50d

Please sign in to comment.