[Checkins] SVN: z3c.feature.core/trunk/ initial import
Paul Carduner
paulcarduner at gmail.com
Fri Mar 27 04:52:36 EDT 2009
Log message for revision 98393:
initial import
Changed:
A z3c.feature.core/trunk/
A z3c.feature.core/trunk/bootstrap.py
A z3c.feature.core/trunk/buildout.cfg
A z3c.feature.core/trunk/setup.py
A z3c.feature.core/trunk/src/
A z3c.feature.core/trunk/src/z3c/
A z3c.feature.core/trunk/src/z3c/__init__.py
A z3c.feature.core/trunk/src/z3c/feature/
A z3c.feature.core/trunk/src/z3c/feature/__init__.py
A z3c.feature.core/trunk/src/z3c/feature/core/
A z3c.feature.core/trunk/src/z3c/feature/core/README.txt
A z3c.feature.core/trunk/src/z3c/feature/core/__init__.py
A z3c.feature.core/trunk/src/z3c/feature/core/base.py
A z3c.feature.core/trunk/src/z3c/feature/core/base.txt
A z3c.feature.core/trunk/src/z3c/feature/core/command-line-project.xml
A z3c.feature.core/trunk/src/z3c/feature/core/example.txt
A z3c.feature.core/trunk/src/z3c/feature/core/file-templates/
A z3c.feature.core/trunk/src/z3c/feature/core/file-templates/README.txt
A z3c.feature.core/trunk/src/z3c/feature/core/file-templates/index-template.txt
A z3c.feature.core/trunk/src/z3c/feature/core/file-templates/test_doc.py
A z3c.feature.core/trunk/src/z3c/feature/core/index.txt
A z3c.feature.core/trunk/src/z3c/feature/core/interfaces.py
A z3c.feature.core/trunk/src/z3c/feature/core/metadata.py
A z3c.feature.core/trunk/src/z3c/feature/core/metadata.txt
A z3c.feature.core/trunk/src/z3c/feature/core/python-package-project.xml
A z3c.feature.core/trunk/src/z3c/feature/core/python.py
A z3c.feature.core/trunk/src/z3c/feature/core/python.txt
A z3c.feature.core/trunk/src/z3c/feature/core/template.py
A z3c.feature.core/trunk/src/z3c/feature/core/testing.py
A z3c.feature.core/trunk/src/z3c/feature/core/tests/
A z3c.feature.core/trunk/src/z3c/feature/core/tests/__init__.py
A z3c.feature.core/trunk/src/z3c/feature/core/tests/test_doc.py
A z3c.feature.core/trunk/src/z3c/feature/core/unittest.py
A z3c.feature.core/trunk/src/z3c/feature/core/unittest.txt
A z3c.feature.core/trunk/src/z3c/feature/core/web/
A z3c.feature.core/trunk/src/z3c/feature/core/web/__init__.py
A z3c.feature.core/trunk/src/z3c/feature/core/web/metadata.py
A z3c.feature.core/trunk/src/z3c/feature/core/web/python.py
A z3c.feature.core/trunk/src/z3c/feature/core/web/templates/
A z3c.feature.core/trunk/src/z3c/feature/core/web/templates/comment-header-zpl.pt
A z3c.feature.core/trunk/src/z3c/feature/core/web/templates/metadata.js
A z3c.feature.core/trunk/src/z3c/feature/core/web/templates/metadata.pt
A z3c.feature.core/trunk/src/z3c/feature/core/web/templates/proprietary-header.pt
A z3c.feature.core/trunk/src/z3c/feature/core/web/unittest.py
A z3c.feature.core/trunk/src/z3c/feature/core/xml.py
A z3c.feature.core/trunk/src/z3c/feature/core/xml.txt
-=-
Added: z3c.feature.core/trunk/bootstrap.py
===================================================================
--- z3c.feature.core/trunk/bootstrap.py (rev 0)
+++ z3c.feature.core/trunk/bootstrap.py 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,52 @@
+##############################################################################
+#
+# Copyright (c) 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.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id$
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+ez = {}
+exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+ ).read() in ez
+ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+import pkg_resources
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+if sys.platform == 'win32':
+ cmd = '"%s"' % cmd # work around spawn lamosity on windows
+
+ws = pkg_resources.working_set
+assert os.spawnle(
+ os.P_WAIT, sys.executable, sys.executable,
+ '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
+ dict(os.environ,
+ PYTHONPATH=
+ ws.find(pkg_resources.Requirement.parse('setuptools')).location
+ ),
+ ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)
Property changes on: z3c.feature.core/trunk/bootstrap.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.feature.core/trunk/buildout.cfg
===================================================================
--- z3c.feature.core/trunk/buildout.cfg (rev 0)
+++ z3c.feature.core/trunk/buildout.cfg 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,32 @@
+[buildout]
+extends = http://download.zope.org/zope3.4/3.4.0/versions.cfg
+develop = .
+ ../z3c.builder.core
+parts = python test coverage-test coverage-report
+versions = versions
+
+[python]
+recipe = zc.recipe.egg
+interpreter = py
+eggs = z3c.feature.core
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = z3c.feature.core [test]
+
+[coverage-test]
+recipe = zc.recipe.testrunner
+eggs = z3c.feature.core [test]
+defaults = ['--coverage', '../../coverage']
+
+[coverage-report]
+recipe = zc.recipe.egg
+eggs = z3c.coverage
+scripts = coverage=coverage-report
+arguments = ('coverage', 'coverage/report')
+
+[gtkeggdeps]
+recipe = zc.recipe.egg
+scripts = gtkeggdeps
+eggs = gtkeggdeps
+ z3c.feature.core
Added: z3c.feature.core/trunk/setup.py
===================================================================
--- z3c.feature.core/trunk/setup.py (rev 0)
+++ z3c.feature.core/trunk/setup.py 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,65 @@
+##############################################################################
+#
+# Copyright (c) 2009 Paul Carduner and Stephan Richter.
+# 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.
+#
+##############################################################################
+
+"""Setup"""
+from setuptools import setup, find_packages
+
+setup (
+ name = 'z3c.feature.core',
+ version = '0.1.0',
+ author = u"Paul Carduner and Stephan Richter",
+ author_email = u"zope-dev at zope.org",
+ description = u"Core Features to use with z3c.builder.core",
+ license = "ZPL",
+ keywords = u"zope3 project builder feature",
+ url = "http://pypi.python.org/pypi/z3c.feature.core",
+ packages = find_packages('src'),
+ include_package_data = True,
+ package_dir = {'':'src'},
+ namespace_packages = ['z3c','z3c.feature'],
+ extras_require = {
+ 'test':[
+ 'zope.testing',
+ 'z3c.coverage',
+ ],
+ },
+ install_requires = [
+ 'setuptools',
+ 'z3c.builder.core',
+ ],
+ zip_safe = False,
+ entry_points = """
+ [z3c.boiler.template]
+ command-line = z3c.feature.core.template:CommandLineProjectTemplate
+ python-package = z3c.feature.core.template:PythonPackageProjectTemplate
+
+ [z3c.feature]
+ meta-data = z3c.feature.core.metadata:MetaDataFeature
+ comment-header-ZPL = z3c.feature.core.metadata:CommentHeaderZPLFeature
+ proprietary-header = z3c.feature.core.metadata:ProprietaryHeaderFeature
+ python-interpreter = z3c.feature.core.python:PythonInterpreterFeature
+ script = z3c.feature.core.python:ScriptFeature
+ unit-testing = z3c.feature.core.unittest:TestingFeature
+ documentation = z3c.feature.core.metadata:DocumentationFeature
+
+ [z3c.builderweb]
+ meta-data = z3c.feature.core.web.metadata:MetaDataWebFeature
+ comment-header-ZPL = z3c.feature.core.web.metadata:CommentHeaderZPLWebFeature
+ proprietary-header = z3c.feature.core.web.metadata:ProprietaryHeaderWebFeature
+ python-interpreter = z3c.feature.core.web.python:PythonInterpreterWebFeature
+ script = z3c.feature.core.web.python:ScriptWebFeature
+ unit-testing = z3c.feature.core.web.unittest:TestingWebFeature
+ documentation = z3c.feature.core.web.metadata:DocumentationWebFeature
+ """,
+ )
Property changes on: z3c.feature.core/trunk/setup.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.feature.core/trunk/src/z3c/__init__.py
===================================================================
--- z3c.feature.core/trunk/src/z3c/__init__.py (rev 0)
+++ z3c.feature.core/trunk/src/z3c/__init__.py 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,7 @@
+try:
+ # Declare this a namespace package if pkg_resources is available.
+ import pkg_resources
+ pkg_resources.declare_namespace(__name__)
+except ImportError:
+ pass
+
Property changes on: z3c.feature.core/trunk/src/z3c/__init__.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.feature.core/trunk/src/z3c/feature/__init__.py
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/__init__.py (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/__init__.py 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,6 @@
+try:
+ # Declare this a namespace package if pkg_resources is available.
+ import pkg_resources
+ pkg_resources.declare_namespace(__name__)
+except ImportError:
+ pass
Property changes on: z3c.feature.core/trunk/src/z3c/feature/__init__.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.feature.core/trunk/src/z3c/feature/core/README.txt
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/README.txt (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/README.txt 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,34 @@
+===============
+Boiler Features
+===============
+
+This package provides high-level components to build a project. The intend is
+that a user can select a set of features that make up a project and the system
+figures out how to create a coherent project from that set of features.
+
+- `base.txt`
+
+ This document provides a tutorial about how to write features based on the
+ base feature provided by this package.
+
+- `metadata.txt`
+
+ This file explains the metadata feature, which is used to create the
+ package's setup information.
+
+- `python.txt`
+
+ This file documents the basic Python features provided by the module.
+
+- `unittest.txt`
+
+ This document provides detailed documentation obout the testing feature.
+
+- `xml.txt`
+
+ This document describes how XML is converted into features and then applied
+ to a project.
+
+- `example.txt`
+
+ A quick example of producing a project from XML feature descriptions.
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/README.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.feature.core/trunk/src/z3c/feature/core/__init__.py
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/__init__.py (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/__init__.py 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1 @@
+#module
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/__init__.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.feature.core/trunk/src/z3c/feature/core/base.py
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/base.py (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/base.py 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,203 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Foundation 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.
+#
+##############################################################################
+"""Base Classes Feature
+
+$Id$
+"""
+import lxml.etree
+import pkg_resources
+import zope.interface
+import zope.schema
+from zope.schema.fieldproperty import FieldProperty
+from z3c.feature.core import interfaces, xml
+
+MISSING_DOCUMENTATION = """
+Sorry, but the authors of the \"%s\" feature are
+big meanies who don't like to make software
+accessible."""
+
+class BaseFeature(object):
+ zope.interface.implements(
+ interfaces.IFeature, interfaces.IBaseFeatureSchema)
+
+ featureSingleton = FieldProperty(interfaces.IFeature['featureSingleton'])
+ featureDependencies = ()
+
+ @property
+ def featureTitle(self):
+ """See ``z3c.feature.core.interfaces.IFeature``"""
+ return self.__class__.__name__
+
+ @property
+ def featureDocumentation(self):
+ """See ``z3c.feature.core.interfaces.IFeature``"""
+ return MISSING_DOCUMENTATION % self.featureTitle
+
+ @classmethod
+ def fromXMLNode(cls, node, omit=()):
+ feature = cls()
+ schema = getFeatureSchema(feature)
+ data = xml.extractData(node, schema)
+ for fieldName in schema:
+ if fieldName in omit:
+ continue
+ value = data.get(fieldName)
+ if value:
+ setattr(feature, fieldName, value)
+ return feature
+
+ @classmethod
+ def fromXML(cls, xml):
+ tree = lxml.etree.fromstring(xml)
+ return cls.fromXMLNode(tree)
+
+ def findEntryPoint(self):
+ set = pkg_resources.working_set
+ for entryPoint in set.iter_entry_points(interfaces.FEATURE_GROUP):
+ if entryPoint.load() == self.__class__:
+ return entryPoint.dist.project_name, entryPoint.name
+ return None, None
+
+ def toXML(self, asString=False, prettyPrint=False):
+ feature = lxml.etree.Element('feature')
+ egg, name = self.findEntryPoint()
+ feature.set('type', egg + ':' + name if egg and name else 'unknown')
+ schema = getFeatureSchema(self)
+ for fieldName in zope.schema.getFields(schema):
+ if fieldName in interfaces.IFeature:
+ continue
+
+ value = getattr(self, fieldName)
+ if value != schema[fieldName].default:
+ featureOption = lxml.etree.SubElement(feature, fieldName)
+ if isinstance(value, (list, tuple, set)):
+ for item in value:
+ itemElem = lxml.etree.SubElement(featureOption, 'item')
+ itemElem.text = str(item)
+ else:
+ featureOption.text = str(value)
+ if asString:
+ return lxml.etree.tostring(feature, pretty_print=prettyPrint)
+ return feature
+
+ def update(self, features=None):
+ """See ``z3c.feature.core.interfaces.IFeature``"""
+
+ def _applyTo(self, context):
+ pass
+
+ def applyTo(self, context):
+ """See ``z3c.feature.core.interfaces.IFeature``"""
+ if interfaces.IHaveAppliedFeatures.providedBy(context):
+ context.appliedFeatures.append(self)
+ self._applyTo(context)
+
+ def __repr__(self):
+ return "<%s %r>" % (self.__class__.__name__, self.featureTitle)
+
+
+def getFeatureSchema(feature):
+ for iface in zope.interface.providedBy(feature).flattened():
+ if interfaces.IFeatureSchema.providedBy(iface):
+ return iface
+ return None
+
+
+def getFeatureTypes(feature):
+ return [iface
+ for iface in zope.interface.providedBy(feature).flattened()
+ if interfaces.IFeatureType.providedBy(iface)]
+
+
+def resolveDependencies(features, resolution=None, seen=None, types=None,
+ all=None):
+ # List of all features.
+ if all is None:
+ all = features
+ # List of all feature types that have been found on singletons.
+ if types is None:
+ types = []
+ # List of features that have been resolved in the correct order.
+ if resolution is None:
+ resolution = []
+ # A list of seen features for a particular dependency sub-path.
+ if seen is None:
+ seen = []
+ # Loop through all features and resolve them.
+ for name, feature in features.items():
+ # If the feature is a singleton record its types.
+ if feature.featureSingleton:
+ for type in getFeatureTypes(feature):
+ if type in types:
+ raise interfaces.DuplicateFeatureConflictError(type)
+ types.append(type)
+ # If a feature is already resolved, skip the feature.
+ if feature in resolution:
+ continue
+ # If we have seen the feature already, we have a cycle.
+ if feature in seen:
+ raise interfaces.CyclicDependencyError(seen[seen.index(feature):])
+ # If we do not have a cycle, add the feature to the list of seen ones
+ seen.append(feature)
+ # Resolve the dependencies of all children.
+ if feature.featureDependencies:
+ try:
+ deps = dict(
+ [(name, all[name]) for name in feature.featureDependencies])
+ except KeyError:
+ raise interfaces.MissingFeatureDependencyError(feature, name)
+ resolveDependencies(deps, resolution, seen, types, all)
+ # Add the feature to the resolution.
+ if feature not in resolution:
+ resolution.append(feature)
+ # Remove the feature from the current dependency path.
+ seen.pop()
+
+ return resolution
+
+def applyFeatures(features, project):
+ """Apply a list of features to the project."""
+ # Make sure the project collects all applied features
+ zope.interface.directlyProvides(project, interfaces.IHaveAppliedFeatures)
+ project.appliedFeatures = []
+ # Apply features one by one.
+ featureDict = dict(
+ [(feature.findEntryPoint()[1] or 'unknwon-%i' %idx, feature)
+ for idx, feature in enumerate(features)])
+ for feature in resolveDependencies(featureDict):
+ feature.update(featureDict)
+ feature.applyTo(project)
+
+
+class FileBasedTemplateBase(object):
+
+ _filename = None
+
+ def getFeatures(self):
+ if self._filename is None:
+ raise ValueError("Missing filename attribute.")
+ return xml.getFeatures(open(self._filename))
+
+
+def FileBasedTemplate(filename, title, description):
+ FileBasedTemplate = type(
+ '<FileBasedTemplate for %s' % filename,
+ (FileBasedTemplateBase,),
+ dict(title=title,
+ description=description,
+ _filename=filename))
+
+ zope.interface.classImplements(
+ FileBasedTemplate, interfaces.IProjectTemplateProvider)
+ return FileBasedTemplate
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/base.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.feature.core/trunk/src/z3c/feature/core/base.txt
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/base.txt (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/base.txt 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,413 @@
+=================
+Building Features
+=================
+
+Features are the high-level concept that is used to build projects. This
+document provides developers with a brief introduction on developing features
+for ZBoiler.
+
+Let's use an example. Let's say that we would like to implement a a feature
+called "Project Management" that creates a few text files -- `CHANGES.txt`,
+`TODO.txt`, and `AUTHORS.txt` -- in the project root.
+
+
+Getting Started
+---------------
+
+While not necessary, it is highly recommended to use the `BaseFeature` class
+as the base implementation, as it fulfills the entire feature API:
+
+ >>> from z3c.feature.core import base
+
+ >>> class ProjectManagementFeature(base.BaseFeature):
+ ... pass
+
+Let's now instantiate the feature and ensure that the interface is fulfilled.
+
+ >>> pm = ProjectManagementFeature()
+
+ >>> from zope.interface.verify import verifyObject
+ >>> from z3c.feature.core import interfaces
+
+ >>> verifyObject(interfaces.IFeature, pm)
+ True
+
+Every feature must provide an interface that describes its configuration
+parameters. This interface is extracted using a small helper function:
+
+ >>> base.getFeatureSchema(pm)
+ <InterfaceClass z3c.feature.core.interfaces.IBaseFeatureSchema>
+
+In this case, the schema is trivial and we will later see how it can be
+changed. If no schema is found, `None` is returned:
+
+ >>> base.getFeatureSchema(object())
+
+A feature also provides a title and some documentation about itself.
+
+ >>> print pm.featureTitle
+ ProjectManagementFeature
+
+ >>> print pm.featureDocumentation
+ <BLANKLINE>
+ Sorry, but the authors of the "ProjectManagementFeature" feature are big
+ meanies who don't like to make software accessible.
+
+Clearly the default values are not desirable and we will change them in the
+next iteration of our project management feature.
+
+Since pluggability is an important aspect of the system, each feature should
+be registered as an entry point for the group:
+
+ >>> interfaces.FEATURE_GROUP
+ 'z3c.feature'
+
+Since we have not yet registered the new feature as an entry point, finding
+the entry point results in nothing:
+
+ >>> pm.findEntryPoint()
+ (None, None)
+
+Usually, the first part of the result is the egg name and the latter is the
+entry point name within the group.
+
+Once the feature is setup, we can apply it to a project:
+
+ >>> from z3c.builder.core import project
+ >>> prj = project.ProjectBuilder(u'test')
+
+Before the feature can be applied, it is updated, so that it has the chance to
+fill in missing values. The `update()` method takes an optional argument that
+is a list of all features to be applied. This allows the feature to access
+other features data.
+
+ >>> pm.update({})
+
+Now we can apply the feature to the project:
+
+ >>> pm.applyTo(prj)
+
+Since we have not implemented any behavior, applying the project management
+feature has no visible effect:
+
+ >>> sorted(prj.keys())
+ []
+
+However, there is also a helper function that applies a list of features to a
+project:
+
+ >>> base.applyFeatures([pm], prj)
+
+A nice side effect of this function is that it tells the project the features
+it has applied:
+
+ >>> interfaces.IHaveAppliedFeatures.providedBy(prj)
+ True
+ >>> prj.appliedFeatures
+ [<ProjectManagementFeature 'ProjectManagementFeature'>]
+
+Another big part of the story is the ability to import from and export to XML,
+so that project definitions can be easily shared. Let's export our project
+management feature first:
+
+ >>> print pm.toXML(asString=True, prettyPrint=True)
+ <feature type="unknown"/>
+
+Pretty boring, simply because our feature dows not have a schema yet and has
+not been registered as an entry point. Let's register our feature as an entry
+point now:
+
+ >>> import pkg_resources
+ >>> from z3c.feature.core import testing
+
+ >>> dist = testing.FeatureDistribution()
+ >>> pkg_resources.working_set.add(dist)
+
+ >>> dist.addEntryPoint(
+ ... interfaces.FEATURE_GROUP, 'ProjectManagement', ProjectManagementFeature)
+
+Now that the entry point is defined, the feature also finds it easily:
+
+ >>> pm.findEntryPoint()
+ ('z3c.feature.testing', 'ProjectManagement')
+
+Let's render the XML again:
+
+ >>> print pm.toXML(asString=True, prettyPrint=True)
+ <feature type="z3c.feature.testing:ProjectManagement"/>
+
+Of course we can also load a feature from XML. This is realized via a static
+method.
+
+ >>> ProjectManagementFeature.fromXML(
+ ... '<feature type="z3c.feature.testing:ProjectManagement"/>')
+ <ProjectManagementFeature 'ProjectManagementFeature'>
+
+Again, since no feature schema is defined, importing is pretty simple as
+well. Let's now look into developing a more interesting feature.
+
+
+A Complete Feature
+------------------
+
+Let's now implement a complete feature that actually generates the promised
+files and provides better documentation as well.
+
+ >>> from z3c.builder.core.base import FileBuilder
+ >>> class HeaderFileBuilder(FileBuilder):
+ ... def __init__(self, name, title=''):
+ ... super(HeaderFileBuilder, self).__init__(name)
+ ... self.title = title
+ ... def render(self):
+ ... cols = len(self.title)
+ ... return '='*cols + '\n'+self.title+'\n' + '='*cols if cols else ''
+
+ >>> import zope.interface
+ >>> class IProjectManagementSchema(zope.interface.Interface):
+ ... includeHeaders = zope.schema.Bool(
+ ... title=u'Include Headers',
+ ... description=u'If set, include headers in generated files.',
+ ... default=False)
+ >>> zope.interface.alsoProvides(
+ ... IProjectManagementSchema, interfaces.IFeatureSchema)
+
+ >>> class ProjectManagementFeature(base.BaseFeature):
+ ... zope.interface.implements(IProjectManagementSchema)
+ ...
+ ... featureTitle = u'Project Management'
+ ... featureDocumentation = (
+ ... u'Adds a CHANGES.txt, TODO.txt, and AUTHORS.txt to the '
+ ... u'project root.')
+ ...
+ ... includeHeaders = False
+ ...
+ ... def _applyTo(self, context):
+ ... for name in (u'TODO.txt', u'CHANGES.txt', u'AUTHORS.txt'):
+ ... title = name[:-4] if self.includeHeaders else ''
+ ... builder = HeaderFileBuilder(name, title)
+ ... context.add(builder)
+
+Everything is pretty straightforward. The only part to look out for is that
+instead of implementing ``applyTo()``, you should implement the ``_applyTo()``
+method. Let's now try it out.
+
+ >>> pm = ProjectManagementFeature()
+ >>> pm
+ <ProjectManagementFeature u'Project Management'>
+ >>> pm.featureTitle
+ u'Project Management'
+ >>> pm.featureDocumentation
+ u'Adds a CHANGES.txt, TODO.txt, and AUTHORS.txt to the project root.'
+
+Now we are ready to apply the feature on the project.
+
+ >>> pm.update()
+ >>> pm.applyTo(prj)
+
+ >>> sorted(prj)
+ [u'AUTHORS.txt', u'CHANGES.txt', u'TODO.txt']
+
+Since we did not set the `includeHeader` flag, all files should be empty:
+
+ >>> prj['AUTHORS.txt'].render()
+ ''
+
+Let's now try with the flag turned on:
+
+ >>> pm.includeHeaders = True
+ >>> prj = project.ProjectBuilder(u'test')
+
+ >>> pm.update()
+ >>> pm.applyTo(prj)
+
+ >>> print prj['AUTHORS.txt'].render()
+ =======
+ AUTHORS
+ =======
+
+Let's also look at XML serialization again. First the serialization to XML:
+
+ >>> dist.addEntryPoint(
+ ... interfaces.FEATURE_GROUP, 'ProjectManagement', ProjectManagementFeature)
+
+ >>> print pm.toXML(True, True)
+ <feature type="z3c.feature.testing:ProjectManagement">
+ <includeHeaders>True</includeHeaders>
+ </feature>
+
+Let's now take that output and generate the feature again:
+
+ >>> pm2 = ProjectManagementFeature.fromXML('''\
+ ... <feature type="z3c.feature.testing:ProjectManagement">
+ ... <includeHeaders>True</includeHeaders>
+ ... </feature>
+ ... ''')
+ >>> pm2
+ <ProjectManagementFeature u'Project Management'>
+ >>> pm2.includeHeaders
+ True
+
+ >>> pm2 = ProjectManagementFeature.fromXML('''\
+ ... <feature type="z3c.feature.testing:ProjectManagement">
+ ... <includeHeaders>False</includeHeaders>
+ ... </feature>
+ ... ''')
+ >>> pm2.includeHeaders
+ False
+
+And that's it! Let's now talk about some advanced features.
+
+
+Project Singletons
+------------------
+
+Features can be used in two ways: singletons and multiples. A singleton
+feature instance can only be applied once to the project. Examples include
+the meta-data, project setup, documentation features. Multiples, on the other
+hand, can have multiple instances applied to a project. Good examples include
+interface, class and HTML page features. By default, the singleton flag is
+set.
+
+ >>> pm.featureSingleton
+ True
+
+
+Dependencies
+------------
+
+In some cases, features depend on other features. Those dependencies come in
+two flavors:
+
+(1) A particular feature must be applied before another feature can be
+ applied.
+
+(2) A particular feature needs to access information of another feature.
+
+Dependencies are specified as part of the feature and are referenced by entry
+point name.
+
+Let's first look at case (1). As an example, we create a feature that creates
+a directory and one that puts a file in that directory.
+
+ >>> from z3c.builder.core.base import DirectoryBuilder
+ >>> class DocsDirectoryFeature(base.BaseFeature):
+ ... name = u'docs'
+ ... def _applyTo(self, context):
+ ... builder = DirectoryBuilder(self.name)
+ ... context.add(builder)
+ >>> docs = DocsDirectoryFeature()
+
+ >>> dist.addEntryPoint(
+ ... interfaces.FEATURE_GROUP, 'DocsDirectoryFeature', DocsDirectoryFeature)
+
+ >>> class IndexFileFeature(base.BaseFeature):
+ ... featureDependencies = ('DocsDirectoryFeature',)
+ ...
+ ... def _applyTo(self, context):
+ ... builder = HeaderFileBuilder(u'index.rst', u'Index')
+ ... context['docs'].add(builder)
+ >>> index = IndexFileFeature()
+
+Let's now apply the two features to a newly created project:
+
+ >>> prj = project.ProjectBuilder(u'test')
+ >>> base.applyFeatures([index, docs], prj)
+
+ >>> prj.appliedFeatures
+ [<DocsDirectoryFeature 'DocsDirectoryFeature'>,
+ <IndexFileFeature 'IndexFileFeature'>]
+
+ >>> sorted(prj)
+ [u'docs']
+ >>> sorted(prj['docs'])
+ [u'index.rst']
+
+It worked. Note that the applied features list even provides the correct order
+in which the features were applied.
+
+Let's now look at case (2). Here the file builder simply wants to access the
+information of the directory builder. In this case dependency resolution is
+not necessary, though having it does not provide a problem either.
+
+To access a feature, we need to implement the `update()` method. So in this
+case, we would like to reuse the name of the docs directory feature.
+
+ >>> class IndexFileFeature(base.BaseFeature):
+ ... featureDependencies = ('DocsDirectoryFeature',)
+ ...
+ ... def update(self, features):
+ ... self.dirName = features['DocsDirectoryFeature'].name
+ ...
+ ... def _applyTo(self, context):
+ ... builder = HeaderFileBuilder(
+ ... u'index.rst', u'Index for `%s`' %self.dirName)
+ ... context.add(builder)
+ >>> index = IndexFileFeature()
+
+Let's now apply the two features to a newly created project:
+
+ >>> prj = project.ProjectBuilder(u'test')
+ >>> base.applyFeatures([index, docs], prj)
+
+ >>> prj.appliedFeatures
+ [<DocsDirectoryFeature 'DocsDirectoryFeature'>,
+ <IndexFileFeature 'IndexFileFeature'>]
+
+ >>> sorted(prj)
+ [u'docs', u'index.rst']
+ >>> print prj['index.rst'].render()
+ ================
+ Index for `docs`
+ ================
+
+
+Enforcing Uniqueness by Feature Type
+------------------------------------
+
+It is sometimes necessary to enforce that only one feature of a particular
+*type* of feature is applied. For example, it makes little sense to apply a
+Google App Engine and Zope 3 project feature in the same run.
+
+You can get a list of all feature types using a simple function call:
+
+ >>> single = base.BaseFeature()
+ >>> base.getFeatureTypes(single)
+ []
+
+So our little single feature does not have any types. Let's now create a
+feature type:
+
+ >>> class ISingle(zope.interface.Interface):
+ ... pass
+ >>> zope.interface.alsoProvides(ISingle, interfaces.IFeatureType)
+
+Once the new type is applied to the single feature, it is found via the query:
+
+ >>> zope.interface.alsoProvides(single, ISingle)
+ >>> base.getFeatureTypes(single)
+ [<InterfaceClass __builtin__.ISingle>]
+
+Let's new create a second feature:
+
+ >>> double = base.BaseFeature()
+ >>> zope.interface.alsoProvides(double, ISingle)
+
+Since both features support the `ISingle` feature type, they cannot be applied
+to the sam eproject:
+
+ >>> prj = project.ProjectBuilder(u'test')
+ >>> base.applyFeatures([single, double], prj)
+ Traceback (most recent call last):
+ ...
+ DuplicateFeatureConflictError: <InterfaceClass __builtin__.ISingle>
+
+However, when the features are not singletons, they can be applied together:
+
+ >>> single.featureSingleton = False
+ >>> double.featureSingleton = False
+
+ >>> base.applyFeatures([single, double], prj)
+ >>> prj.appliedFeatures
+ [<BaseFeature 'BaseFeature'>, <BaseFeature 'BaseFeature'>]
+
+And that's it.
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/base.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.feature.core/trunk/src/z3c/feature/core/command-line-project.xml
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/command-line-project.xml (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/command-line-project.xml 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,17 @@
+<project name="helloworld">
+ <feature type="z3c.feature.core:meta-data">
+ <author>?</author>
+ <author-email>?</author-email>
+ <description>?</description>
+ <version>?</version>
+ <license>?</license>
+ <url>?</url>
+ <keywords>?</keywords>
+ <namespace-packages>?</namespace-packages>
+ <install-requires>?</install-requires>
+ </feature>
+ <feature type="z3c.feature.core:python-interpreter" />
+ <feature type="z3c.feature.core:unit-testing" />
+ <feature type="z3c.feature.core:script" />
+ <feature type="z3c.feature.core:documentation" />
+</project>
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/command-line-project.xml
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.feature.core/trunk/src/z3c/feature/core/example.txt
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/example.txt (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/example.txt 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,312 @@
+============================
+XML Configuration Processing
+============================
+
+We have an xml configuration layer for the project builder.
+
+ >>> from z3c.feature.core import xml
+
+Let's start by defining the simplest possible project definition in
+xml:
+
+ >>> hw = xml.xmlToProject('<project name="HelloWorld"/>')
+
+This provides you with a full project using default settings, once
+you've run the update method.
+
+ >>> hw.setup.update()
+ >>> hw.name
+ u'HelloWorld'
+ >>> hw.setup.version
+ u'0.1.0'
+ >>> hw.setup.license
+ u'GPLv3'
+ >>> hw.setup.url
+ u'http://pypi.python.org/pypi/HelloWorld'
+ >>> hw.setup.keywords
+ []
+ >>> hw.setup.author
+ u''
+ >>> hw.setup.author_email
+ u''
+ >>> hw.setup.description
+ u''
+ >>> print hw.commentHeader
+ ##############################################################################
+ #
+ # This file is part of %(name)s.
+ #
+ # %(name)s is free software: you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License as published by
+ # the Free Software Foundation, either version 3 of the License, or
+ # (at your option) any later version.
+ #
+ # %(name)s is distributed in the hope that it will be useful,
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ # GNU General Public License for more details.
+ #
+ # You should have received a copy of the GNU General Public License
+ # along with %(name)s. If not, see <http://www.gnu.org/licenses/>.
+ #
+ ##############################################################################
+
+
+Project Metadata
+----------------
+
+We can customize this project by adding some features. The simplest
+feature is the meta-data feature which lets you define some typical
+project meta-data:
+
+ >>> hw = xml.xmlToProject('''
+ ... <project name="HelloWorld">
+ ... <feature type="z3c.feature.core:meta-data">
+ ... <license>Zope Public License</license>
+ ... <version>0.5.0</version>
+ ... <author>Paul Carduner and Stephan Richter</author>
+ ... <author-email>zope-dev at zope.org</author-email>
+ ... <description>A simple Zope 3 Application</description>
+ ... <license>ZPL 2.1</license>
+ ... <keywords>
+ ... <item>zope3</item>
+ ... <item>HelloWorld</item>
+ ... <item>project</item>
+ ... </keywords>
+ ... <url>http://svn.zope.org/HelloWorld/trunk</url>
+ ... <commentHeader># Copyright 2009 Cool People.</commentHeader>
+ ... </feature>
+ ... </project>''')
+
+ >>> hw.name
+ u'HelloWorld'
+ >>> hw.setup.version
+ u'0.5.0'
+ >>> hw.setup.license
+ u'Zope Public License'
+ >>> hw.setup.url
+ u'http://svn.zope.org/HelloWorld/trunk'
+ >>> hw.setup.keywords
+ [u'zope3', u'HelloWorld', u'project']
+ >>> hw.setup.author
+ u'Paul Carduner and Stephan Richter'
+ >>> hw.setup.author_email
+ u'zope-dev at zope.org'
+ >>> hw.setup.description
+ u'A simple Zope 3 Application'
+ >>> hw.commentHeader
+ u'# Copyright 2009 Cool People.'
+
+We can also use a custom comment header feature. Since it apepars
+after the meta data feature, it can overwrite anything done by the
+meta data feature.
+
+ >>> hw = xml.xmlToProject('''
+ ... <project name="HelloWorld">
+ ... <feature type="z3c.feature.core:meta-data" />
+ ... <feature type="z3c.feature.core:comment-header-ZPL">
+ ... <year>2009</year>
+ ... <author>Paul Carduner</author>
+ ... </feature>
+ ... </project>''')
+
+ >>> hw
+ <BuildoutProjectBuilder u'HelloWorld'>
+
+ >>> print hw.commentHeader
+ ##############################################################################
+ #
+ # Copyright (c) 2009 Paul Carduner.
+ # 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.
+ #
+ ##############################################################################
+
+Here is another example of a nest feature that adds a proprietary
+copyright header.
+
+ >>> hw = xml.xmlToProject('''
+ ... <project name="HelloWorld">
+ ... <feature type="z3c.feature.core:proprietary-header">
+ ... <year>2009</year>
+ ... <company>Awesomeness LLC.</company>
+ ... <location>Heaven on Earth</location>
+ ... </feature>
+ ... </project>''')
+ >>> print hw.commentHeader
+ ###############################################################################
+ #
+ # Copyright 2009 by Awesomeness LLC., Heaven on Earth
+ #
+ ###############################################################################
+
+
+Buildout
+--------
+
+We can also configure buildout related features that go beyond the
+defaults. Let's first look at the defaults.
+
+ >>> hw = xml.xmlToProject('<project name="HelloWorld"/>')
+ >>> hw.buildout
+ <BuildoutConfigBuilder for u'HelloWorld'>
+ >>> hw.buildout.extends
+ [u'http://download.zope.org/zope3.4/3.4.0/versions.cfg']
+
+Lets add a python interpreter feature
+
+ >>> hw = xml.xmlToProject('''
+ ... <project name="HelloWorld">
+ ... <feature type="z3c.feature.core:python-interpreter"/>
+ ... </project>''')
+
+ >>> hw.buildout
+ <BuildoutConfigBuilder for u'HelloWorld'>
+
+
+Testing
+-------
+
+Let's add some unit testing features:
+
+ >>> hw = xml.xmlToProject('''
+ ... <project name="HelloWorld">
+ ... <feature type="z3c.feature.core:unit-testing"/>
+ ... </project>''')
+
+ >>> hw.update()
+ >>> hw.buildout.names
+ [u'test', u'coverage-test', u'coverage-report']
+
+ >>> hw.buildout['test']
+ <PartBuilder u'test'>
+
+ >>> hw.buildout['coverage-test']
+ <PartBuilder u'coverage-test'>
+
+ >>> hw.buildout['coverage-report']
+ <PartBuilder u'coverage-report'>
+
+ >>> hw.setup.extras_requires
+ {'test': ['z3c.coverage', 'zope.testing']}
+
+ >>> hw.package['tests']['test_doc.py']
+ <SimpleFileBuilder u'test_doc.py'>
+
+ >>> hw.package['README.txt']
+ <SimpleFileBuilder u'README.txt'>
+
+
+Python Shell Script
+-------------------
+
+Lets add a python shell script feature:
+
+ >>> hw = xml.xmlToProject('''
+ ... <project name="HelloWorld">
+ ... <feature type="z3c.feature.core:script"/>
+ ... </project>''')
+
+ >>> hw.update()
+ >>> hw.setup.entry_points
+ {'console_scripts': [u'HelloWorld = HelloWorld.script:main']}
+ >>> hw.package['script.py']
+ <ModuleBuilder u'script.py'>
+
+ >>> print hw.package['script.py'].render()
+ ##############################################################################
+ #
+ # This file is part of HelloWorld....
+ #
+ ##############################################################################
+ """Module Documentation"""
+ <BLANKLINE>
+ def main(args=None):
+ """Runs the HelloWorld script from the HelloWorld project"""
+ print "Successfully ran the HelloWorld script"
+
+
+Documentation Generation
+------------------------
+
+Lets add some documentation generation.
+
+ >>> hw = xml.xmlToProject('''
+ ... <project name="HelloWorld">
+ ... <feature type="z3c.feature.core:documentation"/>
+ ... </project>''')
+
+ >>> hw.update()
+
+We now have a docs buildout section.
+
+ >>> print hw.buildout['docs'].render()
+ [docs]
+ recipe = z3c.recipe.sphinxdoc
+ eggs = z3c.recipe.sphinxdoc
+ HelloWorld [docs]
+ layout.html =
+ default.css =
+
+and a docs extras_require section:
+
+ >>> print hw.setup.extras_requires
+ {'docs': ['Sphinx']}
+
+and an index.txt template file:
+
+ >>> hw.package['index.txt']
+ <DocumentationFileBuilder u'index.txt'>
+
+ >>> print hw.package['index.txt'].render()
+ ========================
+ HelloWorld Documentation
+ ========================
+ <BLANKLINE>
+ Contents:
+ <BLANKLINE>
+ .. toctree::
+ :maxdepth: 2
+ <BLANKLINE>
+ Indices and tables
+ ==================
+ <BLANKLINE>
+ * :ref:`genindex`
+ * :ref:`modindex`
+ * :ref:`search`
+
+If we do this in combination with other builders that produce *.txt
+files (like the doctest builder), then those get added to the
+contents.
+
+ >>> hw = xml.xmlToProject('''
+ ... <project name="HelloWorld">
+ ... <feature type="z3c.feature.core:documentation"/>
+ ... <feature type="z3c.feature.core:unit-testing"/>
+ ... </project>''')
+
+ >>> hw.update()
+ >>> print hw.package['index.txt'].render()
+ ========================
+ HelloWorld Documentation
+ ========================
+ <BLANKLINE>
+ Contents:
+ <BLANKLINE>
+ .. toctree::
+ :maxdepth: 2
+ README
+ <BLANKLINE>
+ Indices and tables
+ ==================
+ <BLANKLINE>
+ * :ref:`genindex`
+ * :ref:`modindex`
+ * :ref:`search`
+ <BLANKLINE>
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/example.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.feature.core/trunk/src/z3c/feature/core/file-templates/README.txt
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/file-templates/README.txt (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/file-templates/README.txt 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,14 @@
+================
+A Simple DocTest
+================
+
+Doctests work by evaluating txt documents that look like python
+interpreter sessions. This test will pass:
+
+ >>> 1+1
+ 2
+
+The following test will not pass (that's why it is commented out):
+
+# >>> print 'apples and bananas'
+# oranges
\ No newline at end of file
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/file-templates/README.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.feature.core/trunk/src/z3c/feature/core/file-templates/index-template.txt
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/file-templates/index-template.txt (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/file-templates/index-template.txt 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,15 @@
+%(heading)s
+
+Contents:
+
+.. toctree::
+ :maxdepth: 2
+
+ %(TOC)s
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/file-templates/index-template.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.feature.core/trunk/src/z3c/feature/core/file-templates/test_doc.py
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/file-templates/test_doc.py (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/file-templates/test_doc.py 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,13 @@
+import unittest
+import zope.testing.doctest
+
+def test_suite():
+ return unittest.TestSuite((
+
+ zope.testing.doctest.DocFileSuite(
+ '../README.txt',
+ optionflags=zope.testing.doctest.NORMALIZE_WHITESPACE |
+ zope.testing.doctest.ELLIPSIS),
+
+
+ ))
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/file-templates/test_doc.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.feature.core/trunk/src/z3c/feature/core/index.txt
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/index.txt (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/index.txt 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,14 @@
+====================
+Core Boiler Features
+====================
+
+.. toctree::
+ :maxdepth: 2
+
+ README
+ base
+ metadata
+ python
+ unittest
+ xml
+ example
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/index.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.feature.core/trunk/src/z3c/feature/core/interfaces.py
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/interfaces.py (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/interfaces.py 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,322 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation 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.
+#
+##############################################################################
+"""Feature interfaces
+
+$Id$
+"""
+import datetime
+import os
+
+import zope.interface
+from zope.interface.interfaces import IInterface
+import zope.schema
+
+from z3c.builder.core.interfaces import troveClassiferVocabulary
+
+FEATURE_GROUP = 'z3c.feature'
+
+class IFeatureType(IInterface):
+ """An interface that describes a particular type of feature."""
+
+class DuplicateFeatureConflictError(ValueError):
+
+ def __init__(self, type):
+ self.type = type
+ ValueError.__init__(self, type)
+
+class CyclicDependencyError(ValueError):
+
+ def __init__(self, cycle):
+ self.cycle = cycle
+ ValueError.__init__(self, cycle)
+
+class MissingFeatureDependencyError(KeyError):
+ def __init__(self, feature, dependencyName):
+ self.feature = feature
+ self.dependencyName = dependencyName
+ KeyError.__init__(self, dependencyName)
+
+ def __str__(self):
+ return ('Feature "%s" depends on "%s" but no "%s" '
+ 'feature was specified') % (self.feature.featureTitle,
+ self.dependencyName,
+ self.dependencyName)
+
+class IFeatureSchema(IInterface):
+ """A schema describing the configuration parameters of a feature."""
+
+class IBaseFeatureSchema(zope.interface.Interface):
+ """A trivial feature schema."""
+zope.interface.directlyProvides(IBaseFeatureSchema, IFeatureSchema)
+
+
+class IFeature(zope.interface.Interface):
+ """An object representing a possible feature."""
+
+ featureTitle = zope.schema.TextLine(
+ title=u"Feature Title",
+ description=u"A user readable title for this feature.")
+
+ featureDocumentation = zope.schema.Text(
+ title=u"Feature Documentation",
+ description=u"""ReSTructured text documentation on the feature.
+
+ This should explain what files were modified/created by the
+ feature and what each piece does, with tips on modifying them
+ later. Documentation for all the features are combined into
+ a single README.txt in the project Root.
+ """)
+
+ featureSingleton = zope.schema.Bool(
+ title=u"Feature Sigelton",
+ description=(u"When set, only one instance of this feature can "
+ u"be applied to the context."),
+ default=True)
+
+ featureDependencies = zope.schema.Tuple(
+ title=u"Feature Dependencies",
+ description=(u"A list of names of features that this feature "
+ u"depends on."),
+ value_type=zope.schema.ASCIILine())
+
+ def update(features=()):
+ """Update the feature.
+
+ Optionally, all other features that are applied are passed into the
+ method as an argument.
+ """
+
+ def applyTo(context):
+ """Apply the given feature to the context."""
+
+ def findEntryPoint():
+ """Returns the egg name and entry point name.
+
+ If no entry point is found, `(None, None)` is returned.
+ """
+
+ def toXML(asString=False, prettyPrint=False):
+ """Returns an etree node object representing the feature in xml.
+
+ Optional keyword arguments include asString and prettyPrint
+ which if set to true will return an xml string that is pretty
+ printed.
+ """
+
+class IHaveAppliedFeatures(zope.interface.Interface):
+ """A component that keeps track of the features applied to it."""
+
+ appliedFeatures = zope.schema.List(
+ title=u'Applied Features',
+ description=u'A list of features that were applied on the builder.')
+
+
+class IProjectTemplateProvider(zope.interface.Interface):
+ """Object that provides a projecte template."""
+
+ title = zope.schema.TextLine(
+ title=u"Title",
+ description=u"A title that can be provided to the user.")
+
+ description = zope.schema.TextLine(
+ title=u"Description",
+ description=u"A description that can be provided to the user.")
+
+ def getFeatures():
+ """Returns a dictionary of entrypoint name to features that
+ are part of this template."""
+
+
+class IFileBasedTemplateProvider(IProjectTemplateProvider):
+
+ filename = zope.schema.TextLine(
+ title=u"Filename")
+
+
+class IMetaDataFeature(zope.interface.Interface):
+
+ license = zope.schema.TextLine(
+ title=u'License',
+ default=u'GNU General Public License (GPL)',
+ required=False)
+
+ version = zope.schema.TextLine(
+ title=u'Version',
+ description=u'An initial version number for the project',
+ default=u'0.1.0',
+ required=False)
+
+ description = zope.schema.TextLine(
+ title=u'Project Description',
+ description=u'Short Description of the project',
+ required=False)
+
+ author = zope.schema.TextLine(
+ title=u'Author(s)',
+ description=u'Name of the project author(s)',
+ required=False)
+
+ author_email = zope.schema.TextLine(
+ title=u'Author Email',
+ description=u'Email address for the project author(s)',
+ required=False)
+
+ keywords = zope.schema.List(
+ title=u'Keywords',
+ description=u'A list of keywords related to the project, one per line.',
+ value_type=zope.schema.TextLine(),
+ required=False)
+
+ url = zope.schema.TextLine(
+ title=u'URL',
+ description=(u'The url for the project. Defaults to '
+ u'http://pypi.python.org/pypi/[project-name]'),
+ required=False)
+
+ classifiers = zope.schema.Set(
+ title=u"Trove Classifiers",
+ value_type=zope.schema.Choice(
+ vocabulary=troveClassiferVocabulary),
+ required=False)
+
+ commentHeader = zope.schema.Text(
+ title=u'Comment Header',
+ description=(u'A comment header that should appear at the top of every '
+ u'python file (like a license header).'),
+ required=False)
+
+ namespace_packages = zope.schema.List(
+ title=u'Namespace Packages',
+ description=(u'A list of namespace packages that should be created, one '
+ u'per line (i.e. zope or zc or z3c or collective)'),
+ value_type=zope.schema.TextLine(),
+ required=False)
+
+ install_requires = zope.schema.List(
+ title=u"Install Requires",
+ description=(u"A list of additional dependencies, one per line "
+ u"(i.e. lxml)"),
+ value_type=zope.schema.TextLine(),
+ required=False)
+
+ extras_require = zope.schema.Dict(
+ title=u"Extras Require",
+ key_type=zope.schema.TextLine(),
+ value_type=zope.schema.List(value_type=zope.schema.TextLine()))
+
+zope.interface.directlyProvides(IMetaDataFeature, IFeatureSchema)
+
+
+class ICommentHeaderZPLFeature(zope.interface.Interface):
+
+ author = zope.schema.TextLine(
+ title=u'Author(s)',
+ description=u'Name of the project author(s)',
+ required=False)
+
+ year = zope.schema.Int(
+ title=u"Year",
+ description=u'The copyright year',
+ default=datetime.date.today().year)
+
+zope.interface.directlyProvides(ICommentHeaderZPLFeature, IFeatureSchema)
+
+
+class IProprietaryHeaderFeature(zope.interface.Interface):
+
+ year = zope.schema.Int(
+ title=u"Year",
+ description=u'The copyright year',
+ default=datetime.date.today().year)
+
+ company = zope.schema.TextLine(
+ title=u'Company',
+ description=u'The name of your company, (i.e. Foo Inc.)')
+
+ location = zope.schema.TextLine(
+ title=u'Location',
+ description=u'Location of your company (i.e. San Francisco, USA)')
+
+zope.interface.directlyProvides(IProprietaryHeaderFeature, IFeatureSchema)
+
+
+class IPythonInterpreterFeature(zope.interface.Interface):
+
+ executableName = zope.schema.ASCIILine(
+ title=u'Executable',
+ description=(u'The path to the python executable. '
+ u'(i.e. /opt/python2.6/bin/python or just python)'),
+ default='python')
+
+zope.interface.directlyProvides(IPythonInterpreterFeature, IFeatureSchema)
+
+
+class ITestingFeature(zope.interface.Interface):
+
+ coverageDirectory = zope.schema.TextLine(
+ title=u"Coverage Directory",
+ description=u"Directory where test coverage data should be placed.",
+ default=u"${buildout:directory}/coverage")
+
+ coverageReportDirectory = zope.schema.TextLine(
+ title=u'Coverage Report Directory',
+ description=u'Directory where coverage reports should be generated',
+ default=u'${buildout:directory}/coverage/report')
+
+zope.interface.directlyProvides(ITestingFeature, IFeatureSchema)
+
+
+class IScriptFeature(zope.interface.Interface):
+
+ scriptName = zope.schema.TextLine(
+ title=u'Script Name',
+ description=(u'The name of the script that will '
+ u'be made available on the command line. '
+ u'Defaults to the name of the project.'),
+ required=False)
+
+ scriptFile = zope.schema.TextLine(
+ title=u'Script File',
+ description=u'The file where the script will be located',
+ default=u"script.py")
+
+ scriptFunction = zope.schema.TextLine(
+ title=u'Script Function',
+ description=u'The function in the script file that runs the script',
+ default=u"main")
+
+zope.interface.directlyProvides(IScriptFeature, IFeatureSchema)
+
+
+class IDocumentationFeature(zope.interface.Interface):
+
+ layoutTemplatePath = zope.schema.URI(
+ title=u'Layout Template',
+ description=u"URL for a layout template. Leave blank for default",
+ required=False)
+
+ cssPath = zope.schema.URI(
+ title=u'CSS url',
+ description=(u'URL for a css file that should be used. Leave blank '
+ u'for default.'),
+ required=False)
+
+ additionalEggs = zope.schema.List(
+ title=u'Additional Packages',
+ description=(u'Additional packages for which documentation should '
+ u'be built'),
+ value_type=zope.schema.TextLine(),
+ required=False)
+
+zope.interface.directlyProvides(IDocumentationFeature, IFeatureSchema)
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/interfaces.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.feature.core/trunk/src/z3c/feature/core/metadata.py
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/metadata.py (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/metadata.py 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,245 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Foundation 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.
+#
+##############################################################################
+"""Meta Data Feature
+
+$Id$
+"""
+import os
+import types
+import zope.interface
+from zope.schema.fieldproperty import FieldProperty
+
+from z3c.builder.core import project, buildout
+from z3c.builder.core.base import getTemplatePath, FileBuilder
+from z3c.builder.core.interfaces import IFileBuilder
+from z3c.feature.core import base, interfaces, xml
+
+
+METADATA_FEATURE_DOCUMENTATION = """
+The Metadata feature sets up the setup.py file which is what
+setuptools uses to generate distributable python eggs.
+"""
+
+COMMENT_HEADER_ZPL_DOCUMENTATION = """
+The Zope Public License file header looks something like this::
+
+%(header)s
+"""
+
+PROPRIETARY_HEADER_DOCUMENTATION = """
+The proprietary header looks something like this::
+
+%(header)s
+"""
+
+DOCUMENTATION_FEATURE_DOCUMENTATION = """
+The ReSTructured Text Documentation feature hooks up scripts
+for generating html (or latex for that matter) documentation
+from ReSTructured text files using Sphinx. There are a few
+pieces involved in this hookup:
+
+ #. ``buildout.cfg`` **part section**
+
+ This looks something like::
+
+ [docs]
+ recipe = z3c.recipe.sphinxdoc
+ eggs = yourproject [docs]
+ z3c.recipe.sphinxdoc
+ default.css =
+ layout.html =
+
+ This buildout part section will generate a script in the
+ bin directory called ``docs`` which you can run liket his::
+
+ $ ./bin/docs
+
+ Documentation will be put into the ``parts/docs/`` directory, with
+ one directory for each package specified in the eggs parameter of
+ the docs section. See the documentation for z3c.recipe.sphinxdoc
+ for more information. It can be found at
+
+ http://pypi.python.org/pypi/z3c.recipe.sphinxdoc
+
+ #. ``setup.py extras_require`` **section**
+
+ For the docs to build correctly, there must be a ``docs`` section in
+ ``extras_require`` that pulls in the Sphinx dependencies.
+
+ #. ``index.txt`` **file in project src**
+
+ An ``index.txt`` file will be added to the src directory. This
+ serves as the root document used by Sphinx to generate all the
+ documentation. See the Sphinx documentation for what sort of things
+ you can put in here at
+
+ http://sphinx.pocoo.org/
+"""
+
+class MetaDataFeature(base.BaseFeature):
+ zope.interface.implements(interfaces.IMetaDataFeature)
+
+ version = FieldProperty(interfaces.IMetaDataFeature['version'])
+ license = FieldProperty(interfaces.IMetaDataFeature['license'])
+ url = FieldProperty(interfaces.IMetaDataFeature['url'])
+ classifiers = FieldProperty(interfaces.IMetaDataFeature['classifiers'])
+ keywords = FieldProperty(interfaces.IMetaDataFeature['keywords'])
+ author = FieldProperty(interfaces.IMetaDataFeature['author'])
+ author_email = FieldProperty(interfaces.IMetaDataFeature['author_email'])
+ description = FieldProperty(interfaces.IMetaDataFeature['description'])
+ commentHeader = FieldProperty(interfaces.IMetaDataFeature['commentHeader'])
+ namespace_packages = FieldProperty(
+ interfaces.IMetaDataFeature['namespace_packages'])
+ install_requires = FieldProperty(
+ interfaces.IMetaDataFeature['install_requires'])
+ extras_require = FieldProperty(interfaces.IMetaDataFeature['extras_require'])
+
+ featureTitle = u'Metadata'
+ featureDocumentation = METADATA_FEATURE_DOCUMENTATION
+
+ @classmethod
+ def fromXMLNode(cls, node, omit=()):
+ feature = super(MetaDataFeature, cls).fromXMLNode(
+ node,
+ omit=('classifiers', 'extras_require'))
+
+ schema = base.getFeatureSchema(feature)
+ data = xml.extractData(node, schema)
+ classifiers = data.get('classifiers')
+
+ feature.classifiers = set()
+ if classifiers:
+ feature.classifiers = [c.strip() for c in classifiers.split('\n')]
+ return feature
+
+ def _applyTo(self, context):
+ """See ``z3c.feature.core.interfaces.IFeature``"""
+ # Assign all meta data to setup.
+ for name in ('version', 'license', 'url', 'keywords', 'author',
+ 'author_email', 'description', 'namespace_packages',
+ 'install_requires','extras_require'):
+ value = getattr(self, name)
+ if value is not None:
+ setattr(context.setup, name, value)
+ # Set the comment header.
+ if self.commentHeader is not None:
+ context.commentHeader = self.commentHeader
+
+
+class CommentHeaderZPLFeature(base.BaseFeature):
+ zope.interface.implements(interfaces.ICommentHeaderZPLFeature)
+
+ _template = unicode(open(getTemplatePath('zpl-header.py')).read())
+
+ year = FieldProperty(interfaces.ICommentHeaderZPLFeature['year'])
+ author = FieldProperty(interfaces.ICommentHeaderZPLFeature['author'])
+
+ featureTitle = u'ZPL Header'
+
+ @property
+ def featureDocumentation(self):
+ """See ``z3c.feature.core.interfaces.IFeature``"""
+ header = ' ' + self.renderCommentHeader().replace('\n', '\n ')
+ return COMMENT_HEADER_ZPL_DOCUMENTATION % {'header':header}
+
+ def renderCommentHeader(self):
+ return self._template % dict(year=self.year,
+ author=self.author)
+
+ def _applyTo(self, context):
+ """See ``z3c.feature.core.interfaces.IFeature``"""
+ context.commentHeader = self.renderCommentHeader()
+
+
+class ProprietaryHeaderFeature(base.BaseFeature):
+ zope.interface.implements(interfaces.IProprietaryHeaderFeature)
+
+ _template = unicode(open(getTemplatePath('proprietary-header.py')).read())
+
+ year = FieldProperty(interfaces.IProprietaryHeaderFeature['year'])
+ company = FieldProperty(interfaces.IProprietaryHeaderFeature['company'])
+ location = FieldProperty(interfaces.IProprietaryHeaderFeature['location'])
+
+ featureTitle = u'Proprietary Header'
+
+ @property
+ def featureDocumentation(self):
+ """See ``z3c.feature.core.interfaces.IFeature``"""
+ header = ' ' + self.renderCommentHeader().replace('\n', '\n ')
+ return PROPRIETARY_HEADER_DOCUMENTATION % {'header':header}
+
+ def renderCommentHeader(self):
+ return self._template % dict(year=self.year,
+ company=self.company,
+ location=self.location)
+
+ def _applyTo(self, context):
+ """See ``z3c.feature.core.interfaces.IFeature``"""
+ context.commentHeader = self.renderCommentHeader()
+
+
+class DocumentationFileBuilder(FileBuilder):
+
+ template = os.path.join(
+ os.path.dirname(__file__), 'file-templates', 'index-template.txt')
+
+ def update(self):
+ project = self.getProject()
+ self.title = project.name + ' Documentation'
+ self.TOC = []
+ for builder in self.__parent__.values():
+ if (IFileBuilder.providedBy(builder) and
+ builder.filename.endswith('.txt') and
+ builder is not self):
+
+ self.TOC.append(builder.filename[:-4])
+
+ def render(self):
+ heading = '%(border)s\n%(title)s\n%(border)s' % dict(
+ border='='*len(self.title),
+ title=self.title)
+ TOC = '\n '.join(self.TOC)
+ return open(self.template).read() % dict(heading=heading,
+ TOC=TOC)
+
+class DocumentationFeature(base.BaseFeature):
+ zope.interface.implements(interfaces.IDocumentationFeature)
+
+ layoutTemplatePath = FieldProperty(
+ interfaces.IDocumentationFeature['layoutTemplatePath'])
+ cssPath = FieldProperty(
+ interfaces.IDocumentationFeature['cssPath'])
+ additionalEggs = FieldProperty(
+ interfaces.IDocumentationFeature['additionalEggs'])
+
+ featureTitle = u'Restructured Text Documentation'
+ featureDocumentation = DOCUMENTATION_FEATURE_DOCUMENTATION
+
+ def _applyTo(self, context):
+ """See ``z3c.feature.core.interfaces.IFeature``"""
+ docsPart = buildout.PartBuilder(u'docs')
+ docsPart.addValue('recipe', 'z3c.recipe.sphinxdoc')
+ eggs = [context.name+' [docs]'] + (self.additionalEggs or [])
+ eggsString = 'z3c.recipe.sphinxdoc'
+ for egg in eggs:
+ eggsString += '\n '+egg
+ docsPart.addValue('eggs', eggsString)
+ docsPart.addValue('layout.html', self.layoutTemplatePath or '')
+ docsPart.addValue('default.css', self.cssPath or '')
+ context.buildout.add(docsPart)
+
+ context.setup.addExtrasRequires('docs', ['Sphinx'])
+
+ indexBuilder = DocumentationFileBuilder(u'index.txt')
+ context.package.add(indexBuilder)
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/metadata.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.feature.core/trunk/src/z3c/feature/core/metadata.txt
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/metadata.txt (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/metadata.txt 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,393 @@
+=================
+Metadata Features
+=================
+
+The `metadata` module provides several features related to the overall setup
+of a package.
+
+ >>> from z3c.feature.core import metadata, interfaces
+
+Meta-Data Feature
+-----------------
+
+The meta-data feature maintains all attributes that are needed for the
+`setup.py` file.
+
+ >>> feature = metadata.MetaDataFeature()
+ >>> feature
+ <MetaDataFeature u'Metadata'>
+
+ >>> feature.version = u'0.0.1'
+ >>> feature.author = u'Paul Carduner'
+ >>> feature.keywords = [u'test', u'some', u'more']
+
+Let's verify that both, the `IFeature` and `IMetaDataFeature` interface, are
+provided:
+
+ >>> from zope.interface.verify import verifyObject
+ >>> verifyObject(interfaces.IFeature, feature)
+ True
+ >>> verifyObject(interfaces.IMetaDataFeature, feature)
+ True
+
+The feature schema is:
+
+ >>> from z3c.feature.core import base
+ >>> base.getFeatureSchema(feature)
+ <InterfaceClass z3c.feature.core.interfaces.IMetaDataFeature>
+
+Good documentation is also provided:
+
+ >>> print feature.featureTitle
+ Metadata
+ >>> print feature.featureDocumentation
+ The Metadata feature sets up the setup.py file which is what
+ setuptools uses to generate distributable python eggs.
+
+This is a singleton feature:
+
+ >>> feature.featureSingleton
+ True
+
+Serialization to XML works:
+
+ >>> print feature.toXML(True, True)
+ <feature type="z3c.feature.core:meta-data">
+ <author>Paul Carduner</author>
+ <version>0.0.1</version>
+ <keywords>
+ <item>test</item>
+ <item>some</item>
+ <item>more</item>
+ </keywords>
+ </feature>
+
+Deserialization from XML works:
+
+ >>> feature = metadata.MetaDataFeature.fromXML('''\
+ ... <feature type="z3c.feature.core:meta-data">
+ ... <author>Paul Carduner</author>
+ ... <version>0.0.1</version>
+ ... <keywords>
+ ... <item>test</item>
+ ... <item>some</item>
+ ... <item>more</item>
+ ... </keywords>
+ ... </feature>
+ ... ''')
+ >>> feature
+ <MetaDataFeature u'Metadata'>
+
+ >>> feature.author
+ u'Paul Carduner'
+ >>> feature.version
+ u'0.0.1'
+ >>> feature.keywords
+ [u'test', u'some', u'more']
+
+Let's now apply the feature to a project:
+
+ >>> from z3c.builder.core import project
+ >>> prj = project.BuildoutProjectBuilder(u'test')
+
+ >>> feature.update()
+ >>> feature.applyTo(prj)
+
+And the data is applied:
+
+ >>> prj.setup.author
+ u'Paul Carduner'
+ >>> prj.setup.version
+ u'0.0.1'
+ >>> prj.setup.keywords
+ [u'test', u'some', u'more']
+
+Okay, we applied the feature successfully by updating the necessary meta-data.
+
+
+ZPL Comment Header
+------------------
+
+This feature sets the comment header for a given project. That header will be
+applied to all Python code files.
+
+ >>> feature = metadata.CommentHeaderZPLFeature()
+ >>> feature
+ <CommentHeaderZPLFeature u'ZPL Header'>
+
+ >>> feature.year = 2008
+ >>> feature.author = u'Paul Carduner'
+
+Let's verify that both, the `IFeature` and `ICommentHeaderZPLFeature`
+interface, are provided:
+
+ >>> verifyObject(interfaces.IFeature, feature)
+ True
+ >>> verifyObject(interfaces.ICommentHeaderZPLFeature, feature)
+ True
+
+The feature schema is:
+
+ >>> base.getFeatureSchema(feature)
+ <InterfaceClass z3c.feature.core.interfaces.ICommentHeaderZPLFeature>
+
+Good documentation is also provided:
+
+ >>> print feature.featureTitle
+ ZPL Header
+ >>> print feature.featureDocumentation
+ <BLANKLINE>
+ The Zope Public License file header looks something like this::
+ <BLANKLINE>
+ ##############################################################################
+ #
+ # Copyright (c) 2008 Paul Carduner.
+ # 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.
+ #
+ ##############################################################################
+
+This is a singleton feature:
+
+ >>> feature.featureSingleton
+ True
+
+Serialization to XML works:
+
+ >>> print feature.toXML(True, True)
+ <feature type="z3c.feature.core:comment-header-ZPL">
+ <year>2008</year>
+ <author>Paul Carduner</author>
+ </feature>
+
+Deserialization from XML works:
+
+ >>> feature = metadata.CommentHeaderZPLFeature.fromXML('''\
+ ... <feature type="z3c.feature.core:comment-header-ZPL">
+ ... <year>2008</year>
+ ... <author>Paul Carduner</author>
+ ... </feature>
+ ... ''')
+ >>> feature
+ <CommentHeaderZPLFeature u'ZPL Header'>
+
+ >>> feature.author
+ u'Paul Carduner'
+ >>> feature.year
+ 2008
+
+Let's now apply the feature to a project:
+
+ >>> from z3c.builder.core import project
+ >>> prj = project.BuildoutProjectBuilder(u'test')
+
+ >>> feature.update()
+ >>> feature.applyTo(prj)
+
+And the data is applied:
+
+ >>> print prj.commentHeader
+ ##############################################################################
+ #
+ # Copyright (c) 2008 Paul Carduner.
+ # 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.
+ #
+ ##############################################################################
+
+
+Proprietary Comment Header
+--------------------------
+
+This feature sets the proprietary comment header for a given project. That
+header will be applied to all Python code files.
+
+ >>> feature = metadata.ProprietaryHeaderFeature()
+ >>> feature
+ <ProprietaryHeaderFeature u'Proprietary Header'>
+
+ >>> feature.year = 2008
+ >>> feature.company = u'Paulo, Inc.'
+ >>> feature.location = u'Berkeley, CA, USA'
+
+Let's verify that both, the `IFeature` and `IProprietaryHeaderFeature`
+interface, are provided:
+
+ >>> verifyObject(interfaces.IFeature, feature)
+ True
+ >>> verifyObject(interfaces.IProprietaryHeaderFeature, feature)
+ True
+
+The feature schema is:
+
+ >>> base.getFeatureSchema(feature)
+ <InterfaceClass z3c.feature.core.interfaces.IProprietaryHeaderFeature>
+
+Good documentation is also provided:
+
+ >>> print feature.featureTitle
+ Proprietary Header
+ >>> print feature.featureDocumentation
+ <BLANKLINE>
+ The proprietary header looks something like this::
+ <BLANKLINE>
+ ###############################################################################
+ #
+ # Copyright 2008 by Paulo, Inc., Berkeley, CA, USA
+ #
+ ###############################################################################
+
+This is a singleton feature:
+
+ >>> feature.featureSingleton
+ True
+
+Serialization to XML works:
+
+ >>> print feature.toXML(True, True)
+ <feature type="z3c.feature.core:proprietary-header">
+ <company>Paulo, Inc.</company>
+ <location>Berkeley, CA, USA</location>
+ <year>2008</year>
+ </feature>
+
+Deserialization from XML works:
+
+ >>> feature = metadata.ProprietaryHeaderFeature.fromXML('''\
+ ... <feature type="z3c.feature.core:proprietary-header">
+ ... <company>Paulo, Inc.</company>
+ ... <location>Berkeley, CA, USA</location>
+ ... <year>2008</year>
+ ... </feature>
+ ... ''')
+ >>> feature
+ <ProprietaryHeaderFeature u'Proprietary Header'>
+
+ >>> feature.year
+ 2008
+ >>> feature.company
+ u'Paulo, Inc.'
+ >>> feature.location
+ u'Berkeley, CA, USA'
+
+Let's now apply the feature to a project:
+
+ >>> from z3c.builder.core import project
+ >>> prj = project.BuildoutProjectBuilder(u'test')
+
+ >>> feature.update()
+ >>> feature.applyTo(prj)
+
+And the data is applied:
+
+ >>> print prj.commentHeader
+ ###############################################################################
+ #
+ # Copyright 2008 by Paulo, Inc., Berkeley, CA, USA
+ #
+ ###############################################################################
+
+
+Documentation Feature
+---------------------
+
+This feature installs a buildout part that creates a script for a
+documentation generator of the package.
+
+ >>> feature = metadata.DocumentationFeature()
+ >>> feature
+ <DocumentationFeature u'Restructured Text Documentation'>
+
+ >>> feature.additionalEggs = [u'package2']
+
+Let's verify that both, the `IFeature` and `IDocumentationFeature`
+interface, are provided:
+
+ >>> verifyObject(interfaces.IFeature, feature)
+ True
+ >>> verifyObject(interfaces.IDocumentationFeature, feature)
+ True
+
+The feature schema is:
+
+ >>> base.getFeatureSchema(feature)
+ <InterfaceClass z3c.feature.core.interfaces.IDocumentationFeature>
+
+Good documentation is also provided:
+
+ >>> print feature.featureTitle
+ Restructured Text Documentation
+ >>> print feature.featureDocumentation
+ <BLANKLINE>
+ The ReSTructured Text Documentation feature hooks up scripts
+ for generating html (or latex for that matter) documentation
+ from ReSTructured text files using Sphinx. There are a few
+ pieces involved in this hookup:
+ ...
+
+This is a singleton feature:
+
+ >>> feature.featureSingleton
+ True
+
+Serialization to XML works:
+
+ >>> print feature.toXML(True, True)
+ <feature type="z3c.feature.core:documentation">
+ <additionalEggs>
+ <item>package2</item>
+ </additionalEggs>
+ </feature>
+
+Deserialization from XML works:
+
+ >>> feature = metadata.DocumentationFeature.fromXML('''\
+ ... <feature type="z3c.feature.core:documentation">
+ ... <additionalEggs>
+ ... <item>package2</item>
+ ... </additionalEggs>
+ ... </feature>
+ ... ''')
+ >>> feature
+ <DocumentationFeature u'Restructured Text Documentation'>
+
+ >>> feature.additionalEggs
+ [u'package2']
+
+Let's now apply the feature to a project:
+
+ >>> from z3c.builder.core import project
+ >>> prj = project.BuildoutProjectBuilder(u'test')
+
+ >>> feature.update()
+ >>> feature.applyTo(prj)
+
+And the data is applied:
+
+ >>> prj.update()
+ >>> print prj.buildout.render()
+ [buildout]
+ extends = http://download.zope.org/zope3.4/3.4.0/versions.cfg
+ develop = .
+ parts = docs
+ versions = versions
+ <BLANKLINE>
+ [docs]
+ recipe = z3c.recipe.sphinxdoc
+ eggs = z3c.recipe.sphinxdoc
+ test [docs]
+ package2
+ layout.html =
+ default.css =
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/metadata.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.feature.core/trunk/src/z3c/feature/core/python-package-project.xml
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/python-package-project.xml (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/python-package-project.xml 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,16 @@
+<project name="helloworld">
+ <feature type="z3c.feature.core:meta-data">
+ <author>?</author>
+ <author-email>?</author-email>
+ <description>?</description>
+ <version>?</version>
+ <license>?</license>
+ <url>?</url>
+ <keywords>?</keywords>
+ <namespace-packages>?</namespace-packages>
+ <install-requires>?</install-requires>
+ </feature>
+ <feature type="z3c.feature.core:python-interpreter" />
+ <feature type="z3c.feature.core:unit-testing" />
+ <feature type="z3c.feature.core:documentation" />
+</project>
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/python-package-project.xml
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.feature.core/trunk/src/z3c/feature/core/python.py
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/python.py (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/python.py 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,126 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Foundation 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.
+#
+##############################################################################
+"""Core Python Features
+
+$Id$
+"""
+import zope.interface
+from zope.schema.fieldproperty import FieldProperty
+
+from z3c.builder.core import project, buildout
+from z3c.builder.core.python import ModuleBuilder, FunctionBuilder
+from z3c.feature.core import base, interfaces, xml
+
+
+PYTHON_INTERPRETER_DOCUMENTATION = """
+The Python Interpreter feature creates an alias to whatever python
+interpreter you want inside your project's bin/ directory.
+Furthermore, it adds your project and all its egg dependencies to the
+python path. After running buildout from your project directory you
+can start up the interpreter as normal::
+
+ $ ./bin/python
+
+ >>> from myproject import mymodule
+ >>> form a.dependency import something
+"""
+
+SCRIPT_FEATURE_DOCUMENTATION = """
+The Command Line Script Feature exposes a python function in your
+project as a command line script. There are several pieces to this:
+
+ #. **The script file.**
+
+ There is a script file located at %(scriptFile)s with a function
+ in it called %(scriptFunction)s. This is what you should modify to
+ make your script actually do something.
+
+ #. **Setuptools entry point.**
+
+ When someone installs your project using setuptools, for example
+ with the command::
+
+ $ easy_install yourproject
+
+ any entry points in the console_script group will turn into
+ executable scripts that the end user can just run. This make your
+ project into an application and not just a set of python
+ libraries.
+
+ The entry point is created by modifying the ``setup.py`` file.
+ Look for the keyword parameter called entry_points.
+
+ #. ``scripts`` **buildout part.**
+
+ Finally there is also a part added to buildout.cfg that makes the
+ script defined in the entry point available in the projects bin/
+ directory. This is only for development purposes.
+"""
+
+class PythonInterpreterFeature(base.BaseFeature):
+ zope.interface.implements(interfaces.IPythonInterpreterFeature)
+
+ executableName = FieldProperty(
+ interfaces.IPythonInterpreterFeature['executableName'])
+
+ featureTitle = u'Python Interpreter'
+ featureDocumentation = PYTHON_INTERPRETER_DOCUMENTATION
+
+ def _applyTo(self, context):
+ pythonPartBuilder = buildout.PartBuilder(u'python')
+ pythonPartBuilder.addValue('recipe', 'zc.recipe.egg')
+ pythonPartBuilder.addValue('interpreter', self.executableName)
+ pythonPartBuilder.addValue('eggs', context.name)
+ context.buildout.add(pythonPartBuilder)
+
+
+class ScriptFeature(base.BaseFeature):
+ zope.interface.implements(interfaces.IScriptFeature)
+
+ scriptName = FieldProperty(interfaces.IScriptFeature['scriptName'])
+ scriptFile = FieldProperty(interfaces.IScriptFeature['scriptFile'])
+ scriptFunction = FieldProperty(interfaces.IScriptFeature['scriptFunction'])
+
+ featureTitle = u'Command Line Script'
+
+ @property
+ def featureDocumentation(self):
+ return SCRIPT_FEATURE_DOCUMENTATION % dict(
+ scriptFunction=self.scriptFunction,
+ scriptFile=self.scriptFile)
+
+ def _applyTo(self, context):
+ scriptName = self.scriptName or context.name
+ moduleBuilder = ModuleBuilder(self.scriptFile)
+ moduleBuilder.add(FunctionBuilder(
+ self.scriptFunction,
+ kwargs={'args':None},
+ docstring=('Runs the %s script '
+ 'from the %s project') % (scriptName, context.name),
+ code='print "Successfully ran the %s script"' % scriptName
+ ))
+
+ context.package.add(moduleBuilder)
+
+ context.setup.addEntryPoints(
+ 'console_scripts', ['%s = %s.%s:%s' % (scriptName,
+ context.name,
+ self.scriptFile[:-3],
+ self.scriptFunction)])
+
+ scriptsPart = buildout.PartBuilder(u'scripts')
+ scriptsPart.addValue('recipe','zc.recipe.egg:scripts')
+ scriptsPart.addValue('eggs', context.name)
+ scriptsPart.addValue('script', scriptName)
+ context.buildout.add(scriptsPart)
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/python.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.feature.core/trunk/src/z3c/feature/core/python.txt
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/python.txt (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/python.txt 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,230 @@
+===============
+Python Features
+===============
+
+The Python features are designed to write Python code and setup the Python
+interpreter.
+
+ >>> from z3c.feature.core import python, interfaces
+
+
+Python Interpreter
+------------------
+
+This feature installs the buildout recipe to create a Python interpreter with
+the context of the package.
+
+ >>> feature = python.PythonInterpreterFeature()
+ >>> feature
+ <PythonInterpreterFeature u'Python Interpreter'>
+
+ >>> feature.executableName = 'py'
+
+Let's verify that both, the `IFeature` and `IPythonInterpreterFeature`
+interface, are provided:
+
+ >>> from zope.interface.verify import verifyObject
+ >>> verifyObject(interfaces.IFeature, feature)
+ True
+ >>> verifyObject(interfaces.IPythonInterpreterFeature, feature)
+ True
+
+The feature schema is:
+
+ >>> from z3c.feature.core import base
+ >>> base.getFeatureSchema(feature)
+ <InterfaceClass z3c.feature.core.interfaces.IPythonInterpreterFeature>
+
+Good documentation is also provided:
+
+ >>> print feature.featureTitle
+ Python Interpreter
+ >>> print feature.featureDocumentation
+ <BLANKLINE>
+ The Python Interpreter feature creates an alias to whatever python
+ interpreter you want inside your project's bin/ directory.
+ Furthermore, it adds your project and all its egg dependencies to the
+ python path. After running buildout from your project directory you
+ can start up the interpreter as normal::
+ <BLANKLINE>
+ $ ./bin/python
+ ...
+
+This is a singleton feature:
+
+ >>> feature.featureSingleton
+ True
+
+Serialization to XML works:
+
+ >>> print feature.toXML(True, True)
+ <feature type="z3c.feature.core:python-interpreter">
+ <executableName>py</executableName>
+ </feature>
+
+Deserialization from XML works:
+
+ >>> feature = python.PythonInterpreterFeature.fromXML('''\
+ ... <feature type="z3c.feature.core:python-interpreter">
+ ... <executableName>py</executableName>
+ ... </feature>
+ ... ''')
+ >>> feature
+ <PythonInterpreterFeature u'Python Interpreter'>
+
+ >>> feature.executableName
+ 'py'
+
+Let's now apply the feature to a project:
+
+ >>> from z3c.builder.core import project
+ >>> prj = project.BuildoutProjectBuilder(u'test')
+
+ >>> feature.update()
+ >>> feature.applyTo(prj)
+
+And the data is applied:
+
+ >>> prj.buildout.update()
+ >>> print prj.buildout.render()
+ [buildout]
+ extends = http://download.zope.org/zope3.4/3.4.0/versions.cfg
+ develop = .
+ parts = python
+ versions = versions
+ <BLANKLINE>
+ [python]
+ recipe = zc.recipe.egg
+ interpreter = py
+ eggs = test
+
+Okay, we applied the feature successfully by creating an interpreter part.
+
+
+Script Feature
+--------------
+
+This feature installs the buildout recipe to create a Python interpreter with
+the context of the package.
+
+ >>> feature = python.ScriptFeature()
+ >>> feature
+ <ScriptFeature u'Command Line Script'>
+
+ >>> feature.scriptName = u'demo'
+ >>> feature.scriptFile = u'demo.py'
+ >>> feature.scriptFunction = u'script'
+
+Let's verify that both, the `IFeature` and `IScriptFeature` interface, are
+provided:
+
+ >>> verifyObject(interfaces.IFeature, feature)
+ True
+ >>> verifyObject(interfaces.IScriptFeature, feature)
+ True
+
+The feature schema is:
+
+ >>> base.getFeatureSchema(feature)
+ <InterfaceClass z3c.feature.core.interfaces.IScriptFeature>
+
+Good documentation is also provided:
+
+ >>> print feature.featureTitle
+ Command Line Script
+ >>> print feature.featureDocumentation
+ The Command Line Script Feature exposes a python function in your
+ project as a command line script. There are several pieces to this...
+
+This is a singleton feature:
+
+ >>> feature.featureSingleton
+ True
+
+Serialization to XML works:
+
+ >>> print feature.toXML(True, True)
+ <feature type="z3c.feature.core:script">
+ <scriptName>demo</scriptName>
+ <scriptFile>demo.py</scriptFile>
+ <scriptFunction>script</scriptFunction>
+ </feature>
+
+Deserialization from XML works:
+
+ >>> feature = python.ScriptFeature.fromXML('''\
+ ... <feature type="z3c.feature.core:script">
+ ... <scriptName>demo</scriptName>
+ ... <scriptFile>demo.py</scriptFile>
+ ... <scriptFunction>script</scriptFunction>
+ ... </feature>
+ ... ''')
+ >>> feature
+ <ScriptFeature u'Command Line Script'>
+
+ >>> feature.scriptName
+ u'demo'
+ >>> feature.scriptFile
+ u'demo.py'
+ >>> feature.scriptFunction
+ u'script'
+
+Let's now apply the feature to a project:
+
+ >>> from z3c.builder.core import project
+ >>> prj = project.BuildoutProjectBuilder(u'test')
+
+ >>> feature.update()
+ >>> feature.applyTo(prj)
+
+And the data is applied:
+
+ >>> prj.update()
+
+ >>> print prj.buildout.render()
+ [buildout]
+ extends = http://download.zope.org/zope3.4/3.4.0/versions.cfg
+ develop = .
+ parts = scripts
+ versions = versions
+ <BLANKLINE>
+ [scripts]
+ recipe = zc.recipe.egg:scripts
+ eggs = test
+ script = demo
+
+ >>> print prj.setup.render()
+ #...
+ setup (
+ name = 'test',
+ version = '0.1.0',
+ author = u"",
+ author_email = u"",
+ description = u"",
+ license = "GPLv3",
+ keywords = u"",
+ url = "http://pypi.python.org/pypi/test",
+ classifiers = [],
+ packages = find_packages('src'),
+ include_package_data = True,
+ package_dir = {'':'src'},
+ namespace_packages = [],
+ extras_require = {},
+ install_requires = [
+ 'setuptools',
+ ],
+ zip_safe = False,
+ entry_points = {'console_scripts': [u'demo = test.demo:script']},
+ )
+
+ >>> print prj.package['demo.py'].render()
+ ##############################################################################
+ #
+ # This file is part of test...
+ #
+ ##############################################################################
+ """Module Documentation"""
+ <BLANKLINE>
+ def script(args=None):
+ """Runs the demo script from the test project"""
+ print "Successfully ran the demo script"
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/python.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.feature.core/trunk/src/z3c/feature/core/template.py
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/template.py (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/template.py 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,69 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Foundation 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.
+#
+##############################################################################
+"""Core Python Features
+
+$Id$
+"""
+import os
+import pkg_resources
+from zope.interface import classImplements
+from z3c.feature.core import interfaces, xml
+
+
+class FileBasedTemplateBase(object):
+
+ filename = None
+
+ def getFeatures(self):
+ if self.filename is None:
+ raise ValueError("Missing filename attribute.")
+ return xml.getFeaturesDict(open(self.filename))
+
+
+def FileBasedTemplate(filename, title, description):
+ FileBasedTemplate = type(
+ '<FileBasedTemplate for %s' % filename,
+ (FileBasedTemplateBase,), dict(title=title,
+ description=description,
+ filename=filename))
+
+ classImplements(FileBasedTemplate, interfaces.IFileBasedTemplateProvider)
+ return FileBasedTemplate
+
+
+def getTemplateList():
+ names = set()
+ templates = {}
+ for entryPoint in pkg_resources.working_set.iter_entry_points('z3c.boiler.template'):
+ template = entryPoint.load()()
+ if entryPoint.name in names:
+ name = entryPoint.dist.project_name+':'+entryPoint.name
+ else:
+ name = entryPoint.name
+ templates[name] = template
+ return templates
+
+
+def getTemplate(name):
+ return getTemplateList()[name]
+
+CommandLineProjectTemplate = FileBasedTemplate(
+ os.path.join(os.path.dirname(__file__),"command-line-project.xml"),
+ u"Command Line Program",
+ u"Includes all the features you would want for a command line program.")
+
+PythonPackageProjectTemplate = FileBasedTemplate(
+ os.path.join(os.path.dirname(__file__),"python-package-project.xml"),
+ u"Python Package",
+ u"Just a simple python package with few bells and whistles.")
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/template.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.feature.core/trunk/src/z3c/feature/core/testing.py
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/testing.py (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/testing.py 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,51 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Foundation 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.
+#
+##############################################################################
+"""Testing Support
+
+$Id$
+"""
+
+
+class EntryPoint(object):
+
+ def __init__(self, group, name, klass, dist):
+ self.group = group
+ self.name = name
+ self.klass = klass
+ self.dist = dist
+
+ def load(self):
+ return self.klass
+
+class FeatureDistribution(object):
+
+ project_name = 'z3c.feature.testing'
+ key = 'z3c.feature.testing'
+ location = 'z3c.feature.testing'
+
+ def __init__(self):
+ self.entryPoints = {}
+
+ def addEntryPoint(self, group, name, klass):
+ eps = self.entryPoints.setdefault(group, {})
+ eps[name] = EntryPoint(group, name, klass, self)
+
+ def get_entry_map(self, group):
+ return self.entryPoints[group]
+
+ def insert_on(self, entries, entry):
+ entries.append(self.location)
+
+ def activate(self):
+ pass
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/testing.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.feature.core/trunk/src/z3c/feature/core/tests/__init__.py
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/tests/__init__.py (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/tests/__init__.py 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1 @@
+#package
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/tests/__init__.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.feature.core/trunk/src/z3c/feature/core/tests/test_doc.py
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/tests/test_doc.py (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/tests/test_doc.py 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,67 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation 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.
+#
+##############################################################################
+"""Test Setup.
+
+$Id$
+"""
+import os
+import shutil
+import unittest
+import tempfile
+import logging
+import zope.testing.doctest
+import zope.component
+from zope.configuration import xmlconfig
+from z3c.builder.core import testing
+
+def test_suite():
+ return unittest.TestSuite((
+
+ zope.testing.doctest.DocFileSuite(
+ '../README.txt',
+ optionflags=zope.testing.doctest.NORMALIZE_WHITESPACE |
+ zope.testing.doctest.ELLIPSIS),
+
+ zope.testing.doctest.DocFileSuite(
+ '../example.txt',
+ optionflags=zope.testing.doctest.NORMALIZE_WHITESPACE |
+ zope.testing.doctest.ELLIPSIS),
+
+ zope.testing.doctest.DocFileSuite(
+ '../base.txt',
+ optionflags=zope.testing.doctest.NORMALIZE_WHITESPACE |
+ zope.testing.doctest.ELLIPSIS),
+
+ zope.testing.doctest.DocFileSuite(
+ '../metadata.txt',
+ optionflags=zope.testing.doctest.NORMALIZE_WHITESPACE |
+ zope.testing.doctest.ELLIPSIS),
+
+ zope.testing.doctest.DocFileSuite(
+ '../python.txt',
+ optionflags=zope.testing.doctest.NORMALIZE_WHITESPACE |
+ zope.testing.doctest.ELLIPSIS),
+
+ zope.testing.doctest.DocFileSuite(
+ '../unittest.txt',
+ optionflags=zope.testing.doctest.NORMALIZE_WHITESPACE |
+ zope.testing.doctest.ELLIPSIS),
+
+ zope.testing.doctest.DocFileSuite(
+ '../xml.txt',
+ setUp=testing.buildSetUp, tearDown=testing.buildTearDown,
+ optionflags=zope.testing.doctest.NORMALIZE_WHITESPACE |
+ zope.testing.doctest.ELLIPSIS),
+
+ ))
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/tests/test_doc.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.feature.core/trunk/src/z3c/feature/core/unittest.py
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/unittest.py (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/unittest.py 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,129 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Foundation 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.
+#
+##############################################################################
+"""Unit Testing Feature
+
+$Id$
+"""
+import os
+import zope.interface
+from zope.schema.fieldproperty import FieldProperty
+
+from z3c.builder.core import buildout, python
+from z3c.builder.core.base import SimpleFileBuilder
+from z3c.feature.core import base, interfaces
+
+TESTING_DOCUMENTATION = """
+The Automated Testing feature generates boiler plate code for running
+unittests, specifically in the form of DocTests. Here are the various
+pieces generated by the Automated Testing Feature:
+
+ 1. **new buildout.cfg sections**
+
+ Three new sections are added to the buildout.cfg file. Each
+ correspond to executable scripts in the bin/ directory. There is
+ a test runner which you can run with this command::
+
+ $ ./bin/test
+
+ There are many command line options that can be used by the test
+ runner. See them all by running::
+
+ $ ./bin/test --help
+
+ You can also generate coverage reports for the tests with the command::
+
+ $ ./bin/coverage-test
+
+ This runs the same test runner as ``./bin/test`` buts adds on the
+ options for generating coverage reports which are always a little
+ painful to remember. By default, this will put all the reports in
+ a ``coverage/`` directory. After you have generated the coverage
+ reports, you render them into nice color-coded html pages with
+ this command::
+
+ $ ./bin/coverage-report
+
+ 2. **new setup.py extras_require section**
+
+ In order to support the test runner, a new extras_require section
+ called ``test`` is added to the ``setup.py`` file. This pulls in
+ z3c.coverage and zope.testing.
+
+ 3. **``tests`` module**
+
+ The test runner will search through your project src for modules
+ starting with the name ``test``. The Automated Testing feature
+ adds a sub package named ``tests`` to the project source, and adds
+ a python module called ``test_doc.py`` into the tests module. The
+ test_doc module hooks up the test suite that references the doc
+ tests.
+"""
+
+class TestingFeature(base.BaseFeature):
+ zope.interface.implements(interfaces.ITestingFeature)
+
+ iface = interfaces.ITestingFeature
+
+ coverageDirectory = FieldProperty(
+ interfaces.ITestingFeature['coverageDirectory'])
+ coverageReportDirectory = FieldProperty(
+ interfaces.ITestingFeature['coverageReportDirectory'])
+
+ featureTitle = u'Automated Tests'
+ featureDocumentation = TESTING_DOCUMENTATION
+
+ def _applyTo(self, project):
+ testPartBuilder = buildout.PartBuilder(
+ u'test',
+ values=[('recipe','zc.recipe.testrunner'),
+ ('eggs',project.projectName+' [test]')])
+
+ project.buildout.add(testPartBuilder)
+
+ coverageTestPart = buildout.PartBuilder(
+ u'coverage-test',
+ values=[('recipe','zc.recipe.testrunner'),
+ ('eggs',project.projectName+' [test]'),
+ ('defaults',"['--coverage', '%s']" % self.coverageDirectory)])
+
+ project.buildout.add(coverageTestPart)
+
+ coverageReportPart = buildout.PartBuilder(
+ u'coverage-report',
+ values=[('recipe','zc.recipe.egg'),
+ ('eggs','z3c.coverage'),
+ ('scripts','coverage=coverage-report'),
+ ('arguments',"('coverage', '%s')" % self.coverageReportDirectory)])
+
+ project.buildout.add(coverageReportPart)
+
+ project.setup.addExtrasRequires('test',('zope.testing',
+ 'z3c.coverage'))
+
+ project.package.add(python.PackageBuilder(u'tests'))
+ project.package['tests'].add(
+ SimpleFileBuilder(u'test_doc.py',
+ template=os.path.join(
+ os.path.dirname(__file__),
+ 'file-templates',
+ 'test_doc.py')
+ ))
+
+ project.package.add(
+ SimpleFileBuilder(u'README.txt',
+ template=os.path.join(
+ os.path.dirname(__file__),
+ 'file-templates',
+ 'README.txt')
+ ))
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/unittest.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.feature.core/trunk/src/z3c/feature/core/unittest.txt
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/unittest.txt (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/unittest.txt 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,96 @@
+=====================
+Unit Testing Features
+=====================
+
+ >>> from z3c.feature.core import interfaces, unittest
+
+Testing Feature
+---------------
+
+The testing feature provides automated testing hook up.
+
+ >>> feature = unittest.TestingFeature()
+ >>> from zope.interface.verify import verifyObject
+ >>> verifyObject(interfaces.ITestingFeature, feature)
+ True
+
+ >>> print feature.featureTitle
+ Automated Tests
+
+We can also convert this to xml.
+
+ >>> print feature.toXML(True, True)
+ <feature type="z3c.feature.core:unit-testing"/>
+
+Let's see how the testing feature modifies the project builder. First
+it adds buildout parts for running the tests, with and without
+coverage reports and for generating coverage reports.
+
+ >>> from z3c.builder.core.project import BuildoutProjectBuilder
+ >>> project = BuildoutProjectBuilder(u'someproject')
+
+ >>> feature.applyTo(project)
+
+ >>> project.update()
+ >>> print project.buildout.render()
+ [buildout]
+ extends = http://download.zope.org/zope3.4/3.4.0/versions.cfg
+ develop = .
+ parts = test coverage-test coverage-report
+ versions = versions
+ <BLANKLINE>
+ [test]
+ recipe = zc.recipe.testrunner
+ eggs = someproject [test]
+ <BLANKLINE>
+ [coverage-test]
+ recipe = zc.recipe.testrunner
+ eggs = someproject [test]
+ defaults = ['--coverage', '${buildout:directory}/coverage']
+ <BLANKLINE>
+ [coverage-report]
+ recipe = zc.recipe.egg
+ eggs = z3c.coverage
+ scripts = coverage=coverage-report
+ arguments = ('coverage', '${buildout:directory}/coverage/report')
+
+Next it also modifies setup.py to add an extras requires section.
+
+ >>> project.setup.extras_requires
+ {'test': ['z3c.coverage', 'zope.testing']}
+
+It also adds a tests package with a test_doc module that hooks up
+doctests.
+
+ >>> print project.package['tests']['test_doc.py'].render()
+ import unittest
+ import zope.testing.doctest
+ <BLANKLINE>
+ def test_suite():
+ return unittest.TestSuite((
+ <BLANKLINE>
+ zope.testing.doctest.DocFileSuite(
+ '../README.txt',
+ optionflags=zope.testing.doctest.NORMALIZE_WHITESPACE |
+ zope.testing.doctest.ELLIPSIS),
+ <BLANKLINE>
+ <BLANKLINE>
+ ))
+
+Finally there is also a sample doctest file.
+
+ >>> print project.package['README.txt'].render()
+ ================
+ A Simple DocTest
+ ================
+ <BLANKLINE>
+ Doctests work by evaluating txt documents that look like python
+ interpreter sessions. This test will pass:
+ ...
+
+Let's now look at the documentation that this feature provides.
+
+ >>> print feature.featureDocumentation
+ The Automated Testing feature generates boiler plate code for running
+ unittests, specifically in the form of DocTests. Here are the various
+ pieces generated by the Automated Testing Feature...
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/unittest.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.feature.core/trunk/src/z3c/feature/core/web/__init__.py
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/web/__init__.py (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/web/__init__.py 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1 @@
+#package
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/web/__init__.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.feature.core/trunk/src/z3c/feature/core/web/metadata.py
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/web/metadata.py (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/web/metadata.py 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,156 @@
+import zope.schema
+from zope.schema.vocabulary import SimpleVocabulary
+from zope.schema.vocabulary import SimpleTerm
+from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
+
+from z3c.form.form import EditForm
+from z3c.form.field import Fields
+from z3c.form.browser.textlines import TextLinesFieldWidget
+
+from z3c.feature.core.metadata import MetaDataFeature
+from z3c.feature.core.metadata import CommentHeaderZPLFeature
+from z3c.feature.core.metadata import ProprietaryHeaderFeature
+from z3c.feature.core.metadata import DocumentationFeature
+from z3c.feature.core.python import PythonInterpreterFeature
+from z3c.feature.core import interfaces
+
+licenseVocabulary = SimpleVocabulary([
+ SimpleTerm('Aladdin Free Public License (AFPL)'),
+ SimpleTerm('DFSG approved'),
+ SimpleTerm('Eiffel Forum License (EFL)'),
+ SimpleTerm('Free For Educational Use'),
+ SimpleTerm('Free For Home Use'),
+ SimpleTerm('Free for non-commercial use'),
+ SimpleTerm('Freely Distributable'),
+ SimpleTerm('Free To Use But Restricted'),
+ SimpleTerm('Freeware'),
+ SimpleTerm('Netscape Public License (NPL)'),
+ SimpleTerm('Nokia Open Source License (NOKOS)'),
+ SimpleTerm('Academic Free License (AFL)'),
+ SimpleTerm('Apache Software License'),
+ SimpleTerm('Apple Public Source License'),
+ SimpleTerm('Artistic License'),
+ SimpleTerm('Attribution Assurance License'),
+ SimpleTerm('BSD License'),
+ SimpleTerm('Common Public License'),
+ SimpleTerm('Eiffel Forum License'),
+ SimpleTerm('GNU Affero General Public License v3'),
+ SimpleTerm('GNU Free Documentation License (FDL)'),
+ SimpleTerm('GNU General Public License (GPL)'),
+ SimpleTerm('GNU Library or Lesser General Public License (LGPL)'),
+ SimpleTerm('IBM Public License'),
+ SimpleTerm('Intel Open Source License'),
+ SimpleTerm('Jabber Open Source License'),
+ SimpleTerm('MIT License'),
+ SimpleTerm('MITRE Collaborative Virtual Workspace License (CVW)'),
+ SimpleTerm('Motosoto License'),
+ SimpleTerm('Mozilla Public License 1.0 (MPL)'),
+ SimpleTerm('Mozilla Public License 1.1 (MPL 1.1)'),
+ SimpleTerm('Nethack General Public License'),
+ SimpleTerm('Nokia Open Source License'),
+ SimpleTerm('Open Group Test Suite License'),
+ SimpleTerm('Python License (CNRI Python License)'),
+ SimpleTerm('Python Software Foundation License'),
+ SimpleTerm('Qt Public License (QPL)'),
+ SimpleTerm('Ricoh Source Code Public License'),
+ SimpleTerm('Sleepycat License'),
+ SimpleTerm('Sun Industry Standards Source License (SISSL)'),
+ SimpleTerm('Sun Public License'),
+ SimpleTerm('University of Illinois/NCSA Open Source License'),
+ SimpleTerm('Vovida Software License 1.0'),
+ SimpleTerm('W3C License'),
+ SimpleTerm('X.Net License'),
+ SimpleTerm('zlib/libpng License'),
+ SimpleTerm('Zope Public License'),
+ SimpleTerm('Other/Proprietary License'),
+ SimpleTerm('Public Domain'),
+ ])
+
+
+class MetaDataWebView(EditForm):
+
+ label = u'Project Metadata'
+ template = ViewPageTemplateFile('templates/metadata.pt')
+ javascript = ViewPageTemplateFile('templates/metadata.js')
+ fields = Fields(zope.schema.Choice(
+ __name__='commonLicense',
+ title=u'License',
+ default=u'GNU General Public License (GPL)',
+ vocabulary=licenseVocabulary,
+ required=False))
+
+ fields += Fields(interfaces.IMetaDataFeature).select(
+ 'license','version','description','author',
+ 'author_email','url','classifiers','keywords',
+ 'namespace_packages','install_requires',
+ 'commentHeader')
+
+ fields = fields.select(
+ 'license','commonLicense','version','description','author',
+ 'author_email','url','classifiers','keywords',
+ 'namespace_packages','install_requires',
+ 'commentHeader')
+
+ fields['keywords'].widgetFactory = TextLinesFieldWidget
+ fields['namespace_packages'].widgetFactory = TextLinesFieldWidget
+ fields['install_requires'].widgetFactory = TextLinesFieldWidget
+
+ def applyChanges(self, data):
+ commonLicense = data.pop('commonLicense')
+ data['license'] = data.get('license', commonLicense)
+ return super(MetaDataWebView, self).applyChanges(data)
+
+
+class MetaDataWebFeature(object):
+ viewFactory = MetaDataWebView
+ contentFactory = MetaDataFeature
+ title = u"Metadata"
+ description = (u"Let's you modify project metadata used by setuptools "
+ u"such as version number, license information, author "
+ u"information, project description, and more.")
+
+
+class CommentHeaderZPLWebView(EditForm):
+ label = u'Comment Header for the Zope Public License'
+ fields = Fields(interfaces.ICommentHeaderZPLFeature).select('year')
+
+
+class CommentHeaderZPLWebFeature(object):
+ viewFactory = CommentHeaderZPLWebView
+ contentFactory = CommentHeaderZPLFeature
+ title = u"ZPL Header"
+ description = u"Adds a ZPL Header to all generated files."
+
+
+
+class ProprietaryHeaderWebView(EditForm):
+ template = ViewPageTemplateFile("templates/proprietary-header.pt")
+ fields = Fields(interfaces.IProprietaryHeaderFeature).select(
+ 'year','company','location')
+
+ def update(self):
+ super(ProprietaryHeaderWebView, self).update()
+ self.commentHeader = self.context.renderCommentHeader()
+
+class ProprietaryHeaderWebFeature(object):
+ viewFactory = ProprietaryHeaderWebView
+ contentFactory = ProprietaryHeaderFeature
+ title = u"Proprietary Header"
+ description = u"Adds a Proprietary Software Header to all generated files."
+
+
+class DocumentationWebView(EditForm):
+ label = u'Documentation'
+ fields = Fields(interfaces.IDocumentationFeature)
+
+
+class DocumentationWebFeature(object):
+ viewFactory = DocumentationWebView
+ contentFactory = DocumentationFeature
+ title = u"Documentation"
+ description = (u"Adds a script for generating project documentation from "
+ u"ReSTructured Text files using Sphinx (just like the python "
+ u"documetation). Great in combination with the "
+ u"Automated Tests Feature")
+
+
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/web/metadata.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.feature.core/trunk/src/z3c/feature/core/web/python.py
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/web/python.py (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/web/python.py 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,35 @@
+from z3c.form.form import EditForm
+from z3c.form.field import Fields
+
+from z3c.feature.core.python import PythonInterpreterFeature
+from z3c.feature.core.python import ScriptFeature
+from z3c.feature.core import interfaces
+
+
+class PythonInterpreterWebView(EditForm):
+ fields = Fields(interfaces.IPythonInterpreterFeature).select('executableName')
+
+class PythonInterpreterWebFeature(object):
+ viewFactory = PythonInterpreterWebView
+ contentFactory = PythonInterpreterFeature
+ title = u'Python Interpreter'
+ description = (u"Adds a Python interpreter with all the path "
+ u"information needed to make project code available.")
+
+
+class ScriptWebView(EditForm):
+
+ fields = Fields(interfaces.IScriptFeature)
+
+ def update(self):
+ super(ScriptWebView, self).update()
+ self.label = self.context.featureTitle
+
+class ScriptWebFeature(object):
+ viewFactory = ScriptWebView
+ contentFactory = ScriptFeature
+ title = u'Console Script'
+ description = (u"Adds an entry point for setuptools to create a "
+ u"console script that runs a python function. "
+ u"Great for projects that run from the command line "
+ u"and require insanely easy installation.")
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/web/python.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.feature.core/trunk/src/z3c/feature/core/web/templates/comment-header-zpl.pt
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/web/templates/comment-header-zpl.pt (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/web/templates/comment-header-zpl.pt 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1 @@
+<div metal:use-macro="macro:form"/>
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/web/templates/comment-header-zpl.pt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.feature.core/trunk/src/z3c/feature/core/web/templates/metadata.js
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/web/templates/metadata.js (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/web/templates/metadata.js 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,25 @@
+$(document).ready(
+ function(){
+
+ $("label[for='form-widgets-license'] span").html("Custom License");
+
+ if ($(this).find("option:selected").val() !== '--NOVALUE--'){
+ $("#form-widgets-license-row").hide();
+ }
+
+ $("#form-widgets-commonLicense-novalue")
+ .html("Choose my own license")
+ .parent()
+ .change(
+ function(){
+ var selected = $(this).find("option:selected").val();
+ $("#form-widgets-license").val("");
+ if (selected == '--NOVALUE--'){
+ $("#form-widgets-license-row").show();
+ $("#form-widgets-license").focus();
+ } else {
+ $("#form-widgets-license-row").hide();
+ }
+ });
+
+ });
Added: z3c.feature.core/trunk/src/z3c/feature/core/web/templates/metadata.pt
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/web/templates/metadata.pt (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/web/templates/metadata.pt 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,20 @@
+<style type="text/css">
+ #form-widgets-license-row{
+ float: left;
+ }
+ #form-widgets-commentHeader{
+ font-family: Courier;
+ height: 200px;
+ width: 400px;
+ }
+ textarea,
+ input.text-widget{
+ width: 300px;
+ }
+</style>
+<div metal:use-macro="macro:form">
+</div>
+
+<script language="Javascript" type="text/javascript"
+ tal:content="structure view/javascript">
+</script>
\ No newline at end of file
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/web/templates/metadata.pt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.feature.core/trunk/src/z3c/feature/core/web/templates/proprietary-header.pt
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/web/templates/proprietary-header.pt (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/web/templates/proprietary-header.pt 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,4 @@
+<div metal:use-macro="macro:form"/>
+
+<p>The comment header will look like this:</p>
+<pre tal:content="view/commentHeader"/>
\ No newline at end of file
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/web/templates/proprietary-header.pt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.feature.core/trunk/src/z3c/feature/core/web/unittest.py
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/web/unittest.py (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/web/unittest.py 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,18 @@
+from z3c.form.form import EditForm
+from z3c.form.field import Fields
+
+from z3c.feature.core.unittest import TestingFeature
+from z3c.feature.core import interfaces
+
+
+class TestingWebView(EditForm):
+ fields = Fields(interfaces.ITestingFeature)
+
+
+class TestingWebFeature(object):
+ viewFactory = TestingWebView
+ contentFactory = TestingFeature
+ title = u"Automated Tests"
+ description = (u"Adds all the boiler plate for running an "
+ u"automated doctest suite along with test "
+ u"coverage reporting.")
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/web/unittest.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.feature.core/trunk/src/z3c/feature/core/xml.py
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/xml.py (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/xml.py 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,123 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Foundation 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.
+#
+##############################################################################
+"""XML Processing
+
+$Id$
+"""
+
+from lxml import etree
+import types
+import pkg_resources
+from zc.buildout import easy_install
+from zope.interface import directlyProvides
+
+from z3c.builder.core import project, base
+from z3c.feature.core import interfaces
+
+target_dir = pkg_resources.working_set.find(
+ pkg_resources.Requirement.parse('zc.buildout')).location
+
+
+class FeatureDocBuilder(base.FileBuilder):
+ """A builder to document all applied features of a project."""
+
+ def render(self):
+ result = open(
+ base.getTemplatePath('zboiler-doc-header.txt'), 'r').read()
+ for feature in self.getProject().appliedFeatures:
+ title = feature.featureTitle
+ result += "\n\n" + title + "\n"
+ result += "-"*len(title) + "\n"
+ docs = feature.featureDocumentation.strip()
+ result += "\n" + docs + "\n\n"
+ return result
+
+
+def getNode(nodeOrFileOrStr):
+ if isinstance(nodeOrFileOrStr, types.StringTypes):
+ return etree.fromstring(nodeOrFileOrStr)
+ elif hasattr(nodeOrFileOrStr, 'read'):
+ data = nodeOrFileOrStr.read()
+ nodeOrFileOrStr.seek(0)
+ return etree.fromstring(data)
+ elif isinstance(nodeOrFileOrStr, etree._Element):
+ return nodeOrFileOrStr
+ else:
+ raise TypeError("Could not get a lxml.etree.Element "
+ "object from %s" % nodeOrFileOrStr)
+
+def getFeatureFactory(featureNode):
+ featureType = featureNode.get('type')
+ egg, entryPoint = featureType.split(':')
+ if egg not in pkg_resources.working_set.by_key:
+ ws = easy_install.install([egg], target_dir, newest=True)
+ distro = ws.find(pkg_resources.Requirement.parse(eggs))
+ pkg_resources.working_set.add(distro)
+ else:
+ distro = pkg_resources.get_distribution(egg)
+ try:
+ featureFactory = distro.load_entry_point(
+ interfaces.FEATURE_GROUP, entryPoint)
+ except ImportError, e:
+ raise ValueError("Unable to load feature factory for %s:%s because: %s" % (interfaces.FEATURE_GROUP, entryPoint, e))
+ return featureFactory
+
+def getFeaturesDict(node):
+ node = getNode(node)
+ features = {}
+ for featureNode in node.xpath('//feature'):
+ featureFactory = getFeatureFactory(featureNode).fromXMLNode(featureNode)
+ feature = featureFactory.fromXMLNode(featureNode)
+ features[featureNode.get('type')] = feature
+ return features
+
+def getFeatures(node):
+ return getFeaturesDict(node).values()
+
+
+def xmlToProject(node):
+ node = getNode(node)
+ name = node.get("name")
+ builder = project.BuildoutProjectBuilder(unicode(name))
+ from z3c.feature.core import base
+ base.applyFeatures(getFeatures(node), builder)
+ builder.add(FeatureDocBuilder(u'ZBOILER.txt'))
+ return builder
+
+def extractData(node, iface, convert=True):
+ node = getNode(node)
+ data = {}
+ for fieldName in iface:
+ matches = node.xpath('./%s'%fieldName.replace('_','-'))
+ match = matches[0] if matches else None
+ if match is not None:
+ if convert:
+ # ignore templated values when converting to actual fields.
+ if match.text == "?":
+ continue
+ # see if this is a composite element representing a list of
+ # items.
+ items = match.xpath('./item')
+ if items:
+ data[fieldName] = [unicode(item.text) for item in items]
+ # otherwise, see if we can parse a value from unicode
+ elif hasattr(iface[fieldName], 'fromUnicode'):
+ data[fieldName] = iface[fieldName].fromUnicode(
+ unicode(match.text))
+ # oh well, we'll just send back the unicode and hope that's ok
+ elif match.text:
+ data[fieldName] = unicode(match.text)
+ else:
+ data[fieldName] = unicode(match.text)
+ return data
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/xml.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.feature.core/trunk/src/z3c/feature/core/xml.txt
===================================================================
--- z3c.feature.core/trunk/src/z3c/feature/core/xml.txt (rev 0)
+++ z3c.feature.core/trunk/src/z3c/feature/core/xml.txt 2009-03-27 08:52:36 UTC (rev 98393)
@@ -0,0 +1,233 @@
+============================
+XML Configuration Processing
+============================
+
+We have an xml configuration layer for the project builder.
+
+ >>> from z3c.feature.core import xml
+
+Getting a node
+--------------
+
+We can get a node in a number of different ways:
+
+- from string
+
+ >>> node = xml.getNode("<root>this is the root node</root>")
+ >>> node
+ <Element root at ...>
+
+- from a file
+
+ >>> import StringIO
+ >>> io = StringIO.StringIO('<root>this is the root node</root>')
+
+ >>> xml.getNode(io)
+ <Element root at ...>
+
+- from a node (just returns the node)
+
+ >>> xml.getNode(node)
+ <Element root at ...>
+
+Or throws type error for something it doesn't know what to do with:
+
+ >>> xml.getNode(False)
+ Traceback (most recent call last):
+ ...
+ TypeError: Could not get a lxml.etree.Element object from False
+
+
+Extracting Data
+---------------
+
+We can extract data from an xml block based on an interface. It will
+do the data conversion automatically if it can.
+
+ >>> import zope.interface
+ >>> import zope.schema
+
+ >>> class IMyFeature(zope.interface.Interface):
+ ... name = zope.schema.TextLine()
+ ... is_cool = zope.schema.Bool()
+ ... developers = zope.schema.Int()
+ ... aList = zope.schema.List()
+ ... inTemplate = zope.schema.TextLine()
+ >>> node = '''
+ ... <feature type="my-feature">
+ ... <name>myproject</name>
+ ... <is-cool>t</is-cool>
+ ... <developers>3</developers>
+ ... <aList><item>one</item><item>two</item></aList>
+ ... <inTemplate>?</inTemplate>
+ ... </feature>
+ ... '''
+
+ >>> sorted(xml.extractData(node, IMyFeature).items())
+ [('aList', [u'one', u'two']),
+ ('developers', 3),
+ ('is_cool', False),
+ ('name', u'myproject')]
+
+
+Applying Features
+-----------------
+
+Once features are loaded they need to be applied on their context. By default
+the context is a project:
+
+ >>> from z3c.builder.core import project
+ >>> context = project.BuildoutProjectBuilder(u'myproject')
+
+ >>> node = xml.getNode('''\
+ ... <project name="sampleproject">
+ ...
+ ... <feature type="z3c.feature.core:meta-data">
+ ... <license>ZPL</license>
+ ... <version>0.1.0</version>
+ ... <author>Paul Carduner and Stephan Richter</author>
+ ... <author-email>zope-dev at zope.org</author-email>
+ ... <description>A utility to start Zope 3 projects</description>
+ ... <license>ZPL 2.1</license>
+ ... <keywords>
+ ... <item>zope3</item>
+ ... <item>project</item>
+ ... <item>builder</item>
+ ... </keywords>
+ ... <url>http://pypi.python.org/pypi/sampleproject</url>
+ ... </feature>
+ ...
+ ... <feature type="z3c.feature.core:python-interpreter">
+ ... <executableName>py</executableName>
+ ... </feature>
+ ... </project>
+ ... ''')
+
+We can extract all the features from this node:
+
+ >>> from pprint import pprint
+ >>> features = xml.getFeatures(node)
+ >>> pprint(sorted(features))
+ [<MetaDataFeature u'Metadata'>,
+ <PythonInterpreterFeature u'Python Interpreter'>]
+
+Let's now apply the feature onto the context.
+
+ >>> from z3c.feature.core import base
+ >>> base.applyFeatures(features, context)
+
+
+Creating a Project
+------------------
+
+We can create a simple project:
+
+ >>> project = xml.xmlToProject('<project name="helloworld"></project>')
+ >>> project
+ <BuildoutProjectBuilder u'helloworld'>
+
+Let's now render the project:
+
+ >>> project.update()
+ >>> project.write(buildPath)
+
+ >>> ls(buildPath)
+ helloworld/
+ ZBOILER.txt
+ bootstrap.py
+ buildout.cfg
+ setup.py
+ src/
+ helloworld/
+ __init__.py
+
+As you can see, when building a project from features, the project creates a
+`ZBOILER.txt` file that documents all applied features:
+
+ >>> more(buildPath, 'helloworld', 'ZBOILER.txt')
+ =========================================================
+ Documentation About Project Features Generated by ZBoiler
+ =========================================================
+ <BLANKLINE>
+ ZBoiler (http://zboiler.com) was used to generate the boiler plate
+ code for this project. To build your project, run these commands::
+ <BLANKLINE>
+ $ python bootstrap.py
+ $ ./bin/buildout
+ <BLANKLINE>
+ What happens next depends on the features you used to generate your
+ project. Check out more information about each feature below.
+
+The set pf all applied features is collected in the project, which now has a
+special interface it directly provides:
+
+ >>> from zope.interface.verify import verifyObject
+ >>> from z3c.feature.core import interfaces
+
+ >>> verifyObject(interfaces.IHaveAppliedFeatures, project)
+ True
+
+ >>> project.appliedFeatures
+ []
+
+Since our simple project does not have any features, none are lsited and the
+text file was rather empty. Let's change that situation:
+
+ >>> from z3c.feature.core.python import ScriptFeature
+
+ >>> feature = ScriptFeature()
+ >>> feature.applyTo(project)
+
+Let's now render the project again:
+
+ >>> project.update()
+ >>> project.write(buildPath, True)
+
+ >>> more(buildPath, 'helloworld', 'ZBOILER.txt')
+ =========================================================
+ Documentation About Project Features Generated by ZBoiler
+ =========================================================
+ <BLANKLINE>
+ ZBoiler (http://zboiler.com) was used to generate the boiler plate
+ code for this project. To build your project, run these commands::
+ <BLANKLINE>
+ $ python bootstrap.py
+ $ ./bin/buildout
+ <BLANKLINE>
+ What happens next depends on the features you used to generate your
+ project. Check out more information about each feature below.
+ <BLANKLINE>
+ <BLANKLINE>
+ <BLANKLINE>
+ Command Line Script
+ -------------------
+ <BLANKLINE>
+ The Command Line Script Feature exposes a python function in your
+ project as a command line script. There are several pieces to this:
+ <BLANKLINE>
+ #. **The script file.**
+ <BLANKLINE>
+ There is a script file located at script.py with a function
+ in it called main. This is what you should modify to
+ make your script actually do something.
+ <BLANKLINE>
+ #. **Setuptools entry point.**
+ <BLANKLINE>
+ When someone installs your project using setuptools, for example
+ with the command::
+ <BLANKLINE>
+ $ easy_install yourproject
+ <BLANKLINE>
+ any entry points in the console_script group will turn into
+ executable scripts that the end user can just run. This make your
+ project into an application and not just a set of python
+ libraries.
+ <BLANKLINE>
+ The entry point is created by modifying the ``setup.py`` file.
+ Look for the keyword parameter called entry_points.
+ <BLANKLINE>
+ #. ``scripts`` **buildout part.**
+ <BLANKLINE>
+ Finally there is also a part added to buildout.cfg that makes the
+ script defined in the entry point available in the projects bin/
+ directory. This is only for development purposes.
Property changes on: z3c.feature.core/trunk/src/z3c/feature/core/xml.txt
___________________________________________________________________
Added: svn:eol-style
+ native
More information about the Checkins
mailing list