diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 00000000..f205e92e --- /dev/null +++ b/.coveragerc @@ -0,0 +1,7 @@ +[run] +source = src + +[report] +exclude_lines = + pragma: no cover + if __name__ == '__main__': diff --git a/.gitignore b/.gitignore index 51495425..6bacfe59 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ build/ dist/ *.egg-info/ .tox/ +.coverage +htmlcov/ diff --git a/.travis.yml b/.travis.yml index 9070ae8f..571cdd42 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,26 @@ language: python sudo: false python: - - 2.7 -install: - - python bootstrap.py - - bin/buildout + - 2.7 + - 3.4 + - 3.5 + - 3.6 + - pypy-5.4.1 script: - - bin/test -v1 --ndiff + - coverage run -m zope.testrunner --test-path=src --auto-color --auto-progress + +after_success: + - coveralls notifications: - email: false + email: false + +install: + - pip install -U pip setuptools + - pip install -U coveralls coverage + - pip install -U -e ".[test]" + + +cache: pip + +before_cache: + - rm -f $HOME/.cache/pip/log/debug.log diff --git a/CHANGES.txt b/CHANGES.rst similarity index 98% rename from CHANGES.txt rename to CHANGES.rst index f626c26b..185a9550 100644 --- a/CHANGES.txt +++ b/CHANGES.rst @@ -2,9 +2,11 @@ CHANGES ======= -3.7.6 (unreleased) +4.0.0 (unreleased) ------------------ +- Add support for Python 3.4, 3.5, 3.6 and PyPy. + - Modernize some of the templates. An increment towards having zope.app.apidoc compatible with Chameleon. diff --git a/README.txt b/README.rst similarity index 100% rename from README.txt rename to README.rst diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 00000000..2a9acf13 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[bdist_wheel] +universal = 1 diff --git a/setup.py b/setup.py index 30b7aecf..6b38eea7 100644 --- a/setup.py +++ b/setup.py @@ -18,67 +18,99 @@ ############################################################################## """Setup for zope.app.apidoc package -$Id$ """ import os from setuptools import setup, find_packages def read(*rnames): - return open(os.path.join(os.path.dirname(__file__), *rnames)).read() + with open(os.path.join(os.path.dirname(__file__), *rnames)) as f: + return f.read() + +static_requires = [ + 'mechanize >= 0.1.8', + 'zope.securitypolicy', + 'zope.app.securitypolicy', +] + +tests_require = [ + 'zope.app.securitypolicy', + 'zope.browserpage >= 4.1.0', + 'zope.securitypolicy', + 'zope.login', + 'zope.testing', + 'zope.testrunner', + 'zope.principalannotation', + 'zope.app.http', + 'zope.app.rotterdam >= 4.0.0', + 'zope.app.principalannotation', + 'zope.app.folder >= 4.0.0', + 'zope.applicationcontrol >= 4.0.0', + 'zope.app.wsgi', +] + static_requires setup( - name = 'zope.app.apidoc', + name='zope.app.apidoc', version='3.7.6dev', - author = 'Zope Corporation and Contributors', - author_email = 'zope-dev@zope.org', - description = 'API Documentation and Component Inspection for Zope 3', + author='Zope Corporation and Contributors', + author_email='zope-dev@zope.org', + description='API Documentation and Component Inspection for Zope 3', long_description=( - read('README.txt') + read('README.rst') + '\n\n.. contents::\n\n' + - read('src', 'zope', 'app', 'apidoc', 'README.txt') + read('src', 'zope', 'app', 'apidoc', 'README.rst') + '\n\n' + - read('src', 'zope', 'app', 'apidoc', 'component.txt') + read('src', 'zope', 'app', 'apidoc', 'component.rst') + '\n\n' + - read('src', 'zope', 'app', 'apidoc', 'interface.txt') + read('src', 'zope', 'app', 'apidoc', 'interface.rst') + '\n\n' + - read('src', 'zope', 'app', 'apidoc', 'presentation.txt') + read('src', 'zope', 'app', 'apidoc', 'presentation.rst') + '\n\n' + - read('src', 'zope', 'app', 'apidoc', 'utilities.txt') + read('src', 'zope', 'app', 'apidoc', 'utilities.rst') + '\n\n' + - read('src', 'zope', 'app', 'apidoc', 'classregistry.txt') + read('src', 'zope', 'app', 'apidoc', 'classregistry.rst') + '\n\n' + - read('CHANGES.txt') - ), - license = "ZPL 2.1", - keywords = "zope3 api documentation", - classifiers = [ + read('CHANGES.rst') + ), + license="ZPL 2.1", + keywords="zope3 api documentation", + classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', 'Intended Audience :: Developers', 'License :: OSI Approved :: Zope Public License', 'Programming Language :: Python', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: Implementation :: CPython', + 'Programming Language :: Python :: Implementation :: PyPy', 'Natural Language :: English', 'Operating System :: OS Independent', 'Topic :: Internet :: WWW/HTTP', - 'Framework :: Zope3'], - url = 'http://pypi.python.org/pypi/zope.app.apidoc', - packages = find_packages('src'), - include_package_data = True, - package_dir = {'':'src'}, - namespace_packages = ['zope', 'zope.app'], - install_requires = [ - 'ZODB3>=3.8.0', + 'Framework :: Zope3', + ], + url='http://github.com/zopefoundation/zope.app.apidoc', + packages=find_packages('src'), + include_package_data=True, + package_dir={'': 'src'}, + namespace_packages=['zope', 'zope.app'], + install_requires=[ + 'persistent', + 'ZODB', 'setuptools', 'zope.annotation', - 'zope.app.appsetup', - 'zope.app.basicskin', - 'zope.app.exception', - 'zope.app.onlinehelp', - 'zope.app.preference', + 'zope.app.appsetup >= 4.0.0', + 'zope.app.basicskin >= 4.0.0', + 'zope.app.exception >= 4.0.0', + 'zope.app.onlinehelp >= 4.0.0.dev0', + 'zope.app.preference >= 4.0.0.dev0', 'zope.app.publisher', - 'zope.app.renderer', - 'zope.app.testing', - 'zope.app.tree', + 'zope.app.renderer >= 4.0.0.dev0', + 'zope.app.tree >= 4.0.0', 'zope.cachedescriptors', 'zope.component>=3.8.0', 'zope.configuration', @@ -87,32 +119,23 @@ def read(*rnames): 'zope.hookable', 'zope.i18n', 'zope.interface', - 'zope.location>=3.7.0', + 'zope.location >= 4.0.3', 'zope.proxy', - 'zope.publisher>=3.12.0', + 'zope.publisher >= 4.3.1', 'zope.schema', 'zope.security', 'zope.site', 'zope.testbrowser', 'zope.testing', - 'zope.traversing>=3.5.0', - ], - extras_require = dict( - test=['zope.app.testing', - 'zope.app.securitypolicy', - 'zope.app.zcmlfiles', - 'zope.browserpage>=3.10.1', - 'zope.securitypolicy', - 'zope.login',], - static=['mechanize >= 0.1.8', - 'zope.securitypolicy', - 'zope.app.zcmlfiles', - 'zope.app.securitypolicy', - ], - ), - entry_points = """ + 'zope.traversing >= 4.1.0', + ], + extras_require={ + 'test': tests_require, + 'static': static_requires, + }, + entry_points=""" [console_scripts] static-apidoc = zope.app.apidoc.static:main - """, - zip_safe = False, - ) + """, + zip_safe=False, +) diff --git a/src/zope/__init__.py b/src/zope/__init__.py index 2e2033b3..2cdb0e40 100644 --- a/src/zope/__init__.py +++ b/src/zope/__init__.py @@ -1,7 +1 @@ -# this is a namespace package -try: - import pkg_resources - pkg_resources.declare_namespace(__name__) -except ImportError: - import pkgutil - __path__ = pkgutil.extend_path(__path__, __name__) +__import__('pkg_resources').declare_namespace(__name__) # pragma: no cover diff --git a/src/zope/app/__init__.py b/src/zope/app/__init__.py index 2e2033b3..2cdb0e40 100644 --- a/src/zope/app/__init__.py +++ b/src/zope/app/__init__.py @@ -1,7 +1 @@ -# this is a namespace package -try: - import pkg_resources - pkg_resources.declare_namespace(__name__) -except ImportError: - import pkgutil - __path__ = pkgutil.extend_path(__path__, __name__) +__import__('pkg_resources').declare_namespace(__name__) # pragma: no cover diff --git a/src/zope/app/apidoc/README.txt b/src/zope/app/apidoc/README.rst similarity index 100% rename from src/zope/app/apidoc/README.txt rename to src/zope/app/apidoc/README.rst diff --git a/src/zope/app/apidoc/apidoc.py b/src/zope/app/apidoc/apidoc.py index 300db581..c6166be1 100644 --- a/src/zope/app/apidoc/apidoc.py +++ b/src/zope/app/apidoc/apidoc.py @@ -13,12 +13,12 @@ ############################################################################## """Zope 3 API Documentation -$Id$ """ +from __future__ import absolute_import __docformat__ = 'restructuredtext' import zope.component -from zope.interface import implements +from zope.interface import implementer from zope.publisher.browser import applySkin from zope.location import locate from zope.location.interfaces import ILocation @@ -26,6 +26,7 @@ from zope.app.apidoc.interfaces import IDocumentationModule from zope.app.apidoc.utilities import ReadContainerBase +@implementer(ILocation) class APIDocumentation(ReadContainerBase): """Represent the complete API Documentation. @@ -33,7 +34,6 @@ class APIDocumentation(ReadContainerBase): items of the container are all registered utilities for `IDocumentationModule`. """ - implements(ILocation) def __init__(self, parent, name): self.__parent__ = parent diff --git a/src/zope/app/apidoc/browser/README.txt b/src/zope/app/apidoc/browser/README.rst similarity index 94% rename from src/zope/app/apidoc/browser/README.txt rename to src/zope/app/apidoc/browser/README.rst index 99e12d00..920d0524 100644 --- a/src/zope/app/apidoc/browser/README.txt +++ b/src/zope/app/apidoc/browser/README.rst @@ -4,7 +4,7 @@ Generic API Doc Views Get a browser started: - >>> from zope.testbrowser.testing import Browser + >>> from zope.testbrowser.wsgi import Browser >>> browser = Browser() >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw') @@ -38,4 +38,3 @@ feel better and does not have all the O-wrap clutter: zope-dev@zope.org.

... - diff --git a/src/zope/app/apidoc/browser/configure.zcml b/src/zope/app/apidoc/browser/configure.zcml index c59e51c0..ec8c2a17 100644 --- a/src/zope/app/apidoc/browser/configure.zcml +++ b/src/zope/app/apidoc/browser/configure.zcml @@ -4,6 +4,8 @@ xmlns:zcml="http://namespaces.zope.org/zcml" i18n_domain="zope"> + + + + + + - diff --git a/src/zope/app/apidoc/browser/nodevmode.txt b/src/zope/app/apidoc/browser/nodevmode.rst similarity index 94% rename from src/zope/app/apidoc/browser/nodevmode.txt rename to src/zope/app/apidoc/browser/nodevmode.rst index 85fef522..07877630 100644 --- a/src/zope/app/apidoc/browser/nodevmode.txt +++ b/src/zope/app/apidoc/browser/nodevmode.rst @@ -9,7 +9,7 @@ informing the user that the API docs are disabled. We do this as we changed the default during the release of Zope 3.3 and many developers will still assume that their instances are running in developer mode, while they aren't. - >>> from zope.testbrowser.testing import Browser + >>> from zope.testbrowser.wsgi import Browser >>> browser = Browser() >>> browser.handleErrors = False >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw') diff --git a/src/zope/app/apidoc/browser/skin.py b/src/zope/app/apidoc/browser/skin.py index e5bea060..55279a24 100644 --- a/src/zope/app/apidoc/browser/skin.py +++ b/src/zope/app/apidoc/browser/skin.py @@ -13,7 +13,6 @@ ############################################################################## """`APIdoc` skin. -$Id$ """ __docformat__ = "reStructuredText" diff --git a/src/zope/app/apidoc/browser/tests.py b/src/zope/app/apidoc/browser/tests.py index fa354929..049e9825 100644 --- a/src/zope/app/apidoc/browser/tests.py +++ b/src/zope/app/apidoc/browser/tests.py @@ -13,21 +13,21 @@ ############################################################################## """Functional Tests for API Documentation. -$Id$ """ import re import unittest import doctest -import zope.app.testing.functional from zope.testing import renormalizing -from zope.app.testing.functional import BrowserTestCase, FunctionalNoDevMode -from zope.app.testing.functional import FunctionalDocFileSuite from zope.app.apidoc.testing import APIDocLayer, APIDocNoDevModeLayer +from zope.app.apidoc.tests import BrowserTestCase + class APIDocTests(BrowserTestCase): """Just a couple of tests ensuring that the templates render.""" + layer = APIDocLayer + def testMenu(self): response = self.publish('/++apidoc++/menu.html', basic='mgr:mgrpw') @@ -67,22 +67,21 @@ def testModuleListView(self): checker = renormalizing.RENormalizing([ (re.compile(r'httperror_seek_wrapper:', re.M), 'HTTPError:'), - ]) +]) def test_suite(): suite = unittest.TestSuite() - APIDocTests.layer = APIDocLayer suite.addTest(unittest.makeSuite(APIDocTests)) - apidoc_doctest = FunctionalDocFileSuite( - "README.txt", + apidoc_doctest = doctest.DocFileSuite( + "README.rst", optionflags=doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE, checker=checker) apidoc_doctest.layer = APIDocLayer suite.addTest( apidoc_doctest, - ) + ) - nodevmode = FunctionalDocFileSuite("nodevmode.txt") + nodevmode = doctest.DocFileSuite("nodevmode.rst") nodevmode.layer = APIDocNoDevModeLayer suite.addTest(nodevmode) return suite diff --git a/src/zope/app/apidoc/classregistry.py b/src/zope/app/apidoc/classregistry.py index b9e7d756..3b378700 100644 --- a/src/zope/app/apidoc/classregistry.py +++ b/src/zope/app/apidoc/classregistry.py @@ -12,8 +12,6 @@ # ############################################################################## """Class Registry - -$Id$ """ __docformat__ = 'restructuredtext' @@ -33,8 +31,10 @@ def getClassesThatImplement(self, iface): Methods returns a list of 2-tuples of the form (path, class). """ - return [(path, klass) for path, klass in self.items() - if iface.implementedBy(klass)] + result = [(path, klass) for path, klass in self.items() + if iface.implementedBy(klass)] + result.sort(key=lambda x: x[0]) + return result def getSubclassesOf(self, klass): """Return all class items that are proper subclasses of klass. diff --git a/src/zope/app/apidoc/classregistry.txt b/src/zope/app/apidoc/classregistry.rst similarity index 100% rename from src/zope/app/apidoc/classregistry.txt rename to src/zope/app/apidoc/classregistry.rst index 09dfbfdb..152d8fd8 100644 --- a/src/zope/app/apidoc/classregistry.txt +++ b/src/zope/app/apidoc/classregistry.rst @@ -68,8 +68,8 @@ This method returns all classes that implement the specified interface: >>> from pprint import pprint >>> pprint(reg.getClassesThatImplement(IA)) #doctest:+ELLIPSIS [('A', ), - ('B', ), ('A2', ), + ('B', ), ('B2', )] >>> pprint(reg.getClassesThatImplement(IB)) #doctest:+ELLIPSIS diff --git a/src/zope/app/apidoc/codemodule/README.txt b/src/zope/app/apidoc/codemodule/README.rst similarity index 96% rename from src/zope/app/apidoc/codemodule/README.txt rename to src/zope/app/apidoc/codemodule/README.rst index ec2f3f4d..052438aa 100644 --- a/src/zope/app/apidoc/codemodule/README.txt +++ b/src/zope/app/apidoc/codemodule/README.rst @@ -26,8 +26,8 @@ different: >>> cm.isPackage() True - >>> cm.keys() - [] + >>> sorted(cm.keys()) + [u'BTrees', u'ZConfig', u'ZODB', u'persistent', u'transaction', u'zope'] Module @@ -90,7 +90,7 @@ still get to them: >>> names = module['tests'].keys() >>> names.sort() >>> names - ['Root', 'rootLocation', 'setUp', 'tearDown', 'test_suite'] + ['BrowserTestCase', 'Root', 'rootLocation', 'setUp', 'tearDown', 'test_suite'] Classes @@ -265,8 +265,8 @@ Text files represent plain-text documentation files like this one. Once we have a text file documentation object >>> import os - >>> path = os.path.join(os.path.dirname(codemodule.__file__), 'README.txt') - >>> readme = codemodule.text.TextFile(path, 'README.txt', module) + >>> path = os.path.join(os.path.dirname(codemodule.__file__), 'README.rst') + >>> readme = codemodule.text.TextFile(path, 'README.rst', module) we can ask it for the content of the file: @@ -325,8 +325,7 @@ the parser info object, >>> info = info.replace('\\', '/') >>> print info #doctest:+ELLIPSIS - File - ".../zope/app/apidoc/codemodule/configure.zcml", line 1.0-54.0 + File ".../zope/app/apidoc/codemodule/configure.zcml", ... the sub-directives, @@ -340,4 +339,3 @@ and finally a list of all prefixes. {u'http://namespaces.zope.org/apidoc': u'apidoc', u'http://namespaces.zope.org/browser': u'browser', u'http://namespaces.zope.org/zope': None} - diff --git a/src/zope/app/apidoc/codemodule/browser/README.txt b/src/zope/app/apidoc/codemodule/browser/README.rst similarity index 88% rename from src/zope/app/apidoc/codemodule/browser/README.txt rename to src/zope/app/apidoc/codemodule/browser/README.rst index be655c21..d6e70697 100644 --- a/src/zope/app/apidoc/codemodule/browser/README.txt +++ b/src/zope/app/apidoc/codemodule/browser/README.rst @@ -44,7 +44,7 @@ Return info objects for all classes in this module. >>> pprint(details.getClasses()) [{'doc': 'Represent the code browser documentation root', 'name': 'CodeModule', - 'url': 'http://127.0.0.1/++apidoc++/Code/zope/app/apidoc/codemodule/codemodule/CodeModule'}] + 'url': 'http://127.0.0.1/++etc++site/++apidoc++/Code/zope/app/apidoc/codemodule/codemodule/CodeModule'}] This module doesn't contain anything else. @@ -75,17 +75,17 @@ way up to the root, but we just want to go to the root module. >>> bc.request = details.request >>> pprint(bc(), width=1) [{'name': u'[top]', - 'url': 'http://127.0.0.1/++apidoc++/Code'}, + 'url': 'http://127.0.0.1/++etc++site/++apidoc++/Code'}, {'name': u'zope', - 'url': 'http://127.0.0.1/++apidoc++/Code/zope'}, + 'url': 'http://127.0.0.1/++etc++site/++apidoc++/Code/zope'}, {'name': 'app', - 'url': 'http://127.0.0.1/++apidoc++/Code/zope/app'}, + 'url': 'http://127.0.0.1/++etc++site/++apidoc++/Code/zope/app'}, {'name': 'apidoc', - 'url': 'http://127.0.0.1/++apidoc++/Code/zope/app/apidoc'}, + 'url': 'http://127.0.0.1/++etc++site/++apidoc++/Code/zope/app/apidoc'}, {'name': 'codemodule', - 'url': 'http://127.0.0.1/++apidoc++/Code/zope/app/apidoc/codemodule'}, + 'url': 'http://127.0.0.1/++etc++site/++apidoc++/Code/zope/app/apidoc/codemodule'}, {'name': 'codemodule', - 'url': 'http://127.0.0.1/++apidoc++/Code/zope/app/apidoc/codemodule/codemodule'}] + 'url': 'http://127.0.0.1/++etc++site/++apidoc++/Code/zope/app/apidoc/codemodule/codemodule'}] Class Details @@ -109,7 +109,7 @@ Get all bases of this class. >>> pprint(details.getBases()) [{'path': 'zope.app.apidoc.codemodule.module.Module', - 'url': 'http://127.0.0.1/++apidoc++/Code/zope/app/apidoc/codemodule/module/Module'}] + 'url': 'http://127.0.0.1/++etc++site/++apidoc++/Code/zope/app/apidoc/codemodule/module/Module'}] `getKnownSubclasses()` ~~~~~~~~~~~~~~~~~~~~~~ @@ -130,9 +130,9 @@ Prepare a list of classes for presentation. ... zope.app.apidoc.apidoc.APIDocumentation, ... zope.app.apidoc.codemodule.codemodule.Module])) [{'path': 'zope.app.apidoc.apidoc.APIDocumentation', - 'url': 'http://127.0.0.1/++apidoc++/Code/zope/app/apidoc/apidoc/APIDocumentation'}, + 'url': 'http://127.0.0.1/++etc++site/++apidoc++/Code/zope/app/apidoc/apidoc/APIDocumentation'}, {'path': 'zope.app.apidoc.codemodule.module.Module', - 'url': 'http://127.0.0.1/++apidoc++/Code/zope/app/apidoc/codemodule/module/Module'}] + 'url': 'http://127.0.0.1/++etc++site/++apidoc++/Code/zope/app/apidoc/codemodule/module/Module'}] `getBaseURL()` ~~~~~~~~~~~~~~ @@ -143,7 +143,7 @@ Note that the following output is a bit different than usual, since we have not setup all path elements. >>> details.getBaseURL() - 'http://127.0.0.1/++apidoc++' + 'http://127.0.0.1/++etc++site/++apidoc++' `getInterfaces()` ~~~~~~~~~~~~~~~~~ @@ -178,11 +178,11 @@ Get all attributes of this class. {'interface': {'path': 'zope.app.apidoc.interfaces.IDocumentationModule', 'url': 'zope.app.apidoc.interfaces.IDocumentationModule'}, 'name': 'title', - 'read_perm': None, + 'read_perm': 'zope.Public', 'type': 'Message', 'type_link': 'zope/i18nmessageid/message/Message', 'value': "u'Code Browser'", - 'write_perm': None} + 'write_perm': u'n/a'} `getMethods()` ~~~~~~~~~~~~~~ @@ -192,16 +192,16 @@ Get all methods of this class. [{'doc': u'

Setup module and class tree.

\n', 'interface': None, 'name': 'setup', - 'read_perm': None, + 'read_perm': u'n/a', 'signature': '()', - 'write_perm': None}, + 'write_perm': u'n/a'}, {'doc': u'', 'interface': {'path': 'zope.interface.common.mapping.IEnumerableMapping', 'url': 'zope.interface.common.mapping.IEnumerableMapping'}, 'name': 'values', - 'read_perm': None, + 'read_perm': 'zope.Public', 'signature': '()', - 'write_perm': None}] + 'write_perm': u'n/a'}] `getDoc()` ~~~~~~~~~~ @@ -251,7 +251,7 @@ Get all attributes of this function. Return the URL for the API Documentation Tool. >>> details.getBaseURL() - 'http://127.0.0.1/++apidoc++' + 'http://127.0.0.1/++etc++site/++apidoc++' Text File Details @@ -262,7 +262,7 @@ documentation component: >>> details = browser.text.TextFileDetails() >>> details.context = traverse(cm, - ... 'zope/app/apidoc/codemodule/README.txt') + ... 'zope/app/apidoc/codemodule/README.rst') >>> details.request = TestRequest() Here are the methods: @@ -330,7 +330,7 @@ Returns the URL of the directive docuemntation in the ZCML documentation module. >>> details.url() - u'http://127.0.0.1/++apidoc++/ZCML/ALL/configure/index.html' + u'http://127.0.0.1/++etc++site/++apidoc++/ZCML/ALL/configure/index.html' `objectURL(value, field, rootURL)` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -342,7 +342,7 @@ crafts a documentation URL for it: >>> field = GlobalObject() >>> details.objectURL('.interfaces.IZCMLFile', field, '') - 'http://127.0.0.1/++apidoc++/Interface/zope.app.apidoc.codemodule.interfaces.IZCMLFile/index.html' + 'http://127.0.0.1/++etc++site/++apidoc++/Interface/zope.app.apidoc.codemodule.interfaces.IZCMLFile/index.html' >>> details.objectURL('.zcml.ZCMLFile', field, '') '/zope/app/apidoc/codemodule/zcml/ZCMLFile/index.html' @@ -371,8 +371,7 @@ will be listed too. >>> details.context = details.context.subs[0] >>> pprint(details.attributes()) [{'name': u'class', - 'url': - 'http://127.0.0.1/++apidoc++/Code/zope/app/apidoc/codemodule/module/Module/index.html', + 'url': 'http://127.0.0.1/++etc++site/++apidoc++/Code/zope/app/apidoc/codemodule/module/Module/index.html', 'value': u'.module.Module', 'values': []}] @@ -481,20 +480,20 @@ class. In the following section we are going to demonstrate the methods used to collect the data. First we need to create an object though; let's use a root folder: - >>> rootFolder + >>> rootFolder.__parent__ Now we instantiate the view >>> from zope.publisher.browser import TestRequest >>> request = TestRequest() - >>> inspect = introspector.Introspector(rootFolder, request) + >>> inspect = introspector.Introspector(rootFolder.__parent__, request) so that we can start looking at the methods. First we should note that the class documentation view is directly available: >>> inspect.klassView - + >>> inspect.klassView.context @@ -512,8 +511,7 @@ You can also get the base URL of the request: Next you can get a list of all directly provided interfaces: >>> ifaces = inspect.getDirectlyProvidedInterfaces() - >>> ifaces.sort() - >>> ifaces + >>> sorted(ifaces) ['zope.component.interfaces.ISite', 'zope.site.interfaces.IRootFolder'] The ``getProvidedInterfaces()`` and ``getBases()`` method simply forwards its @@ -524,12 +522,12 @@ object's attributes: >>> pprint(list(inspect.getAttributes())) [{'interface': None, 'name': 'data', - 'read_perm': None, + 'read_perm': u'n/a', 'type': 'OOBTree', 'type_link': 'BTrees/OOBTree/OOBTree', 'value': '', 'value_linkable': True, - 'write_perm': None}] + 'write_perm': u'n/a'}] Of course, the methods are listed as well: @@ -538,22 +536,22 @@ Of course, the methods are listed as well: {'doc': u'', 'interface': 'zope.component.interfaces.IPossibleSite', 'name': 'getSiteManager', - 'read_perm': None, + 'read_perm': 'zope.Public', 'signature': '()', - 'write_perm': None}, + 'write_perm': u'n/a'}, ... {'doc': u'', 'interface': 'zope.container.interfaces.IBTreeContainer', 'name': 'keys', - 'read_perm': None, + 'read_perm': 'zope.View', 'signature': '(key=None)', - 'write_perm': None}, + 'write_perm': u'n/a'}, {'doc': u'', 'interface': 'zope.component.interfaces.IPossibleSite', 'name': 'setSiteManager', - 'read_perm': None, + 'read_perm': 'zope.ManageServices', 'signature': '(sm)', - 'write_perm': None}, + 'write_perm': u'n/a'}, ...] The final methods deal with inspecting the objects data further. For exmaple, @@ -586,7 +584,7 @@ and then get the sequence items: Similar functionality exists for a mapping. But we first have to add an item: - >>> rootFolder['list'] = list + >>> rootFolder.__parent__['list'] = list Now let's have a look: @@ -594,11 +592,13 @@ Now let's have a look: True >>> pprint(inspect.getMappingItems()) - [{'key': u'list', + [... + {'key': u'list', 'key_string': "u'list'", 'value': "['one', 'two']", 'value_type': 'ContainedProxy', - 'value_type_link': 'zope/container/contained/ContainedProxy'}] + 'value_type_link': 'zope/container/contained/ContainedProxy'}, + ...] The final two methods doeal with the introspection of the annotations. If an object is annotatable, @@ -608,7 +608,7 @@ object is annotatable, then we can get an annotation mapping: - >>> rootFolder.__annotations__ = {'my.list': list} + >>> rootFolder.__parent__.__annotations__ = {'my.list': list} >>> pprint(inspect.getAnnotationsInfo()) [{'key': 'my.list', diff --git a/src/zope/app/apidoc/codemodule/browser/class_.py b/src/zope/app/apidoc/codemodule/browser/class_.py index b10f4d31..3610619d 100644 --- a/src/zope/app/apidoc/codemodule/browser/class_.py +++ b/src/zope/app/apidoc/codemodule/browser/class_.py @@ -13,7 +13,6 @@ ############################################################################## """Class Views -$Id$ """ __docformat__ = 'restructuredtext' diff --git a/src/zope/app/apidoc/codemodule/browser/introspector.txt b/src/zope/app/apidoc/codemodule/browser/introspector.rst similarity index 86% rename from src/zope/app/apidoc/codemodule/browser/introspector.txt rename to src/zope/app/apidoc/codemodule/browser/introspector.rst index 1cb620ae..4dbe395a 100644 --- a/src/zope/app/apidoc/codemodule/browser/introspector.txt +++ b/src/zope/app/apidoc/codemodule/browser/introspector.rst @@ -6,7 +6,7 @@ The "Introspector" view provides access to information about the current obejct, the context of the introspector view. When in `devmode`, the introspector is simply available as follows: - >>> from zope.testbrowser.testing import Browser + >>> from zope.testbrowser.wsgi import Browser >>> browser = Browser() >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw') >>> browser.handleErrors = False @@ -169,22 +169,33 @@ provides is the Dublin Core: Annotations -
- + +
+ + + + +
+
+ ... @@ -194,14 +205,14 @@ As you can see you can click on the annotation to discover it further: >>> print browser.contents Constructor +

Constructor

+
- __init__(dict=None, **kwargs) + __init__(*args, **kwargs)
-
... That's it! The introspector view has a lot more potential, but that's for diff --git a/src/zope/app/apidoc/codemodule/browser/menu.py b/src/zope/app/apidoc/codemodule/browser/menu.py index cd44916b..bc4b8d11 100644 --- a/src/zope/app/apidoc/codemodule/browser/menu.py +++ b/src/zope/app/apidoc/codemodule/browser/menu.py @@ -13,7 +13,6 @@ ############################################################################## """Code Module Menu -$Id$ """ __docformat__ = 'restructuredtext' from zope.component import getUtility @@ -66,22 +65,22 @@ def findClasses(self): >>> from pprint import pprint >>> pprint(info) [{'path': 'zope.app.apidoc.codemodule.browser.Foo', - 'url': 'http://127.0.0.1/++apidoc++/Code/zope/app/apidoc/codemodule/browser/Foo/'}, + 'url': 'http://127.0.0.1/++etc++site/++apidoc++/Code/zope/app/apidoc/codemodule/browser/Foo/'}, {'path': 'zope.app.apidoc.codemodule.browser.Foo2', - 'url': 'http://127.0.0.1/++apidoc++/Code/zope/app/apidoc/codemodule/browser/Foo2/'}] + 'url': 'http://127.0.0.1/++etc++site/++apidoc++/Code/zope/app/apidoc/codemodule/browser/Foo2/'}] >>> menu.request = TestRequest(form={'path': 'o2'}) >>> info = menu.findClasses() >>> pprint(info) [{'path': 'zope.app.apidoc.codemodule.browser.Foo2', - 'url': 'http://127.0.0.1/++apidoc++/Code/zope/app/apidoc/codemodule/browser/Foo2/'}] + 'url': 'http://127.0.0.1/++etc++site/++apidoc++/Code/zope/app/apidoc/codemodule/browser/Foo2/'}] >>> menu.request = TestRequest(form={'path': 'Blah'}) >>> info = menu.findClasses() >>> pprint(info) [{'path': 'zope.app.apidoc.codemodule.browser.Blah', - 'url': 'http://127.0.0.1/++apidoc++/Code/zope/app/apidoc/codemodule/browser/Blah/'}] + 'url': 'http://127.0.0.1/++etc++site/++apidoc++/Code/zope/app/apidoc/codemodule/browser/Blah/'}] """ path = self.request.get('path', None) @@ -96,7 +95,7 @@ def findClasses(self): {'path': p, 'url': absoluteURL(klass, self.request) + '/' }) - results.sort(lambda x, y: cmp(x['path'], y['path'])) + results.sort(key=lambda x: x['path']) return results def findAllClasses(self): @@ -139,6 +138,7 @@ def findAllClasses(self): classModule.setup() # run setup if not yet done results = [] counter = 0 + for p in classRegistry.keys(): klass = traverse(classModule, p.replace('.', '/')) results.append( @@ -148,5 +148,5 @@ def findAllClasses(self): }) counter += 1 - results.sort(lambda x, y: cmp(x['path'], y['path'])) + results.sort(key=lambda x: x['path']) return results diff --git a/src/zope/app/apidoc/codemodule/browser/tests.py b/src/zope/app/apidoc/codemodule/browser/tests.py index dab1fda6..0c000b00 100644 --- a/src/zope/app/apidoc/codemodule/browser/tests.py +++ b/src/zope/app/apidoc/codemodule/browser/tests.py @@ -13,28 +13,31 @@ ############################################################################## """Tests for the Code Documentation Module -$Id$ """ +from __future__ import absolute_import import os import unittest import doctest import re +from zope import component as ztapi +from zope import interface from zope.component.interfaces import IFactory from zope.configuration import xmlconfig -from zope.interface import implements +from zope.interface import implementer from zope.testing import renormalizing -from zope.traversing.interfaces import IContainmentRoot +from zope.app.component.testing import PlacefulSetup import zope.app import zope.app.appsetup.appsetup from zope.app.renderer.rest import ReStructuredTextSourceFactory from zope.app.renderer.rest import IReStructuredTextSource from zope.app.renderer.rest import ReStructuredTextToHTMLRenderer -from zope.app.testing import placelesssetup, setup, ztapi -from zope.app.testing.functional import BrowserTestCase -from zope.app.testing.functional import FunctionalDocFileSuite +from zope.app.apidoc.tests import BrowserTestCase + +from zope.app.apidoc.apidoc import apidocNamespace +from zope.traversing.interfaces import ITraversable from zope.app.apidoc.interfaces import IDocumentationModule from zope.app.apidoc.apidoc import APIDocumentation from zope.app.apidoc.codemodule.interfaces import IAPIDocRootModule @@ -54,56 +57,82 @@ def foo(cls, bar=1, *args): """This is the foo function.""" foo.deprecated = True -meta = ''' - - - - - - -''' +# meta = ''' +# +# +# +# +# +# +# ''' + +def _setUp_AppSetup(): + config_file = os.path.join( + os.path.dirname(zope.app.apidoc.__file__), 'configure.zcml') + + # # Fix up path for tests. + global old_context + old_context = zope.app.appsetup.appsetup.getConfigContext() + zope.app.appsetup.appsetup.__config_context = xmlconfig.file( + config_file, zope.app.apidoc, execute=False) + +def _tearDown_AppSetup(): + zope.app.appsetup.appsetup.__config_context = old_context + def setUp(test): - test.globs['rootFolder'] = setup.placefulSetUp(True) + test.globs['rootFolder'] = PlacefulSetup().setUp(True, True) + # from zope.interface import alsoProvides + # from zope.annotation.interfaces import IAnnotatable + # alsoProvides(test.globs['rootFolder'], IAnnotatable) + # alsoProvides(test.globs['rootFolder'].__parent__, IAnnotatable) + @implementer(IAPIDocRootModule) class RootModule(str): - implements(IAPIDocRootModule) + pass # Register zope package to apidoc - ztapi.provideUtility(IAPIDocRootModule, RootModule('zope'), "zope") + ztapi.provideUtility(RootModule('zope'), IAPIDocRootModule, "zope") # Set up apidoc module test.globs['apidoc'] = APIDocumentation(test.globs['rootFolder'], '++apidoc++') - # Register documentation modules - ztapi.provideUtility(IDocumentationModule, CodeModule(), "Code") - ztapi.provideUtility(IDocumentationModule, ZCMLModule(), "ZCML") # Register Renderer Components - ztapi.provideUtility(IFactory, ReStructuredTextSourceFactory, - 'zope.source.rest') - ztapi.browserView(IReStructuredTextSource, '', - ReStructuredTextToHTMLRenderer) - # Cheat and register the ReST factory for STX as well. - ztapi.provideUtility(IFactory, ReStructuredTextSourceFactory, - 'zope.source.stx') + # ztapi.provideUtility(IFactory, ReStructuredTextSourceFactory, + # 'zope.source.rest') + # ztapi.browserView(IReStructuredTextSource, '', + # ReStructuredTextToHTMLRenderer) + # # Cheat and register the ReST factory for STX as well. + # ztapi.provideUtility(IFactory, ReStructuredTextSourceFactory, + # 'zope.source.stx') + import zope.app.renderer + context = xmlconfig.file('ftesting.zcml', zope.app.apidoc) + + from zope.dublincore.interfaces import IWriteZopeDublinCore + IWriteZopeDublinCore(test.globs['rootFolder'].__parent__) + + # Register documentation modules. Override what we got from + # ftesting-base (non-devmode) + # ztapi.provideUtility(CodeModule(), IDocumentationModule,"Code") + # ztapi.provideUtility(ZCMLModule(), IDocumentationModule, "ZCML") # Register ++apidoc++ namespace - from zope.app.apidoc.apidoc import apidocNamespace - from zope.traversing.interfaces import ITraversable - ztapi.provideAdapter(None, ITraversable, apidocNamespace, name="apidoc") - ztapi.provideView(None, None, ITraversable, "apidoc", apidocNamespace) + # from zope.app.apidoc.apidoc import apidocNamespace + # from zope.traversing.interfaces import ITraversable + # ztapi.provideAdapter(apidocNamespace, (interface.Interface,), ITraversable, name="apidoc") + # ztapi.provideView(None, None, ITraversable, "apidoc", apidocNamespace) # Register ++apidoc++ namespace - from zope.traversing.namespace import view - from zope.traversing.interfaces import ITraversable - ztapi.provideAdapter(None, ITraversable, view, name="view") - ztapi.provideView(None, None, ITraversable, "view", view) + # ztapi.provideView(None, None, ITraversable, "view", view) + # from zope.traversing.namespace import view + # from zope.traversing.interfaces import ITraversable + # ztapi.provideAdapter(None, ITraversable, view, name="view") - context = xmlconfig.string(meta) + # context = xmlconfig.string(meta) # Fix up path for tests. global old_context @@ -114,19 +143,19 @@ class RootModule(str): global old_source_file old_source_file = zope.app.appsetup.appsetup.__config_source zope.app.appsetup.appsetup.__config_source = os.path.join( - os.path.dirname(zope.app.zcmlfiles.__file__), 'meta.zcml') + os.path.dirname(zope.app.apidoc.__file__), 'meta.zcml') # Register the index.html view for codemodule.class_.Class - from zope.publisher.browser import BrowserView - from zope.app.apidoc.codemodule.class_ import Class - from zope.app.apidoc.codemodule.browser.class_ import ClassDetails - class Details(ClassDetails, BrowserView): - pass - ztapi.browserView(Class, 'index.html', Details) + # from zope.publisher.browser import BrowserView + # from zope.app.apidoc.codemodule.class_ import Class + # from zope.app.apidoc.codemodule.browser.class_ import ClassDetails + # class Details(ClassDetails, BrowserView): + # pass + # ztapi.browserView(Class, 'index.html', Details) def tearDown(test): - setup.placefulTearDown() + PlacefulSetup().tearDown() global old_context, old_source_file zope.app.appsetup.appsetup.__config_context = old_context zope.app.appsetup.appsetup.__config_source = old_source_file @@ -183,17 +212,18 @@ def testFunctionDetailsView(self): body = response.getBody() self.assert_(body.find('handleNamespace(ob, name)') > 0) self.checkForBrokenLinks( - body, '/++apidoc++/Code/zope/app/apidoc/apidoc/handleNamesapce', - basic='mgr:mgrpw') + body, + '/++apidoc++/Code/zope/app/apidoc/apidoc/handleNamespace', + basic='mgr:mgrpw') def testTextFileDetailsView(self): response = self.publish( - '/++apidoc++/Code/zope/app/apidoc/README.txt/index.html', + '/++apidoc++/Code/zope/app/apidoc/README.rst/index.html', basic='mgr:mgrpw') self.assertEqual(response.getStatus(), 200) body = response.getBody() self.checkForBrokenLinks( - body, '/++apidoc++/Code/zope/app/apidoc/README.txt/index.html', + body, '/++apidoc++/Code/zope/app/apidoc/README.rst/index.html', basic='mgr:mgrpw') def testZCMLFileDetailsView(self): @@ -210,15 +240,15 @@ def testZCMLFileDetailsView(self): def test_suite(): checker = renormalizing.RENormalizing([ (re.compile(r" with base 10: 'text'"), r': text'), - ]) + ]) CodeModuleTests.layer = APIDocLayer - introspector = FunctionalDocFileSuite( - "introspector.txt", + introspector = doctest.DocFileSuite( + "introspector.rst", optionflags=doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE) introspector.layer = APIDocLayer return unittest.TestSuite(( doctest.DocFileSuite( - 'README.txt', + 'README.rst', setUp=setUp, tearDown=tearDown,checker=checker, optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS), doctest.DocTestSuite( @@ -227,7 +257,7 @@ def test_suite(): optionflags=doctest.NORMALIZE_WHITESPACE), unittest.makeSuite(CodeModuleTests), introspector, - )) + )) if __name__ == '__main__': - unittest.main(default="test_suite") + unittest.main() diff --git a/src/zope/app/apidoc/codemodule/codemodule.py b/src/zope/app/apidoc/codemodule/codemodule.py index 4f619763..db02f262 100644 --- a/src/zope/app/apidoc/codemodule/codemodule.py +++ b/src/zope/app/apidoc/codemodule/codemodule.py @@ -16,13 +16,12 @@ This module is able to take a dotted name of any class and display documentation for it. -$Id$ """ __docformat__ = 'restructuredtext' import zope.component from zope.i18nmessageid import ZopeMessageFactory as _ -from zope.interface import implements +from zope.interface import implementer from zope.app.apidoc.interfaces import IDocumentationModule from zope.app.apidoc.classregistry import safe_import @@ -30,9 +29,9 @@ from zope.app.apidoc.codemodule.module import Module +@implementer(IDocumentationModule) class CodeModule(Module): """Represent the code browser documentation root""" - implements(IDocumentationModule) # See zope.app.apidoc.interfaces.IDocumentationModule title = _('Code Browser') diff --git a/src/zope/app/apidoc/codemodule/configure.zcml b/src/zope/app/apidoc/codemodule/configure.zcml index 5ed60645..5d0d9bc6 100644 --- a/src/zope/app/apidoc/codemodule/configure.zcml +++ b/src/zope/app/apidoc/codemodule/configure.zcml @@ -33,6 +33,9 @@
+ + + diff --git a/src/zope/app/apidoc/codemodule/directives.txt b/src/zope/app/apidoc/codemodule/directives.rst similarity index 100% rename from src/zope/app/apidoc/codemodule/directives.txt rename to src/zope/app/apidoc/codemodule/directives.rst diff --git a/src/zope/app/apidoc/codemodule/module.py b/src/zope/app/apidoc/codemodule/module.py index 3cfe815c..a560e999 100644 --- a/src/zope/app/apidoc/codemodule/module.py +++ b/src/zope/app/apidoc/codemodule/module.py @@ -13,14 +13,13 @@ ############################################################################## """Module representation for code browser -$Id$ """ __docformat__ = 'restructuredtext' import os import types import zope -from zope.interface import implements +from zope.interface import implementer from zope.interface import providedBy from zope.interface.interface import InterfaceClass from zope.location.interfaces import ILocation @@ -41,9 +40,9 @@ IGNORE_FILES = ('tests', 'tests.py', 'ftests', 'ftests.py', 'CVS', 'gadfly', 'setup.py', 'introspection.py', 'Mount.py') +@implementer(ILocation, IModuleDocumentation) class Module(ReadContainerBase): """This class represents a Python module.""" - implements(ILocation, IModuleDocumentation) def __init__(self, parent, name, module, setup=True): """Initialize object.""" @@ -55,6 +54,18 @@ def __init__(self, parent, name, module, setup=True): if setup: self.__setup() + def __XXXrepr__(self): + cls = self.__class__ + path = [] + i = self + while i is not None: + path.append(getattr(i, '__name__', '') or '') + i = i.__parent__ + path.reverse() + path = '.'.join(path) + return "<%s.%s '%s' at %s>" % (cls.__module__, cls.__name__, + path, id(self)) + def __setup(self): """Setup the module sub-tree.""" # Detect packages @@ -95,7 +106,7 @@ def __setup(self): self._children[file] = ZCMLFile(path, self._module, self, file) - elif os.path.isfile(path) and file.endswith('.txt'): + elif os.path.isfile(path) and file.endswith(('.txt', '.rst')): self._children[file] = TextFile(path, file, self) # List the classes and functions in module, if any are available. @@ -133,8 +144,8 @@ def __setup(self): if attr is None: continue - if isinstance(attr, hookable): - attr = attr.implementation + if isinstance(attr, hookable): + attr = attr.implementation if isinstance(attr, (types.ClassType, types.TypeType)): self._children[name] = Class(self, name, attr) @@ -187,7 +198,9 @@ def get(self, key, default=None): obj = safe_import(path) if obj is not None: - return Module(self, key, obj) + child = Module(self, key, obj) + self._children[key] = child + return child # Maybe it is a simple attribute of the module if obj is None: diff --git a/src/zope/app/apidoc/codemodule/tests.py b/src/zope/app/apidoc/codemodule/tests.py index 8f5a9ac6..41a598c9 100644 --- a/src/zope/app/apidoc/codemodule/tests.py +++ b/src/zope/app/apidoc/codemodule/tests.py @@ -13,7 +13,6 @@ ############################################################################## """Tests for the Code Documentation Module -$Id$ """ import os import unittest @@ -21,28 +20,37 @@ from zope.configuration import xmlconfig import zope.app.appsetup.appsetup -from zope.app.testing import placelesssetup +from zope.component import testing def setUp(test): - placelesssetup.setUp() + testing.setUp() meta = ''' - - + ''' - xmlconfig.string(meta) + context = xmlconfig.string(meta) - meta = os.path.join(os.path.dirname(zope.app.zcmlfiles.__file__), 'meta.zcml') - context = xmlconfig.file(meta, zope.app.zcmlfiles) - context.provideFeature('devmode') - meta = os.path.join(os.path.dirname(zope.app.apidoc.__file__), 'meta.zcml') - context = xmlconfig.file(meta, zope.app.apidoc, context) + # ctx = xmlconfig.file('meta.zcml', zope.security) + # ctx = xmlconfig.file('meta.zcml', ztapi, context=ctx) + # ctx = xmlconfig.file('meta.zcml', zope.browserresource, context=ctx) + # ctx = xmlconfig.file('meta.zcml', zope.browserpage, context=ctx) + # ctx = xmlconfig.file('configure.zcml', zope.location, context=ctx) + # ctx = xmlconfig.file('configure.zcml', zope.traversing, context=ctx) + # ctx = xmlconfig.file('configure.zcml', zope.security, context=ctx) + # xmlconfig.file('configure.zcml', zope.app.tree, context=ctx) + + + # meta = os.path.join(os.path.dirname(zope.app.zcmlfiles.__file__), 'meta.zcml') + # context = xmlconfig.file(meta, zope.app.zcmlfiles) + # context.provideFeature('devmode') + # meta = os.path.join(os.path.dirname(zope.app.apidoc.__file__), 'meta.zcml') + # context = xmlconfig.file(meta, zope.app.apidoc, context) # Fix up path for tests. global old_context @@ -50,20 +58,20 @@ def setUp(test): zope.app.appsetup.appsetup.__config_context = context def tearDown(test): - placelesssetup.tearDown() + testing.tearDown() global old_context zope.app.appsetup.appsetup.__config_context = old_context def test_suite(): return unittest.TestSuite(( - doctest.DocFileSuite('README.txt', + doctest.DocFileSuite('README.rst', setUp=setUp, tearDown=tearDown, optionflags=doctest.NORMALIZE_WHITESPACE), - doctest.DocFileSuite('directives.txt', - setUp=placelesssetup.setUp, - tearDown=placelesssetup.tearDown), - )) + doctest.DocFileSuite('directives.rst', + setUp=testing.setUp, + tearDown=testing.tearDown), + )) if __name__ == '__main__': unittest.main(default="test_suite") diff --git a/src/zope/app/apidoc/codemodule/zcml.py b/src/zope/app/apidoc/codemodule/zcml.py index d56db1cc..47dc4b0b 100644 --- a/src/zope/app/apidoc/codemodule/zcml.py +++ b/src/zope/app/apidoc/codemodule/zcml.py @@ -12,8 +12,6 @@ # ############################################################################## """ZCML File Representation - -$Id$ """ __docformat__ = "reStructuredText" import copy @@ -23,7 +21,7 @@ from zope.cachedescriptors.property import Lazy from zope.configuration import xmlconfig, config -from zope.interface import implements, directlyProvides +from zope.interface import implementer, directlyProvides from zope.location.interfaces import ILocation import zope.app.appsetup.appsetup @@ -80,9 +78,10 @@ def endElementNS(self, name, qname): self.currentElement = self.currentElement.__parent__ +@implementer(IDirective) class Directive(object): """Representation of a ZCML directive.""" - implements(IDirective) + def __init__(self, name, schema, attrs, context, info, prefixes): self.name = name @@ -98,9 +97,9 @@ def __repr__(self): return '' %str(self.name) +@implementer(ILocation, IZCMLFile) class ZCMLFile(object): """Representation of an entire ZCML file.""" - implements(ILocation, IZCMLFile) def __init__(self, filename, package, parent, name): # Retrieve the directive registry @@ -109,6 +108,7 @@ def __init__(self, filename, package, parent, name): self.__parent__ = parent self.__name__ = name + @Lazy def rootElement(self): # Get the context that was originally generated during startup and # create a new context using its registrations @@ -143,5 +143,3 @@ def rootElement(self): directlyProvides(root, IRootDirective) root.__parent__ = self return root - - rootElement = Lazy(rootElement) diff --git a/src/zope/app/apidoc/component.txt b/src/zope/app/apidoc/component.rst similarity index 100% rename from src/zope/app/apidoc/component.txt rename to src/zope/app/apidoc/component.rst diff --git a/src/zope/app/apidoc/disabled.zcml b/src/zope/app/apidoc/disabled.zcml index f1cda57f..11292129 100644 --- a/src/zope/app/apidoc/disabled.zcml +++ b/src/zope/app/apidoc/disabled.zcml @@ -4,6 +4,8 @@ xmlns:zcml="http://namespaces.zope.org/zcml" i18n_domain="zope"> + + + + + + + diff --git a/src/zope/app/apidoc/ftesting-base.zcml b/src/zope/app/apidoc/ftesting-base.zcml index 7bb0148a..22453289 100644 --- a/src/zope/app/apidoc/ftesting-base.zcml +++ b/src/zope/app/apidoc/ftesting-base.zcml @@ -1,26 +1,142 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -52,6 +168,6 @@ password="globalmgrpw" /> - + diff --git a/src/zope/app/apidoc/ifacemodule/README.txt b/src/zope/app/apidoc/ifacemodule/README.rst similarity index 89% rename from src/zope/app/apidoc/ifacemodule/README.txt rename to src/zope/app/apidoc/ifacemodule/README.rst index 7a449873..0cbfcab0 100644 --- a/src/zope/app/apidoc/ifacemodule/README.txt +++ b/src/zope/app/apidoc/ifacemodule/README.rst @@ -20,24 +20,27 @@ After registering an interface >>> provideInterface('IFoo', IFoo) Now let's lookup an interface that is registered. - + >>> module.get('IFoo') >>> module.get('__builtin__.IFoo') - + Now we find an interface that is not in the site manager, but exists. >>> module.get('zope.app.apidoc.interfaces.IDocumentationModule') - + Finally, you can list all registered interfaces: >>> ifaces = module.items() >>> ifaces.sort() >>> from pprint import pprint >>> pprint(ifaces) - [(u'IFoo', ), - (u'__builtin__.IFoo', )] + [... + (u'IFoo', ), + ... + (u'__builtin__.IFoo', ), + ...] diff --git a/src/zope/app/apidoc/ifacemodule/browser.txt b/src/zope/app/apidoc/ifacemodule/browser.rst similarity index 64% rename from src/zope/app/apidoc/ifacemodule/browser.txt rename to src/zope/app/apidoc/ifacemodule/browser.rst index 29fae724..62e136c0 100644 --- a/src/zope/app/apidoc/ifacemodule/browser.txt +++ b/src/zope/app/apidoc/ifacemodule/browser.rst @@ -221,7 +221,7 @@ we get a result: Return a list of attributes in the order they were specified. - >>> pprint(details.getAttributes()) + >>> pprint(sorted(details.getAttributes(), key=lambda x: x['name'])) [{'doc': u'

This is bar.

\n', 'name': 'bar'}, {'doc': u'

This is foo.

\n', @@ -233,7 +233,7 @@ Return a list of attributes in the order they were specified. Return a list of methods in the order they were specified. - >>> pprint(details.getMethods()) + >>> pprint(sorted(details.getMethods(), key=lambda x: x['name'])) [{'doc': u'

This is blah.

\n', 'name': 'blah', 'signature': '()'}, @@ -296,132 +296,20 @@ interface.Interface. Get adapters where this interface is required. - >>> pprint(sorted(details.getGenericRequiredAdapters()), width=1) - [{'doc': u'', - 'factory': 'None.append', - 'factory_url': None, - 'name': u'', - 'provided': None, - 'required': [{'isInterface': True, - 'isType': False, - 'module': 'zope.interface', - 'name': 'Interface'}], - 'zcml': None}, - {'doc': u'', - 'factory': 'zope.location.traversing.LocationPhysicallyLocatable', - 'factory_url': 'zope/location/traversing/LocationPhysicallyLocatable', - 'name': u'', - 'provided': {'module': 'zope.location.interfaces', - 'name': 'ILocationInfo'}, - 'required': [{'isInterface': True, - 'isType': False, - 'module': 'zope.interface', - 'name': 'Interface'}], - 'zcml': None}, - {'doc': u'', - 'factory': 'zope.site.site.SiteManagerAdapter', - 'factory_url': 'zope/site/site/SiteManagerAdapter', - 'name': u'', - 'provided': {'module': 'zope.interface.interfaces', - 'name': 'IComponentLookup'}, - 'required': [{'isInterface': True, - 'isType': False, - 'module': 'zope.interface', - 'name': 'Interface'}], - 'zcml': None}, - {'doc': u'', - 'factory': 'zope.traversing.adapters.DefaultTraversable', - 'factory_url': 'zope/traversing/adapters/DefaultTraversable', - 'name': u'', - 'provided': {'module': 'zope.traversing.interfaces', - 'name': 'ITraversable'}, - 'required': [{'isInterface': True, - 'isType': False, - 'module': 'zope.interface', - 'name': 'Interface'}], - 'zcml': None}, - {'doc': u'', - 'factory': 'zope.traversing.adapters.Traverser', - 'factory_url': 'zope/traversing/adapters/Traverser', - 'name': u'', - 'provided': {'module': 'zope.traversing.interfaces', - 'name': 'ITraverser'}, - 'required': [{'isInterface': True, - 'isType': False, - 'module': 'zope.interface', - 'name': 'Interface'}], - 'zcml': None}, - {'doc': u'', - 'factory': 'zope.traversing.namespace.etc', - 'factory_url': 'zope/traversing/namespace/etc', - 'name': u'etc', - 'provided': {'module': 'zope.traversing.interfaces', - 'name': 'ITraversable'}, - 'required': [{'isInterface': True, - 'isType': False, - 'module': 'zope.interface', - 'name': 'Interface'}], - 'zcml': None}, - {'doc': u'', - 'factory': 'zope.traversing.namespace.etc', - 'factory_url': 'zope/traversing/namespace/etc', - 'name': u'etc', - 'provided': {'module': 'zope.traversing.interfaces', - 'name': 'ITraversable'}, - 'required': [{'isInterface': True, - 'isType': False, - 'module': 'zope.interface', - 'name': 'Interface'}, - {'isInterface': True, - 'isType': False, - 'module': 'zope.interface', - 'name': 'Interface'}], - 'zcml': None}, - {'doc': u'', - 'factory': 'zope.traversing.namespace.etc', - 'factory_url': 'zope/traversing/namespace/etc', - 'name': u'etc', - 'provided': {'module': 'zope.traversing.interfaces', - 'name': 'ITraversable'}, - 'required': [{'isInterface': True, - 'isType': False, - 'module': 'zope.interface', - 'name': 'Interface'}, - {'isInterface': True, - 'isType': False, - 'module': 'zope.interface', - 'name': 'Interface'}], - 'zcml': None}, - {'doc': u'', - 'factory': 'zope.traversing.namespace.etc', - 'factory_url': 'zope/traversing/namespace/etc', - 'name': u'etc', - 'provided': {'module': 'zope.traversing.interfaces', - 'name': 'ITraversable'}, - 'required': [{'isInterface': True, - 'isType': False, - 'module': 'zope.interface', - 'name': 'Interface'}, - {'isInterface': True, - 'isType': False, - 'module': 'zope.interface', - 'name': 'Interface'}], - 'zcml': None}, - {'doc': u'', - 'factory': 'zope.traversing.namespace.etc', - 'factory_url': 'zope/traversing/namespace/etc', - 'name': u'etc', - 'provided': {'module': 'zope.traversing.interfaces', - 'name': 'ITraversable'}, - 'required': [{'isInterface': True, - 'isType': False, - 'module': 'zope.interface', - 'name': 'Interface'}, - {'isInterface': True, - 'isType': False, - 'module': 'zope.interface', - 'name': 'Interface'}], - 'zcml': None}] + >>> required = details.getGenericRequiredAdapters() + >>> {'doc': u'', + ... 'factory': 'None.append', + ... 'factory_url': None, + ... 'name': u'', + ... 'provided': None, + ... 'required': [{'isInterface': True, + ... 'isType': False, + ... 'module': 'zope.interface', + ... 'name': 'Interface'}], + ... 'zcml': None} in required + True + >>> len(required) >= 10 + True `getProvidedAdapters()` diff --git a/src/zope/app/apidoc/ifacemodule/tests.py b/src/zope/app/apidoc/ifacemodule/tests.py index 877b4598..aeb2df7d 100644 --- a/src/zope/app/apidoc/ifacemodule/tests.py +++ b/src/zope/app/apidoc/ifacemodule/tests.py @@ -13,49 +13,28 @@ ############################################################################## """Tests for the Interface Documentation Module -$Id$ """ import unittest import doctest -from zope.component.interfaces import IFactory -from zope.interface.interfaces import IInterface +from zope.app.component.testing import PlacefulSetup, setUpTraversal from zope.app.apidoc.testing import APIDocLayer from zope.app.apidoc.apidoc import APIDocumentation -from zope.app.apidoc.interfaces import IDocumentationModule + from zope.app.apidoc.ifacemodule.ifacemodule import InterfaceModule -from zope.app.renderer.rest import ReStructuredTextSourceFactory -from zope.app.renderer.rest import IReStructuredTextSource -from zope.app.renderer.rest import ReStructuredTextToHTMLRenderer -from zope.app.testing import ztapi, setup -from zope.app.testing.functional import BrowserTestCase -from zope.app.tree.interfaces import IUniqueId -from zope.app.tree.adapters import LocationUniqueId +from zope.app.apidoc.tests import BrowserTestCase def setUp(test): - root_folder = setup.placefulSetUp(True) - - ztapi.provideAdapter(IInterface, IUniqueId, LocationUniqueId) + root_folder = PlacefulSetup().buildFolders(True) + setUpTraversal() # Set up apidoc module test.globs['apidoc'] = APIDocumentation(root_folder, '++apidoc++') - # Register InterfaceModule - ztapi.provideUtility(IDocumentationModule, InterfaceModule(), "Interface") - - # Register Renderer Components - ztapi.provideUtility(IFactory, ReStructuredTextSourceFactory, - 'zope.source.rest') - ztapi.browserView(IReStructuredTextSource, '', - ReStructuredTextToHTMLRenderer) - # Cheat and register the ReST factory for STX as well - ztapi.provideUtility(IFactory, ReStructuredTextSourceFactory, - 'zope.source.stx') - def tearDown(test): - setup.placefulTearDown() + pass class InterfaceModuleTests(BrowserTestCase): @@ -67,7 +46,7 @@ def testMenu(self): response = self.publish( '/++apidoc++/Interface/menu.html', basic='mgr:mgrpw', - env = {'name_only': True, 'search_str': 'IDoc'}) + env={'name_only': 'True', 'search_str': 'IDoc'}) self.assertEqual(response.getStatus(), 200) body = response.getBody() self.assert_(body.find( @@ -89,15 +68,19 @@ def testInterfaceDetailsView(self): def test_suite(): + readme = doctest.DocFileSuite('README.rst', + setUp=setUp, tearDown=tearDown, + optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS) + readme.layer = APIDocLayer + browser = doctest.DocFileSuite('browser.rst', + setUp=setUp, tearDown=tearDown, + optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS) + browser.layer = APIDocLayer return unittest.TestSuite(( - doctest.DocFileSuite('README.txt', - setUp=setUp, tearDown=tearDown, - optionflags=doctest.NORMALIZE_WHITESPACE), - doctest.DocFileSuite('browser.txt', - setUp=setUp, tearDown=tearDown, - optionflags=doctest.NORMALIZE_WHITESPACE), - unittest.makeSuite(InterfaceModuleTests), - )) + readme, + browser, + unittest.defaultTestLoader.loadTestsFromName(__name__) + )) if __name__ == '__main__': unittest.main(defaultTest="test_suite") diff --git a/src/zope/app/apidoc/interface.txt b/src/zope/app/apidoc/interface.rst similarity index 99% rename from src/zope/app/apidoc/interface.txt rename to src/zope/app/apidoc/interface.rst index 46d9ea95..d76a7c66 100644 --- a/src/zope/app/apidoc/interface.txt +++ b/src/zope/app/apidoc/interface.rst @@ -227,7 +227,7 @@ This function returns a page-template-friendly dictionary for a method: >>> pprint(interface.getMethodInfoDictionary(IFoo['blah'])) #doc {'doc': - u'

This is the blah method.

\n', + u'

This is the `blah` method.

\n', 'name': 'blah', 'signature': '(one, two, three=None, *args, **kwargs)'} diff --git a/src/zope/app/apidoc/presentation.txt b/src/zope/app/apidoc/presentation.rst similarity index 100% rename from src/zope/app/apidoc/presentation.txt rename to src/zope/app/apidoc/presentation.rst diff --git a/src/zope/app/apidoc/testing.py b/src/zope/app/apidoc/testing.py index 42bcef10..933f7094 100644 --- a/src/zope/app/apidoc/testing.py +++ b/src/zope/app/apidoc/testing.py @@ -13,18 +13,26 @@ ############################################################################## """zope.app.apidoc common test related classes/functions/objects. -$Id$ """ __docformat__ = "reStructuredText" import os -from zope.app.testing.functional import ZCMLLayer -APIDocNoDevModeLayer = ZCMLLayer( - os.path.join(os.path.split(__file__)[0], 'ftesting-base.zcml'), - __name__, 'APIDocNoDevModeLayer', allow_teardown=True) +import zope.app.apidoc +from zope.app.wsgi.testlayer import BrowserLayer +from zope.testbrowser.wsgi import TestBrowserLayer -APIDocLayer = ZCMLLayer( - os.path.join(os.path.split(__file__)[0], 'ftesting.zcml'), - __name__, 'APIDocLayer', allow_teardown=True) +class _BrowserLayer(TestBrowserLayer, BrowserLayer): + pass + +APIDocNoDevModeLayer = _BrowserLayer( + zope.app.apidoc, + name="APIDocNoDevModeLayer", + zcml_file='ftesting-base.zcml', + allowTearDown=True) + +APIDocLayer = _BrowserLayer( + zope.app.apidoc, + name="APIDocLayer", + allowTearDown=True) diff --git a/src/zope/app/apidoc/tests.py b/src/zope/app/apidoc/tests.py index ddcdb658..5b1ac9f5 100644 --- a/src/zope/app/apidoc/tests.py +++ b/src/zope/app/apidoc/tests.py @@ -13,47 +13,121 @@ ############################################################################## """Tests for the Interface Documentation Module -$Id$ """ -from pprint import PrettyPrinter +from __future__ import absolute_import +import os import unittest import doctest import zope.component.testing -from zope.component.interfaces import IFactory -from zope.interface import implements +from zope.configuration import xmlconfig +# from zope.component.interfaces import IFactory +from zope.interface import implementer from zope.traversing.interfaces import IContainmentRoot from zope.location import LocationProxy -from zope.app.testing import placelesssetup, ztapi, setup -from zope.app.renderer.rest import ReStructuredTextSourceFactory -from zope.app.renderer.rest import IReStructuredTextSource -from zope.app.renderer.rest import ReStructuredTextToHTMLRenderer + +# from zope.app.renderer.rest import ReStructuredTextSourceFactory +# from zope.app.renderer.rest import IReStructuredTextSource +# from zope.app.renderer.rest import ReStructuredTextToHTMLRenderer + +import zope.testing.module + +from webtest import TestApp + + +def _setUp_AppSetup(): + config_file = os.path.join( + os.path.dirname(zope.app.apidoc.__file__), 'configure.zcml') + + # # Fix up path for tests. + global old_context + old_context = zope.app.appsetup.appsetup.getConfigContext() + zope.app.appsetup.appsetup.__config_context = xmlconfig.file( + config_file, zope.app.apidoc, execute=False) + +def _tearDown_AppSetup(): + zope.app.appsetup.appsetup.__config_context = old_context + + +class BrowserTestCase(unittest.TestCase): + + def setUp(self): + super(BrowserTestCase, self).setUp() + _setUp_AppSetup() + self._testapp = TestApp(self.layer.make_wsgi_app()) + + def tearDown(self): + _tearDown_AppSetup() + super(BrowserTestCase, self).tearDown() + + + def checkForBrokenLinks(self, orig_response, path, basic=None): + response = self.publish(path, basic=basic) + links = response.html.find_all('a') + + for link in links: + try: + href = link.attrs['href'] + except KeyError: + pass + if '++apidoc++' in href: + # XXX: We are this! Enable it + # We don't install this at test time + continue + if href.startswith('http://dev.zope.org'): + # Don't try to follow external links + continue + if href.startswith('./'): + href = href[2:] + + if not href.startswith('/'): + href = path.rsplit('/', 1)[0] + '/' + href + self.publish(href, basic=basic) + + def publish(self, path, basic=None, form=None, headers=None, env=None): + assert basic + self._testapp.authorization = ('Basic', tuple(basic.split(':'))) + env = env or {} + env['wsgi.handleErrors'] = False + if form: + response = self._testapp.post(path, params=form, + extra_environ=env, headers=headers) + else: + response = self._testapp.get(path, extra_environ=env, headers=headers) + + response.getBody = lambda: response.unicode_normal_body + response.getStatus = lambda: response.status_int + response.getHeader = lambda n: response.headers[n] + return response + def setUp(test): + import zope.app.renderer zope.component.testing.setUp() # Register Renderer Components - ztapi.provideUtility(IFactory, ReStructuredTextSourceFactory, - 'zope.source.rest') - ztapi.browserView(IReStructuredTextSource, '', - ReStructuredTextToHTMLRenderer) - # Cheat and register the ReST renderer as the STX one as well. - ztapi.provideUtility(IFactory, ReStructuredTextSourceFactory, - 'zope.source.stx') - ztapi.browserView(IReStructuredTextSource, '', - ReStructuredTextToHTMLRenderer) - setup.setUpTestAsModule(test, 'zope.app.apidoc.doctest') + xmlconfig.file('configure.zcml', zope.app.renderer) + # ztapi.provideUtility(IFactory, ReStructuredTextSourceFactory, + # 'zope.source.rest') + # ztapi.browserView(IReStructuredTextSource, '', + # ReStructuredTextToHTMLRenderer) + # # Cheat and register the ReST renderer as the STX one as well. + # ztapi.provideUtility(IFactory, ReStructuredTextSourceFactory, + # 'zope.source.stx') + # ztapi.browserView(IReStructuredTextSource, '', + # ReStructuredTextToHTMLRenderer) + zope.testing.module.setUp(test, 'zope.app.apidoc.doctest') def tearDown(test): - placelesssetup.tearDown() - setup.tearDownTestAsModule(test) + zope.component.testing.tearDown() + zope.testing.module.tearDown(test, 'zope.app.apidoc.doctest') # Generally useful classes and functions -class Root: - implements(IContainmentRoot) +@implementer(IContainmentRoot) +class Root(object): __parent__ = None __name__ = '' @@ -65,31 +139,31 @@ def rootLocation(obj, name): def test_suite(): return unittest.TestSuite(( doctest.DocTestSuite('zope.app.apidoc.browser.apidoc', - setUp=setUp, tearDown=placelesssetup.tearDown), - doctest.DocFileSuite('README.txt', + setUp=setUp, tearDown=tearDown), + doctest.DocFileSuite('README.rst', setUp=setUp, - tearDown=placelesssetup.tearDown, + tearDown=tearDown, optionflags=doctest.NORMALIZE_WHITESPACE), - doctest.DocFileSuite('classregistry.txt', + doctest.DocFileSuite('classregistry.rst', optionflags=doctest.NORMALIZE_WHITESPACE), - doctest.DocFileSuite('interface.txt', + doctest.DocFileSuite('interface.rst', setUp=setUp, - tearDown=placelesssetup.tearDown, + tearDown=tearDown, optionflags=doctest.NORMALIZE_WHITESPACE), - doctest.DocFileSuite('component.txt', + doctest.DocFileSuite('component.rst', setUp=setUp, - tearDown=placelesssetup.tearDown, + tearDown=tearDown, optionflags=doctest.NORMALIZE_WHITESPACE), - doctest.DocFileSuite('presentation.txt', + doctest.DocFileSuite('presentation.rst', setUp=zope.component.testing.setUp, tearDown=zope.component.testing.tearDown, optionflags=doctest.NORMALIZE_WHITESPACE, globs={'__file__': __file__}), - doctest.DocFileSuite('utilities.txt', + doctest.DocFileSuite('utilities.rst', setUp=setUp, - tearDown=placelesssetup.tearDown, + tearDown=tearDown, optionflags=doctest.NORMALIZE_WHITESPACE), - )) + )) if __name__ == '__main__': unittest.main(defaultTest="test_suite") diff --git a/src/zope/app/apidoc/typemodule/tests.py b/src/zope/app/apidoc/typemodule/tests.py index dc990737..4e5b813c 100644 --- a/src/zope/app/apidoc/typemodule/tests.py +++ b/src/zope/app/apidoc/typemodule/tests.py @@ -13,19 +13,21 @@ ############################################################################## """Tests for the Book Documentation Module -$Id$ """ import unittest import doctest -from zope.app.testing.functional import BrowserTestCase -from zope.app.testing import placelesssetup +from zope.component import testing +from zope.app.apidoc.tests import BrowserTestCase + from zope.app.apidoc.testing import APIDocLayer class TypeModuleTests(BrowserTestCase): """Just a couple of tests ensuring that the templates render.""" + layer = APIDocLayer + def testMenu(self): response = self.publish( '/++apidoc++/Type/@@menu.html', @@ -38,13 +40,12 @@ def testMenu(self): def test_suite(): - TypeModuleTests.layer = APIDocLayer return unittest.TestSuite(( doctest.DocTestSuite('zope.app.apidoc.typemodule.type', - setUp=placelesssetup.setUp, - tearDown=placelesssetup.tearDown), - unittest.makeSuite(TypeModuleTests), - )) + setUp=testing.setUp, + tearDown=testing.tearDown), + unittest.defaultTestLoader.loadTestsFromName(__name__), + )) if __name__ == '__main__': unittest.main(default='test_suite') diff --git a/src/zope/app/apidoc/utilities.py b/src/zope/app/apidoc/utilities.py index 1f5c7f25..6f754516 100644 --- a/src/zope/app/apidoc/utilities.py +++ b/src/zope/app/apidoc/utilities.py @@ -13,8 +13,8 @@ ############################################################################## """Utilties to make the life of Documentation Modules easier. -$Id$ """ +from __future__ import absolute_import __docformat__ = 'restructuredtext' import re @@ -24,7 +24,7 @@ from os.path import dirname from zope.component import createObject, getMultiAdapter -from zope.interface import implements, implementedBy +from zope.interface import implementer, implementedBy from zope.publisher.browser import TestRequest from zope.security.checker import getCheckerForInstancesOf, Global from zope.security.interfaces import INameBasedChecker @@ -41,11 +41,16 @@ _remove_html_overhead = re.compile( r'(?sm)^\n(.*)\n\n') -space_re = re.compile('\n^( *)\S', re.M) +space_re = re.compile(r'\n^( *)\S', re.M) _marker = object() -BASEDIR = dirname(dirname(dirname(dirname(zope.app.__file__)))) +try: + _path = zope.app.__file__ +except AttributeError: + _path = zope.app.__path__[0] +BASEDIR = dirname(dirname(dirname(dirname(_path)))) +del _path def relativizePath(path): return path.replace(BASEDIR, 'Zope3') @@ -58,16 +63,15 @@ def truncateSysPath(path): return path.replace(syspath, '')[1:] return path - +@implementer(IReadContainer) class ReadContainerBase(object): """Base for `IReadContainer` objects.""" - implements(IReadContainer) def get(self, key, default=None): - raise NotImplemented + raise NotImplementedError() def items(self): - raise NotImplemented + raise NotImplementedError() def __getitem__(self, key): default = object() @@ -80,13 +84,13 @@ def __contains__(self, key): return self.get(key) is not None def keys(self): - return map(lambda x: x[0], self.items()) + return [x[0] for x in self.items()] def __iter__(self): return self.values().__iter__() def values(self): - return map(lambda x: x[1], self.items()) + return [x[1] for x in self.items()] def __len__(self): return len(self.items()) @@ -229,7 +233,7 @@ def getPublicAttributes(obj): for attr in dir(obj): if attr.startswith('_'): continue - + try: getattr(obj, attr) except AttributeError: @@ -293,7 +297,7 @@ def columnize(entries, columns=3): 'plaintext': 'zope.source.plaintext', 'structuredtext': 'zope.source.stx', 'restructuredtext': 'zope.source.rest' - } +} def getDocFormat(module): """Convert a module's __docformat__ specification to a renderer source diff --git a/src/zope/app/apidoc/utilities.txt b/src/zope/app/apidoc/utilities.rst similarity index 100% rename from src/zope/app/apidoc/utilities.txt rename to src/zope/app/apidoc/utilities.rst diff --git a/src/zope/app/apidoc/utilitymodule/README.txt b/src/zope/app/apidoc/utilitymodule/README.rst similarity index 95% rename from src/zope/app/apidoc/utilitymodule/README.txt rename to src/zope/app/apidoc/utilitymodule/README.rst index 2d7fabc9..f7db1c5b 100644 --- a/src/zope/app/apidoc/utilitymodule/README.txt +++ b/src/zope/app/apidoc/utilitymodule/README.rst @@ -31,10 +31,13 @@ Now we can get a single utility interface by path: and list all available interfaces: >>> module.items() - [('zope.app.apidoc.interfaces.IDocumentationModule', + [... + ('zope.app.apidoc.interfaces.IDocumentationModule', ), + ... ('zope.security.interfaces.IPermission', - )] + ), + ...] `UtilityInterface` class @@ -74,7 +77,8 @@ If you try to get a non-existent utility, `None` is returned: You can get a list of available utilities as well, of course: >>> ut_iface.items() - [('VXRpbGl0eQ==', <...apidoc.utilitymodule.utilitymodule.Utility ...>), + [... + ('VXRpbGl0eQ==', <...apidoc.utilitymodule.utilitymodule.Utility ...>), ('X19ub25hbWVfXw==', <...apidoc.utilitymodule.utilitymodule.Utility ...>)] Bu what are those strange names? Since utility names can be any string, it is diff --git a/src/zope/app/apidoc/utilitymodule/browser.txt b/src/zope/app/apidoc/utilitymodule/browser.rst similarity index 94% rename from src/zope/app/apidoc/utilitymodule/browser.txt rename to src/zope/app/apidoc/utilitymodule/browser.rst index 8cb11d6e..5ec8eb57 100644 --- a/src/zope/app/apidoc/utilitymodule/browser.txt +++ b/src/zope/app/apidoc/utilitymodule/browser.rst @@ -40,7 +40,7 @@ You can now get the title and link from the menu: >>> menu.getMenuTitle(node) 'iface' >>> menu.getMenuLink(node) - 'http://127.0.0.1/++apidoc++/Interface/foo.bar.iface/index.html' + 'http://127.0.0.1/++etc++site/++apidoc++/Interface/foo.bar.iface/index.html' Next, let's get the menu title and link for a utility with a name. We first have to create a utility registration @@ -61,7 +61,7 @@ We can now ask the menu to give us the tile and link for the utility: >>> menu.getMenuTitle(node) 'FooBar' >>> menu.getMenuLink(node) - 'http://127.0.0.1/++apidoc++/Utility/foo.bar.iface/Rm9vQmFy/index.html' + 'http://127.0.0.1/++etc++site/++apidoc++/Utility/foo.bar.iface/Rm9vQmFy/index.html' Finally, we get menu title and link for a utility without a name: @@ -76,7 +76,7 @@ Finally, we get menu title and link for a utility without a name: >>> menu.getMenuTitle(node) 'no name' >>> menu.getMenuLink(node) - 'http://127.0.0.1/++apidoc++/Utility/foo.bar.iface/X19ub25hbWVfXw==/index.html' + 'http://127.0.0.1/++etc++site/++apidoc++/Utility/foo.bar.iface/X19ub25hbWVfXw==/index.html' `UtilityDetails` class diff --git a/src/zope/app/apidoc/utilitymodule/tests.py b/src/zope/app/apidoc/utilitymodule/tests.py index 6d7a1a4c..61ba96b8 100644 --- a/src/zope/app/apidoc/utilitymodule/tests.py +++ b/src/zope/app/apidoc/utilitymodule/tests.py @@ -13,7 +13,6 @@ ############################################################################## """Tests for the Utility Documentation Module -$Id$ """ import unittest import doctest @@ -26,32 +25,48 @@ from zope.app.apidoc.interfaces import IDocumentationModule from zope.app.apidoc.apidoc import APIDocumentation from zope.app.apidoc.testing import APIDocLayer -from zope.app.testing import setup, ztapi -from zope.app.testing.functional import BrowserTestCase -from zope.app.tree.interfaces import IUniqueId -from zope.app.tree.adapters import LocationUniqueId +from zope.app.component.testing import PlacefulSetup, setUpTraversal + +from zope.app.apidoc.testing import APIDocLayer +from zope.app.apidoc.apidoc import APIDocumentation + +from zope.app.apidoc.ifacemodule.ifacemodule import InterfaceModule +from zope.app.apidoc.tests import BrowserTestCase def setUp(test): - root_folder = setup.placefulSetUp(True) - ztapi.provideAdapter(None, IUniqueId, LocationUniqueId) - ztapi.provideAdapter(None, IPhysicallyLocatable, - LocationPhysicallyLocatable) + root_folder = PlacefulSetup().buildFolders(True) + setUpTraversal() # Set up apidoc module test.globs['apidoc'] = APIDocumentation(root_folder, '++apidoc++') - # Register documentation modules - ztapi.provideUtility(IDocumentationModule, UtilityModule(), 'Utility') - def tearDown(test): - setup.placefulTearDown() + pass + +# def setUp(test): +# root_folder = setup.placefulSetUp(True) +# ztapi.provideAdapter(None, IUniqueId, LocationUniqueId) +# ztapi.provideAdapter(None, IPhysicallyLocatable, +# LocationPhysicallyLocatable) + +# # Set up apidoc module +# test.globs['apidoc'] = APIDocumentation(root_folder, '++apidoc++') + +# # Register documentation modules +# ztapi.provideUtility(IDocumentationModule, UtilityModule(), 'Utility') + + +# def tearDown(test): +# setup.placefulTearDown() class UtilityModuleTests(BrowserTestCase): """Just a couple of tests ensuring that the templates render.""" + layer = APIDocLayer + def testMenu(self): response = self.publish( '/++apidoc++/Utility/menu.html', @@ -89,19 +104,22 @@ def testUtilityDetailsView(self): def test_suite(): - UtilityModuleTests.layer = APIDocLayer + + readme = doctest.DocFileSuite('README.rst', + setUp=setUp, + tearDown=tearDown, + optionflags=doctest.NORMALIZE_WHITESPACE| doctest.ELLIPSIS) + readme.layer = APIDocLayer + browser = doctest.DocFileSuite('browser.rst', + setUp=setUp, + tearDown=tearDown, + optionflags=doctest.NORMALIZE_WHITESPACE) + browser.layer = APIDocLayer return unittest.TestSuite(( - doctest.DocFileSuite('README.txt', - setUp=setUp, - tearDown=tearDown, - optionflags=doctest.NORMALIZE_WHITESPACE| - doctest.ELLIPSIS), - doctest.DocFileSuite('browser.txt', - setUp=setUp, - tearDown=tearDown, - optionflags=doctest.NORMALIZE_WHITESPACE), - unittest.makeSuite(UtilityModuleTests), - )) + readme, + browser, + unittest.defaultTestLoader.loadTestsFromName(__name__), + )) if __name__ == '__main__': unittest.main(default="test_suite") diff --git a/src/zope/app/apidoc/zcmlmodule/README.txt b/src/zope/app/apidoc/zcmlmodule/README.rst similarity index 96% rename from src/zope/app/apidoc/zcmlmodule/README.txt rename to src/zope/app/apidoc/zcmlmodule/README.rst index d676a6dd..c82caf3c 100644 --- a/src/zope/app/apidoc/zcmlmodule/README.txt +++ b/src/zope/app/apidoc/zcmlmodule/README.rst @@ -83,10 +83,10 @@ One can get a directive using the common mapping interface: >>> ns.get('foo') is None True - >>> print '\n'.join([name for name, dir in ns.items()][:3]) - addMenuItem - addform - containerViews + >>> print('\n'.join([name for name, dir in ns.items()][:3])) + defaultSkin + defaultView + page `quoteNS(ns)` diff --git a/src/zope/app/apidoc/zcmlmodule/__init__.py b/src/zope/app/apidoc/zcmlmodule/__init__.py index a3c87151..08ac19a9 100644 --- a/src/zope/app/apidoc/zcmlmodule/__init__.py +++ b/src/zope/app/apidoc/zcmlmodule/__init__.py @@ -18,13 +18,12 @@ the evaluation is stored in thread-global variables, so that we have to parse the files only once. -$Id$ """ __docformat__ = 'restructuredtext' -from zope.configuration import docutils, xmlconfig +from zope.configuration import docutils from zope.i18nmessageid import ZopeMessageFactory as _ -from zope.interface import implements +from zope.interface import implementer from zope.location.interfaces import ILocation import zope.app.appsetup.appsetup @@ -48,10 +47,10 @@ def unquoteNS(ns): return ns +@implementer(ILocation) class Namespace(ReadContainerBase): """Simple namespace object for the ZCML Documentation Module.""" - implements(ILocation) def __init__(self, parent, name): self.__parent__ = parent @@ -94,11 +93,10 @@ def items(self): return list +@implementer(ILocation) class Directive(object): """Represents a ZCML Directive.""" - implements(ILocation) - def __init__(self, ns, name, schema, handler, info, subdirs): self.__parent__ = ns self.__name__ = name @@ -108,14 +106,13 @@ def __init__(self, ns, name, schema, handler, info, subdirs): self.subdirs = subdirs +@implementer(IDocumentationModule) class ZCMLModule(ReadContainerBase): r"""Represent the Documentation of all ZCML namespaces. This documentation is implemented using a simple `IReadContainer`. The items of the container.""" - implements(IDocumentationModule) - # See zope.app.apidoc.interfaces.IDocumentationModule title = _('ZCML Reference') diff --git a/src/zope/app/apidoc/zcmlmodule/browser.txt b/src/zope/app/apidoc/zcmlmodule/browser.rst similarity index 97% rename from src/zope/app/apidoc/zcmlmodule/browser.txt rename to src/zope/app/apidoc/zcmlmodule/browser.rst index d1feec84..f0f79209 100644 --- a/src/zope/app/apidoc/zcmlmodule/browser.txt +++ b/src/zope/app/apidoc/zcmlmodule/browser.rst @@ -62,7 +62,7 @@ And we can get its menu title and link. >>> menu.getMenuTitle(node) 'page' >>> menu.getMenuLink(node) - 'http://127.0.0.1/++apidoc++/ZCML/http_co__sl__sl_namespaces.zope.org_sl_browser/page/index.html' + 'http://127.0.0.1/++etc++site/++apidoc++/ZCML/http_co__sl__sl_namespaces.zope.org_sl_browser/page/index.html' Note that the directive's namespace URL is encoded, so it can be used in a URL. diff --git a/src/zope/app/apidoc/zcmlmodule/tests.py b/src/zope/app/apidoc/zcmlmodule/tests.py index fa5d12d7..bae1929e 100644 --- a/src/zope/app/apidoc/zcmlmodule/tests.py +++ b/src/zope/app/apidoc/zcmlmodule/tests.py @@ -13,57 +13,73 @@ ############################################################################## """Tests for the ZCML Documentation Module -$Id$ """ +from __future__ import absolute_import import os import unittest import doctest from zope.configuration import xmlconfig -from zope.traversing.interfaces import IPhysicallyLocatable -from zope.location.traversing import LocationPhysicallyLocatable + import zope.app.appsetup.appsetup -from zope.app.tree.interfaces import IUniqueId -from zope.app.tree.adapters import LocationUniqueId -from zope.app.testing import setup, ztapi -from zope.app.testing.functional import BrowserTestCase +from zope import component as ztapi +import zope.traversing +import zope.app.tree +import zope.security +import zope.browserresource +import zope.browserpage +import zope.location + + +from zope.app.component.testing import PlacefulSetup + +import zope.app.apidoc from zope.app.apidoc.testing import APIDocLayer from zope.app.apidoc.tests import Root +from zope.app.apidoc.tests import BrowserTestCase from zope.app.apidoc.apidoc import APIDocumentation from zope.app.apidoc.interfaces import IDocumentationModule from zope.app.apidoc.zcmlmodule import Namespace, Directive from zope.app.apidoc.zcmlmodule import ZCMLModule -from zope.app.apidoc.tests import Root -import zope.app.zcmlfiles +def _setUp_AppSetup(): + config_file = os.path.join( + os.path.dirname(zope.app.apidoc.__file__), 'configure.zcml') + + # # Fix up path for tests. + global old_context + old_context = zope.app.appsetup.appsetup.getConfigContext() + zope.app.appsetup.appsetup.__config_context = xmlconfig.file( + config_file, zope.app.apidoc, execute=False) + +def _tearDown_AppSetup(): + zope.app.appsetup.appsetup.__config_context = old_context def setUp(test): - root_folder = setup.placefulSetUp(True) + root_folder = PlacefulSetup().setUp(True, True) - ztapi.provideAdapter(None, IUniqueId, LocationUniqueId) - ztapi.provideAdapter(None, IPhysicallyLocatable, - LocationPhysicallyLocatable) + ctx = xmlconfig.file('meta.zcml', zope.security) + ctx = xmlconfig.file('meta.zcml', ztapi, context=ctx) + ctx = xmlconfig.file('meta.zcml', zope.browserresource, context=ctx) + ctx = xmlconfig.file('meta.zcml', zope.browserpage, context=ctx) + ctx = xmlconfig.file('configure.zcml', zope.location, context=ctx) + ctx = xmlconfig.file('configure.zcml', zope.traversing, context=ctx) + ctx = xmlconfig.file('configure.zcml', zope.security, context=ctx) + xmlconfig.file('configure.zcml', zope.app.tree, context=ctx) # Set up apidoc module test.globs['apidoc'] = APIDocumentation(root_folder, '++apidoc++') # Register documentation modules - ztapi.provideUtility(IDocumentationModule, ZCMLModule(), 'ZCML') - - config_file = os.path.join( - os.path.dirname(zope.app.zcmlfiles.__file__), 'meta.zcml') + ztapi.provideUtility(ZCMLModule(), IDocumentationModule,'ZCML') - # Fix up path for tests. - global old_context - old_context = zope.app.appsetup.appsetup.getConfigContext() - zope.app.appsetup.appsetup.__config_context = xmlconfig.file( - config_file, zope.app.zcmlfiles, execute=False) + _setUp_AppSetup() def tearDown(test): - setup.placefulTearDown() - zope.app.appsetup.appsetup.__config_context = old_context + PlacefulSetup().tearDown() + _tearDown_AppSetup() from zope.app.apidoc import zcmlmodule zcmlmodule.namespaces = None zcmlmodule.subdirs = None @@ -81,6 +97,15 @@ def foo(): pass class ZCMLModuleTests(BrowserTestCase): """Just a couple of tests ensuring that the templates render.""" + layer = APIDocLayer + + def setUp(self): + super(ZCMLModuleTests, self).setUp() + _setUp_AppSetup() + + def tearDown(self): + _tearDown_AppSetup() + super(ZCMLModuleTests, self).tearDown() def testMenu(self): response = self.publish( @@ -104,16 +129,16 @@ def testDirectiveDetailsView(self): def test_suite(): - ZCMLModuleTests.layer = APIDocLayer + return unittest.TestSuite(( - doctest.DocFileSuite('README.txt', + doctest.DocFileSuite('README.rst', setUp=setUp, tearDown=tearDown, optionflags=doctest.NORMALIZE_WHITESPACE), - doctest.DocFileSuite('browser.txt', + doctest.DocFileSuite('browser.rst', setUp=setUp, tearDown=tearDown, optionflags=doctest.NORMALIZE_WHITESPACE), - unittest.makeSuite(ZCMLModuleTests), - )) + unittest.defaultTestLoader.loadTestsFromName(__name__), + )) if __name__ == '__main__': unittest.main(default='test_suite') diff --git a/tox.ini b/tox.ini new file mode 100644 index 00000000..3377c397 --- /dev/null +++ b/tox.ini @@ -0,0 +1,8 @@ +[tox] +envlist = py27,py34,py35,py36,pypy + +[testenv] +commands = + zope-testrunner --test-path=src [] +deps = + .[test]