diff --git a/CHANGES.txt b/CHANGES.txt index 7a46c24..bfc54a4 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -4,7 +4,9 @@ Changelog 1.0.5 (unreleased) ------------------ -- Nothing changed yet. +- Cleanup: PEP8, plone-coding conventions, ReST fixes, documentation + overhaul, et al. + [jensens] 1.0.4 (2015-03-21) diff --git a/README.rst b/README.rst index cd86a73..1b1e91d 100644 --- a/README.rst +++ b/README.rst @@ -2,11 +2,10 @@ Introduction ============ ``plone.resource`` publishes directories of static files via the ZPublisher. -These directories may be located either in the ZODB (as OFS folders and -files), or on the filesystem. +These directories may be located either in the ZODB (as OFS folders and files), or on the filesystem. -Each resource directory has a type and a name. When combined, these are used -to traverse to the resource directory. For example:: +Each resource directory has a type and a name. When combined, these are used to traverse to the resource directory. +For example:: /++theme++mytheme/ /++sitelayout++mylayout/ @@ -16,133 +15,130 @@ to traverse to the resource directory. For example:: Where resources can be stored ----------------------------- -Resource directory contents can be found by the traverser in several different -places. The following locations are tried in order. +Resource directory contents can be found by the traverser in several different places. +The following locations are tried in order. Files in the ZODB ^^^^^^^^^^^^^^^^^ - Installing ``plone.resource`` creates a folder called portal_resources which - can be used to store resource directories persistently. By convention, the - top-level folders under this folder correspond to resource types, and the - second-level folders correspond to the resource directory name. +Installing ``plone.resource`` creates a Zope-folder called ``portal_resources``. +It can be used to store resource directories persistently. +By convention: - So, the file traversable at /++theme++mytheme/myfile could be physically - located at some_site/++etc++site/resources/theme/mytheme +- the top-level folders under this folder correspond to resource types, +- the second-level folders correspond to the resource directory name. - (XXX: provide a helper to upload a tarball/zip) +So, the file traversable at ``/++theme++mytheme/myfile`` could be physically located at ``some_site/++etc++site/resources/theme/mytheme`` + +.. TODO (XXX: provide a helper to upload a tarball/zip) Files in Python distributions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - A folder in a Python distribution (e.g. egg) can be registered as a resource - directory of a particular type and name using the plone:static ZCML - directive. For example, this registers a directory named "theme" as a - resource directory of type "theme". It would be accessible at - ++theme++mytheme:: +A folder in a Python distribution (e.g. egg) can be registered as a resource directory of a particular type and name using the ``plone:static`` ZCML directive. +For example, this registers a directory named "theme" as a resource directory of type "theme" under the name "mytheme". +It would be accessible at ``++theme++mytheme``:: + directory="theme" + type="theme" + name="mytheme" + /> .. note:: You must do ```` before you can use the plone:static directive. - The name of the resource directory defaults to the name of the package, so - can be omitted. e.g. the following directive in a package named "mytheme" - would result in the same registration as above:: +The name of the resource directory defaults to the name of the package, so can be omitted. +E.g. the following directive in a package named "mytheme" would result in the same registration as above:: + directory="resources" + type="theme" + /> - Traversing upward in directory paths using .. is not supported, as it could - allow unwanted file access. +Traversing upward in directory paths using ``..`` is not supported for security reasons, as it could allow unwanted file access. Minimum zcml config example ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Note:: - +:: + + - + .. Files in a central resource directory ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - If the ``plone:static`` directive is used from ``site.zcml`` (i.e., with no - active package in the ZCML import context), then it may specify the - absolute path to a top-level resources directory. This directory should - have the same sub-directory structure as the in-ZODB resources directory in - that top-level directories are resource types, and 2nd-level directories - are resource directory names. In addition, in order for resources to be - available, the top-level directories require a traverser to be registered. +If the ``plone:static`` directive is used from ``site.zcml`` (i.e., with no active package in the ZCML import context), +then it may specify the absolute path to a top-level resources directory. - For example, the following in ``site.zcml`` would register the given path - within the buildout root:: +This directory should have the same sub-directory structure as explained above (in-ZODB resources directory): - +- the top-level folders under this folder correspond to resource types, +- the second-level folders correspond to the resource directory name. + +In addition, in order for resources to be available, the top-level directories *require a traverser* to be registered! + +For example, the following in ``site.zcml`` registers the given path within the buildout root:: + + - Typically, this can be injected into ``site.zcml`` by specifying the - ``resources option`` in the `plone.recipe.zope2instance`_ - buildout recipe, like this:: +In order to automate this at buildout time, `plone.recipe.zope2instance`_ recipe has the option ``resources``. +It injects the above zcml snippet with into ``site.zcml`` by specifying the option like this:: + [instance] + ... resources = ${buildout:directory}/resources + ... - As a worked example, if one wanted to serve resources for use with - ``plone.app.theming``, which provides the ``++theme++`` traverser, then - a resource located at:: +Example: +Using ``plone.app.theming`` - which provides the ``++theme++`` traverser - given an image file located in filesystem at:: - ${directory}/resources/theme/my.project/logo.png + ${buildout:directory}/resources/theme/my.project/logo.png`` - would be traversable at a URL like so:: +This would be traversable at a URL like so:: - http://localhost:8080/Plone/++theme++my.project/logo.png + http://localhost:8080/Plone/++theme++my.project/logo.png .. _`plone.recipe.zope2instance`: http://pypi.python.org/pypi/plone.recipe.zope2instance Additional traversers --------------------- - Traversers can be registered via ZCML using an adapter like so:: +Custom traversers can be registered via ZCML using an adapter like so:: - + - with a corresponding factory definition of:: +with a corresponding simple factory definition of:: - from plone.resource.traversal import ResourceTraverser - class MyTraverser(ResourceTraverser): - name = 'demo' + from plone.resource.traversal import ResourceTraverser + class MyTraverser(ResourceTraverser): + name = 'demo' - This, when coupled with configuration like that in the - `Files in a central resource directory`_ section above, would mean that - resources located at:: +This, when coupled with configuration like that in the `Files in a central resource directory`_ section above, would mean that resources located at:: - ${directory}/resources/demo/my.project/logo.png + ${buildout:directory}/resources/demo/my.project/logo.png - would be traversable at a URL like so:: +would be traversable at a URL like so:: - http://localhost:8080/Plone/++demo++my.project/logo.png + http://localhost:8080/Plone/++demo++my.project/logo.png -What types of resources can be stored -------------------------------------- +.. TODO: What types of resources can be stored diff --git a/plone/__init__.py b/plone/__init__.py index 1de0d9d..68c04af 100644 --- a/plone/__init__.py +++ b/plone/__init__.py @@ -1,6 +1,2 @@ -# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages -try: - __import__('pkg_resources').declare_namespace(__name__) -except ImportError: # pragma: no cover - from pkgutil import extend_path - __path__ = extend_path(__path__, __name__) +# -*- coding: utf-8 -*- +__import__('pkg_resources').declare_namespace(__name__) diff --git a/plone/resource/__init__.py b/plone/resource/__init__.py index e69de29..40a96af 100644 --- a/plone/resource/__init__.py +++ b/plone/resource/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/plone/resource/caching.py b/plone/resource/caching.py index b23bfed..2cf9182 100644 --- a/plone/resource/caching.py +++ b/plone/resource/caching.py @@ -1,9 +1,13 @@ -from zope.interface import Interface -from zope.interface import implements -from zope.component import adapts +# -*- coding: utf-8 -*- from plone.caching.interfaces import IRulesetLookup from plone.resource.interfaces import IUniqueResourceRequest +from zope.component import adapter +from zope.interface import implementer +from zope.interface import Interface + +@implementer(IRulesetLookup) +@adapter(Interface, IUniqueResourceRequest) class UniqueResourceLookup(object): """Unique resource ruleset lookup. @@ -11,9 +15,6 @@ class UniqueResourceLookup(object): IUniqueResourceRequest. """ - implements(IRulesetLookup) - adapts(Interface, IUniqueResourceRequest) - def __init__(self, published, request): pass diff --git a/plone/resource/directory.py b/plone/resource/directory.py index c20a8bd..dbe4cad 100644 --- a/plone/resource/directory.py +++ b/plone/resource/directory.py @@ -1,33 +1,32 @@ -import os.path -import re -import zipfile - +# -*- coding: utf-8 -*- from Acquisition import aq_base, aq_parent from OFS.Image import File from OFS.interfaces import IObjectManager +from plone.resource.file import FilesystemFile +from plone.resource.interfaces import IResourceDirectory +from plone.resource.interfaces import IWritableResourceDirectory from Products.BTreeFolder2.BTreeFolder2 import BTreeFolder2 from Products.CMFCore.utils import getToolByName from StringIO import StringIO from zExceptions import NotFound -from zope.interface import implements +from zope.interface import implementer from zope.site.hooks import getSite - -from plone.resource.file import FilesystemFile -from plone.resource.interfaces import IResourceDirectory -from plone.resource.interfaces import IWritableResourceDirectory +import os.path +import re +import zipfile # filter dot files, Mac resource forks FILTERS = (r'\..*', '__MACOSX') FILTERS = [re.compile(pattern) for pattern in FILTERS] +@implementer(IWritableResourceDirectory) class PersistentResourceDirectory(object): """A resource directory stored in the ZODB. It is assumed that directories provide IObjectManager and that files are instances of OFS.Image.File. """ - implements(IWritableResourceDirectory) def __init__(self, context=None): if context is None: @@ -94,7 +93,7 @@ def readFile(self, path): def listDirectory(self): return [n for n in self.context.objectIds() - if not any(filter.match(n) for filter in FILTERS)] + if not any(filter.match(n) for filter in FILTERS)] def isDirectory(self, path): try: @@ -181,10 +180,11 @@ def importZip(self, f): data = f.open(member).read() self.writeFile(path, data) + +@implementer(IResourceDirectory) class FilesystemResourceDirectory(object): """A resource directory based on files in the filesystem. """ - implements(IResourceDirectory) __allow_access_to_unprotected_subobjects__ = True @@ -241,7 +241,7 @@ def readFile(self, path): def listDirectory(self): names = os.listdir(self.directory) return [n for n in names - if not any(filter.match(n) for filter in FILTERS)] + if not any(filter.match(n) for filter in FILTERS)] def isDirectory(self, path): return os.path.isdir(self._resolveSubpath(path)) @@ -250,7 +250,6 @@ def isFile(self, path): return os.path.isfile(self._resolveSubpath(path)) def exportZip(self, out): - prefix = self.__name__ zf = zipfile.ZipFile(out, 'w') toStrip = len(self.directory.replace(os.path.sep, '/')) + 1 @@ -266,6 +265,8 @@ def exportZip(self, out): ): continue - zf.writestr('/'.join([prefix, path,]), self.readFile(path)) - + zf.writestr( + '/'.join([self.__name__, path, ]), + self.readFile(path) + ) zf.close() diff --git a/plone/resource/download.py b/plone/resource/download.py index 35362c0..2fd7474 100644 --- a/plone/resource/download.py +++ b/plone/resource/download.py @@ -1,6 +1,8 @@ +# -*- coding: utf-8 -*- from StringIO import StringIO from zope.publisher.browser import BrowserView + class DownloadView(BrowserView): def __call__(self): @@ -16,7 +18,10 @@ def __call__(self): self.context.exportZip(out) response.setHeader('Content-Type', 'application/zip') - response.setHeader('Content-Disposition', 'attachment; filename="%s.zip"' % name) + response.setHeader( + 'Content-Disposition', + 'attachment; filename="%s.zip"' % name + ) response.setHeader('Content-Length', len(out.getvalue())) response.write(out.getvalue()) diff --git a/plone/resource/file.py b/plone/resource/file.py index b7bc18f..24346c1 100644 --- a/plone/resource/file.py +++ b/plone/resource/file.py @@ -1,23 +1,19 @@ -import os -import os.path -import datetime -import mimetypes -from dateutil.tz import tzlocal - +# -*- coding: utf-8 -*- from datetime import time +from dateutil.tz import tzlocal from email.utils import formatdate - -from zope.component import adapts +from z3c.caching.interfaces import ILastModified from zope.component import adapter - +from zope.component import adapts +from zope.filerepresentation.interfaces import IRawReadFile from zope.interface import implementer from zope.interface import implements - -from z3c.caching.interfaces import ILastModified - -from zope.filerepresentation.interfaces import IRawReadFile - from ZPublisher.Iterators import filestream_iterator +import datetime +import mimetypes +import os +import os.path + class ResourceIterator(filestream_iterator): """Resource iterator that allows (inefficient) coercion to str/unicode. @@ -31,6 +27,7 @@ def __str__(self): def __unicode__(self): return self.read().decode('utf-8') + class FilesystemFile(object): """Representation of a file. When called, it will set response headers and return the file's contents @@ -41,8 +38,9 @@ def __init__(self, parent, request, path, name): self.request = request self.__name__ = name self.__parent__ = parent - - self.lastModifiedTimestamp = float(os.path.getmtime(path)) or time.time() + self.lastModifiedTimestamp = float( + os.path.getmtime(path) + ) or time.time() def getContentType(self, default='application/octet-stream'): extension = os.path.splitext(self.__name__)[1].lower() @@ -51,7 +49,10 @@ def getContentType(self, default='application/octet-stream'): def __call__(self, REQUEST=None, RESPONSE=None): contentType = self.getContentType() - lastModifiedHeader = formatdate(self.lastModifiedTimestamp, usegmt=True) + lastModifiedHeader = formatdate( + self.lastModifiedTimestamp, + usegmt=True + ) request = REQUEST if request is None: @@ -67,6 +68,7 @@ def __call__(self, REQUEST=None, RESPONSE=None): return ResourceIterator(self.path, 'rb') + class FileLastModified(object): """Determine when a file was last modified, for caching purposes """ @@ -77,7 +79,11 @@ def __init__(self, context): self.context = context def __call__(self): - return datetime.datetime.fromtimestamp(self.context.lastModifiedTimestamp, tz=tzlocal()) + return datetime.datetime.fromtimestamp( + self.context.lastModifiedTimestamp, + tz=tzlocal() + ) + @implementer(IRawReadFile) @adapter(FilesystemFile) diff --git a/plone/resource/interfaces.py b/plone/resource/interfaces.py index 054c377..0b4404d 100644 --- a/plone/resource/interfaces.py +++ b/plone/resource/interfaces.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- from zope.interface import Attribute from zope.interface import Interface from zope.publisher.interfaces import IPublishTraverse diff --git a/plone/resource/manifest.py b/plone/resource/manifest.py index 992d374..84eb6e8 100644 --- a/plone/resource/manifest.py +++ b/plone/resource/manifest.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- """Utilities for working with manifest files. The manifest is stored in a file ``manifest.cfg`` in the root of a resource @@ -27,20 +28,18 @@ ``bar``. ``title`` and ``description`` will be ``None`` if not found in the manifest. ``bar`` will be ``baz`` if not found. """ - -import logging from ConfigParser import SafeConfigParser - -from zope.component import getUtility - -from plone.resource.interfaces import IResourceDirectory from plone.resource.directory import FILTERS +from plone.resource.interfaces import IResourceDirectory from plone.resource.utils import iterDirectoriesOfType +from zope.component import getUtility +import logging MANIFEST_FILENAME = 'manifest.cfg' LOGGER = logging.getLogger('plone.resource.manifest') + class ManifestFormat(object): """Describes a manifest format. @@ -60,12 +59,14 @@ class ManifestFormat(object): ``[theme:parameters]``. """ - def __init__(self, resourceType, keys, defaults=None, parameterSections=None): + def __init__(self, resourceType, keys, defaults=None, + parameterSections=None): self.resourceType = resourceType self.keys = keys self.defaults = defaults or {} self.parameterSections = parameterSections or [] + def getManifest(fp, format, defaults=None): """Read the manifest from the given open file pointer according to the given ManifestFormat. Pass a dict as ``defaults`` to override the defaults @@ -94,7 +95,9 @@ def getManifest(fp, format, defaults=None): return results -def extractManifestFromZipFile(zipfile, format, defaults=None, manifestFilename=MANIFEST_FILENAME): + +def extractManifestFromZipFile(zipfile, format, defaults=None, + manifestFilename=MANIFEST_FILENAME): """Get a resource name and manifest from the given open ``zipfile.ZipFile`` using the given format. Returns a tuple:: @@ -123,7 +126,11 @@ def extractManifestFromZipFile(zipfile, format, defaults=None, manifestFilename= path = member.filename.lstrip('/') # Skip filtered files (OS X junk and dot files, mainly) - if any(any(filter.match(n) for filter in FILTERS) for n in path.split('/')): + if any( + any( + filter.match(n) for filter in FILTERS + ) for n in path.split('/') + ): continue pathSegments = path.rstrip('/').split('/') @@ -141,7 +148,10 @@ def extractManifestFromZipFile(zipfile, format, defaults=None, manifestFilename= if isDirectory or len(pathSegments) > 0: resourceName = pathSegments[0] else: - raise ValueError("Found a top level file - expected a single top level directory") + raise ValueError( + "Found a top level file - expected a single top level " + "directory" + ) # Did we find a manifest file? if ( @@ -160,7 +170,9 @@ def extractManifestFromZipFile(zipfile, format, defaults=None, manifestFilename= return (resourceName, manifestDict) -def getAllResources(format, defaults=None, filter=None, manifestFilename=MANIFEST_FILENAME): + +def getAllResources(format, defaults=None, filter=None, + manifestFilename=MANIFEST_FILENAME): """Get a dict of all resources of the resource type indicated by the manifest format. Returns a dict where the keys are the resource ids and the values are manifests. The value may be None if no manifest was found. @@ -192,13 +204,19 @@ def getAllResources(format, defaults=None, filter=None, manifestFilename=MANIFES try: resources[name] = getManifest(manifest, format, defaults) except: - LOGGER.exception("Unable to read manifest for theme directory %s", name) + LOGGER.exception( + "Unable to read manifest for theme directory {0}".format( + name + ) + ) finally: manifest.close() return resources -def getZODBResources(format, defaults=None, filter=None, manifestFilename=MANIFEST_FILENAME): + +def getZODBResources(format, defaults=None, filter=None, + manifestFilename=MANIFEST_FILENAME): """Get a dict of all resources in the ZODB of the resource type indicated by the manifest format. Returns a dict where the keys are the resource ids and the values are manifests. The value may be None if no manifest was @@ -237,11 +255,12 @@ def getZODBResources(format, defaults=None, filter=None, manifestFilename=MANIFE try: resources[name] = getManifest(manifest, format, defaults) except: - LOGGER.exception("Unable to read manifest for %s directory %s", - manifest.resourceType, name, + LOGGER.exception( + "Unable to read manifest for {0} directory {1}".format( + manifest.resourceType, name ) + ) finally: manifest.close() return resources - diff --git a/plone/resource/testing.py b/plone/resource/testing.py index 9d5a197..ba5f3f2 100644 --- a/plone/resource/testing.py +++ b/plone/resource/testing.py @@ -1,9 +1,13 @@ -from plone.testing import Layer, z2, zca, publisher -from plone.app.testing import PloneSandboxLayer -from plone.app.testing import PLONE_FIXTURE -from plone.app.testing import IntegrationTesting +# -*- coding: utf-8 -*- from plone.app.testing import applyProfile - +from plone.app.testing import IntegrationTesting +from plone.app.testing import PLONE_FIXTURE +from plone.app.testing import PloneSandboxLayer +from plone.resource.traversal import ResourceTraverser +from plone.testing import Layer +from plone.testing import publisher +from plone.testing import z2 +from plone.testing import zca from zope.configuration import xmlconfig @@ -12,7 +16,9 @@ class DemoTraverser(Layer): def setUp(self): # Stack a new configuration context - self['configurationContext'] = context = zca.stackConfigurationContext(self.get('configurationContext')) + self['configurationContext'] = context = zca.stackConfigurationContext( + self.get('configurationContext') + ) import plone.resource xmlconfig.file('testing.zcml', plone.resource, context=context) @@ -22,8 +28,11 @@ def tearDown(self): del self['configurationContext'] DEMO_TRAVERSER_FIXTURE = DemoTraverser() -DEMO_TRAVERSER_INTEGRATION_TESTING = \ - z2.IntegrationTesting(bases=(DEMO_TRAVERSER_FIXTURE,), name="plone.resource:DemoTraverser") +DEMO_TRAVERSER_INTEGRATION_TESTING = z2.IntegrationTesting( + bases=(DEMO_TRAVERSER_FIXTURE,), + name="plone.resource:DemoTraverser" +) + class PloneResource(PloneSandboxLayer): defaultBases = (PLONE_FIXTURE,) @@ -31,7 +40,11 @@ class PloneResource(PloneSandboxLayer): def setUpZope(self, app, configurationContext): # Load ZCML import plone.resource - xmlconfig.file('configure.zcml', plone.resource, context=configurationContext) + xmlconfig.file( + 'configure.zcml', + plone.resource, + context=configurationContext + ) def setUpPloneSite(self, portal): # install into the Plone site @@ -41,10 +54,11 @@ def setUpPloneSite(self, portal): commit() PLONE_RESOURCE_FIXTURE = PloneResource() -PLONE_RESOURCE_INTEGRATION_TESTING = \ - IntegrationTesting(bases=(PLONE_RESOURCE_FIXTURE,), name="plone.resource:Integration") +PLONE_RESOURCE_INTEGRATION_TESTING = IntegrationTesting( + bases=(PLONE_RESOURCE_FIXTURE,), + name="plone.resource:Integration" +) -from plone.resource.traversal import ResourceTraverser class DemoTraverser(ResourceTraverser): name = 'demo' diff --git a/plone/resource/traversal.py b/plone/resource/traversal.py index e7abe76..eb0ce03 100644 --- a/plone/resource/traversal.py +++ b/plone/resource/traversal.py @@ -1,11 +1,11 @@ -import urllib -from zope.interface import alsoProvides -from zope.traversing.namespace import SimpleHandler - +# -*- coding: utf-8 -*- from plone.resource.interfaces import IUniqueResourceRequest from plone.resource.utils import queryResourceDirectory - from zExceptions import NotFound +from zope.interface import alsoProvides +from zope.traversing.namespace import SimpleHandler +import urllib + class ResourceTraverser(SimpleHandler): @@ -15,12 +15,12 @@ def __init__(self, context, request=None): self.context = context def traverse(self, name, remaining): - type = self.name + _type = self.name # Note: also fixes possible unicode problems name = urllib.quote(name) - res = queryResourceDirectory(type, name) + res = queryResourceDirectory(_type, name) if res is not None: return res diff --git a/plone/resource/utils.py b/plone/resource/utils.py index 2f9450f..510ca40 100644 --- a/plone/resource/utils.py +++ b/plone/resource/utils.py @@ -1,6 +1,9 @@ -from zope.component import queryUtility, getUtilitiesFor +# -*- coding: utf-8 -*- from plone.resource.interfaces import IResourceDirectory from zExceptions import NotFound +from zope.component import getUtilitiesFor +from zope.component import queryUtility + def iterDirectoriesOfType(type, filter_duplicates=True): """ @@ -49,6 +52,7 @@ def iterDirectoriesOfType(type, filter_duplicates=True): if not filter_duplicates or u.__name__ not in found: yield u + def queryResourceDirectory(type, name): """Find the IResourceDirectory of the given name and type. Returns None if not found. @@ -61,7 +65,7 @@ def queryResourceDirectory(type, name): try: return res[type][name] except (KeyError, NotFound,): - pass # pragma: no cover + pass # pragma: no cover # 2. Global resource directory: # Try (global resource directory)/$type/$name @@ -70,7 +74,7 @@ def queryResourceDirectory(type, name): try: return res[type][name] except (KeyError, NotFound,): - pass # pragma: no cover + pass # pragma: no cover # 3. Packaged type-specific resource directory: # Try (directory named after type + name) @@ -81,6 +85,7 @@ def queryResourceDirectory(type, name): return None + def cloneResourceDirectory(source, target): """Copy all directories and files in the resource directory source to the writable resource directory target diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 6f94f83..0000000 --- a/setup.cfg +++ /dev/null @@ -1,3 +0,0 @@ -[zopeskel] -template = plone - diff --git a/setup.py b/setup.py index 975f071..9c4330c 100644 --- a/setup.py +++ b/setup.py @@ -1,44 +1,50 @@ -from setuptools import setup, find_packages +# -*- coding: utf-8 -*- +from setuptools import find_packages +from setuptools import setup version = '1.0.5.dev0' -setup(name='plone.resource', - version=version, - description="", - long_description=open("README.rst").read() + "\n" + - open("CHANGES.txt").read(), - classifiers=[ +setup( + name='plone.resource', + version=version, + description="", + long_description=( + open("README.rst").read() + + "\n" + + open("CHANGES.txt").read() + ), + classifiers=[ "Framework :: Plone", "Programming Language :: Python", - ], - keywords='', - author='David Glick, Plone Foundation', - author_email='davidglick@groundwire.org', - url='https://svn.plone.org/svn/plone/plone.resource', - license='GPL', - packages=find_packages(exclude=['ez_setup']), - namespace_packages=['plone'], - include_package_data=True, - zip_safe=False, - install_requires=[ - 'setuptools', - 'zope.interface', - 'zope.component', - 'zope.traversing', - 'zope.publisher', - 'zope.configuration', - 'zope.schema', - 'zope.filerepresentation', - 'z3c.caching', - 'python-dateutil', - 'plone.caching', - 'Zope2', - ], - extras_require = { - 'test': ['plone.app.testing'] - }, - entry_points=""" - [z3c.autoinclude.plugin] - target = plone - """, - ) + ], + keywords='', + author='David Glick, Plone Foundation', + author_email='davidglick@groundwire.org', + url='https://svn.plone.org/svn/plone/plone.resource', + license='GPL', + packages=find_packages(exclude=['ez_setup']), + namespace_packages=['plone'], + include_package_data=True, + zip_safe=False, + install_requires=[ + 'plone.caching', + 'python-dateutil', + 'setuptools', + 'z3c.caching', + 'zope.component', + 'zope.configuration', + 'zope.filerepresentation', + 'zope.interface', + 'zope.publisher', + 'zope.schema', + 'zope.traversing', + 'Zope2', + ], + extras_require={ + 'test': ['plone.app.testing'] + }, + entry_points=""" + [z3c.autoinclude.plugin] + target = plone + """, +)