[Checkins] SVN: martian/tags/0.9/ Create a 0.9 release tag.

Jan-Wijbrand Kolman janwijbrand at gmail.com
Tue Oct 2 07:51:20 EDT 2007


Log message for revision 80475:
  Create a 0.9 release tag.
  
  

Changed:
  A   martian/tags/0.9/
  D   martian/tags/0.9/CHANGES.txt
  A   martian/tags/0.9/CHANGES.txt
  D   martian/tags/0.9/CREDITS.txt
  A   martian/tags/0.9/CREDITS.txt
  D   martian/tags/0.9/src/martian/core.py
  A   martian/tags/0.9/src/martian/core.py
  D   martian/tags/0.9/src/martian/scan.py
  A   martian/tags/0.9/src/martian/scan.py
  D   martian/tags/0.9/src/martian/scan.txt
  A   martian/tags/0.9/src/martian/scan.txt

-=-
Copied: martian/tags/0.9 (from rev 80465, martian/trunk)

Deleted: martian/tags/0.9/CHANGES.txt
===================================================================
--- martian/trunk/CHANGES.txt	2007-10-02 05:30:26 UTC (rev 80465)
+++ martian/tags/0.9/CHANGES.txt	2007-10-02 11:51:20 UTC (rev 80475)
@@ -1,24 +0,0 @@
-CHANGES
-*******
-
-0.8.1 (2007-08-13)
-==================
-
-Feature changes
----------------
-
-* Don't grok tests or ftests modules.
-
-Bugs fixed
-----------
-
-* Fix a bug where if a class had multiple base classes, this could end up
-  in the resultant list multiple times.
-  
-0.8 (2007-07-02)
-================
-
-Feature changes
----------------
-
-* Initial public release.

Copied: martian/tags/0.9/CHANGES.txt (from rev 80474, martian/trunk/CHANGES.txt)
===================================================================
--- martian/tags/0.9/CHANGES.txt	                        (rev 0)
+++ martian/tags/0.9/CHANGES.txt	2007-10-02 11:51:20 UTC (rev 80475)
@@ -0,0 +1,34 @@
+CHANGES
+*******
+
+unreleased
+==========
+
+Feature changes
+---------------
+
+* Reverted the behaviour where modules called tests or ftests were skipped
+  by default and added an API to provides a filtering function for skipping
+  modules to be grokked.
+
+0.8.1 (2007-08-13)
+==================
+
+Feature changes
+---------------
+
+* Don't grok tests or ftests modules.
+
+Bugs fixed
+----------
+
+* Fix a bug where if a class had multiple base classes, this could end up
+  in the resultant list multiple times.
+
+0.8 (2007-07-02)
+================
+
+Feature changes
+---------------
+
+* Initial public release.

Deleted: martian/tags/0.9/CREDITS.txt
===================================================================
--- martian/trunk/CREDITS.txt	2007-10-02 05:30:26 UTC (rev 80465)
+++ martian/tags/0.9/CREDITS.txt	2007-10-02 11:51:20 UTC (rev 80475)
@@ -1,17 +0,0 @@
-CREDITS
-=======
-
-* Martijn Faassen
- 
-* Wolfgang Schnerring
-
-* Christian Theune
-
-* Philipp von Weitershausen
-
-* Jan-Wijbrand Kolman
-
-Thank you
----------
-
-* The core Grok developers.

Copied: martian/tags/0.9/CREDITS.txt (from rev 80474, martian/trunk/CREDITS.txt)
===================================================================
--- martian/tags/0.9/CREDITS.txt	                        (rev 0)
+++ martian/tags/0.9/CREDITS.txt	2007-10-02 11:51:20 UTC (rev 80475)
@@ -0,0 +1,19 @@
+CREDITS
+=======
+
+* Martijn Faassen
+
+* Wolfgang Schnerring
+
+* Christian Theune
+
+* Philipp von Weitershausen
+
+* Jan-Wijbrand Kolman
+
+* Luciano Ramalho
+
+Thank you
+---------
+
+* The core Grok developers.

Deleted: martian/tags/0.9/src/martian/core.py
===================================================================
--- martian/trunk/src/martian/core.py	2007-10-02 05:30:26 UTC (rev 80465)
+++ martian/tags/0.9/src/martian/core.py	2007-10-02 11:51:20 UTC (rev 80475)
@@ -1,222 +0,0 @@
-import types, inspect
-
-from zope.interface import implements
-
-from martian.interfaces import IGrokker, IMultiGrokker
-from martian import util, scan
-from martian.components import (GrokkerBase, ClassGrokker, InstanceGrokker,
-                                GlobalGrokker)
-from martian.error import GrokError
-
-class MultiGrokkerBase(GrokkerBase):
-    implements(IMultiGrokker)
-
-    def register(self, grokker):
-        raise NotImplementedError
-    
-    def grok(self, name, obj, **kw):
-        grokked_status = False
-
-        for g, name, obj in self.grokkers(name, obj):
-            grokked = g.grok(name, obj, **kw)
-            if grokked not in (True, False):
-                raise GrokError(
-                    "%r returns %r instead of True or False." %
-                    (g, grokked), None)
-            if grokked:
-                grokked_status = True
-        
-        return grokked_status
-
-    def clear(self):
-        raise NotImplementedError
-    
-    def grokkers(self, name, obj):
-        raise NotImplementedError
-
-class ModuleGrokker(MultiGrokkerBase):
-  
-    def __init__(self, grokker=None, prepare=None, finalize=None):
-        if grokker is None:
-            grokker = MultiGrokker()
-        self._grokker = grokker
-        self.prepare = prepare
-        self.finalize = finalize
-        
-    def register(self, grokker):
-        self._grokker.register(grokker)
-
-    def clear(self):
-        self._grokker.clear()
-    
-    def grok(self, name, module, **kw):
-        grokked_status = False
-
-        # prepare module grok - this can also influence the kw dictionary
-        if self.prepare is not None:
-            self.prepare(name, module, kw)
-
-        # sort grokkers by priority
-        grokkers = sorted(self.grokkers(name, module),
-                          key=lambda (grokker, name, obj): grokker.priority,
-                          reverse=True)
-        
-        for g, name, obj in grokkers:
-            grokked = g.grok(name, obj, **kw)
-            if grokked not in (True, False):
-                raise GrokError(
-                    "%r returns %r instead of True or False." %
-                    (g, grokked), None)
-            if grokked:
-                grokked_status = True
-                
-        # finalize module grok
-        if self.finalize is not None:
-            self.finalize(name, module, kw)
-
-        return grokked_status
-
-    def grokkers(self, name, module):
-        grokker = self._grokker
-        # get any global grokkers
-        for t in grokker.grokkers(name, module):
-            yield t
-        
-        # try to grok everything in module
-        for name in dir(module):
-            if name.startswith('__grok_'):
-                continue
-            obj = getattr(module, name)
-            if not util.defined_locally(obj, module.__name__):
-                continue
-            if util.is_baseclass(name, obj):
-                continue
-            for t in grokker.grokkers(name, obj):
-                yield t
-
-class MultiInstanceOrClassGrokkerBase(MultiGrokkerBase):
-
-    def __init__(self):
-        self.clear()
-        
-    def register(self, grokker):
-        key = grokker.component_class
-        grokkers = self._grokkers.setdefault(key, [])
-        for g in grokkers:
-            if g.__class__ is grokker.__class__:
-                return
-        grokkers.append(grokker)
-
-    def clear(self):
-        self._grokkers = {}
-
-    def grokkers(self, name, obj):
-        used_grokkers = set()
-        for base in self.get_bases(obj):
-            grokkers = self._grokkers.get(base)
-            if grokkers is None:
-                continue
-            for grokker in grokkers:
-                if grokker not in used_grokkers:
-                    yield grokker, name, obj
-                    used_grokkers.add(grokker)
-
-class MultiInstanceGrokker(MultiInstanceOrClassGrokkerBase):
-    def get_bases(self, obj):
-        return inspect.getmro(obj.__class__)
-
-class MultiClassGrokker(MultiInstanceOrClassGrokkerBase):
-    def get_bases(self, obj):
-        if type(obj) is types.ModuleType:
-            return []
-        return inspect.getmro(obj)
-
-class MultiGlobalGrokker(MultiGrokkerBase):
-
-    def __init__(self):
-        self.clear()
-
-    def register(self, grokker):
-        for g in self._grokkers:
-            if grokker.__class__ is g.__class__:
-                return
-        self._grokkers.append(grokker)
-
-    def clear(self):
-        self._grokkers = []
-
-    def grokkers(self, name, module):
-        for grokker in self._grokkers:
-            yield grokker, name, module
-    
-class MultiGrokker(MultiGrokkerBase):
-    
-    def __init__(self):
-        self.clear()
-        
-    def register(self, grokker):
-        if isinstance(grokker, InstanceGrokker):
-            self._multi_instance_grokker.register(grokker)
-        elif isinstance(grokker, ClassGrokker):
-            self._multi_class_grokker.register(grokker)
-        elif isinstance(grokker, GlobalGrokker):
-            self._multi_global_grokker.register(grokker)
-        else:
-            assert 0, "Unknown type of grokker: %r" % grokker
-
-    def clear(self):
-        self._multi_instance_grokker = MultiInstanceGrokker()
-        self._multi_class_grokker = MultiClassGrokker()
-        self._multi_global_grokker = MultiGlobalGrokker()
-
-    def grokkers(self, name, obj):
-        obj_type = type(obj)
-        if obj_type in (type, types.ClassType):
-            return self._multi_class_grokker.grokkers(name, obj)
-        elif obj_type is types.ModuleType:
-            return self._multi_global_grokker.grokkers(name, obj)
-        else:
-            return self._multi_instance_grokker.grokkers(name, obj)
-        
-class MetaMultiGrokker(MultiGrokker):
-    """Multi grokker which comes pre-registered with meta-grokkers.
-    """
-    def clear(self):
-        super(MetaMultiGrokker, self).clear()
-        # bootstrap the meta-grokkers
-        self.register(ClassMetaGrokker(self))
-        self.register(InstanceMetaGrokker(self))
-        self.register(GlobalMetaGrokker(self))
-
-def grok_dotted_name(dotted_name, grokker, **kw):
-    module_info = scan.module_info_from_dotted_name(dotted_name)
-    grok_package(module_info, grokker, **kw)
-    
-def grok_package(module_info, grokker, **kw):
-    grok_module(module_info, grokker, **kw)
-    for sub_module_info in module_info.getSubModuleInfos():
-        grok_package(sub_module_info, grokker, **kw)
-
-def grok_module(module_info, grokker, **kw):
-    grokker.grok(module_info.dotted_name, module_info.getModule(), **kw)
-    
-# deep meta mode here - we define grokkers that can pick up the
-# three kinds of grokker: ClassGrokker, InstanceGrokker and ModuleGrokker
-class MetaGrokker(ClassGrokker):
-    def __init__(self, multi_grokker):
-        """multi_grokker - the grokker to register grokkers with.
-        """
-        self.multi_grokker = multi_grokker
-        
-    def grok(self, name, obj, **kw):
-        self.multi_grokker.register(obj())
-        return True
-    
-class ClassMetaGrokker(MetaGrokker):
-    component_class = ClassGrokker
-
-class InstanceMetaGrokker(MetaGrokker):
-    component_class = InstanceGrokker
-
-class GlobalMetaGrokker(MetaGrokker):
-    component_class = GlobalGrokker

Copied: martian/tags/0.9/src/martian/core.py (from rev 80471, martian/trunk/src/martian/core.py)
===================================================================
--- martian/tags/0.9/src/martian/core.py	                        (rev 0)
+++ martian/tags/0.9/src/martian/core.py	2007-10-02 11:51:20 UTC (rev 80475)
@@ -0,0 +1,222 @@
+import types, inspect
+
+from zope.interface import implements
+
+from martian.interfaces import IGrokker, IMultiGrokker
+from martian import util, scan
+from martian.components import (GrokkerBase, ClassGrokker, InstanceGrokker,
+                                GlobalGrokker)
+from martian.error import GrokError
+
+class MultiGrokkerBase(GrokkerBase):
+    implements(IMultiGrokker)
+
+    def register(self, grokker):
+        raise NotImplementedError
+
+    def grok(self, name, obj, **kw):
+        grokked_status = False
+
+        for g, name, obj in self.grokkers(name, obj):
+            grokked = g.grok(name, obj, **kw)
+            if grokked not in (True, False):
+                raise GrokError(
+                    "%r returns %r instead of True or False." %
+                    (g, grokked), None)
+            if grokked:
+                grokked_status = True
+
+        return grokked_status
+
+    def clear(self):
+        raise NotImplementedError
+
+    def grokkers(self, name, obj):
+        raise NotImplementedError
+
+class ModuleGrokker(MultiGrokkerBase):
+
+    def __init__(self, grokker=None, prepare=None, finalize=None):
+        if grokker is None:
+            grokker = MultiGrokker()
+        self._grokker = grokker
+        self.prepare = prepare
+        self.finalize = finalize
+
+    def register(self, grokker):
+        self._grokker.register(grokker)
+
+    def clear(self):
+        self._grokker.clear()
+
+    def grok(self, name, module, **kw):
+        grokked_status = False
+
+        # prepare module grok - this can also influence the kw dictionary
+        if self.prepare is not None:
+            self.prepare(name, module, kw)
+
+        # sort grokkers by priority
+        grokkers = sorted(self.grokkers(name, module),
+                          key=lambda (grokker, name, obj): grokker.priority,
+                          reverse=True)
+
+        for g, name, obj in grokkers:
+            grokked = g.grok(name, obj, **kw)
+            if grokked not in (True, False):
+                raise GrokError(
+                    "%r returns %r instead of True or False." %
+                    (g, grokked), None)
+            if grokked:
+                grokked_status = True
+
+        # finalize module grok
+        if self.finalize is not None:
+            self.finalize(name, module, kw)
+
+        return grokked_status
+
+    def grokkers(self, name, module):
+        grokker = self._grokker
+        # get any global grokkers
+        for t in grokker.grokkers(name, module):
+            yield t
+
+        # try to grok everything in module
+        for name in dir(module):
+            if name.startswith('__grok_'):
+                continue
+            obj = getattr(module, name)
+            if not util.defined_locally(obj, module.__name__):
+                continue
+            if util.is_baseclass(name, obj):
+                continue
+            for t in grokker.grokkers(name, obj):
+                yield t
+
+class MultiInstanceOrClassGrokkerBase(MultiGrokkerBase):
+
+    def __init__(self):
+        self.clear()
+
+    def register(self, grokker):
+        key = grokker.component_class
+        grokkers = self._grokkers.setdefault(key, [])
+        for g in grokkers:
+            if g.__class__ is grokker.__class__:
+                return
+        grokkers.append(grokker)
+
+    def clear(self):
+        self._grokkers = {}
+
+    def grokkers(self, name, obj):
+        used_grokkers = set()
+        for base in self.get_bases(obj):
+            grokkers = self._grokkers.get(base)
+            if grokkers is None:
+                continue
+            for grokker in grokkers:
+                if grokker not in used_grokkers:
+                    yield grokker, name, obj
+                    used_grokkers.add(grokker)
+
+class MultiInstanceGrokker(MultiInstanceOrClassGrokkerBase):
+    def get_bases(self, obj):
+        return inspect.getmro(obj.__class__)
+
+class MultiClassGrokker(MultiInstanceOrClassGrokkerBase):
+    def get_bases(self, obj):
+        if type(obj) is types.ModuleType:
+            return []
+        return inspect.getmro(obj)
+
+class MultiGlobalGrokker(MultiGrokkerBase):
+
+    def __init__(self):
+        self.clear()
+
+    def register(self, grokker):
+        for g in self._grokkers:
+            if grokker.__class__ is g.__class__:
+                return
+        self._grokkers.append(grokker)
+
+    def clear(self):
+        self._grokkers = []
+
+    def grokkers(self, name, module):
+        for grokker in self._grokkers:
+            yield grokker, name, module
+
+class MultiGrokker(MultiGrokkerBase):
+
+    def __init__(self):
+        self.clear()
+
+    def register(self, grokker):
+        if isinstance(grokker, InstanceGrokker):
+            self._multi_instance_grokker.register(grokker)
+        elif isinstance(grokker, ClassGrokker):
+            self._multi_class_grokker.register(grokker)
+        elif isinstance(grokker, GlobalGrokker):
+            self._multi_global_grokker.register(grokker)
+        else:
+            assert 0, "Unknown type of grokker: %r" % grokker
+
+    def clear(self):
+        self._multi_instance_grokker = MultiInstanceGrokker()
+        self._multi_class_grokker = MultiClassGrokker()
+        self._multi_global_grokker = MultiGlobalGrokker()
+
+    def grokkers(self, name, obj):
+        obj_type = type(obj)
+        if obj_type in (type, types.ClassType):
+            return self._multi_class_grokker.grokkers(name, obj)
+        elif obj_type is types.ModuleType:
+            return self._multi_global_grokker.grokkers(name, obj)
+        else:
+            return self._multi_instance_grokker.grokkers(name, obj)
+
+class MetaMultiGrokker(MultiGrokker):
+    """Multi grokker which comes pre-registered with meta-grokkers.
+    """
+    def clear(self):
+        super(MetaMultiGrokker, self).clear()
+        # bootstrap the meta-grokkers
+        self.register(ClassMetaGrokker(self))
+        self.register(InstanceMetaGrokker(self))
+        self.register(GlobalMetaGrokker(self))
+
+def grok_dotted_name(dotted_name, grokker, exclude_filter=None, **kw):
+    module_info = scan.module_info_from_dotted_name(dotted_name, exclude_filter)
+    grok_package(module_info, grokker, **kw)
+
+def grok_package(module_info, grokker, **kw):
+    grok_module(module_info, grokker, **kw)
+    for sub_module_info in module_info.getSubModuleInfos():
+        grok_package(sub_module_info, grokker, **kw)
+
+def grok_module(module_info, grokker, **kw):
+    grokker.grok(module_info.dotted_name, module_info.getModule(), **kw)
+
+# deep meta mode here - we define grokkers that can pick up the
+# three kinds of grokker: ClassGrokker, InstanceGrokker and ModuleGrokker
+class MetaGrokker(ClassGrokker):
+    def __init__(self, multi_grokker):
+        """multi_grokker - the grokker to register grokkers with.
+        """
+        self.multi_grokker = multi_grokker
+
+    def grok(self, name, obj, **kw):
+        self.multi_grokker.register(obj())
+        return True
+
+class ClassMetaGrokker(MetaGrokker):
+    component_class = ClassGrokker
+
+class InstanceMetaGrokker(MetaGrokker):
+    component_class = InstanceGrokker
+
+class GlobalMetaGrokker(MetaGrokker):
+    component_class = GlobalGrokker

Deleted: martian/tags/0.9/src/martian/scan.py
===================================================================
--- martian/trunk/src/martian/scan.py	2007-10-02 05:30:26 UTC (rev 80465)
+++ martian/tags/0.9/src/martian/scan.py	2007-10-02 11:51:20 UTC (rev 80475)
@@ -1,154 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2006-2007 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.
-#
-##############################################################################
-"""Scanning packages and modules
-"""
-
-import os
-
-from zope.interface import implements
-
-from martian.interfaces import IModuleInfo
-
-def is_package(path):
-    if not os.path.isdir(path):
-        return False
-    init_py = os.path.join(path, '__init__.py')
-    init_pyc = init_py + 'c'
-    # Check whether either __init__.py or __init__.pyc exist
-    return os.path.isfile(init_py) or os.path.isfile(init_pyc)
-
-
-class ModuleInfo(object):
-    implements(IModuleInfo)
-    
-    def __init__(self, path, dotted_name):
-        # Normalize .pyc files to .py
-        if path.endswith('c'):
-            path = path[:-1]
-        self.path = path
-        self.dotted_name = dotted_name
-
-        name_parts = dotted_name.split('.')
-        self.name = name_parts[-1]
-        if self.isPackage():
-            self.package_dotted_name = dotted_name
-        else:
-            self.package_dotted_name = '.'.join(name_parts[:-1])
-
-        self._module = None
-
-    def getResourcePath(self, name):
-        """Get the absolute path of a resource directory 'relative' to this
-        package or module.
-
-        Case one: get the resource directory with name <name> from the same
-        directory as this module
-
-        Case two: get the resource directory with name <name> from the children
-        of this package
-        """
-        return os.path.join(os.path.dirname(self.path), name)
-
-    def getSubModuleInfos(self, exclude_filter=lambda x:False):
-        if not self.isPackage():
-            return []
-        directory = os.path.dirname(self.path)
-        module_infos = []
-        seen = []
-        for entry in sorted(os.listdir(directory)):
-            entry_path = os.path.join(directory, entry)
-            name, ext = os.path.splitext(entry)
-            dotted_name = self.dotted_name + '.' + name
-            if exclude_filter(name):
-                continue
-            # Case one: modules
-            if (os.path.isfile(entry_path) and ext in ['.py', '.pyc']):
-                if name == '__init__':
-                    continue
-                # Avoid duplicates when both .py and .pyc exist
-                if name in seen:
-                    continue
-                seen.append(name)
-                module_infos.append(ModuleInfo(entry_path, dotted_name))
-            # Case two: packages
-            elif is_package(entry_path):
-                # We can blindly use __init__.py even if only
-                # __init__.pyc exists because we never actually use
-                # that filename.
-                module_infos.append(ModuleInfo(
-                    os.path.join(entry_path, '__init__.py'), dotted_name))
-        return module_infos
-
-    def getSubModuleInfo(self, name):
-        path = os.path.join(os.path.dirname(self.path), name)
-        if is_package(path):
-            return ModuleInfo(os.path.join(path, '__init__.py'),
-                              '%s.%s' % (self.package_dotted_name, name))
-        elif os.path.isfile(path + '.py') or os.path.isfile(path + '.pyc'):
-                return ModuleInfo(path + '.py',
-                                  '%s.%s' % (self.package_dotted_name, name))
-        else:
-            return None
-        
-
-    def getAnnotation(self, key, default):
-        key = key.replace('.', '_')
-        key = '__%s__' % key
-        module = self.getModule()
-        return getattr(module, key, default)
-
-    def getModule(self):
-        if self._module is None:
-            self._module = resolve(self.dotted_name)
-        return self._module
-
-    def isPackage(self):
-        return self.path.endswith('__init__.py')
-
-    def __repr__(self):
-        return "<ModuleInfo object for '%s'>" % self.dotted_name
-
-
-def module_info_from_dotted_name(dotted_name):
-    module = resolve(dotted_name)
-    return ModuleInfo(module.__file__, dotted_name)
-
-def module_info_from_module(module):
-    return ModuleInfo(module.__file__, module.__name__)
-
-
-# taken from zope.dottedname.resolve
-def resolve(name, module=None):
-    name = name.split('.')
-    if not name[0]:
-        if module is None:
-            raise ValueError("relative name without base module")
-        module = module.split('.')
-        name.pop(0)
-        while not name[0]:
-            module.pop()
-            name.pop(0)
-        name = module + name
-
-    used = name.pop(0)
-    found = __import__(used)
-    for n in name:
-        used += '.' + n
-        try:
-            found = getattr(found, n)
-        except AttributeError:
-            __import__(used)
-            found = getattr(found, n)
-
-    return found

Copied: martian/tags/0.9/src/martian/scan.py (from rev 80471, martian/trunk/src/martian/scan.py)
===================================================================
--- martian/tags/0.9/src/martian/scan.py	                        (rev 0)
+++ martian/tags/0.9/src/martian/scan.py	2007-10-02 11:51:20 UTC (rev 80475)
@@ -0,0 +1,159 @@
+##############################################################################
+#
+# Copyright (c) 2006-2007 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.
+#
+##############################################################################
+"""Scanning packages and modules
+"""
+
+import os
+
+from zope.interface import implements
+
+from martian.interfaces import IModuleInfo
+
+def is_package(path):
+    if not os.path.isdir(path):
+        return False
+    init_py = os.path.join(path, '__init__.py')
+    init_pyc = init_py + 'c'
+    # Check whether either __init__.py or __init__.pyc exist
+    return os.path.isfile(init_py) or os.path.isfile(init_pyc)
+
+
+class ModuleInfo(object):
+    implements(IModuleInfo)
+
+    def __init__(self, path, dotted_name, exclude_filter=None):
+        # Normalize .pyc files to .py
+        if path.endswith('c'):
+            path = path[:-1]
+        self.path = path
+        self.dotted_name = dotted_name
+
+        if exclude_filter is None:
+            self.exclude_filter = lambda x: False
+        else:
+            self.exclude_filter = exclude_filter
+
+        name_parts = dotted_name.split('.')
+        self.name = name_parts[-1]
+        if self.isPackage():
+            self.package_dotted_name = dotted_name
+        else:
+            self.package_dotted_name = '.'.join(name_parts[:-1])
+
+        self._module = None
+
+    def getResourcePath(self, name):
+        """Get the absolute path of a resource directory 'relative' to this
+        package or module.
+
+        Case one: get the resource directory with name <name> from the same
+        directory as this module
+
+        Case two: get the resource directory with name <name> from the children
+        of this package
+        """
+        return os.path.join(os.path.dirname(self.path), name)
+
+    def getSubModuleInfos(self):
+        if not self.isPackage():
+            return []
+        directory = os.path.dirname(self.path)
+        module_infos = []
+        seen = []
+        for entry in sorted(os.listdir(directory)):
+            entry_path = os.path.join(directory, entry)
+            name, ext = os.path.splitext(entry)
+            dotted_name = self.dotted_name + '.' + name
+            if self.exclude_filter(name):
+                continue
+            # Case one: modules
+            if (os.path.isfile(entry_path) and ext in ['.py', '.pyc']):
+                if name == '__init__':
+                    continue
+                # Avoid duplicates when both .py and .pyc exist
+                if name in seen:
+                    continue
+                seen.append(name)
+                module_infos.append(ModuleInfo(entry_path, dotted_name))
+            # Case two: packages
+            elif is_package(entry_path):
+                # We can blindly use __init__.py even if only
+                # __init__.pyc exists because we never actually use
+                # that filename.
+                module_infos.append(ModuleInfo(
+                    os.path.join(entry_path, '__init__.py'), dotted_name))
+        return module_infos
+
+    def getSubModuleInfo(self, name):
+        path = os.path.join(os.path.dirname(self.path), name)
+        if is_package(path):
+            return ModuleInfo(os.path.join(path, '__init__.py'),
+                              '%s.%s' % (self.package_dotted_name, name))
+        elif os.path.isfile(path + '.py') or os.path.isfile(path + '.pyc'):
+                return ModuleInfo(path + '.py',
+                                  '%s.%s' % (self.package_dotted_name, name))
+        else:
+            return None
+
+
+    def getAnnotation(self, key, default):
+        key = key.replace('.', '_')
+        key = '__%s__' % key
+        module = self.getModule()
+        return getattr(module, key, default)
+
+    def getModule(self):
+        if self._module is None:
+            self._module = resolve(self.dotted_name)
+        return self._module
+
+    def isPackage(self):
+        return self.path.endswith('__init__.py')
+
+    def __repr__(self):
+        return "<ModuleInfo object for '%s'>" % self.dotted_name
+
+
+def module_info_from_dotted_name(dotted_name, exclude_filter=None):
+    module = resolve(dotted_name)
+    return ModuleInfo(module.__file__, dotted_name, exclude_filter)
+
+def module_info_from_module(module, exclude_filter=None):
+    return ModuleInfo(module.__file__, module.__name__, exclude_filter)
+
+
+# taken from zope.dottedname.resolve
+def resolve(name, module=None):
+    name = name.split('.')
+    if not name[0]:
+        if module is None:
+            raise ValueError("relative name without base module")
+        module = module.split('.')
+        name.pop(0)
+        while not name[0]:
+            module.pop()
+            name.pop(0)
+        name = module + name
+
+    used = name.pop(0)
+    found = __import__(used)
+    for n in name:
+        used += '.' + n
+        try:
+            found = getattr(found, n)
+        except AttributeError:
+            __import__(used)
+            found = getattr(found, n)
+
+    return found

Deleted: martian/tags/0.9/src/martian/scan.txt
===================================================================
--- martian/trunk/src/martian/scan.txt	2007-10-02 05:30:26 UTC (rev 80465)
+++ martian/tags/0.9/src/martian/scan.txt	2007-10-02 11:51:20 UTC (rev 80475)
@@ -1,198 +0,0 @@
-Scanning modules
-================
-
-Martian can grok modules or packages. In order to grok packages, it
-needs to scan all modules in it. The martian.scan package provides an
-abstraction over packages and modules that helps with the scanning
-process.
-
-  >>> from martian.scan import module_info_from_dotted_name
-  
-We have provided a special test fixture package called stoneage that we are
-going to scan, in ``martian.tests.stoneage``.
-
-Modules
--------
-
-The scanning module defines a class ``ModuleInfo`` that provides
-information about a module or a package. Let's take a look at the
-``cave`` module in the stone-age package::
-
-  >>> module_info = module_info_from_dotted_name('martian.tests.stoneage.cave')
-  
-We get a ``ModuleInfo`` object representing the ``cave module::
-
-  >>> module_info
-  <ModuleInfo object for 'martian.tests.stoneage.cave'>
-  
-``cave`` is a module, not a package.
-
-  >>> module_info.isPackage()
-  False
-
-We can retrieve the name of the module::
-
-  >>> module_info.name
-  'cave'
-
-We can also retrieve the dotted name of the module::
-
-  >>> module_info.dotted_name
-  'martian.tests.stoneage.cave'
-
-And the dotted name of the package the module is in::
-
-  >>> module_info.package_dotted_name
-  'martian.tests.stoneage'
-
-It is possible to get the actual module object that the ModuleInfo
-object stands for, in this case the package's ``cave.py``::
-
-  >>> module = module_info.getModule()
-  >>> module
-  <module 'martian.tests.stoneage.cave' from '...cave.py...'>
-
-We can store a module-level annotation in the module::
-
-  >>> module.__grok_foobar__ = 'GROK LOVE FOO'
-
-The ModuleInfo object allows us to retrieve the annotation again::
-
-  >>> module_info.getAnnotation('grok.foobar', None)
-  'GROK LOVE FOO'
-
-If a requested annotation does not exist, we get the default value::
-
-  >>> module_info.getAnnotation('grok.barfoo', 42)
-  42
-
-A module has no sub-modules in it (only packages have this)::
-
-  >>> module_info.getSubModuleInfos()
-  []
-
-Trying to retrieve any sub modules will give back None::
-
-  >>> print module_info.getSubModuleInfo('doesnotexist')
-  None
-
-Packages
---------
-
-Now let's scan a package::
-
-  >>> module_info = module_info_from_dotted_name('martian.tests.stoneage')
-
-We will get a ModuleInfo instance representing the ``stoneage`` package::
-
-  >>> module_info
-  <ModuleInfo object for 'martian.tests.stoneage'>
-
-The object knows it is a package::
-
-  >>> module_info.isPackage()
-  True
-
-Like with the module, we can get the package's name::
-
-  >>> module_info.name
-  'stoneage'
-
-We can also get the package's dotted name back from it::
-
-  >>> module_info.dotted_name
-  'martian.tests.stoneage'
-
-It is also possible to get the dotted name of the nearest package the
-package resides in. This will always be itself::
-
-  >>> module_info.package_dotted_name
-  'martian.tests.stoneage'
-
-Now let's go into the package and a few sub modules that are in it::
-
-  >>> module_info.getSubModuleInfo('cave')
-  <ModuleInfo object for 'martian.tests.stoneage.cave'>
-
-  >>> module_info.getSubModuleInfo('hunt')
-  <ModuleInfo object for 'martian.tests.stoneage.hunt'>
-
-Trying to retrieve non-existing sub modules gives back None::
-
-  >>> print module_info.getSubModuleInfo('doesnotexist')
-  None
-
-It is possible to get the actual module object that the ModuleInfo
-object stands for, in this case the package's ``__init__.py``::
-
-  >>> module = module_info.getModule()
-  >>> module
-  <module 'martian.tests.stoneage' from '...__init__.py...'>
-
-A package has sub modules::
-
-  >>> sub_modules = module_info.getSubModuleInfos()
-  >>> sub_modules
-  [<ModuleInfo object for 'martian.tests.stoneage.cave'>,
-   <ModuleInfo object for 'martian.tests.stoneage.hunt'>,
-   <ModuleInfo object for 'martian.tests.stoneage.painting'>]
-
-Resource paths
---------------
-
-Resources can be stored in a directory alongside a module (in their
-containing package).  We can get the path to such a resource directory
-using the ``getResourcePath`` method.
-
-For packages, a resource path will be a child of the package directory:
-
-  >>> import os.path
-  >>> expected_resource_path = os.path.join(os.path.dirname(
-  ...     module.__file__), 'stoneage-templates')
-  >>> resource_path = module_info.getResourcePath('stoneage-templates')
-  >>> resource_path == expected_resource_path
-  True
-
-For modules, a resource path will be a sibling of the module's file:
-
-  >>> cave_module_info = module_info_from_dotted_name(
-  ...    'martian.tests.stoneage.cave')
-  >>> expected_resource_path = os.path.join(os.path.dirname(
-  ...     cave_module_info.getModule().__file__), 'cave-templates')
-  >>> resource_path = cave_module_info.getResourcePath('cave-templates')
-  >>> resource_path == expected_resource_path
-  True
-
-
-Skipping packages and modules
------------------------------
-
-By default no packages and modules are skipped from the grokking
-procedure to guarantee a generic behaviour::
-
-  >>> from martian.scan import ModuleInfo, module_info_from_dotted_name
-  >>> module_info = module_info_from_dotted_name(
-  ...     'martian.tests.withtestspackages')
-  >>> module_info
-  <ModuleInfo object for 'martian.tests.withtestspackages'>
-  >>> # *Will* contain the module info for the tests and ftests packages
-  >>> print module_info.getSubModuleInfos()
-  [...<ModuleInfo object for 'martian.tests.withtestspackages.tests'>...]
-
-You can, however, tell ``getSubmoduleInfos()`` to skip certain names
-of packages and modules. To do that, you have to give a filter
-function which takes a name and returns a boolean. Names, for which
-the function returns ``True`` are skipped from the result.
-
-For example, to get only those packages, which are *not* named 'tests'
-nor 'ftests' we could do::
-
-  >>> from martian.scan import ModuleInfo, module_info_from_dotted_name
-  >>> module_info = module_info_from_dotted_name(
-  ...     'martian.tests.withtestsmodules')
-  >>> module_info
-  <ModuleInfo object for 'martian.tests.withtestsmodules'>
-  >>> no_tests_filter = lambda x: x in ['tests', 'ftests']
-  >>> print module_info.getSubModuleInfos(exclude_filter=no_tests_filter)
-  [<ModuleInfo object for 'martian.tests.withtestsmodules.subpackage'>]
-

Copied: martian/tags/0.9/src/martian/scan.txt (from rev 80468, martian/trunk/src/martian/scan.txt)
===================================================================
--- martian/tags/0.9/src/martian/scan.txt	                        (rev 0)
+++ martian/tags/0.9/src/martian/scan.txt	2007-10-02 11:51:20 UTC (rev 80475)
@@ -0,0 +1,199 @@
+Scanning modules
+================
+
+Martian can grok modules or packages. In order to grok packages, it
+needs to scan all modules in it. The martian.scan package provides an
+abstraction over packages and modules that helps with the scanning
+process.
+
+  >>> from martian.scan import module_info_from_dotted_name
+
+We have provided a special test fixture package called stoneage that we are
+going to scan, in ``martian.tests.stoneage``.
+
+Modules
+-------
+
+The scanning module defines a class ``ModuleInfo`` that provides
+information about a module or a package. Let's take a look at the
+``cave`` module in the stone-age package::
+
+  >>> module_info = module_info_from_dotted_name('martian.tests.stoneage.cave')
+
+We get a ``ModuleInfo`` object representing the ``cave module::
+
+  >>> module_info
+  <ModuleInfo object for 'martian.tests.stoneage.cave'>
+
+``cave`` is a module, not a package.
+
+  >>> module_info.isPackage()
+  False
+
+We can retrieve the name of the module::
+
+  >>> module_info.name
+  'cave'
+
+We can also retrieve the dotted name of the module::
+
+  >>> module_info.dotted_name
+  'martian.tests.stoneage.cave'
+
+And the dotted name of the package the module is in::
+
+  >>> module_info.package_dotted_name
+  'martian.tests.stoneage'
+
+It is possible to get the actual module object that the ModuleInfo
+object stands for, in this case the package's ``cave.py``::
+
+  >>> module = module_info.getModule()
+  >>> module
+  <module 'martian.tests.stoneage.cave' from '...cave.py...'>
+
+We can store a module-level annotation in the module::
+
+  >>> module.__grok_foobar__ = 'GROK LOVE FOO'
+
+The ModuleInfo object allows us to retrieve the annotation again::
+
+  >>> module_info.getAnnotation('grok.foobar', None)
+  'GROK LOVE FOO'
+
+If a requested annotation does not exist, we get the default value::
+
+  >>> module_info.getAnnotation('grok.barfoo', 42)
+  42
+
+A module has no sub-modules in it (only packages have this)::
+
+  >>> module_info.getSubModuleInfos()
+  []
+
+Trying to retrieve any sub modules will give back None::
+
+  >>> print module_info.getSubModuleInfo('doesnotexist')
+  None
+
+Packages
+--------
+
+Now let's scan a package::
+
+  >>> module_info = module_info_from_dotted_name('martian.tests.stoneage')
+
+We will get a ModuleInfo instance representing the ``stoneage`` package::
+
+  >>> module_info
+  <ModuleInfo object for 'martian.tests.stoneage'>
+
+The object knows it is a package::
+
+  >>> module_info.isPackage()
+  True
+
+Like with the module, we can get the package's name::
+
+  >>> module_info.name
+  'stoneage'
+
+We can also get the package's dotted name back from it::
+
+  >>> module_info.dotted_name
+  'martian.tests.stoneage'
+
+It is also possible to get the dotted name of the nearest package the
+package resides in. This will always be itself::
+
+  >>> module_info.package_dotted_name
+  'martian.tests.stoneage'
+
+Now let's go into the package and a few sub modules that are in it::
+
+  >>> module_info.getSubModuleInfo('cave')
+  <ModuleInfo object for 'martian.tests.stoneage.cave'>
+
+  >>> module_info.getSubModuleInfo('hunt')
+  <ModuleInfo object for 'martian.tests.stoneage.hunt'>
+
+Trying to retrieve non-existing sub modules gives back None::
+
+  >>> print module_info.getSubModuleInfo('doesnotexist')
+  None
+
+It is possible to get the actual module object that the ModuleInfo
+object stands for, in this case the package's ``__init__.py``::
+
+  >>> module = module_info.getModule()
+  >>> module
+  <module 'martian.tests.stoneage' from '...__init__.py...'>
+
+A package has sub modules::
+
+  >>> sub_modules = module_info.getSubModuleInfos()
+  >>> sub_modules
+  [<ModuleInfo object for 'martian.tests.stoneage.cave'>,
+   <ModuleInfo object for 'martian.tests.stoneage.hunt'>,
+   <ModuleInfo object for 'martian.tests.stoneage.painting'>]
+
+Resource paths
+--------------
+
+Resources can be stored in a directory alongside a module (in their
+containing package).  We can get the path to such a resource directory
+using the ``getResourcePath`` method.
+
+For packages, a resource path will be a child of the package directory:
+
+  >>> import os.path
+  >>> expected_resource_path = os.path.join(os.path.dirname(
+  ...     module.__file__), 'stoneage-templates')
+  >>> resource_path = module_info.getResourcePath('stoneage-templates')
+  >>> resource_path == expected_resource_path
+  True
+
+For modules, a resource path will be a sibling of the module's file:
+
+  >>> cave_module_info = module_info_from_dotted_name(
+  ...    'martian.tests.stoneage.cave')
+  >>> expected_resource_path = os.path.join(os.path.dirname(
+  ...     cave_module_info.getModule().__file__), 'cave-templates')
+  >>> resource_path = cave_module_info.getResourcePath('cave-templates')
+  >>> resource_path == expected_resource_path
+  True
+
+
+Skipping packages and modules
+-----------------------------
+
+By default no packages and modules are skipped from the grokking
+procedure to guarantee a generic behaviour::
+
+  >>> from martian.scan import ModuleInfo, module_info_from_dotted_name
+  >>> module_info = module_info_from_dotted_name(
+  ...     'martian.tests.withtestspackages')
+  >>> module_info
+  <ModuleInfo object for 'martian.tests.withtestspackages'>
+  >>> # *Will* contain the module info for the tests and ftests packages
+  >>> print module_info.getSubModuleInfos()
+  [...<ModuleInfo object for 'martian.tests.withtestspackages.tests'>...]
+
+You can, however, tell ``getSubmoduleInfos()`` to skip certain names
+of packages and modules. To do that, you have to give a filter
+function which takes a name and returns a boolean. Names, for which
+the function returns ``True`` are skipped from the result.
+
+For example, to get only those packages, which are *not* named 'tests'
+nor 'ftests' we could do::
+
+  >>> from martian.scan import ModuleInfo, module_info_from_dotted_name
+  >>> no_tests_filter = lambda x: x in ['tests', 'ftests']
+  >>> module_info = module_info_from_dotted_name(
+  ...     'martian.tests.withtestsmodules', exclude_filter=no_tests_filter)
+  >>> module_info
+  <ModuleInfo object for 'martian.tests.withtestsmodules'>
+  >>> no_tests_filter = lambda x: x in ['tests', 'ftests']
+  >>> print module_info.getSubModuleInfos()
+  [<ModuleInfo object for 'martian.tests.withtestsmodules.subpackage'>]
+



More information about the Checkins mailing list