Commits

Jonathan Eunice committed 1d35b73

Using different implementation of chainstuf to avoid downstream error. Ready for 1.0.3

Comments (0)

Files changed (10)

 Change Log
 ==========
 
+1.0.3 (September 23, 2013)
+''''''''''''''''''''''''''
+
+  * Switched to local version of ``chainstuf`` until bug
+    with generator values in
+    ``stuf.chainstuf`` can be tracked down and corrected.
+    This was blocking a downstream feature-release of ``say``.
+
 1.0.2 (September 19, 2013)
 ''''''''''''''''''''''''''
 
 Change Log
 ==========
 
+1.0.3 (September 23, 2013)
+''''''''''''''''''''''''''
+
+  * Switched to local version of ``chainstuf`` until bug
+    with generator values in
+    ``stuf.chainstuf`` can be tracked down and corrected.
+    This was blocking a downstream feature-release of ``say``.
+
 1.0.2 (September 19, 2013)
 ''''''''''''''''''''''''''
 
 # The short X.Y version.
 version = '1.0'
 # The full version, including alpha/beta/rc tags.
-release = '1.0.2'
+release = '1.0.3'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.

options/__init__.py

 from options.core import *
+from options.version import __version__
 
-__all__ = 'Unset Prohibited Transient attrs ' \
-          'Options OptionsChain OptionsContext'.split()
+__all__ = """
+    Unset Prohibited Transient attrs
+    Options OptionsChain OptionsContext
+    __version__
+""".split()

options/chainstuf.py

+"""
+Sidecar to ``stuf`` that adds ``ChainMap``-like
+container ``chainstuf``.  ``stuf`` itself provides
+a ``chainstuf``, but as of 0.9.12, it has a bug
+when using generators as mapping values. I have
+not been able to track it down, so this less-complete
+version that nonetheless lacks the generator bug
+is used instead.
+"""
+
+try:
+    from collections import ChainMap
+except ImportError:
+    from stuf.collects import ChainMap
+
+
+class chainstuf(ChainMap):
+    """
+    A stuf-like surfacing of the ChainMap collection
+    (multi-layer dict) introduced in Python 3. Uses a
+    workalike replacement under Python 2.
+    """
+    def __init__(self, *maps):
+        ChainMap.__init__(self, *maps)
+
+    def __getattr__(self, key):
+        # handle normal object attributes
+        if key in self.__dict__:
+            return self.__dict__[key]
+        # handle special attributes
+        else:
+            for m in self.maps:
+                try:
+                    return m[key]
+                except KeyError:
+                    pass
+            raise KeyError(key)
+
+    def __setattr__(self, key, value):
+        # handle normal object attributes
+        if key == 'maps' or key in self.__dict__:
+            ChainMap.__setattr__(self, key, value)
+        else:
+            self.maps[0][key] = value
 
 import sys
 
-from stuf import orderedstuf, chainstuf
+from stuf import orderedstuf  #, chainstuf
+# temporarily pulled stuf version of chainstuf in favor of
+# local version until a bug with generator values can be
+# tracked down and fixed
+from options.chainstuf import chainstuf
 from options.configparser import ConfigParser
 from options.nulltype import NullType
 from options.funclike import *
 
+
 # Define sentinel objects
 Unset      = NullType('Unset')
 Prohibited = NullType('Prohibited')

options/nulltype.py

         if self.name is not None:
             return self.name
         else:
-            return repr(self)
+            return 'NullType(id: {0})'.format(id(self))
 
     if _PY3:
         def __bool__(self):

options/version.py

+__version__ = '1.0.3'
 #! /usr/bin/env python
 
 from setuptools import setup, find_packages
+import sys
+
+_PY3 = sys.version_info[0] == 3
 
 def linelist(text):
     """
     Returns each non-blank line in text enclosed in a list.
     """
     return [ l.strip() for l in text.strip().splitlines() if l.split() ]
-    
+
     # The double-mention of l.strip() is yet another fine example of why
     # Python needs en passant aliasing.
 
+def getmetadata(filepath):
+    """
+    Return a dictionary of metadata from a file, without importing it. This
+    trick needed because importing can set off ImportError, in that setup.py
+    runs by definition before the modules it sets up (or their dependencies) are
+    available.
+    """
+    if _PY3:
+        exec(open(filepath).read())
+        return vars()
+    else:
+        execfile(filepath)
+        return locals()
+
+metadata = getmetadata('./options/version.py')
+
 
 setup(
     name='options',
-    version='1.0.2',
+    version=metadata['__version__'],
     author='Jonathan Eunice',
     author_email='jonathan.eunice@gmail.com',
     description='Container for flexible class, instance, and function call options',
     o.update({'g': g})
     assert next(o.g) == 5
 
-    # oo = o.push()
-    # assert next(oo.g) == 6
+    oo = o.push({})
+    assert next(oo.g) == 6
 
 
 def test_addflat():