[Checkins] SVN: Sandbox/faassen/iface/ Initial import of an experimental package playing with interface registry
Martijn Faassen
faassen at startifact.com
Tue Jan 5 17:37:00 EST 2010
Log message for revision 107724:
Initial import of an experimental package playing with interface registry
concepts.
Changed:
A Sandbox/faassen/iface/
A Sandbox/faassen/iface/bootstrap.py
A Sandbox/faassen/iface/buildout.cfg
A Sandbox/faassen/iface/setup.py
A Sandbox/faassen/iface/src/
A Sandbox/faassen/iface/src/iface/
A Sandbox/faassen/iface/src/iface/__init__.py
A Sandbox/faassen/iface/src/iface/mapping.py
A Sandbox/faassen/iface/src/iface/mapping.txt
A Sandbox/faassen/iface/src/iface/tests.py
-=-
Added: Sandbox/faassen/iface/bootstrap.py
===================================================================
--- Sandbox/faassen/iface/bootstrap.py (rev 0)
+++ Sandbox/faassen/iface/bootstrap.py 2010-01-05 22:37:00 UTC (rev 107724)
@@ -0,0 +1,84 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id$
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+is_jython = sys.platform.startswith('java')
+
+try:
+ import pkg_resources
+except ImportError:
+ ez = {}
+ exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+ ).read() in ez
+ ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+ import pkg_resources
+
+if sys.platform == 'win32':
+ def quote(c):
+ if ' ' in c:
+ return '"%s"' % c # work around spawn lamosity on windows
+ else:
+ return c
+else:
+ def quote (c):
+ return c
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+ws = pkg_resources.working_set
+
+if len(sys.argv) > 2 and sys.argv[1] == '--version':
+ VERSION = '==%s' % sys.argv[2]
+ args = sys.argv[3:] + ['bootstrap']
+else:
+ VERSION = ''
+ args = sys.argv[1:] + ['bootstrap']
+
+if is_jython:
+ import subprocess
+
+ assert subprocess.Popen([sys.executable] + ['-c', quote(cmd), '-mqNxd',
+ quote(tmpeggs), 'zc.buildout' + VERSION],
+ env=dict(os.environ,
+ PYTHONPATH=
+ ws.find(pkg_resources.Requirement.parse('setuptools')).location
+ ),
+ ).wait() == 0
+
+else:
+ assert os.spawnle(
+ os.P_WAIT, sys.executable, quote (sys.executable),
+ '-c', quote (cmd), '-mqNxd', quote (tmpeggs), 'zc.buildout' + VERSION,
+ dict(os.environ,
+ PYTHONPATH=
+ ws.find(pkg_resources.Requirement.parse('setuptools')).location
+ ),
+ ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout' + VERSION)
+import zc.buildout.buildout
+zc.buildout.buildout.main(args)
+shutil.rmtree(tmpeggs)
Added: Sandbox/faassen/iface/buildout.cfg
===================================================================
--- Sandbox/faassen/iface/buildout.cfg (rev 0)
+++ Sandbox/faassen/iface/buildout.cfg 2010-01-05 22:37:00 UTC (rev 107724)
@@ -0,0 +1,13 @@
+[buildout]
+develop = .
+parts = devpython test
+
+[devpython]
+recipe = zc.recipe.egg
+interpreter = devpython
+eggs = iface
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = iface
+defaults = ['--tests-pattern', '^f?tests$', '-v']
Added: Sandbox/faassen/iface/setup.py
===================================================================
--- Sandbox/faassen/iface/setup.py (rev 0)
+++ Sandbox/faassen/iface/setup.py 2010-01-05 22:37:00 UTC (rev 107724)
@@ -0,0 +1,43 @@
+import os
+from setuptools import setup, find_packages
+
+def read(*filenames):
+ return open(os.path.join(os.path.dirname(__file__), *filenames)).read()
+
+# long_description = (
+# read('src', 'traject', 'traject.txt')
+# + '\n' +
+# read('CHANGES.txt')
+# + '\n' +
+# 'Download\n'
+# '********\n'
+# )
+
+setup(name='iface',
+ version = '0.11dev',
+ description="Interfaces and lookup for Python.",
+ long_description='',
+ # Use classifiers that are already listed at:
+ # http://pypi.python.org/pypi?%3Aaction=list_classifiers
+ classifiers=['Development Status :: 4 - Beta',
+ 'Environment :: Web Environment',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: Zope Public License',
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python',
+ 'Topic :: Software Development :: Libraries',
+ ],
+ keywords="interface interfaces",
+ author="Martijn Faassen and Thomas Lotze",
+ author_email="faassen at startifact.com",
+ license="ZPL",
+ package_dir={'': 'src'},
+ packages=find_packages('src'),
+ include_package_data=True,
+ zip_safe=False,
+ install_requires=['setuptools',
+ ],
+ entry_points="""
+ # Add entry points here
+ """,
+ )
Added: Sandbox/faassen/iface/src/iface/__init__.py
===================================================================
--- Sandbox/faassen/iface/src/iface/__init__.py (rev 0)
+++ Sandbox/faassen/iface/src/iface/__init__.py 2010-01-05 22:37:00 UTC (rev 107724)
@@ -0,0 +1,2 @@
+from iface.mapping import Map, MapKey
+
Added: Sandbox/faassen/iface/src/iface/mapping.py
===================================================================
--- Sandbox/faassen/iface/src/iface/mapping.py (rev 0)
+++ Sandbox/faassen/iface/src/iface/mapping.py 2010-01-05 22:37:00 UTC (rev 107724)
@@ -0,0 +1,33 @@
+class MapKey(object):
+ def __init__(self, key, parents=()):
+ self.key = key
+ self.parents = parents
+ # we need Python's mro, but we don't have classes. We create
+ # some with the same structure as our parent structure. then we
+ # get the mro
+ self._mro_helper = type('fake_type',
+ tuple(parent._mro_helper for
+ parent in parents),
+ {'mapkey': self})
+ # we then store the mro without the last entry, which is
+ # always object
+ self._mro = self._mro_helper.__mro__[:-1]
+
+ def __hash__(self):
+ return hash(self.key)
+
+ def __repr__(self):
+ return "<MapKey: %r>" % self.key
+
+class Map(dict):
+ def __getitem__(self, key):
+ for base in key._mro:
+ if base is object:
+ break
+ try:
+ return super(Map, self).__getitem__(base.mapkey)
+ except KeyError:
+ pass
+ raise KeyError(key)
+
+
Added: Sandbox/faassen/iface/src/iface/mapping.txt
===================================================================
--- Sandbox/faassen/iface/src/iface/mapping.txt (rev 0)
+++ Sandbox/faassen/iface/src/iface/mapping.txt 2010-01-05 22:37:00 UTC (rev 107724)
@@ -0,0 +1,99 @@
+A mapping with acyclic directed graph key
+=========================================
+
+A normal mapping (dictionary) in Python has keys that are completely
+independent from each other. If you look up a particular key, either that
+key is present in the mapping or not at all.
+
+This is a mapping that understands about relations between keys. Keys
+can have zero or more parents. If a key is not found, a value will
+still be found if a parent key can be found.
+
+We create a special kind of keys that can have parents. First we
+create one without parents::
+
+ >>> from iface import MapKey
+ >>> a = MapKey('a')
+
+Now we create keys ``b`` and ``c`` that both have ``a`` for a parent::
+
+ >>> b = MapKey('b', [a])
+ >>> c = MapKey('c', [a])
+
+Finally we create a key ``d`` that has two parents, ``b`` and ``c``::
+
+ >>> d = MapKey('d', [b, c])
+
+Now we create a mapping::
+
+ >>> from iface import Map
+ >>> map = Map()
+
+``a`` can be used just like any dictionary key::
+
+ >>> map[a] = u'Value for A'
+ >>> map[a]
+ u'Value for A'
+ >>> del map[a]
+ >>> map[a]
+ Traceback (most recent call last):
+ ...
+ KeyError: <MapKey: 'a'>
+
+We now register something for ``b``::
+
+ >>> map[b] = u'Value for B'
+
+Of course we can find ``b``::
+ >>> map[b]
+ u'Value for B'
+
+We cannot find ``c`` as there is no relation to ``b``::
+
+ >>> map[c]
+ Traceback (most recent call last):
+ ...
+ KeyError: <MapKey: 'c'>
+
+Neither can we find ``a``, as ``b`` is not an ancestor of ``a``::
+
+ >>> map[a]
+ Traceback (most recent call last):
+ ...
+ KeyError: <MapKey: 'a'>
+
+Now for the special behavor. Since ``d`` does have ``b`` as an
+ancestor, we can look it up, finding the value for B::
+
+ >>> map[d]
+ u'Value for B'
+
+We register a value for ``c``::
+
+ >>> map[c] = u'Value for C'
+
+When we look up the value for ``d`` we get still the value for ``b``,
+as it comes first in the parent resolution order (similar to Python's
+method resolution order for classes)::
+
+ >>> map[d]
+ u'Value for B'
+
+When we take out the value for ``b`` we get the value for ``c`` when we
+look up ``d``::
+
+ >>> del map[b]
+ >>> map[d]
+ u'Value for C'
+
+If we store a ``d`` key itself, then we will get its value, not the
+value of its ancestor ``c``::
+
+ >>> map[d] = u'Value for D'
+ >>> map[d]
+ u'Value for D'
+
+next: multi lookup. What is the behavior of zope.interface? Do earlier
+entries in the lookup list always weigh more heavily than the second
+one? We need backtracking in case we don't find anything for the next
+entry. That's not exactly efficient.
Added: Sandbox/faassen/iface/src/iface/tests.py
===================================================================
--- Sandbox/faassen/iface/src/iface/tests.py (rev 0)
+++ Sandbox/faassen/iface/src/iface/tests.py 2010-01-05 22:37:00 UTC (rev 107724)
@@ -0,0 +1,12 @@
+import unittest, doctest
+
+def test_suite():
+ suite = unittest.TestSuite()
+
+ optionflags = doctest.NORMALIZE_WHITESPACE + doctest.ELLIPSIS
+
+ suite.addTests([
+ doctest.DocFileSuite('mapping.txt',
+ optionflags=optionflags)])
+ return suite
+
More information about the checkins
mailing list