[Checkins] SVN: z3c.autoinclude/trunk/ merge adding-salt branch to trunk

Ethan Jucovy ejucovy at openplans.org
Fri Apr 18 13:36:42 EDT 2008


Log message for revision 85470:
  merge adding-salt branch to trunk

Changed:
  U   z3c.autoinclude/trunk/README.txt
  U   z3c.autoinclude/trunk/src/z3c/autoinclude/README.txt
  U   z3c.autoinclude/trunk/src/z3c/autoinclude/__init__.py
  A   z3c.autoinclude/trunk/src/z3c/autoinclude/dependency.py
  D   z3c.autoinclude/trunk/src/z3c/autoinclude/include.py
  U   z3c.autoinclude/trunk/src/z3c/autoinclude/meta.zcml
  A   z3c.autoinclude/trunk/src/z3c/autoinclude/plugin.py
  U   z3c.autoinclude/trunk/src/z3c/autoinclude/tests/APackage/a/configure.zcml
  U   z3c.autoinclude/trunk/src/z3c/autoinclude/tests/BCPackage/b/c/configure.zcml
  A   z3c.autoinclude/trunk/src/z3c/autoinclude/tests/BasePackage/
  A   z3c.autoinclude/trunk/src/z3c/autoinclude/tests/FooPackage/
  U   z3c.autoinclude/trunk/src/z3c/autoinclude/tests/TestDirective/setup.py
  U   z3c.autoinclude/trunk/src/z3c/autoinclude/tests/TestDirective/testdirective/zcml.py
  A   z3c.autoinclude/trunk/src/z3c/autoinclude/tests/base2/
  A   z3c.autoinclude/trunk/src/z3c/autoinclude/tests/base2_plug/
  A   z3c.autoinclude/trunk/src/z3c/autoinclude/utils.py
  U   z3c.autoinclude/trunk/src/z3c/autoinclude/zcml.py

-=-
Modified: z3c.autoinclude/trunk/README.txt
===================================================================
--- z3c.autoinclude/trunk/README.txt	2008-04-18 17:31:30 UTC (rev 85469)
+++ z3c.autoinclude/trunk/README.txt	2008-04-18 17:36:41 UTC (rev 85470)
@@ -1,12 +1,12 @@
-This package adds a new ZCML directive: "autoinclude". This directive
-searches through the dependencies in your setup.py file
+This package adds a new ZCML directive: "includeDependencies". This
+directive searches through the dependencies in your setup.py file
 (install_requires), and includes the meta.zcml and configure.zcml
 files in those packages that it finds. Inclusion order matches the
 order in the setup.py file. You can pass a path for the package you
-want to autoinclude for, but typically you pass in the current
-package, as follows::
+want to include dependencies for, but typically you pass in the
+current package, as follows::
 
-  <autoinclude package="." />
+  <includeDependencies package="." />
 
 The motivation behind this is to prevent having to repeat yourself in
 two places when you want to depend on a Zope 3 or Grok-based
@@ -21,19 +21,19 @@
 
 The next versions of Grok_ and grokproject_ will use this functionality
 out of the box. The grokproject command will automatically add the
-``autoinclude`` directive in the ZCML of the project it generates. You
-can then stop worrying about manual ZCML inclusion in the vast
+``includeDependencies`` directive in the ZCML of the project it generates.
+You can then stop worrying about manual ZCML inclusion in the vast
 majority of cases.
 
-The ``autoinclude`` directive automatically includes
+The ``includeDependencies`` directive automatically includes
 ``configure.zcml`` and ``meta.zcml`` files that in the main package
 directories. In some cases, a package may use unusual names or
 locations for its ZCML files. In that case you will need to modify
 your package's ``configure.zcml`` and ``meta.zcml`` yourself to
 include the ZCML using the manual ``include`` directive.
 
-To make the ``autoinclude`` directive available for use in your
-application or framework, you need to include it (in your
+To make the ``includeDependencies`` directive available for use in
+your application or framework, you need to include it (in your
 ``meta.zcml`` for instance), like this::
 
   <include package="z3c.autoinclude" file="meta.zcml" />

Modified: z3c.autoinclude/trunk/src/z3c/autoinclude/README.txt
===================================================================
--- z3c.autoinclude/trunk/src/z3c/autoinclude/README.txt	2008-04-18 17:31:30 UTC (rev 85469)
+++ z3c.autoinclude/trunk/src/z3c/autoinclude/README.txt	2008-04-18 17:36:41 UTC (rev 85470)
@@ -2,10 +2,37 @@
 Auto inclusion of zcml files
 ============================
 
-This package provides a facility to automatically include zcml
-dependencies such as configure.zcml and meta.zcml based on
-install_requires in the project's setup.py.
+This package provides a facility to automatically load zcml files
+such as configure.zcml and meta.zcml for a project's dependencies
+and extension packages.
 
+Autoinclusion is signalled by custom zcml directives defined in
+z3c.autoinclude's meta.zcml file.
+
+To trigger autoinclusion of a package's dependencies, include the
+following directive::
+
+  <includeDependencies package='.' />
+
+To trigger autoinclusion of a package's extensions, include the
+following directive::
+
+  <includePlugins package='.' />
+
+And to signal a package as an extension to a base package, use
+the following entry point (in your project's setup.py)::
+
+  [z3c.autoinclude.plugin]
+  target = basepackage.dotted.modulename
+
+
+Automatic inclusion of package dependencies
+===========================================
+
+The z3c.autoinclude.dependency module uses an egg's install_requires
+information (in the project's setup.py) to find and implicitly load
+zcml from all dependencies of a project.
+
 We have created a test environment to simulate setuptools
 dependencies.
 
@@ -61,17 +88,17 @@
     >>> from pkg_resources import get_provider
     >>> b_dist = get_provider(reqs[0])
 
-We can adapt a distribution to an IncludeFinder::
+We can adapt a distribution to a DependencyFinder::
 
-    >>> from z3c.autoinclude.include import IncludeFinder
-    >>> a_include_finder = IncludeFinder(a_dist)
-    >>> b_include_finder = IncludeFinder(b_dist)
-    >>> xyz_include_finder = IncludeFinder(xyz_dist)
-    >>> sibling_include_finder = IncludeFinder(sibling_dist)
+    >>> from z3c.autoinclude.dependency import DependencyFinder
+    >>> a_include_finder = DependencyFinder(a_dist)
+    >>> b_include_finder = DependencyFinder(b_dist)
+    >>> xyz_include_finder = DependencyFinder(xyz_dist)
+    >>> sibling_include_finder = DependencyFinder(sibling_dist)
 
 The include finder provides functionality to determine what namespace
 packages exist in the distribution. In the case of ``APackage``, there
-are no namespace package::
+are no namespace packages::
 
     >>> a_include_finder.namespaceDottedNames()
     []
@@ -180,3 +207,104 @@
      ...
      DistributionNotFound: NonexistentPackage
 
+Now let's just clean up our test log in preparation for the next test::
+
+    >>> from testdirective.zcml import clear_test_log
+    >>> clear_test_log()
+    >>> pprint(test_log)
+    []
+
+
+=========================================
+Automatic inclusion of extension packages
+=========================================
+
+There is additional functionality for registering and autoincluding
+extension packages for a particular platform.
+
+In this test environment, ``BasePackage`` provides the ``basepackage``
+module which we will treat as our platform.  ``FooPackage`` wants to
+broadcast itself as a plugin for ``basepackage`` and thereby register
+its ZCML as a candidate for automatic inclusion. ``TestDirective``
+also broadcasts itself as a plugin for ``basepackage``.
+
+So, once again, we must first set up our testing infrastructure::
+
+    >>> ws = install_projects(['BasePackage', 'FooPackage', 'TestDirective',
+    ...                        'base2', 'base2_plug'],
+    ...                       target_dir)
+    >>> for dist in ws:
+    ...   dist.activate()
+    ...   if dist.project_name == 'FooPackage':
+    ...     foo_dist = dist
+    ...   elif dist.project_name == 'BasePackage':
+    ...     base_dist = dist
+
+Given a module name, we can ask for distributions which have been broadcast
+themselves as plugging into that module via entry points::
+
+    >>> from z3c.autoinclude.plugin import find_plugins
+    >>> sorted(find_plugins('basepackage'))
+    [FooPackage 0.0 (...), TestDirective 0.0 (...)]
+
+Armed with a valid module name we can find the ZCML files within it
+which must be loaded::
+
+    >>> from z3c.autoinclude.plugin import zcml_to_include
+    >>> zcml_to_include('foo')
+    ['configure.zcml']
+
+By default the function looks for the standard ZCML files ``meta.zcml``,
+``configure.zcml``, and ``overrides.zcml`` but this behavior can be
+overridden::
+
+    >>> zcml_to_include('foo', ['meta.zcml'])
+    []
+
+Finally, we know how to get a list of all module dottednames within
+a distribution, through the DistributionManager adapter::
+
+    >>> from z3c.autoinclude.utils import DistributionManager
+    >>> DistributionManager(foo_dist).dottedNames()
+    ['foo']
+
+So between these functions we can now get a dictionary of all
+extension modules which must be loaded for each ZCML group given
+a base platform.
+
+For consistency, we use the same API as with dependency autoinclusion.
+This time we adapt a base platform (represented by a string referring
+to an importable dotted module name) to a PluginFinder and call its
+`includableInfo` method::
+
+    >>> from z3c.autoinclude.plugin import PluginFinder
+    >>> pprint(PluginFinder('basepackage').includableInfo(['configure.zcml',
+    ...                                                    'meta.zcml']))
+    {'configure.zcml': ['foo'], 'meta.zcml': ['testdirective']}
+
+``FooPackage`` has a test-logging directive in its configure.zcml
+which is defined in meta.zcml in ``TestDirective``.  ``FooPackage``
+does not know anything about ``TestDirective`` and does not explicitly
+include its ZCML; so for the test-logging directive to succeed when
+the ZCML of ``FooPackage`` is loaded, the meta.zcml from ``TestDirective``
+must be loaded first.  Since ``TestDirective`` offers itself as a
+plugin for ``BasePackage`` and zcmlgroups are loaded in the
+conventional order with all meta.zcml first, none of this should
+explode when we load the ZCML from ``BasePackage`` and the test log
+should accurately reflect that the ``FooPackage`` ZCML has been loaded::
+
+    >>> import basepackage
+    >>> dummy = xmlconfig.file(resource_filename('basepackage', 'configure.zcml'),
+    ...                        package=basepackage)
+    >>> pprint(test_log)
+    [u'foo has been loaded']
+
+
+``base2`` is a namespace package. ``base2.plug`` is a package that
+defines a plugin for base2.
+
+#    >>> import base2
+#    >>> dummy = xmlconfig.file(resource_filename('base2', 'configure.zcml'),
+#    ...                        package=base2)
+#    >>> pprint(test_log)
+#    [u'base2.plug has been loaded']

Modified: z3c.autoinclude/trunk/src/z3c/autoinclude/__init__.py
===================================================================
--- z3c.autoinclude/trunk/src/z3c/autoinclude/__init__.py	2008-04-18 17:31:30 UTC (rev 85469)
+++ z3c.autoinclude/trunk/src/z3c/autoinclude/__init__.py	2008-04-18 17:36:41 UTC (rev 85470)
@@ -1,2 +1,2 @@
 #
-from include import package_includes
+from dependency import package_includes

Copied: z3c.autoinclude/trunk/src/z3c/autoinclude/dependency.py (from rev 85469, z3c.autoinclude/branches/adding-salt/src/z3c/autoinclude/dependency.py)
===================================================================
--- z3c.autoinclude/trunk/src/z3c/autoinclude/dependency.py	                        (rev 0)
+++ z3c.autoinclude/trunk/src/z3c/autoinclude/dependency.py	2008-04-18 17:36:41 UTC (rev 85470)
@@ -0,0 +1,43 @@
+import os
+from zope.dottedname.resolve import resolve
+from pkg_resources import resource_exists
+from pkg_resources import get_provider
+from pkg_resources import get_distribution
+import logging
+from z3c.autoinclude.utils import DistributionManager
+
+log = logging.getLogger("z3c.autoinclude")
+
+class DependencyFinder(DistributionManager):
+    def includableInfo(self, include_candidates):
+        """Return the packages in the dependencies which are includable.
+
+        include_candidates - a list of include files we are looking for
+
+        Returns a dictionary with the include candidates as keys, and lists
+        of dotted names of packages that contain the include candidates as
+        values.
+        """
+        result = {}
+        for req in self.context.requires():
+            dist_manager = DistributionManager(get_provider(req))
+            for dotted_name in dist_manager.dottedNames():
+                module = resolve(dotted_name)
+                for candidate in include_candidates:
+                    candidate_path = os.path.join(
+                        os.path.dirname(module.__file__), candidate)
+                    if os.path.isfile(candidate_path):
+                        result.setdefault(candidate, []).append(dotted_name)
+        return result
+
+def package_includes(project_name, zcml_filenames=None):
+    """
+    Convenience function for finding zcml to load from requirements for
+    a given project. Takes a project name. DistributionNotFound errors
+    will be raised for uninstalled projects.
+    """
+    if zcml_filenames is None:
+        zcml_filenames = ['meta.zcml', 'configure.zcml', 'overrides.zcml']
+    dist = get_distribution(project_name)
+    include_finder = DependencyFinder(dist)
+    return include_finder.includableInfo(zcml_filenames)

Deleted: z3c.autoinclude/trunk/src/z3c/autoinclude/include.py
===================================================================
--- z3c.autoinclude/trunk/src/z3c/autoinclude/include.py	2008-04-18 17:31:30 UTC (rev 85469)
+++ z3c.autoinclude/trunk/src/z3c/autoinclude/include.py	2008-04-18 17:36:41 UTC (rev 85470)
@@ -1,101 +0,0 @@
-import os
-from zope.dottedname.resolve import resolve
-from pkg_resources import resource_exists
-from pkg_resources import get_provider
-from pkg_resources import get_distribution
-import logging
-
-log = logging.getLogger("z3c.autoinclude")
-
-class IncludeFinder(object):
-    def __init__(self, dist):
-        self.context = dist
-
-    def namespaceDottedNames(self):
-        """Return dotted names of all namespace packages in distribution.
-        """
-        try:
-            return list(self.context.get_metadata_lines('namespace_packages.txt'))
-        except IOError:
-            return []
-        
-    def dottedNames(self):
-        """Return dotted names of all relevant packages in a distribution.
-
-        Relevant packages are those packages that are directly under the
-        namespace packages in the distribution, but not the namespace packages
-        themselves. If no namespace packages exist, return those packages that
-        are directly in the distribution.
-        """
-        dist_path = self.context.location
-        ns_dottednames = self.namespaceDottedNames()
-        if not ns_dottednames:
-            return subpackageDottedNames(dist_path)
-        result = []
-        for ns_dottedname in ns_dottednames:
-            path = os.path.join(dist_path, *ns_dottedname.split('.'))
-            result.extend(subpackageDottedNames(path, ns_dottedname))
-        return result
-
-    def includableInfo(self, include_candidates):
-        """Return the packages in the dependencies which are includable.
-
-        include_candidates - a list of include files we are looking for
-
-        Returns a dictionary with the include candidates as keys, and lists
-        of dotted names of packages that contain the include candidates as
-        values.
-        """
-        result = {}
-        for req in self.context.requires():
-            include_finder = IncludeFinder(get_provider(req))
-            for dotted_name in include_finder.dottedNames():
-                module = resolve(dotted_name)
-                for candidate in include_candidates:
-                    candidate_path = os.path.join(
-                        os.path.dirname(module.__file__), candidate)
-                    if os.path.isfile(candidate_path):
-                        result.setdefault(candidate, []).append(dotted_name)
-        return result
-
-    
-def subpackageDottedNames(package_path, ns_dottedname=None):
-    # we do not look for subpackages in zipped eggs
-    if not os.path.isdir(package_path):
-        return []
-
-    result = []
-    for subpackage_name in os.listdir(package_path):
-        full_path = os.path.join(package_path, subpackage_name)
-        if isPythonPackage(full_path):
-            if ns_dottedname:
-                result.append('%s.%s' % (ns_dottedname, subpackage_name))
-            else:
-                result.append(subpackage_name)
-    return result
-
-def isPythonPackage(path):
-    if not os.path.isdir(path):
-        return False
-    for init_variant in ['__init__.py', '__init__.pyc', '__init__.pyo']:
-        if os.path.isfile(os.path.join(path, init_variant)):
-            return True
-    return False
-
-def package_includes(project_name, zcml_filenames=None):
-    """
-    Convenience function for finding zcml to load from requirements for
-    a given project. Takes a project name. DistributionNotFound errors
-    will be raised for uninstalled projects.
-    """
-    if zcml_filenames is None:
-        zcml_filenames = ['meta.zcml', 'configure.zcml', 'overrides.zcml']
-    dist = get_distribution(project_name)
-    include_finder = IncludeFinder(dist)
-    return include_finder.includableInfo(zcml_filenames)
-
-def debug_includes(dist, include_type, dotted_names):
-    if not dotted_names:
-        return
-    log.debug('%s - autoinclude %s: %r', dist.project_name,
-              include_type, list(dotted_names))

Modified: z3c.autoinclude/trunk/src/z3c/autoinclude/meta.zcml
===================================================================
--- z3c.autoinclude/trunk/src/z3c/autoinclude/meta.zcml	2008-04-18 17:31:30 UTC (rev 85469)
+++ z3c.autoinclude/trunk/src/z3c/autoinclude/meta.zcml	2008-04-18 17:36:41 UTC (rev 85470)
@@ -4,16 +4,34 @@
 
   <meta:directives namespace="http://namespaces.zope.org/zope">
     <meta:directive
-        name="autoinclude"
+        name="includeDependencies"
         schema=".zcml.IAutoIncludeDirective"
         handler=".zcml.autoIncludeDirective"
         />
     <meta:directive
-        name="autoincludeOverrides"
+        name="includeDependenciesOverrides"
         schema=".zcml.IAutoIncludeDirective"
         handler=".zcml.autoIncludeOverridesDirective"
         />
 
+    <!-- deprecated -->
+    <meta:directive
+        name="autoinclude"
+        schema=".zcml.IAutoIncludeDirective"
+        handler=".zcml.deprecatedAutoIncludeDirective"
+        />
+    <meta:directive
+        name="autoincludeOverrides"
+        schema=".zcml.IAutoIncludeDirective"
+        handler=".zcml.deprecatedAutoIncludeOverridesDirective"
+        />
+
+    <meta:directive
+        name="includePlugins"
+        schema=".zcml.IIncludePluginsDirective"
+        handler=".zcml.includePluginsDirective"
+        />
+
   </meta:directives>
 
 </configure>
\ No newline at end of file

Copied: z3c.autoinclude/trunk/src/z3c/autoinclude/plugin.py (from rev 85469, z3c.autoinclude/branches/adding-salt/src/z3c/autoinclude/plugin.py)
===================================================================
--- z3c.autoinclude/trunk/src/z3c/autoinclude/plugin.py	                        (rev 0)
+++ z3c.autoinclude/trunk/src/z3c/autoinclude/plugin.py	2008-04-18 17:36:41 UTC (rev 85470)
@@ -0,0 +1,41 @@
+import os
+from pkg_resources import iter_entry_points
+from pkg_resources import resource_filename
+from z3c.autoinclude.utils import DistributionManager
+from z3c.autoinclude.utils import distributionForDottedName
+
+class PluginFinder(DistributionManager):
+    def __init__(self, platform_dottedname):
+        self.context = distributionForDottedName(platform_dottedname)
+        self.dottedname = platform_dottedname
+
+    def includableInfo(self, include_candidates):
+        includable_info = {}
+
+        for plugin_distribution in find_plugins(self.dottedname):
+            include_finder = DistributionManager(plugin_distribution)
+            for plugin_dottedname in include_finder.dottedNames():
+                groups = zcml_to_include(plugin_dottedname, include_candidates)
+                for group in groups:
+                    includable_info.setdefault(group, []).append(plugin_dottedname)
+        return includable_info
+
+
+def find_plugins(dotted_name):
+    plugins = []
+    for ep in iter_entry_points('z3c.autoinclude.plugin'):
+        if ep.module_name == dotted_name:
+            plugins.append(ep.dist)
+    return plugins
+
+def zcml_to_include(dotted_name, zcmlgroups=None):
+    if zcmlgroups is None:
+        zcmlgroups = ('meta.zcml', 'configure.zcml', 'overrides.zcml')
+    
+    includable_info = []
+
+    for zcmlgroup in zcmlgroups:
+        filename = resource_filename(dotted_name, zcmlgroup)
+        if os.path.isfile(filename):
+            includable_info.append(zcmlgroup)
+    return includable_info

Modified: z3c.autoinclude/trunk/src/z3c/autoinclude/tests/APackage/a/configure.zcml
===================================================================
--- z3c.autoinclude/trunk/src/z3c/autoinclude/tests/APackage/a/configure.zcml	2008-04-18 17:31:30 UTC (rev 85469)
+++ z3c.autoinclude/trunk/src/z3c/autoinclude/tests/APackage/a/configure.zcml	2008-04-18 17:36:41 UTC (rev 85470)
@@ -1,6 +1,6 @@
 <configure xmlns="http://namespaces.zope.org/zope">
    <include package="z3c.autoinclude" file="meta.zcml" />
-   <autoinclude package="." />
+   <includeDependencies package="." />
    <!-- APackage is autoincluded. 
    This means that BCPackage and TestDirective will be included, in no particular order.
    TestDirective has a meta.zcml.

Modified: z3c.autoinclude/trunk/src/z3c/autoinclude/tests/BCPackage/b/c/configure.zcml
===================================================================
--- z3c.autoinclude/trunk/src/z3c/autoinclude/tests/BCPackage/b/c/configure.zcml	2008-04-18 17:31:30 UTC (rev 85469)
+++ z3c.autoinclude/trunk/src/z3c/autoinclude/tests/BCPackage/b/c/configure.zcml	2008-04-18 17:36:41 UTC (rev 85470)
@@ -1,6 +1,6 @@
 <configure xmlns="http://namespaces.zope.org/zope">
   <include package="z3c.autoinclude" file="meta.zcml" />
-  <autoinclude package="." />
+  <includeDependencies package="." />
   <test test_string="BCPackage has been loaded" />
   <!-- BCPackage is autoincluded.
   This means that SiblingPackage and TestDirective will be included, in no particular order.

Copied: z3c.autoinclude/trunk/src/z3c/autoinclude/tests/BasePackage (from rev 85469, z3c.autoinclude/branches/adding-salt/src/z3c/autoinclude/tests/BasePackage)

Copied: z3c.autoinclude/trunk/src/z3c/autoinclude/tests/FooPackage (from rev 85469, z3c.autoinclude/branches/adding-salt/src/z3c/autoinclude/tests/FooPackage)

Modified: z3c.autoinclude/trunk/src/z3c/autoinclude/tests/TestDirective/setup.py
===================================================================
--- z3c.autoinclude/trunk/src/z3c/autoinclude/tests/TestDirective/setup.py	2008-04-18 17:31:30 UTC (rev 85469)
+++ z3c.autoinclude/trunk/src/z3c/autoinclude/tests/TestDirective/setup.py	2008-04-18 17:36:41 UTC (rev 85470)
@@ -23,5 +23,7 @@
       ],
       entry_points="""
       # -*- Entry points: -*-
+      [z3c.autoinclude.plugin]
+      target = basepackage
       """,
       )

Modified: z3c.autoinclude/trunk/src/z3c/autoinclude/tests/TestDirective/testdirective/zcml.py
===================================================================
--- z3c.autoinclude/trunk/src/z3c/autoinclude/tests/TestDirective/testdirective/zcml.py	2008-04-18 17:31:30 UTC (rev 85469)
+++ z3c.autoinclude/trunk/src/z3c/autoinclude/tests/TestDirective/testdirective/zcml.py	2008-04-18 17:36:41 UTC (rev 85470)
@@ -3,6 +3,10 @@
 
 test_log = []
 
+def clear_test_log():
+    while test_log:
+        test_log.pop()
+
 class ITestDirective(Interface):
     """Auto-include any ZCML in the dependencies of this package."""
     

Copied: z3c.autoinclude/trunk/src/z3c/autoinclude/tests/base2 (from rev 85469, z3c.autoinclude/branches/adding-salt/src/z3c/autoinclude/tests/base2)

Copied: z3c.autoinclude/trunk/src/z3c/autoinclude/tests/base2_plug (from rev 85469, z3c.autoinclude/branches/adding-salt/src/z3c/autoinclude/tests/base2_plug)

Copied: z3c.autoinclude/trunk/src/z3c/autoinclude/utils.py (from rev 85469, z3c.autoinclude/branches/adding-salt/src/z3c/autoinclude/utils.py)
===================================================================
--- z3c.autoinclude/trunk/src/z3c/autoinclude/utils.py	                        (rev 0)
+++ z3c.autoinclude/trunk/src/z3c/autoinclude/utils.py	2008-04-18 17:36:41 UTC (rev 85470)
@@ -0,0 +1,79 @@
+import logging
+import os
+from pkg_resources import find_distributions
+import sys
+from zope.dottedname.resolve import resolve
+
+log = logging.getLogger("z3c.autoinclude")
+
+class DistributionManager(object):
+    def __init__(self, dist):
+        self.context = dist
+
+    def namespaceDottedNames(self):
+        """Return dotted names of all namespace packages in distribution.
+        """
+        try:
+            return list(self.context.get_metadata_lines('namespace_packages.txt'))
+        except IOError:
+            return []
+        
+    def dottedNames(self):
+        """Return dotted names of all relevant packages in a distribution.
+
+        Relevant packages are those packages that are directly under the
+        namespace packages in the distribution, but not the namespace packages
+        themselves. If no namespace packages exist, return those packages that
+        are directly in the distribution.
+        """
+        dist_path = self.context.location
+        ns_dottednames = self.namespaceDottedNames()
+        if not ns_dottednames:
+            return subpackageDottedNames(dist_path)
+        result = []
+        for ns_dottedname in ns_dottednames:
+            path = os.path.join(dist_path, *ns_dottedname.split('.'))
+            result.extend(subpackageDottedNames(path, ns_dottedname))
+        return result
+    
+def subpackageDottedNames(package_path, ns_dottedname=None):
+    # we do not look for subpackages in zipped eggs
+    if not os.path.isdir(package_path):
+        return []
+
+    result = []
+    for subpackage_name in os.listdir(package_path):
+        full_path = os.path.join(package_path, subpackage_name)
+        if isPythonPackage(full_path):
+            if ns_dottedname:
+                result.append('%s.%s' % (ns_dottedname, subpackage_name))
+            else:
+                result.append(subpackage_name)
+    return result
+
+def isPythonPackage(path):
+    if not os.path.isdir(path):
+        return False
+    for init_variant in ['__init__.py', '__init__.pyc', '__init__.pyo']:
+        if os.path.isfile(os.path.join(path, init_variant)):
+            return True
+    return False
+
+def distributionForPackage(package):
+
+    package_filename = package.__file__
+    for path in sys.path:
+        if package_filename.startswith(path):
+            break
+    dists = list(find_distributions(path, True))
+    assert dists, "No distributions found for package %s/%s" % (path, package_filename)
+    return dists[0]
+
+def distributionForDottedName(dotted_name):
+    return distributionForPackage(resolve(dotted_name))
+
+def debug_includes(dist, include_type, dotted_names):
+    if not dotted_names:
+        return
+    log.debug('%s - autoinclude %s: %r', dist.project_name,
+              include_type, list(dotted_names))

Modified: z3c.autoinclude/trunk/src/z3c/autoinclude/zcml.py
===================================================================
--- z3c.autoinclude/trunk/src/z3c/autoinclude/zcml.py	2008-04-18 17:31:30 UTC (rev 85469)
+++ z3c.autoinclude/trunk/src/z3c/autoinclude/zcml.py	2008-04-18 17:36:41 UTC (rev 85470)
@@ -1,13 +1,12 @@
-import sys
-
-from pkg_resources import find_distributions
 from zope.interface import Interface
 from zope.configuration.xmlconfig import include, includeOverrides
 from zope.configuration.fields import GlobalObject
 from zope.dottedname.resolve import resolve
 
-from z3c.autoinclude.include import IncludeFinder
-from z3c.autoinclude.include import debug_includes
+from z3c.autoinclude.dependency import DependencyFinder
+from z3c.autoinclude.utils import debug_includes
+from z3c.autoinclude.utils import distributionForPackage
+from z3c.autoinclude.plugin import PluginFinder
 
 class IAutoIncludeDirective(Interface):
     """Auto-include any ZCML in the dependencies of this package."""
@@ -20,35 +19,56 @@
         required=True,
         )
 
+def includeZCMLGroup(_context, dist, info, zcmlgroup, override=False):
+    includable_zcml = list(info.get(zcmlgroup, []))
+    debug_includes(dist, zcmlgroup, includable_zcml)
+    for dotted_name in includable_zcml:
+        includable_package = resolve(dotted_name)
+        if override:
+            includeOverrides(_context, zcmlgroup, includable_package)
+        else:
+            include(_context, zcmlgroup, includable_package)
+
 def autoIncludeOverridesDirective(_context, package):
     dist = distributionForPackage(package)
-    info = IncludeFinder(dist).includableInfo(['overrides.zcml'])
+    info = DependencyFinder(dist).includableInfo(['overrides.zcml'])
+    includeZCMLGroup(_context, dist, info, 'overrides.zcml', override=True)
 
-    overrides_zcml = list(info.get('overrides.zcml', []))
-    debug_includes(dist, 'overrides.zcml', overrides_zcml)
-    for dotted_name in overrides_zcml:
-        dependency_package = resolve(dotted_name)
-        includeOverrides(_context, 'overrides.zcml', dependency_package)
-
 def autoIncludeDirective(_context, package):
     dist = distributionForPackage(package)
-    info = IncludeFinder(dist).includableInfo(['configure.zcml', 'meta.zcml'])
+    info = DependencyFinder(dist).includableInfo(['configure.zcml', 'meta.zcml'])
 
-    meta_zcml = list(info.get('meta.zcml', []))
-    debug_includes(dist, 'meta.zcml', meta_zcml)
-    for dotted_name in meta_zcml:
-        dependency_package = resolve(dotted_name)
-        include(_context, 'meta.zcml', dependency_package)
+    includeZCMLGroup(_context, dist, info, 'meta.zcml')
+    includeZCMLGroup(_context, dist, info, 'configure.zcml')
 
-    configure_zcml = list(info.get('configure.zcml', []))
-    debug_includes(dist, 'configure.zcml', configure_zcml)
-    for dotted_name in configure_zcml:
-        dependency_package = resolve(dotted_name)
-        include(_context, 'configure.zcml', dependency_package)
+class IIncludePluginsDirective(Interface):
+    """Auto-include any ZCML in the dependencies of this package."""
     
-def distributionForPackage(package):
-    package_filename = package.__file__
-    for path in sys.path:
-        if package_filename.startswith(path):
-            break
-    return list(find_distributions(path, True))[0]
+    package = GlobalObject(
+        title=u"Package to auto-include for",
+        description=u"""
+        Auto-include all dependencies of this package.
+        """,
+        required=True,
+        )
+
+def includePluginsDirective(_context, package):
+    dist = distributionForPackage(package)
+    dotted_name = package.__name__
+    info = PluginFinder(dotted_name).includableInfo(['meta.zcml',
+                                                     'configure.zcml',
+                                                     'overrides.zcml'])
+
+    includeZCMLGroup(_context, dist, info, 'meta.zcml')
+    includeZCMLGroup(_context, dist, info, 'configure.zcml')
+    includeZCMLGroup(_context, dist, info, 'overrides.zcml', override=True)
+
+import warnings
+def deprecatedAutoIncludeDirective(_context, package):
+    warnings.warn("The <autoinclude> directive is deprecated and will be removed in z3c.autoinclude 0.3. Please use <includeDependencies> instead.", DeprecationWarning, stacklevel=2)
+    autoIncludeDirective(_context, package)
+
+def deprecatedAutoIncludeOverridesDirective(_context, package):
+    warnings.warn("The <autoincludeOverrides> directive is deprecated and will be removed in z3c.autoinclude 0.3. Please use <includeDependenciesOverrides> instead.", DeprecationWarning, stacklevel=2)
+    autoIncludeOverridesDirective(_context, package)
+



More information about the Checkins mailing list