[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