Merge lp:~sidnei/zope3/reduce-deps into lp:~landscape/zope3/trunk
- reduce-deps
- Merge into trunk
Proposed by
Sidnei da Silva
Status: | Merged |
---|---|
Approved by: | Sidnei da Silva |
Approved revision: | 18 |
Merge reported by: | Sidnei da Silva |
Merged at revision: | not available |
Proposed branch: | lp:~sidnei/zope3/reduce-deps |
Merge into: | lp:~landscape/zope3/trunk |
Diff against target: |
152296 lines (+21/-149533) 513 files modified
src/zc/sourcefactory/README.txt (+0/-211) src/zc/sourcefactory/__init__.py (+0/-1) src/zc/sourcefactory/adapters.py (+0/-28) src/zc/sourcefactory/adapters.txt (+0/-46) src/zc/sourcefactory/basic.py (+0/-30) src/zc/sourcefactory/browser/README.txt (+0/-207) src/zc/sourcefactory/browser/__init__.py (+0/-1) src/zc/sourcefactory/browser/configure.zcml (+0/-18) src/zc/sourcefactory/browser/mapping.py (+0/-67) src/zc/sourcefactory/browser/source.py (+0/-83) src/zc/sourcefactory/browser/tests.py (+0/-35) src/zc/sourcefactory/browser/token.py (+0/-84) src/zc/sourcefactory/browser/token.txt (+0/-93) src/zc/sourcefactory/configure-z2.zcml (+0/-25) src/zc/sourcefactory/configure.zcml (+0/-24) src/zc/sourcefactory/constructors.txt (+0/-46) src/zc/sourcefactory/contextual.py (+0/-27) src/zc/sourcefactory/factories.py (+0/-67) src/zc/sourcefactory/ftesting.zcml (+0/-10) src/zc/sourcefactory/interfaces.py (+0/-142) src/zc/sourcefactory/mapping.py (+0/-78) src/zc/sourcefactory/mapping.txt (+0/-68) src/zc/sourcefactory/named.py (+0/-42) src/zc/sourcefactory/policies.py (+0/-186) src/zc/sourcefactory/source.py (+0/-76) src/zc/sourcefactory/tests.py (+0/-41) src/zodbcode/DEPENDENCIES.cfg (+0/-5) src/zodbcode/__init__.py (+0/-2) src/zodbcode/class_.py (+0/-436) src/zodbcode/function.py (+0/-201) src/zodbcode/interfaces.py (+0/-54) src/zodbcode/module.py (+0/-343) src/zodbcode/module.txt (+0/-300) src/zodbcode/patch.py (+0/-468) src/zodbcode/tests/__init__.py (+0/-2) src/zodbcode/tests/_pmtest.py (+0/-25) src/zodbcode/tests/atestmodule.py (+0/-53) src/zodbcode/tests/test_class.py (+0/-215) src/zodbcode/tests/test_module.py (+0/-444) src/zodbcode/tests/test_patch.py (+0/-77) src/zodbcode/tests/tobeimportedbyatestmodule.py (+0/-22) src/zope/app/basicskin/__init__.py (+0/-23) src/zope/app/basicskin/configure.zcml (+0/-44) src/zope/app/basicskin/dialog_macros.pt (+0/-16) src/zope/app/basicskin/standardmacros.py (+0/-51) src/zope/app/basicskin/tests/__init__.py (+0/-2) src/zope/app/basicskin/tests/test_standardmacros.py (+0/-120) src/zope/app/basicskin/view_macros.pt (+0/-48) src/zope/app/basicskin/zmi_stylesheet.css (+0/-45) src/zope/app/basicskin/zopetopbasic.css (+0/-183) src/zope/app/basicskin/zopetopstructure.css (+0/-255) src/zope/app/basicskin/zopetopwidgets.css (+0/-351) src/zope/app/broken/__init__.py (+0/-1) src/zope/app/broken/broken.pt (+0/-19) src/zope/app/broken/broken.py (+0/-123) src/zope/app/broken/browser.zcml (+0/-14) src/zope/app/broken/configure.zcml (+0/-15) src/zope/app/broken/interfaces.py (+0/-21) src/zope/app/broken/tests.py (+0/-89) src/zope/app/content/__init__.py (+0/-32) src/zope/app/content/configure.zcml (+0/-13) src/zope/app/content/interfaces.py (+0/-27) src/zope/app/dav/__init__.py (+0/-1) src/zope/app/dav/adapter.py (+0/-88) src/zope/app/dav/configure.zcml (+0/-143) src/zope/app/dav/dav-configure.zcml (+0/-1) src/zope/app/dav/dav-meta.zcml (+0/-1) src/zope/app/dav/ftesting.zcml (+0/-44) src/zope/app/dav/interfaces.py (+0/-246) src/zope/app/dav/meta.zcml (+0/-12) src/zope/app/dav/metaconfigure.py (+0/-26) src/zope/app/dav/metadirectives.py (+0/-37) src/zope/app/dav/mkcol.py (+0/-66) src/zope/app/dav/opaquenamespaces.py (+0/-244) src/zope/app/dav/propfind.py (+0/-294) src/zope/app/dav/proppatch.py (+0/-227) src/zope/app/dav/testing.py (+0/-26) src/zope/app/dav/tests/__init__.py (+0/-1) src/zope/app/dav/tests/dav.py (+0/-55) src/zope/app/dav/tests/dav.zcml (+0/-10) src/zope/app/dav/tests/test_adapter.py (+0/-148) src/zope/app/dav/tests/test_directives.py (+0/-47) src/zope/app/dav/tests/test_doctests.py (+0/-27) src/zope/app/dav/tests/test_functional_mkcol.py (+0/-71) src/zope/app/dav/tests/test_functional_propfind.py (+0/-111) src/zope/app/dav/tests/test_functional_proppatch.py (+0/-168) src/zope/app/dav/tests/test_mkcol.py (+0/-86) src/zope/app/dav/tests/test_propfind.py (+0/-520) src/zope/app/dav/tests/test_proppatch.py (+0/-437) src/zope/app/dav/tests/unitfixtures.py (+0/-71) src/zope/app/dav/widget.py (+0/-85) src/zope/app/error/README.txt (+0/-15) src/zope/app/error/__init__.py (+0/-1) src/zope/app/error/browser/__init__.py (+0/-53) src/zope/app/error/browser/configure.zcml (+0/-42) src/zope/app/error/browser/error.pt (+0/-61) src/zope/app/error/browser/error_config.pt (+0/-56) src/zope/app/error/browser/errorentry.pt (+0/-87) src/zope/app/error/browser/texttbentry.pt (+0/-9) src/zope/app/error/configure.zcml (+0/-7) src/zope/app/error/error.py (+0/-52) src/zope/app/error/interfaces.py (+0/-34) src/zope/app/error/tests.py (+0/-33) src/zope/app/file/DEPENDENCIES.cfg (+0/-10) src/zope/app/file/PACKAGE.cfg (+0/-3) src/zope/app/file/SETUP.cfg (+0/-5) src/zope/app/file/__init__.py (+0/-21) src/zope/app/file/browser/__init__.py (+0/-2) src/zope/app/file/browser/configure.zcml (+0/-126) src/zope/app/file/browser/file.py (+0/-503) src/zope/app/file/browser/file.txt (+0/-654) src/zope/app/file/browser/file_add.pt (+0/-62) src/zope/app/file/browser/file_upload.pt (+0/-61) src/zope/app/file/browser/image.py (+0/-112) src/zope/app/file/browser/image_edit.pt (+0/-24) src/zope/app/file/browser/preview.pt (+0/-9) src/zope/app/file/browser/tests/__init__.py (+0/-2) src/zope/app/file/browser/tests/test_file.py (+0/-30) src/zope/app/file/browser/tests/test_functional.py (+0/-331) src/zope/app/file/browser/tests/test_imagedata.py (+0/-80) src/zope/app/file/browser/url.txt (+0/-95) src/zope/app/file/configure.zcml (+0/-105) src/zope/app/file/file-configure.zcml (+0/-1) src/zope/app/file/file.py (+0/-284) src/zope/app/file/ftesting.zcml (+0/-56) src/zope/app/file/i18n.py (+0/-22) src/zope/app/file/image.py (+0/-162) src/zope/app/file/interfaces.py (+0/-53) src/zope/app/file/testing.py (+0/-26) src/zope/app/file/tests/__init__.py (+0/-2) src/zope/app/file/tests/test_file.py (+0/-27) src/zope/app/file/tests/test_image.py (+0/-184) src/zope/app/folder/__init__.py (+0/-20) src/zope/app/folder/browser/__init__.py (+0/-2) src/zope/app/folder/browser/configure.zcml (+0/-36) src/zope/app/folder/browser/preview.pt (+0/-9) src/zope/app/folder/configure.zcml (+0/-15) src/zope/app/folder/filerepresentation.py (+0/-20) src/zope/app/folder/folder.py (+0/-19) src/zope/app/folder/interfaces.py (+0/-19) src/zope/app/folder/testing.py (+0/-26) src/zope/app/generations/README.txt (+0/-354) src/zope/app/generations/__init__.py (+0/-17) src/zope/app/generations/browser/__init__.py (+0/-1) src/zope/app/generations/browser/configure.zcml (+0/-23) src/zope/app/generations/browser/managerdetails.pt (+0/-30) src/zope/app/generations/browser/managerdetails.py (+0/-87) src/zope/app/generations/browser/managers.pt (+0/-62) src/zope/app/generations/browser/managers.py (+0/-298) src/zope/app/generations/browser/tests.py (+0/-92) src/zope/app/generations/configure.zcml (+0/-36) src/zope/app/generations/demo/__init__.py (+0/-31) src/zope/app/generations/demo/evolve1.py (+0/-26) src/zope/app/generations/demo/evolve2.py (+0/-26) src/zope/app/generations/demo/evolve3.py (+0/-25) src/zope/app/generations/demo/install.py (+0/-25) src/zope/app/generations/demo2/__init__.py (+0/-1) src/zope/app/generations/demo3/__init__.py (+0/-17) src/zope/app/generations/demo3/install.py (+0/-27) src/zope/app/generations/ftesting.zcml (+0/-40) src/zope/app/generations/generations.py (+0/-521) src/zope/app/generations/interfaces.py (+0/-91) src/zope/app/generations/subscriber.zcml (+0/-28) src/zope/app/generations/testing.py (+0/-26) src/zope/app/generations/tests.py (+0/-37) src/zope/app/generations/utility.py (+0/-164) src/zope/app/i18n/__init__.py (+0/-27) src/zope/app/i18n/browser/__init__.py (+0/-28) src/zope/app/i18n/browser/configure.zcml (+0/-66) src/zope/app/i18n/browser/exportimport.pt (+0/-50) src/zope/app/i18n/browser/exportimport.py (+0/-34) src/zope/app/i18n/browser/synchronize.pt (+0/-129) src/zope/app/i18n/browser/synchronize.py (+0/-231) src/zope/app/i18n/browser/tests/__init__.py (+0/-2) src/zope/app/i18n/browser/tests/test_translate.py (+0/-128) src/zope/app/i18n/browser/translate.pt (+0/-139) src/zope/app/i18n/browser/translate.py (+0/-111) src/zope/app/i18n/browser/translatemessage.pt (+0/-38) src/zope/app/i18n/configure.zcml (+0/-79) src/zope/app/i18n/filters.py (+0/-222) src/zope/app/i18n/interfaces.py (+0/-148) src/zope/app/i18n/messagecatalog.py (+0/-98) src/zope/app/i18n/tests/__init__.py (+0/-9) src/zope/app/i18n/tests/configure.zcml (+0/-10) src/zope/app/i18n/tests/placelesssetup.py (+0/-7) src/zope/app/i18n/tests/test_filters.py (+0/-99) src/zope/app/i18n/tests/test_messagecatalog.py (+0/-103) src/zope/app/i18n/tests/test_translationdomain.py (+0/-286) src/zope/app/i18n/translationdomain.py (+0/-279) src/zope/app/i18n/xmlrpc/__init__.py (+0/-2) src/zope/app/i18n/xmlrpc/configure.zcml (+0/-16) src/zope/app/i18n/xmlrpc/methods.py (+0/-33) src/zope/app/interface/__init__.py (+0/-142) src/zope/app/interface/configure.zcml (+0/-7) src/zope/app/interface/interfaces.py (+0/-29) src/zope/app/interface/tests/__init__.py (+0/-1) src/zope/app/interface/tests/test_interface.py (+0/-200) src/zope/app/interface/tests/test_queryinterface.py (+0/-30) src/zope/app/interface/vocabulary.py (+0/-21) src/zope/app/interface/wref.py (+0/-52) src/zope/app/locales/README.txt (+0/-6) src/zope/app/locales/TRANSLATE.txt (+0/-60) src/zope/app/locales/__init__.py (+0/-1) src/zope/app/locales/configure.zcml (+0/-7) src/zope/app/locales/de/LC_MESSAGES/zope.po (+0/-6862) src/zope/app/locales/en/LC_MESSAGES/zope.po (+0/-15) src/zope/app/locales/es/LC_MESSAGES/zope.po (+0/-6952) src/zope/app/locales/extract.py (+0/-680) src/zope/app/locales/fr/LC_MESSAGES/zope.po (+0/-6775) src/zope/app/locales/he/LC_MESSAGES/zope.po (+0/-6568) src/zope/app/locales/hu/LC_MESSAGES/zope.po (+0/-7427) src/zope/app/locales/interfaces.py (+0/-60) src/zope/app/locales/it/LC_MESSAGES/zope.po (+0/-8627) src/zope/app/locales/ja/LC_MESSAGES/zope.po (+0/-7026) src/zope/app/locales/nl/LC_MESSAGES/zope.po (+0/-5441) src/zope/app/locales/pl/LC_MESSAGES/zope.po (+0/-6689) src/zope/app/locales/pt_BR/LC_MESSAGES/zope.po (+0/-7597) src/zope/app/locales/pygettext.py (+0/-541) src/zope/app/locales/ru/LC_MESSAGES/zope.po (+0/-5815) src/zope/app/locales/tests.py (+0/-57) src/zope/app/locales/tr/LC_MESSAGES/zope.po (+0/-6612) src/zope/app/locales/zh_CN/LC_MESSAGES/zope.po (+0/-7259) src/zope/app/locales/zh_TW/LC_MESSAGES/zope.po (+0/-7207) src/zope/app/locales/zope.pot (+0/-5717) src/zope/app/localpermission/__init__.py (+0/-1) src/zope/app/localpermission/browser.zcml (+0/-31) src/zope/app/localpermission/configure.zcml (+0/-36) src/zope/app/localpermission/permission.py (+0/-98) src/zope/app/localpermission/tests.py (+0/-24) src/zope/app/principalannotation/__init__.py (+0/-23) src/zope/app/principalannotation/bootstrap.py (+0/-38) src/zope/app/principalannotation/bootstrap.zcml (+0/-8) src/zope/app/principalannotation/browser.zcml (+0/-13) src/zope/app/principalannotation/configure.zcml (+0/-7) src/zope/app/principalannotation/interfaces.py (+0/-18) src/zope/app/principalannotation/tests.py (+0/-48) src/zope/app/renderer/__init__.py (+0/-42) src/zope/app/renderer/configure.zcml (+0/-53) src/zope/app/renderer/i18n.py (+0/-22) src/zope/app/renderer/interfaces.py (+0/-42) src/zope/app/renderer/plaintext.py (+0/-56) src/zope/app/renderer/rest.py (+0/-112) src/zope/app/renderer/stx.py (+0/-75) src/zope/app/renderer/tests/__init__.py (+0/-1) src/zope/app/renderer/tests/test_renderers.py (+0/-29) src/zope/app/renderer/tests/test_vocabulary.py (+0/-84) src/zope/app/renderer/vocabulary.py (+0/-29) src/zope/app/rotterdam/__init__.py (+0/-36) src/zope/app/rotterdam/configure.zcml (+0/-160) src/zope/app/rotterdam/dialog_macros.pt (+0/-174) src/zope/app/rotterdam/editingwidgets.py (+0/-124) src/zope/app/rotterdam/ftesting.zcml (+0/-42) src/zope/app/rotterdam/i18n.py (+0/-22) src/zope/app/rotterdam/navigation_macros.pt (+0/-40) src/zope/app/rotterdam/onlinehelp.js (+0/-9) src/zope/app/rotterdam/popup_macros.pt (+0/-83) src/zope/app/rotterdam/simpleeditingrow.pt (+0/-36) src/zope/app/rotterdam/simpleeditingrowfragment.pt (+0/-1) src/zope/app/rotterdam/site_management.css (+0/-59) src/zope/app/rotterdam/site_management_tablelayout.css (+0/-75) src/zope/app/rotterdam/standardmacros.py (+0/-22) src/zope/app/rotterdam/template.pt (+0/-244) src/zope/app/rotterdam/template_tablelayout.pt (+0/-209) src/zope/app/rotterdam/testing.py (+0/-26) src/zope/app/rotterdam/tests/__init__.py (+0/-2) src/zope/app/rotterdam/tests/output/test1.xml (+0/-1) src/zope/app/rotterdam/tests/output/test2.xml (+0/-1) src/zope/app/rotterdam/tests/output/test3.xml (+0/-1) src/zope/app/rotterdam/tests/output/test4.xml (+0/-1) src/zope/app/rotterdam/tests/output/test5.xml (+0/-1) src/zope/app/rotterdam/tests/output/test6.xml (+0/-1) src/zope/app/rotterdam/tests/output/test7.xml (+0/-1) src/zope/app/rotterdam/tests/output/test8.xml (+0/-1) src/zope/app/rotterdam/tests/test_editingwidgets.py (+0/-21) src/zope/app/rotterdam/tests/test_navtree.py (+0/-83) src/zope/app/rotterdam/tests/test_xmlnavigationviews.py (+0/-130) src/zope/app/rotterdam/tests/util.py (+0/-31) src/zope/app/rotterdam/view_macros.pt (+0/-46) src/zope/app/rotterdam/xmlobject.py (+0/-242) src/zope/app/rotterdam/xmltree.js (+0/-463) src/zope/app/rotterdam/zope3.css (+0/-591) src/zope/app/rotterdam/zope3.js (+0/-87) src/zope/app/rotterdam/zope3_tablelayout.css (+0/-664) src/zope/app/security/__init__.py (+0/-19) src/zope/app/security/_protections.py (+0/-19) src/zope/app/security/_protections.zcml (+0/-126) src/zope/app/security/basicauthadapter.py (+0/-20) src/zope/app/security/browser/__init__.py (+0/-17) src/zope/app/security/browser/auth.py (+0/-140) src/zope/app/security/browser/authutilitysearchview.pt (+0/-21) src/zope/app/security/browser/authutilitysearchview.txt (+0/-68) src/zope/app/security/browser/configure.zcml (+0/-49) src/zope/app/security/browser/login.pt (+0/-19) src/zope/app/security/browser/login_failed.pt (+0/-18) src/zope/app/security/browser/loginlogout.txt (+0/-71) src/zope/app/security/browser/logout.pt (+0/-37) src/zope/app/security/browser/principalterms.py (+0/-21) src/zope/app/security/browser/redirect.pt (+0/-39) src/zope/app/security/browser/tests.py (+0/-39) src/zope/app/security/configure.zcml (+0/-15) src/zope/app/security/ftpauth.py (+0/-20) src/zope/app/security/globalmodules.zcml (+0/-437) src/zope/app/security/i18n.py (+0/-17) src/zope/app/security/interfaces.py (+0/-33) src/zope/app/security/loginpassword.py (+0/-20) src/zope/app/security/meta.zcml (+0/-6) src/zope/app/security/metaconfigure.py (+0/-24) src/zope/app/security/metadirectives.py (+0/-27) src/zope/app/security/permission.py (+0/-26) src/zope/app/security/principal.py (+0/-20) src/zope/app/security/principallogging.py (+0/-20) src/zope/app/security/principalregistry.py (+0/-33) src/zope/app/security/protectclass.py (+0/-23) src/zope/app/security/settings.py (+0/-28) src/zope/app/security/standardpermissions.zcml (+0/-26) src/zope/app/security/tests/__init__.py (+0/-19) src/zope/app/security/tests/ftesting.zcml (+0/-9) src/zope/app/security/tests/persistentlist.txt (+0/-51) src/zope/app/security/tests/test_basicauthadapter.py (+0/-36) src/zope/app/security/tests/test_ftpauth.py (+0/-36) src/zope/app/security/tests/test_interfaces.py (+0/-66) src/zope/app/security/tests/test_loginpassword.py (+0/-36) src/zope/app/security/tests/test_logout.py (+0/-38) src/zope/app/security/tests/test_permission.py (+0/-42) src/zope/app/security/tests/test_principal.py (+0/-33) src/zope/app/security/tests/test_principallogging.py (+0/-36) src/zope/app/security/tests/test_principalregistry.py (+0/-89) src/zope/app/security/tests/test_vocabulary.py (+0/-42) src/zope/app/security/tests/tests.py (+0/-14) src/zope/app/security/vocabulary.py (+0/-22) src/zope/app/securitypolicy/__init__.py (+0/-17) src/zope/app/securitypolicy/browser/__init__.py (+0/-17) src/zope/app/securitypolicy/browser/configure.zcml (+0/-96) src/zope/app/securitypolicy/browser/granting.pt (+0/-85) src/zope/app/securitypolicy/browser/granting.py (+0/-241) src/zope/app/securitypolicy/browser/granting.txt (+0/-203) src/zope/app/securitypolicy/browser/granting_ftest.txt (+0/-195) src/zope/app/securitypolicy/browser/manage_access.pt (+0/-94) src/zope/app/securitypolicy/browser/manage_permissionform.pt (+0/-96) src/zope/app/securitypolicy/browser/manage_roleform.pt (+0/-76) src/zope/app/securitypolicy/browser/rolepermissionview.py (+0/-240) src/zope/app/securitypolicy/browser/tests/__init__.py (+0/-2) src/zope/app/securitypolicy/browser/tests/functional.py (+0/-38) src/zope/app/securitypolicy/browser/tests/functional.zcml (+0/-6) src/zope/app/securitypolicy/browser/tests/rolepermissionmanager.py (+0/-87) src/zope/app/securitypolicy/browser/tests/test_functional.py (+0/-155) src/zope/app/securitypolicy/browser/tests/test_granting.py (+0/-32) src/zope/app/securitypolicy/browser/tests/test_rolepermissionview.py (+0/-221) src/zope/app/securitypolicy/configure.zcml (+0/-8) src/zope/app/securitypolicy/ftesting.zcml (+0/-43) src/zope/app/securitypolicy/testing.py (+0/-26) src/zope/app/session/SETUP.cfg (+0/-3) src/zope/app/session/__init__.py (+0/-18) src/zope/app/session/api.txt (+0/-129) src/zope/app/session/browser.zcml (+0/-44) src/zope/app/session/configure.zcml (+0/-9) src/zope/app/session/ftesting.zcml (+0/-57) src/zope/app/session/http.py (+0/-29) src/zope/app/session/interfaces.py (+0/-29) src/zope/app/session/session.py (+0/-31) src/zope/app/session/testing.py (+0/-27) src/zope/app/session/tests.py (+0/-171) src/zope/app/session/zope.app.session-configure.zcml (+0/-1) src/zope/app/zcmlfiles/__init__.py (+0/-1) src/zope/app/zcmlfiles/browser.zcml (+0/-17) src/zope/app/zcmlfiles/configure.zcml (+0/-83) src/zope/app/zcmlfiles/ftesting.zcml (+0/-10) src/zope/app/zcmlfiles/menus.zcml (+0/-37) src/zope/app/zcmlfiles/meta.zcml (+0/-13) src/zope/app/zcmlfiles/tests.py (+0/-30) src/zope/app/zopeappgenerations/__init__.py (+0/-31) src/zope/app/zopeappgenerations/configure.zcml (+0/-9) src/zope/app/zopeappgenerations/evolve2.py (+0/-43) src/zope/app/zopeappgenerations/evolve3.py (+0/-98) src/zope/app/zopeappgenerations/evolve4.py (+0/-25) src/zope/app/zopeappgenerations/evolve5.py (+0/-43) src/zope/app/zptpage/DEPENDENCIES.cfg (+0/-11) src/zope/app/zptpage/PACKAGE.cfg (+0/-3) src/zope/app/zptpage/SETUP.cfg (+0/-5) src/zope/app/zptpage/__init__.py (+0/-18) src/zope/app/zptpage/browser/__init__.py (+0/-2) src/zope/app/zptpage/browser/collector266.txt (+0/-232) src/zope/app/zptpage/browser/collector269.txt (+0/-141) src/zope/app/zptpage/browser/configure.zcml (+0/-75) src/zope/app/zptpage/browser/inlinecode.pt (+0/-78) src/zope/app/zptpage/browser/preview.pt (+0/-9) src/zope/app/zptpage/browser/tests.py (+0/-224) src/zope/app/zptpage/browser/url.txt (+0/-73) src/zope/app/zptpage/browser/zptpage.py (+0/-56) src/zope/app/zptpage/configure.zcml (+0/-70) src/zope/app/zptpage/ftesting.zcml (+0/-44) src/zope/app/zptpage/i18n.py (+0/-22) src/zope/app/zptpage/interfaces.py (+0/-71) src/zope/app/zptpage/testing.py (+0/-26) src/zope/app/zptpage/tests/__init__.py (+0/-2) src/zope/app/zptpage/tests/test_zptpage.py (+0/-241) src/zope/app/zptpage/tests/test_zptpageeval.py (+0/-70) src/zope/app/zptpage/textindex/DEPENDENCIES.cfg (+0/-1) src/zope/app/zptpage/textindex/SETUP.cfg (+0/-3) src/zope/app/zptpage/textindex/__init__.py (+0/-1) src/zope/app/zptpage/textindex/configure.zcml (+0/-9) src/zope/app/zptpage/textindex/tests.py (+0/-55) src/zope/app/zptpage/textindex/zope.app.zptpage.textindex-configure.zcml (+0/-1) src/zope/app/zptpage/textindex/zptpage.py (+0/-45) src/zope/app/zptpage/zptpage-configure.zcml (+0/-1) src/zope/app/zptpage/zptpage.py (+0/-159) src/zope/index/DEPENDENCIES.cfg (+0/-5) src/zope/index/__init__.py (+0/-1) src/zope/index/field/README.txt (+0/-207) src/zope/index/field/__init__.py (+0/-1) src/zope/index/field/index.py (+0/-107) src/zope/index/field/sorting.py (+0/-132) src/zope/index/field/tests.py (+0/-323) src/zope/index/interfaces.py (+0/-156) src/zope/index/keyword/__init__.py (+0/-1) src/zope/index/keyword/index.py (+0/-184) src/zope/index/keyword/interfaces.py (+0/-31) src/zope/index/keyword/tests.py (+0/-381) src/zope/index/nbest.py (+0/-79) src/zope/index/tests.py (+0/-100) src/zope/index/text/__init__.py (+0/-1) src/zope/index/text/baseindex.py (+0/-322) src/zope/index/text/cosineindex.py (+0/-113) src/zope/index/text/htmlsplitter.py (+0/-47) src/zope/index/text/interfaces.py (+0/-218) src/zope/index/text/lexicon.py (+0/-204) src/zope/index/text/okapiindex.py (+0/-363) src/zope/index/text/okascore.c (+0/-130) src/zope/index/text/okascore.py (+0/-7) src/zope/index/text/parsetree.py (+0/-133) src/zope/index/text/queryparser.py (+0/-253) src/zope/index/text/ricecode.py (+0/-209) src/zope/index/text/setops.py (+0/-65) src/zope/index/text/stopdict.py (+0/-37) src/zope/index/text/tests/__init__.py (+0/-2) src/zope/index/text/tests/hs-tool.py (+0/-145) src/zope/index/text/tests/mhindex.py (+0/-585) src/zope/index/text/tests/test_baseindex.py (+0/-475) src/zope/index/text/tests/test_cosineindex.py (+0/-116) src/zope/index/text/tests/test_htmlsplitter.py (+0/-105) src/zope/index/text/tests/test_index.py (+0/-225) src/zope/index/text/tests/test_lexicon.py (+0/-405) src/zope/index/text/tests/test_okapiindex.py (+0/-147) src/zope/index/text/tests/test_parsetree.py (+0/-286) src/zope/index/text/tests/test_queryengine.py (+0/-79) src/zope/index/text/tests/test_queryparser.py (+0/-426) src/zope/index/text/tests/test_setops.py (+0/-263) src/zope/index/text/tests/test_textindex.py (+0/-257) src/zope/index/text/tests/test_textindexwrapper.py (+0/-22) src/zope/index/text/tests/test_widcode.py (+0/-110) src/zope/index/text/tests/wordstats.py (+0/-59) src/zope/index/text/textindex.py (+0/-87) src/zope/index/text/textindex.txt (+0/-156) src/zope/index/text/widcode.py (+0/-124) src/zope/index/topic/__init__.py (+0/-1) src/zope/index/topic/filter.py (+0/-81) src/zope/index/topic/index.py (+0/-109) src/zope/index/topic/interfaces.py (+0/-53) src/zope/index/topic/tests/__init__.py (+0/-2) src/zope/index/topic/tests/test_filter.py (+0/-119) src/zope/index/topic/tests/test_index.py (+0/-399) src/zope/intid/__init__.py (+0/-180) src/zope/intid/configure.zcml (+0/-34) src/zope/intid/interfaces.py (+0/-115) src/zope/intid/subscribers.zcml (+0/-10) src/zope/intid/tests.py (+0/-336) src/zope/keyreference/__init__.py (+0/-18) src/zope/keyreference/configure.zcml (+0/-32) src/zope/keyreference/interfaces.py (+0/-54) src/zope/keyreference/persistent.py (+0/-129) src/zope/keyreference/persistent.txt (+0/-246) src/zope/keyreference/testing.py (+0/-43) src/zope/keyreference/tests.py (+0/-61) src/zope/login/__init__.py (+0/-1) src/zope/login/configure.zcml (+0/-15) src/zope/login/ftp.py (+0/-35) src/zope/login/http.py (+0/-36) src/zope/login/tests/__init__.py (+0/-1) src/zope/login/tests/test_basicauth.py (+0/-49) src/zope/login/tests/test_ftpauth.py (+0/-53) src/zope/principalannotation/README.txt (+0/-214) src/zope/principalannotation/__init__.py (+0/-1) src/zope/principalannotation/configure.zcml (+0/-21) src/zope/principalannotation/interfaces.py (+0/-42) src/zope/principalannotation/tests.py (+0/-42) src/zope/principalannotation/utility.py (+0/-128) src/zope/structuredtext/__init__.py (+0/-64) src/zope/structuredtext/docbook.py (+0/-273) src/zope/structuredtext/document.py (+0/-779) src/zope/structuredtext/html.py (+0/-285) src/zope/structuredtext/regressions/Acquisition.ref (+0/-260) src/zope/structuredtext/regressions/Acquisition.stx (+0/-277) src/zope/structuredtext/regressions/ExtensionClass.ref (+0/-614) src/zope/structuredtext/regressions/ExtensionClass.stx (+0/-714) src/zope/structuredtext/regressions/InnerLinks.ref (+0/-11) src/zope/structuredtext/regressions/InnerLinks.stx (+0/-10) src/zope/structuredtext/regressions/Links.ref (+0/-23) src/zope/structuredtext/regressions/Links.stx (+0/-24) src/zope/structuredtext/regressions/MultiMapping.ref (+0/-415) src/zope/structuredtext/regressions/MultiMapping.stx (+0/-408) src/zope/structuredtext/regressions/examples.ref (+0/-48) src/zope/structuredtext/regressions/examples.stx (+0/-47) src/zope/structuredtext/regressions/examples1.ref (+0/-15) src/zope/structuredtext/regressions/examples1.stx (+0/-9) src/zope/structuredtext/regressions/index.ref (+0/-48) src/zope/structuredtext/regressions/index.stx (+0/-52) src/zope/structuredtext/regressions/table.ref (+0/-72) src/zope/structuredtext/regressions/table.stx (+0/-32) src/zope/structuredtext/stdom.py (+0/-484) src/zope/structuredtext/stletters.py (+0/-31) src/zope/structuredtext/stng.py (+0/-525) src/zope/structuredtext/tests.py (+0/-289) test.py (+21/-1) |
To merge this branch: | bzr merge lp:~sidnei/zope3/reduce-deps |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Sidnei da Silva (community) | Approve | ||
Review via email: mp+29237@code.launchpad.net |
Commit message
Description of the change
Reduce deps
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === removed directory 'src/zc/sourcefactory' |
2 | === removed file 'src/zc/sourcefactory/README.txt' |
3 | --- src/zc/sourcefactory/README.txt 2010-03-01 20:29:16 +0000 |
4 | +++ src/zc/sourcefactory/README.txt 1970-01-01 00:00:00 +0000 |
5 | @@ -1,211 +0,0 @@ |
6 | -================ |
7 | -Source Factories |
8 | -================ |
9 | - |
10 | -Source factories are used to simplify the creation of sources for certain |
11 | -standard cases. |
12 | - |
13 | -Sources split up the process of providing input fields with choices for users |
14 | -into several components: a context binder, a source class, a terms class, and a |
15 | -term class. |
16 | - |
17 | -This is the correct abstraction and will fit many complex cases very well. To |
18 | -reduce the amount of work to do for some standard cases, the source factories |
19 | -allow users to define only the business relevant code for getting a list of |
20 | -values, getting a token and a title to display. |
21 | - |
22 | -.. contents:: |
23 | - |
24 | -Simple case |
25 | -=========== |
26 | - |
27 | -In the most simple case, you only have to provide a method that returns a list |
28 | -of values and derive from `BasicSourceFactory`: |
29 | - |
30 | - >>> import zc.sourcefactory.basic |
31 | - >>> class MyStaticSource(zc.sourcefactory.basic.BasicSourceFactory): |
32 | - ... def getValues(self): |
33 | - ... return ['a', 'b', 'c'] |
34 | - |
35 | -When calling the source factory, we get a source: |
36 | - |
37 | - >>> source = MyStaticSource() |
38 | - >>> import zope.schema.interfaces |
39 | - >>> zope.schema.interfaces.ISource.providedBy(source) |
40 | - True |
41 | - |
42 | -The values match our `getValues`-method of the factory: |
43 | - |
44 | - >>> list(source) |
45 | - ['a', 'b', 'c'] |
46 | - >>> 'a' in source |
47 | - True |
48 | - >>> len(source) |
49 | - 3 |
50 | - |
51 | - |
52 | -Contextual sources |
53 | -================== |
54 | - |
55 | -Sometimes we need context to determine the values. In this case, the |
56 | -`getValues`-method gets a parameter `context`. |
57 | - |
58 | -Let's assume we have a small object containing data to be used by the source: |
59 | - |
60 | - >>> class Context(object): |
61 | - ... values = [] |
62 | - |
63 | - >>> import zc.sourcefactory.contextual |
64 | - >>> class MyDynamicSource( |
65 | - ... zc.sourcefactory.contextual.BasicContextualSourceFactory): |
66 | - ... def getValues(self, context): |
67 | - ... return context.values |
68 | - |
69 | -When instanciating, we get a ContextSourceBinder: |
70 | - |
71 | - >>> binder = MyDynamicSource() |
72 | - >>> zope.schema.interfaces.IContextSourceBinder.providedBy(binder) |
73 | - True |
74 | - |
75 | -Binding it to a context, we get a source: |
76 | - |
77 | - >>> context = Context() |
78 | - >>> source = binder(context) |
79 | - >>> zope.schema.interfaces.ISource.providedBy(source) |
80 | - True |
81 | - |
82 | - >>> list(source) |
83 | - [] |
84 | - |
85 | -Modifying the context also modifies the data in the source: |
86 | - |
87 | - >>> context.values = [1,2,3,4] |
88 | - >>> list(source) |
89 | - [1, 2, 3, 4] |
90 | - >>> 1 in source |
91 | - True |
92 | - >>> len(source) |
93 | - 4 |
94 | - |
95 | -It's possible to have the default machinery return different sources, by |
96 | -providing a source_class argument when calling the binder. One can also |
97 | -provide arguments to the source. |
98 | - |
99 | - >>> class MultiplierSource(zc.sourcefactory.source.FactoredContextualSource): |
100 | - ... def __init__(self, factory, context, multiplier): |
101 | - ... super(MultiplierSource, self).__init__(factory, context) |
102 | - ... self.multiplier = multiplier |
103 | - ... |
104 | - ... def _get_filtered_values(self): |
105 | - ... for value in self.factory.getValues(self.context): |
106 | - ... yield self.multiplier * value |
107 | - >>> class MultiplierSourceFactory(MyDynamicSource): |
108 | - ... source_class = MultiplierSource |
109 | - >>> binder = MultiplierSourceFactory() |
110 | - >>> source = binder(context, multiplier=5) |
111 | - >>> list(source) |
112 | - [5, 10, 15, 20] |
113 | - >>> 5 in source |
114 | - True |
115 | - >>> len(source) |
116 | - 4 |
117 | - |
118 | -Filtering |
119 | -========= |
120 | - |
121 | -Additional to providing the `getValues`-method you can also provide a |
122 | -`filterValue`-method that will allow you to reduce the items from the list, |
123 | -piece by piece. |
124 | - |
125 | -This is useful if you want to have more specific sources (by subclassing) that |
126 | -share the same basic origin of the data but have different filters applied to |
127 | -it: |
128 | - |
129 | - >>> class FilteringSource(zc.sourcefactory.basic.BasicSourceFactory): |
130 | - ... def getValues(self): |
131 | - ... return xrange(1,20) |
132 | - ... def filterValue(self, value): |
133 | - ... return value % 2 |
134 | - >>> source = FilteringSource() |
135 | - >>> list(source) |
136 | - [1, 3, 5, 7, 9, 11, 13, 15, 17, 19] |
137 | - |
138 | -Subclassing modifies the filter, not the original data: |
139 | - |
140 | - >>> class OtherFilteringSource(FilteringSource): |
141 | - ... def filterValue(self, value): |
142 | - ... return not value % 2 |
143 | - >>> source = OtherFilteringSource() |
144 | - >>> list(source) |
145 | - [2, 4, 6, 8, 10, 12, 14, 16, 18] |
146 | - |
147 | -The "in" operator gets applied also to filtered values: |
148 | - |
149 | - >>> 2 in source |
150 | - True |
151 | - >>> 3 in source |
152 | - False |
153 | - |
154 | -The "len" also gets applied to filtered values: |
155 | - |
156 | - >>> len(source) |
157 | - 9 |
158 | - |
159 | - |
160 | -Scaling |
161 | -======= |
162 | - |
163 | -Sometimes the number of items available through a source is very large. So |
164 | -large that you only want to access them if absolutely neccesary. One such |
165 | -occasion is with truth-testing a source. By default Python will call |
166 | -__nonzero__ to get the boolean value of an object, but if that isn't available |
167 | -__len__ is called to see what it returns. That might be very expensive, so we |
168 | -want to make sure it isn't called. |
169 | - |
170 | - >>> class MyExpensiveSource(zc.sourcefactory.basic.BasicSourceFactory): |
171 | - ... def getValues(self): |
172 | - ... yield 'a' |
173 | - ... raise RuntimeError('oops, iterated too far') |
174 | - |
175 | - >>> source = MyExpensiveSource() |
176 | - |
177 | - >>> bool(source) |
178 | - True |
179 | - |
180 | - |
181 | -Simple case |
182 | -=========== |
183 | - |
184 | -In the most simple case, you only have to provide a method that returns a list |
185 | -of values and derive from `BasicSourceFactory`: |
186 | - |
187 | - >>> import zc.sourcefactory.basic |
188 | - >>> class MyStaticSource(zc.sourcefactory.basic.BasicSourceFactory): |
189 | - ... def getValues(self): |
190 | - ... return ['a', 'b', 'c'] |
191 | - |
192 | -When calling the source factory, we get a source: |
193 | - |
194 | - >>> source = MyStaticSource() |
195 | - >>> import zope.schema.interfaces |
196 | - >>> zope.schema.interfaces.ISource.providedBy(source) |
197 | - True |
198 | - |
199 | -The values match our `getValues`-method of the factory: |
200 | - |
201 | - >>> list(source) |
202 | - ['a', 'b', 'c'] |
203 | - >>> 'a' in source |
204 | - True |
205 | - >>> len(source) |
206 | - 3 |
207 | - |
208 | - |
209 | -WARNING about the standard adapters for ITerms |
210 | -============================================== |
211 | - |
212 | -The standard adapters for ITerms are only suitable if the value types returned |
213 | -by your `getValues` function are homogenous. Mixing integers, persistent |
214 | -objects, strings, and unicode within one source may create non-unique tokens. |
215 | -In this case, you have to provide a custom `getToken`-method to provide unique |
216 | -and unambigous tokens. |
217 | |
218 | === removed file 'src/zc/sourcefactory/__init__.py' |
219 | --- src/zc/sourcefactory/__init__.py 2010-03-01 20:29:16 +0000 |
220 | +++ src/zc/sourcefactory/__init__.py 1970-01-01 00:00:00 +0000 |
221 | @@ -1,1 +0,0 @@ |
222 | -# This directory is a Python package. |
223 | |
224 | === removed file 'src/zc/sourcefactory/adapters.py' |
225 | --- src/zc/sourcefactory/adapters.py 2010-03-01 20:29:16 +0000 |
226 | +++ src/zc/sourcefactory/adapters.py 1970-01-01 00:00:00 +0000 |
227 | @@ -1,28 +0,0 @@ |
228 | -############################################################################## |
229 | -# |
230 | -# Copyright (c) 2006-2007 Zope Corporation and Contributors. |
231 | -# All Rights Reserved. |
232 | -# |
233 | -# This software is subject to the provisions of the Zope Public License, |
234 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
235 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
236 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
237 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
238 | -# FOR A PARTICULAR PURPOSE. |
239 | -# |
240 | -############################################################################## |
241 | -"""Support to adapt factored sources to some common interfaces. |
242 | - |
243 | -""" |
244 | -__docformat__ = "reStructuredText" |
245 | - |
246 | -import zope.schema.interfaces |
247 | -import zope.component |
248 | -import zc.sourcefactory.source |
249 | - |
250 | -@zope.interface.implementer(zope.schema.interfaces.ISourceQueriables) |
251 | -@zope.component.adapter(zc.sourcefactory.source.FactoredSource) |
252 | -def getSourceQueriables(factored_source): |
253 | - return zope.component.queryMultiAdapter( |
254 | - (factored_source, factored_source.factory), |
255 | - zope.schema.interfaces.ISourceQueriables) |
256 | |
257 | === removed file 'src/zc/sourcefactory/adapters.txt' |
258 | --- src/zc/sourcefactory/adapters.txt 2010-03-01 20:29:16 +0000 |
259 | +++ src/zc/sourcefactory/adapters.txt 1970-01-01 00:00:00 +0000 |
260 | @@ -1,46 +0,0 @@ |
261 | -=========================== |
262 | -Common adapters for sources |
263 | -=========================== |
264 | - |
265 | -To allow adapting factored sources specific to the factory, a couple of |
266 | -standard interfaces that can be adapters are re-adapted as using a |
267 | -multi-adapter for (FactoredSource, SourceFactory). |
268 | - |
269 | -ISourceQueriables |
270 | -================= |
271 | - |
272 | - >>> from zc.sourcefactory.basic import BasicSourceFactory |
273 | - >>> class Factory(BasicSourceFactory): |
274 | - ... def getValues(self): |
275 | - ... return [1,2,3] |
276 | - >>> source = Factory() |
277 | - |
278 | - >>> from zope.schema.interfaces import ISourceQueriables |
279 | - >>> import zope.interface |
280 | - >>> class SourceQueriables(object): |
281 | - ... zope.interface.implements(ISourceQueriables) |
282 | - ... def __init__(self, source, factory): |
283 | - ... self.source = source |
284 | - ... self.factory = factory |
285 | - ... def getQueriables(self): |
286 | - ... return [('test', None)] |
287 | - |
288 | - >>> from zc.sourcefactory.source import FactoredSource |
289 | - >>> zope.component.provideAdapter(factory=SourceQueriables, |
290 | - ... provides=ISourceQueriables, |
291 | - ... adapts=(FactoredSource, Factory)) |
292 | - |
293 | - >>> queriables = ISourceQueriables(source) |
294 | - >>> queriables.factory |
295 | - <Factory object at 0x...> |
296 | - >>> queriables.source |
297 | - <zc.sourcefactory.source.FactoredSource object at 0x...> |
298 | - >>> queriables.getQueriables() |
299 | - [('test', None)] |
300 | - |
301 | -Cleanup |
302 | -------- |
303 | - |
304 | - >>> zope.component.getSiteManager().unregisterAdapter(factory=SourceQueriables, |
305 | - ... provided=ISourceQueriables, required=(FactoredSource, Factory)) |
306 | - True |
307 | |
308 | === removed file 'src/zc/sourcefactory/basic.py' |
309 | --- src/zc/sourcefactory/basic.py 2010-03-01 20:29:16 +0000 |
310 | +++ src/zc/sourcefactory/basic.py 1970-01-01 00:00:00 +0000 |
311 | @@ -1,30 +0,0 @@ |
312 | -############################################################################## |
313 | -# |
314 | -# Copyright (c) 2006-2007 Zope Corporation and Contributors. |
315 | -# All Rights Reserved. |
316 | -# |
317 | -# This software is subject to the provisions of the Zope Public License, |
318 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
319 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
320 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
321 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
322 | -# FOR A PARTICULAR PURPOSE. |
323 | -# |
324 | -############################################################################## |
325 | -"""The most basic source factory that supports all the required interfaces. |
326 | - |
327 | -This is used for sources that do not require the context. |
328 | - |
329 | -""" |
330 | -__docformat__ = "reStructuredText" |
331 | - |
332 | - |
333 | -import zc.sourcefactory.factories |
334 | -import zc.sourcefactory.policies |
335 | - |
336 | -class BasicSourceFactory(zc.sourcefactory.factories.BasicSourceFactory, |
337 | - zc.sourcefactory.policies.BasicSourcePolicy): |
338 | - """Basic source factory implementation including a factory and the |
339 | - basic policies. |
340 | - |
341 | - """ |
342 | |
343 | === removed directory 'src/zc/sourcefactory/browser' |
344 | === removed file 'src/zc/sourcefactory/browser/README.txt' |
345 | --- src/zc/sourcefactory/browser/README.txt 2010-03-01 20:29:16 +0000 |
346 | +++ src/zc/sourcefactory/browser/README.txt 1970-01-01 00:00:00 +0000 |
347 | @@ -1,207 +0,0 @@ |
348 | -===================================================== |
349 | -Browser views for sources created by source factories |
350 | -===================================================== |
351 | - |
352 | -Sources that were created using source factories already come with ready-made |
353 | -terms and term objects. |
354 | - |
355 | - |
356 | -Simple use |
357 | -========== |
358 | - |
359 | -Let's start with a simple source factory: |
360 | - |
361 | - >>> import zc.sourcefactory.basic |
362 | - >>> class DemoSource(zc.sourcefactory.basic.BasicSourceFactory): |
363 | - ... def getValues(self): |
364 | - ... return ['a', 'b', 'c', 'd'] |
365 | - >>> source = DemoSource() |
366 | - >>> list(source) |
367 | - ['a', 'b', 'c', 'd'] |
368 | - |
369 | -We need a request first, then we can adapt the source to ITerms: |
370 | - |
371 | - >>> from zope.publisher.browser import TestRequest |
372 | - >>> import zope.browser.interfaces |
373 | - >>> import zope.component |
374 | - >>> request = TestRequest() |
375 | - >>> terms = zope.component.getMultiAdapter( |
376 | - ... (source, request), zope.browser.interfaces.ITerms) |
377 | - >>> terms |
378 | - <zc.sourcefactory.browser.source.FactoredTerms object at 0x...> |
379 | - |
380 | -For each value we get a factored term: |
381 | - |
382 | - >>> terms.getTerm('a') |
383 | - <zc.sourcefactory.browser.source.FactoredTerm object at 0x...> |
384 | - >>> terms.getTerm('b') |
385 | - <zc.sourcefactory.browser.source.FactoredTerm object at 0x...> |
386 | - >>> terms.getTerm('c') |
387 | - <zc.sourcefactory.browser.source.FactoredTerm object at 0x...> |
388 | - >>> terms.getTerm('d') |
389 | - <zc.sourcefactory.browser.source.FactoredTerm object at 0x...> |
390 | - |
391 | -Unicode values are allowed as well: |
392 | - |
393 | - >>> terms.getTerm(u'\xd3') |
394 | - <zc.sourcefactory.browser.source.FactoredTerm object at 0x...> |
395 | - |
396 | -Our terms are ITitledTokenizedTerm-compatible: |
397 | - |
398 | - >>> import zope.schema.interfaces |
399 | - >>> zope.schema.interfaces.ITitledTokenizedTerm.providedBy( |
400 | - ... terms.getTerm('a')) |
401 | - True |
402 | - |
403 | -In the most simple case, the title of a term is the string representation of |
404 | -the object: |
405 | - |
406 | - >>> terms.getTerm('a').title |
407 | - u'a' |
408 | - |
409 | -If an adapter from the value to IDCDescriptiveProperties exists, the title |
410 | -will be retrieved from this adapter: |
411 | - |
412 | - >>> import persistent |
413 | - >>> class MyObject(persistent.Persistent): |
414 | - ... custom_title = u'My custom title' |
415 | - ... _p_oid = 12 |
416 | - >>> class DCDescriptivePropertiesAdapter(object): |
417 | - ... def __init__(self, context): |
418 | - ... self.title = context.custom_title |
419 | - ... self.description = u"" |
420 | - >>> from zope.component import provideAdapter |
421 | - >>> from zope.dublincore.interfaces import IDCDescriptiveProperties |
422 | - >>> provideAdapter(DCDescriptivePropertiesAdapter, [MyObject], |
423 | - ... IDCDescriptiveProperties) |
424 | - >>> terms.getTerm(MyObject()).title |
425 | - u'My custom title' |
426 | - |
427 | -Extended use: provide your own titles |
428 | -===================================== |
429 | - |
430 | -Instead of relying on string representation or IDCDescriptiveProperties |
431 | -adapters you can specify the `getTitle` method on the source factory to |
432 | -determine the title for a value: |
433 | - |
434 | - >>> class DemoSourceWithTitles(DemoSource): |
435 | - ... def getTitle(self, value): |
436 | - ... return 'Custom title ' + value.custom_title |
437 | - >>> source2 = DemoSourceWithTitles() |
438 | - >>> terms2 = zope.component.getMultiAdapter( |
439 | - ... (source2, request), zope.browser.interfaces.ITerms) |
440 | - >>> o1 = MyObject() |
441 | - >>> o1.custom_title = u"Object one" |
442 | - >>> o2 = MyObject() |
443 | - >>> o2.custom_title = u"Object two" |
444 | - >>> terms2.getTerm(o1).title |
445 | - u'Custom title Object one' |
446 | - >>> terms2.getTerm(o2).title |
447 | - u'Custom title Object two' |
448 | - |
449 | - |
450 | -Extended use: provide your own tokens |
451 | -===================================== |
452 | - |
453 | -Instead of relying on default adapters to generate tokens for your values, you |
454 | -can override the `getToken` method on the source factory to determine the |
455 | -token for a value: |
456 | - |
457 | - >>> class DemoObjectWithToken(object): |
458 | - ... token = None |
459 | - >>> o1 = DemoObjectWithToken() |
460 | - >>> o1.token = "one" |
461 | - >>> o2 = DemoObjectWithToken() |
462 | - >>> o2.token = "two" |
463 | - |
464 | - >>> class DemoSourceWithTokens(DemoSource): |
465 | - ... values = [o1, o2] |
466 | - ... def getValues(self): |
467 | - ... return self.values |
468 | - ... def getToken(self, value): |
469 | - ... return value.token |
470 | - |
471 | - >>> source3 = DemoSourceWithTokens() |
472 | - >>> terms3 = zope.component.getMultiAdapter( |
473 | - ... (source3, request), zope.browser.interfaces.ITerms) |
474 | - |
475 | - >>> terms3.getTerm(o1).token |
476 | - 'one' |
477 | - >>> terms3.getTerm(o2).token |
478 | - 'two' |
479 | - |
480 | -Looking up by the custom tokens works as well: |
481 | - |
482 | - >>> terms3.getValue("one") is o1 |
483 | - True |
484 | - >>> terms3.getValue("two") is o2 |
485 | - True |
486 | - >>> terms3.getValue("three") |
487 | - Traceback (most recent call last): |
488 | - KeyError: "No value with token 'three'" |
489 | - |
490 | - |
491 | -Value mapping sources |
492 | -===================== |
493 | - |
494 | - XXX to come |
495 | - |
496 | - |
497 | -Contextual sources |
498 | -================== |
499 | - |
500 | -Let's start with an object that we can use as the context: |
501 | - |
502 | - >>> zip_to_city = {'06112': 'Halle', |
503 | - ... '06844': 'Dessau'} |
504 | - >>> import zc.sourcefactory.contextual |
505 | - >>> class DemoContextualSource( |
506 | - ... zc.sourcefactory.contextual.BasicContextualSourceFactory): |
507 | - ... def getValues(self, context): |
508 | - ... return context.keys() |
509 | - ... def getTitle(self, context, value): |
510 | - ... return context[value] |
511 | - ... def getToken(self, context, value): |
512 | - ... return 'token-%s' % value |
513 | - >>> source = DemoContextualSource()(zip_to_city) |
514 | - >>> sorted(list(source)) |
515 | - ['06112', '06844'] |
516 | - |
517 | -Let's look at the terms: |
518 | - |
519 | - >>> terms = zope.component.getMultiAdapter( |
520 | - ... (source, request), zope.browser.interfaces.ITerms) |
521 | - >>> terms |
522 | - <zc.sourcefactory.browser.source.FactoredContextualTerms object at 0x...> |
523 | - |
524 | -For each value we get a factored term with the right title from the context: |
525 | - |
526 | - >>> terms.getTerm('06112') |
527 | - <zc.sourcefactory.browser.source.FactoredTerm object at 0x...> |
528 | - >>> terms.getTerm('06112').title |
529 | - 'Halle' |
530 | - >>> terms.getTerm('06844') |
531 | - <zc.sourcefactory.browser.source.FactoredTerm object at 0x...> |
532 | - >>> terms.getTerm('06844').title |
533 | - 'Dessau' |
534 | - >>> terms.getTerm('06844').token |
535 | - 'token-06844' |
536 | - |
537 | -And in reverse we can get the value for a given token as well: |
538 | - |
539 | - >>> terms.getValue('token-06844') |
540 | - '06844' |
541 | - |
542 | -Interfaces |
543 | -========== |
544 | - |
545 | -Both the FactoredSource and FactoredContextualSource have associated |
546 | -interfaces. |
547 | - |
548 | - >>> from zc.sourcefactory import interfaces |
549 | - >>> from zc.sourcefactory import source |
550 | - >>> from zope import interface |
551 | - >>> interface.classImplements( |
552 | - ... source.FactoredSource, interfaces.IFactoredSource) |
553 | - >>> interface.classImplements( |
554 | - ... source.FactoredContextualSource, interfaces.IContextualSource) |
555 | |
556 | === removed file 'src/zc/sourcefactory/browser/__init__.py' |
557 | --- src/zc/sourcefactory/browser/__init__.py 2010-03-01 20:29:16 +0000 |
558 | +++ src/zc/sourcefactory/browser/__init__.py 1970-01-01 00:00:00 +0000 |
559 | @@ -1,1 +0,0 @@ |
560 | -# This directory is a Python package. |
561 | |
562 | === removed file 'src/zc/sourcefactory/browser/configure.zcml' |
563 | --- src/zc/sourcefactory/browser/configure.zcml 2010-03-01 20:29:16 +0000 |
564 | +++ src/zc/sourcefactory/browser/configure.zcml 1970-01-01 00:00:00 +0000 |
565 | @@ -1,18 +0,0 @@ |
566 | -<?xml version="1.0" encoding="utf-8"?> |
567 | -<configure |
568 | - xmlns="http://namespaces.zope.org/zope" |
569 | - xmlns:browser="http://namespaces.zope.org/browser" |
570 | - i18n_domain="zc.sourcefactory"> |
571 | - |
572 | - <adapter factory=".source.FactoredTerms"/> |
573 | - <adapter factory=".source.FactoredContextualTerms"/> |
574 | - |
575 | - <adapter factory=".mapping.MappedTerms"/> |
576 | - |
577 | - <adapter factory=".token.fromString"/> |
578 | - <adapter factory=".token.fromUnicode"/> |
579 | - <adapter factory=".token.fromInteger"/> |
580 | - <adapter factory=".token.fromPersistent"/> |
581 | - <adapter factory=".token.fromInterface"/> |
582 | - |
583 | -</configure> |
584 | |
585 | === removed file 'src/zc/sourcefactory/browser/mapping.py' |
586 | --- src/zc/sourcefactory/browser/mapping.py 2010-03-01 20:29:16 +0000 |
587 | +++ src/zc/sourcefactory/browser/mapping.py 1970-01-01 00:00:00 +0000 |
588 | @@ -1,67 +0,0 @@ |
589 | -############################################################################## |
590 | -# |
591 | -# Copyright (c) 2006-2007 Zope Corporation and Contributors. |
592 | -# All Rights Reserved. |
593 | -# |
594 | -# This software is subject to the provisions of the Zope Public License, |
595 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
596 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
597 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
598 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
599 | -# FOR A PARTICULAR PURPOSE. |
600 | -# |
601 | -############################################################################## |
602 | -"""Mapping-source related terms stuff |
603 | - |
604 | -""" |
605 | -__docformat__ = "reStructuredText" |
606 | - |
607 | - |
608 | -import zope.proxy |
609 | -import zope.interface |
610 | -import zope.component |
611 | -import zope.browser |
612 | -import zope.publisher.interfaces.browser |
613 | - |
614 | -import zc.sourcefactory.mapping |
615 | - |
616 | - |
617 | -class MappedTerms(object): |
618 | - """A terms implementation that knows how to handle a source that was |
619 | - created through a source factory. |
620 | - """ |
621 | - |
622 | - zope.interface.implements(zope.browser.interfaces.ITerms) |
623 | - |
624 | - zope.component.adapts(zc.sourcefactory.mapping.ValueMappingSource, |
625 | - zope.publisher.interfaces.browser.IBrowserRequest) |
626 | - |
627 | - def __init__(self, source, request): |
628 | - self.base = zope.component.getMultiAdapter( |
629 | - [source.base, request], zope.browser.interfaces.ITerms) |
630 | - self.source = source |
631 | - self.request = request |
632 | - |
633 | - def getTerm(self, value): |
634 | - real_value = self.source.mapReverse(value) |
635 | - term = self.base.getTerm(real_value) |
636 | - return MappedTermProxy(value, term) |
637 | - |
638 | - def getValue(self, token): |
639 | - return self.source.map(self.base.getValue(token)) |
640 | - |
641 | - |
642 | -class MappedTermProxy(zope.proxy.ProxyBase): |
643 | - """A mapped term that provides access to the mapped value |
644 | - without destroying the real term. |
645 | - |
646 | - """ |
647 | - |
648 | - __slots__ = ('value',) |
649 | - |
650 | - def __new__(self, value, baseterm): |
651 | - return zope.proxy.ProxyBase.__new__(self, baseterm) |
652 | - |
653 | - def __init__(self, value, baseterm): |
654 | - zope.proxy.ProxyBase.__init__(self, baseterm) |
655 | - self.value = value |
656 | |
657 | === removed file 'src/zc/sourcefactory/browser/source.py' |
658 | --- src/zc/sourcefactory/browser/source.py 2010-03-01 20:29:16 +0000 |
659 | +++ src/zc/sourcefactory/browser/source.py 1970-01-01 00:00:00 +0000 |
660 | @@ -1,83 +0,0 @@ |
661 | -############################################################################## |
662 | -# |
663 | -# Copyright (c) 2006-2007 Zope Corporation and Contributors. |
664 | -# All Rights Reserved. |
665 | -# |
666 | -# This software is subject to the provisions of the Zope Public License, |
667 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
668 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
669 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
670 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
671 | -# FOR A PARTICULAR PURPOSE. |
672 | -# |
673 | -############################################################################## |
674 | -"""Interfaces for zc.z4m. |
675 | - |
676 | -""" |
677 | -__docformat__ = "reStructuredText" |
678 | - |
679 | - |
680 | -import zope.interface |
681 | -import zope.component |
682 | -import zope.browser.interfaces |
683 | -import zope.publisher.interfaces.browser |
684 | -import zope.schema.interfaces |
685 | - |
686 | -import zc.sourcefactory.source |
687 | - |
688 | - |
689 | -class FactoredTerms(object): |
690 | - """A terms implementation that knows how to handle a source that was |
691 | - created through a source factory. |
692 | - """ |
693 | - |
694 | - zope.interface.implements(zope.browser.interfaces.ITerms) |
695 | - |
696 | - zope.component.adapts( |
697 | - zc.sourcefactory.source.FactoredSource, |
698 | - zope.publisher.interfaces.browser.IBrowserRequest) |
699 | - |
700 | - def __init__(self, source, request): |
701 | - self.source = source |
702 | - self.request = request |
703 | - |
704 | - def getTerm(self, value): |
705 | - title = self.source.factory.getTitle(value) |
706 | - token = self.source.factory.getToken(value) |
707 | - return self.source.factory.createTerm( |
708 | - self.source, value, title, token, self.request) |
709 | - |
710 | - def getValue(self, token): |
711 | - return self.source.factory.getValue(self.source, token) |
712 | - |
713 | - |
714 | -class FactoredContextualTerms(FactoredTerms): |
715 | - """A terms implementation that knows how to handle a source that was |
716 | - created through a contextual source factory. |
717 | - """ |
718 | - |
719 | - zope.component.adapts( |
720 | - zc.sourcefactory.source.FactoredContextualSource, |
721 | - zope.publisher.interfaces.browser.IBrowserRequest) |
722 | - |
723 | - def getTerm(self, value): |
724 | - title = self.source.factory.getTitle(self.source.context, value) |
725 | - token = self.source.factory.getToken(self.source.context, value) |
726 | - return self.source.factory.createTerm( |
727 | - self.source.context, self.source, value, title, token, |
728 | - self.request) |
729 | - |
730 | - def getValue(self, token): |
731 | - return self.source.factory.getValue(self.source.context, self.source, |
732 | - token) |
733 | - |
734 | - |
735 | -class FactoredTerm(object): |
736 | - """A title tokenized term.""" |
737 | - |
738 | - zope.interface.implements(zope.schema.interfaces.ITitledTokenizedTerm) |
739 | - |
740 | - def __init__(self, value, title, token): |
741 | - self.value = value |
742 | - self.title = title |
743 | - self.token = token |
744 | |
745 | === removed file 'src/zc/sourcefactory/browser/tests.py' |
746 | --- src/zc/sourcefactory/browser/tests.py 2010-03-01 20:29:16 +0000 |
747 | +++ src/zc/sourcefactory/browser/tests.py 1970-01-01 00:00:00 +0000 |
748 | @@ -1,35 +0,0 @@ |
749 | -############################################################################## |
750 | -# |
751 | -# Copyright (c) 2006-2007 Zope Corporation and Contributors. |
752 | -# All Rights Reserved. |
753 | -# |
754 | -# This software is subject to the provisions of the Zope Public License, |
755 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
756 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
757 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
758 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
759 | -# FOR A PARTICULAR PURPOSE. |
760 | -# |
761 | -############################################################################## |
762 | -"""Unit tests |
763 | - |
764 | -""" |
765 | -__docformat__ = "reStructuredText" |
766 | - |
767 | -import unittest |
768 | - |
769 | -from zope.testing import doctest |
770 | -import zope.app.testing.functional |
771 | - |
772 | -from zc.sourcefactory.tests import SourceFactoryLayer |
773 | - |
774 | -def test_suite(): |
775 | - suite = unittest.TestSuite() |
776 | - token = zope.app.testing.functional.FunctionalDocFileSuite('token.txt') |
777 | - token.layer = SourceFactoryLayer |
778 | - readme = zope.app.testing.functional.FunctionalDocFileSuite( |
779 | - 'README.txt', optionflags=doctest.ELLIPSIS) |
780 | - readme.layer = SourceFactoryLayer |
781 | - suite.addTest(token) |
782 | - suite.addTest(readme) |
783 | - return suite |
784 | |
785 | === removed file 'src/zc/sourcefactory/browser/token.py' |
786 | --- src/zc/sourcefactory/browser/token.py 2010-03-01 20:29:16 +0000 |
787 | +++ src/zc/sourcefactory/browser/token.py 1970-01-01 00:00:00 +0000 |
788 | @@ -1,84 +0,0 @@ |
789 | -############################################################################## |
790 | -# |
791 | -# Copyright (c) 2006-2007 Zope Corporation and Contributors. |
792 | -# All Rights Reserved. |
793 | -# |
794 | -# This software is subject to the provisions of the Zope Public License, |
795 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
796 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
797 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
798 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
799 | -# FOR A PARTICULAR PURPOSE. |
800 | -# |
801 | -############################################################################## |
802 | -"""Various token adapters. |
803 | - |
804 | -""" |
805 | -__docformat__ = "reStructuredText" |
806 | - |
807 | -try: |
808 | - import hashlib |
809 | -except ImportError: |
810 | - import md5 as hashlib # Python 2.4 compat |
811 | - |
812 | -import ZODB.utils |
813 | -import ZODB.interfaces |
814 | -import persistent.interfaces |
815 | - |
816 | -import zope.proxy |
817 | -import zope.component |
818 | -import zope.interface |
819 | - |
820 | -import zc.sourcefactory.interfaces |
821 | - |
822 | - |
823 | -@zope.component.adapter(str) |
824 | -@zope.interface.implementer(zc.sourcefactory.interfaces.IToken) |
825 | -def fromString(value): |
826 | - # We hash generic strings to be sure they are suitable |
827 | - # for URL encoding. |
828 | - return hashlib.md5(value).hexdigest() |
829 | - |
830 | - |
831 | -@zope.component.adapter(unicode) |
832 | -@zope.interface.implementer(zc.sourcefactory.interfaces.IToken) |
833 | -def fromUnicode(value): |
834 | - value = value.encode("utf-8") |
835 | - return fromString(value) |
836 | - |
837 | - |
838 | -@zope.component.adapter(int) |
839 | -@zope.interface.implementer(zc.sourcefactory.interfaces.IToken) |
840 | -def fromInteger(value): |
841 | - # We do not have to hash integers as their string representations |
842 | - # are definitely suitable for URL encoding. |
843 | - return str(value) |
844 | - |
845 | - |
846 | -@zope.component.adapter(persistent.interfaces.IPersistent) |
847 | -@zope.interface.implementer(zc.sourcefactory.interfaces.IToken) |
848 | -def fromPersistent(value): |
849 | - # Persistent objects are identified by their oid. If it is persistent but |
850 | - # not added to the database, we try to get to the parent, add the value to |
851 | - # the database and get the oid then. |
852 | - # We have to remove proxies to avoid security here. |
853 | - value_unproxied = zope.proxy.removeAllProxies(value) |
854 | - try: |
855 | - oid = value_unproxied._p_oid |
856 | - except AttributeError: |
857 | - oid = None |
858 | - |
859 | - if oid is None: |
860 | - if not hasattr(value, '__parent__'): |
861 | - raise ValueError('Can not determine OID for %r' % value) |
862 | - connection = ZODB.interfaces.IConnection(value_unproxied.__parent__) |
863 | - connection.add(value_unproxied) |
864 | - oid = value_unproxied._p_oid |
865 | - return ZODB.utils.oid_repr(oid) |
866 | - |
867 | - |
868 | -@zope.component.adapter(zope.interface.interfaces.IInterface) |
869 | -@zope.interface.implementer(zc.sourcefactory.interfaces.IToken) |
870 | -def fromInterface(value): |
871 | - # Interface are identified by their module path and name |
872 | - return "%s.%s" % (value.__module__, value.__name__) |
873 | |
874 | === removed file 'src/zc/sourcefactory/browser/token.txt' |
875 | --- src/zc/sourcefactory/browser/token.txt 2010-03-01 20:29:16 +0000 |
876 | +++ src/zc/sourcefactory/browser/token.txt 1970-01-01 00:00:00 +0000 |
877 | @@ -1,93 +0,0 @@ |
878 | -====== |
879 | -Tokens |
880 | -====== |
881 | - |
882 | -Tokens are an identifying representation of an object, suitable for |
883 | -transmission amongs URL-encoded data. |
884 | - |
885 | -The sourcefactory package provides a few standard generators for tokens: |
886 | - |
887 | - >>> import zc.sourcefactory.browser.token |
888 | - |
889 | -We have generators for strings: |
890 | - |
891 | - >>> zc.sourcefactory.browser.token.fromString('somestring') |
892 | - '1f129c42de5e4f043cbd88ff6360486f' |
893 | - |
894 | -Unicode |
895 | -======= |
896 | - |
897 | - Argh, I have to write the umlauts as unicode escapes otherwise |
898 | - distutils will have a encoding error in preparing upload to pypi: |
899 | - |
900 | - >>> zc.sourcefactory.browser.token.fromUnicode( |
901 | - ... u'somestring with umlauts \u00F6\u00E4\u00FC') |
902 | - '45dadc304e0d6ae7f4864368bad74951' |
903 | - |
904 | -Integer |
905 | -======= |
906 | - |
907 | - >>> zc.sourcefactory.browser.token.fromInteger(12) |
908 | - '12' |
909 | - |
910 | -Persistent |
911 | -========== |
912 | - |
913 | - >>> import persistent |
914 | - >>> class PersistentDummy(persistent.Persistent): |
915 | - ... pass |
916 | - >>> p = PersistentDummy() |
917 | - >>> p._p_oid = 1234 |
918 | - >>> zc.sourcefactory.browser.token.fromPersistent(p) |
919 | - '1234' |
920 | - |
921 | -If an object is persistent but has not been added to a database yet, it will |
922 | -be added to the database of it's __parent__: |
923 | - |
924 | - >>> root = getRootFolder() |
925 | - >>> p1 = PersistentDummy() |
926 | - >>> p1.__parent__ = root |
927 | - >>> zc.sourcefactory.browser.token.fromPersistent(p1) |
928 | - '0x...' |
929 | - |
930 | -If an object has no parent, we fail: |
931 | - |
932 | - >>> p2 = PersistentDummy() |
933 | - >>> zc.sourcefactory.browser.token.fromPersistent(p2) |
934 | - Traceback (most recent call last): |
935 | - ValueError: Can not determine OID for <PersistentDummy object at 0x...> |
936 | - |
937 | -Security proxied objects are unwrapped to get to their oid or connection |
938 | -attribute: |
939 | - |
940 | - >>> from zope.security.proxy import ProxyFactory |
941 | - >>> p3 = PersistentDummy() |
942 | - >>> root['p3'] = p3 |
943 | - >>> p3.__parent__ = root |
944 | - >>> p3p = ProxyFactory(p3) |
945 | - >>> p3p._p_jar |
946 | - Traceback (most recent call last): |
947 | - ... |
948 | - ForbiddenAttribute: ('_p_jar', <PersistentDummy object at 0x...>) |
949 | - |
950 | - >>> zc.sourcefactory.browser.token.fromPersistent(p3p) |
951 | - '0x...' |
952 | - |
953 | - |
954 | -As a side-effect `p3` now has an _p_oid assigned. When an object already has |
955 | -an OID the connection is not queried, so a __parent__ would not be necessary: |
956 | - |
957 | - >>> del p3.__parent__ |
958 | - >>> zc.sourcefactory.browser.token.fromPersistent(p3p) |
959 | - '0x...' |
960 | - |
961 | - |
962 | - |
963 | -Interfaces |
964 | -========== |
965 | - |
966 | - >>> from zope.interface import Interface |
967 | - >>> class I(Interface): |
968 | - ... pass |
969 | - >>> zc.sourcefactory.browser.token.fromInterface(I) |
970 | - '__builtin__.I' |
971 | |
972 | === removed file 'src/zc/sourcefactory/configure-z2.zcml' |
973 | --- src/zc/sourcefactory/configure-z2.zcml 2010-03-01 20:29:16 +0000 |
974 | +++ src/zc/sourcefactory/configure-z2.zcml 1970-01-01 00:00:00 +0000 |
975 | @@ -1,25 +0,0 @@ |
976 | -<?xml version="1.0" encoding="utf-8"?> |
977 | -<configure |
978 | - xmlns="http://namespaces.zope.org/zope" |
979 | - > |
980 | - <!-- Configuration for usage with Zope 2/Five --> |
981 | - |
982 | - <class class=".source.FactoredSource"> |
983 | - <require |
984 | - interface=".interfaces.IFactoredSource" |
985 | - permission="zope2.View" |
986 | - /> |
987 | - </class> |
988 | - |
989 | - <class class=".source.FactoredContextualSource"> |
990 | - <require |
991 | - interface=".interfaces.IContextualSource" |
992 | - permission="zope2.View" |
993 | - /> |
994 | - </class> |
995 | - |
996 | - <adapter factory=".adapters.getSourceQueriables"/> |
997 | - |
998 | - <include package=".browser"/> |
999 | - |
1000 | -</configure> |
1001 | |
1002 | === removed file 'src/zc/sourcefactory/configure.zcml' |
1003 | --- src/zc/sourcefactory/configure.zcml 2010-03-01 20:29:16 +0000 |
1004 | +++ src/zc/sourcefactory/configure.zcml 1970-01-01 00:00:00 +0000 |
1005 | @@ -1,24 +0,0 @@ |
1006 | -<?xml version="1.0" encoding="utf-8"?> |
1007 | -<configure |
1008 | - xmlns="http://namespaces.zope.org/zope" |
1009 | - > |
1010 | - |
1011 | - <class class=".source.FactoredSource"> |
1012 | - <require |
1013 | - interface=".interfaces.IFactoredSource" |
1014 | - permission="zope.View" |
1015 | - /> |
1016 | - </class> |
1017 | - |
1018 | - <class class=".source.FactoredContextualSource"> |
1019 | - <require |
1020 | - interface=".interfaces.IContextualSource" |
1021 | - permission="zope.View" |
1022 | - /> |
1023 | - </class> |
1024 | - |
1025 | - <adapter factory=".adapters.getSourceQueriables"/> |
1026 | - |
1027 | - <include package=".browser"/> |
1028 | - |
1029 | -</configure> |
1030 | |
1031 | === removed file 'src/zc/sourcefactory/constructors.txt' |
1032 | --- src/zc/sourcefactory/constructors.txt 2010-03-01 20:29:16 +0000 |
1033 | +++ src/zc/sourcefactory/constructors.txt 1970-01-01 00:00:00 +0000 |
1034 | @@ -1,46 +0,0 @@ |
1035 | -=================== |
1036 | -Custom constructors |
1037 | -=================== |
1038 | - |
1039 | -Source factories are intended to behave as natural as possible. A side-effect |
1040 | -of using a custom factory method (__new__) on the base class is that |
1041 | -sub-classes may have a hard time if their constructor (__init__) has a |
1042 | -different signature. |
1043 | - |
1044 | -zc.sourcefactory takes extra measures to allow using a custom constructor with |
1045 | -a different signature. |
1046 | - |
1047 | ->>> import zc.sourcefactory.basic |
1048 | - |
1049 | ->>> class Source(zc.sourcefactory.basic.BasicSourceFactory): |
1050 | -... |
1051 | -... def __init__(self, values): |
1052 | -... super(Source, self).__init__() |
1053 | -... self.values = values |
1054 | -... |
1055 | -... def getValues(self): |
1056 | -... return self.values |
1057 | - |
1058 | ->>> source = Source([1, 2, 3]) |
1059 | ->>> list(source) |
1060 | -[1, 2, 3] |
1061 | - |
1062 | -This is also true for contextual sources. The example is a bit silly |
1063 | -but it shows that it works in principal: |
1064 | - |
1065 | ->>> import zc.sourcefactory.contextual |
1066 | ->>> default_values = (4, 5, 6) |
1067 | ->>> context_values = (6, 7, 8) |
1068 | ->>> class ContextualSource( |
1069 | -... zc.sourcefactory.contextual.BasicContextualSourceFactory): |
1070 | -... |
1071 | -... def __init__(self, defaults): |
1072 | -... super(ContextualSource, self).__init__() |
1073 | -... self.defaults = defaults |
1074 | -... |
1075 | -... def getValues(self, context): |
1076 | -... return self.defaults + context |
1077 | - |
1078 | ->>> contextual_source = ContextualSource(default_values)(context_values) |
1079 | ->>> list(contextual_source) |
1080 | -[4, 5, 6, 6, 7, 8] |
1081 | |
1082 | === removed file 'src/zc/sourcefactory/contextual.py' |
1083 | --- src/zc/sourcefactory/contextual.py 2010-03-01 20:29:16 +0000 |
1084 | +++ src/zc/sourcefactory/contextual.py 1970-01-01 00:00:00 +0000 |
1085 | @@ -1,27 +0,0 @@ |
1086 | -############################################################################## |
1087 | -# |
1088 | -# Copyright (c) 2006-2007 Zope Corporation and Contributors. |
1089 | -# All Rights Reserved. |
1090 | -# |
1091 | -# This software is subject to the provisions of the Zope Public License, |
1092 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
1093 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
1094 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
1095 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
1096 | -# FOR A PARTICULAR PURPOSE. |
1097 | -# |
1098 | -############################################################################## |
1099 | -"""The most basic source factory that supports context binding. |
1100 | - |
1101 | -""" |
1102 | -__docformat__ = "reStructuredText" |
1103 | - |
1104 | - |
1105 | -import zc.sourcefactory.factories |
1106 | -import zc.sourcefactory.policies |
1107 | - |
1108 | - |
1109 | -class BasicContextualSourceFactory( |
1110 | - zc.sourcefactory.factories.ContextualSourceFactory, |
1111 | - zc.sourcefactory.policies.BasicContextualSourcePolicy): |
1112 | - """Abstract base implementation for a basic contextual source factory.""" |
1113 | |
1114 | === removed file 'src/zc/sourcefactory/factories.py' |
1115 | --- src/zc/sourcefactory/factories.py 2010-03-01 20:29:16 +0000 |
1116 | +++ src/zc/sourcefactory/factories.py 1970-01-01 00:00:00 +0000 |
1117 | @@ -1,67 +0,0 @@ |
1118 | -############################################################################## |
1119 | -# |
1120 | -# Copyright (c) 2006-2007 Zope Corporation and Contributors. |
1121 | -# All Rights Reserved. |
1122 | -# |
1123 | -# This software is subject to the provisions of the Zope Public License, |
1124 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
1125 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
1126 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
1127 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
1128 | -# FOR A PARTICULAR PURPOSE. |
1129 | -# |
1130 | -############################################################################## |
1131 | -"""Basic factories. |
1132 | - |
1133 | -""" |
1134 | -__docformat__ = "reStructuredText" |
1135 | - |
1136 | - |
1137 | -import zope.interface |
1138 | -import zope.schema.interfaces |
1139 | - |
1140 | -import zc.sourcefactory.interfaces |
1141 | -import zc.sourcefactory.source |
1142 | - |
1143 | - |
1144 | -class BasicSourceFactory(object): |
1145 | - """Abstract base class for a source factory. |
1146 | - |
1147 | - Implementors must provide an implementation for `getValues`. |
1148 | - """ |
1149 | - |
1150 | - zope.interface.implements(zc.sourcefactory.interfaces.ISourceFactory) |
1151 | - |
1152 | - def __new__(cls, *args, **kw): |
1153 | - """Create the factory object and return source.""" |
1154 | - factory = object.__new__(cls) |
1155 | - factory.__init__(*args, **kw) |
1156 | - return zc.sourcefactory.source.FactoredSource(factory) |
1157 | - |
1158 | - |
1159 | -class ContextualSourceFactory(BasicSourceFactory): |
1160 | - """Abstract base class for a source factory for a context-bound source. |
1161 | - |
1162 | - Implementors must provide an implementation for `getValues`. |
1163 | - """ |
1164 | - |
1165 | - source_class = zc.sourcefactory.source.FactoredContextualSource |
1166 | - |
1167 | - def __new__(cls, *args, **kw): |
1168 | - """Create the factory object and return source.""" |
1169 | - factory = object.__new__(cls) |
1170 | - factory.__init__(*args, **kw) |
1171 | - return FactoredContextualSourceBinder(factory, cls.source_class) |
1172 | - |
1173 | - |
1174 | -class FactoredContextualSourceBinder(object): |
1175 | - """A context source binder for factored sources.""" |
1176 | - |
1177 | - zope.interface.implements(zope.schema.interfaces.IContextSourceBinder) |
1178 | - |
1179 | - def __init__(self, factory, source_class): |
1180 | - self.factory = factory |
1181 | - self.source_class = source_class |
1182 | - |
1183 | - def __call__(self, context, *args, **kwargs): |
1184 | - return self.source_class(self.factory, context, *args, **kwargs) |
1185 | |
1186 | === removed file 'src/zc/sourcefactory/ftesting.zcml' |
1187 | --- src/zc/sourcefactory/ftesting.zcml 2010-03-01 20:29:16 +0000 |
1188 | +++ src/zc/sourcefactory/ftesting.zcml 1970-01-01 00:00:00 +0000 |
1189 | @@ -1,10 +0,0 @@ |
1190 | -<configure |
1191 | - xmlns="http://namespaces.zope.org/zope" |
1192 | - xmlns:browser="http://namespaces.zope.org/browser" |
1193 | - > |
1194 | - |
1195 | - <include package="zope.app.zcmlfiles" /> |
1196 | - <include package="zope.app.keyreference" /> |
1197 | - <include package="zc.sourcefactory" /> |
1198 | - |
1199 | -</configure> |
1200 | |
1201 | === removed file 'src/zc/sourcefactory/interfaces.py' |
1202 | --- src/zc/sourcefactory/interfaces.py 2010-03-01 20:29:16 +0000 |
1203 | +++ src/zc/sourcefactory/interfaces.py 1970-01-01 00:00:00 +0000 |
1204 | @@ -1,142 +0,0 @@ |
1205 | -############################################################################## |
1206 | -# |
1207 | -# Copyright (c) 2006-2007 Zope Corporation and Contributors. |
1208 | -# All Rights Reserved. |
1209 | -# |
1210 | -# This software is subject to the provisions of the Zope Public License, |
1211 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
1212 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
1213 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
1214 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
1215 | -# FOR A PARTICULAR PURPOSE. |
1216 | -# |
1217 | -############################################################################## |
1218 | -"""Interfaces for zc.sourcefactory. |
1219 | - |
1220 | -""" |
1221 | -__docformat__ = "reStructuredText" |
1222 | - |
1223 | - |
1224 | -import zope.interface |
1225 | -import zope.schema.interfaces |
1226 | - |
1227 | -class ISourceFactory(zope.interface.Interface): |
1228 | - |
1229 | - def __call__(): |
1230 | - """Create and return the source or source binder.""" |
1231 | - |
1232 | - |
1233 | -class IFactoredSource(zope.schema.interfaces.IIterableSource): |
1234 | - """An iterable source that was created from a source factory.""" |
1235 | - |
1236 | - factory = zope.interface.Attribute("The source factory.") |
1237 | - |
1238 | - |
1239 | -class IContextualSource(IFactoredSource): |
1240 | - """A source operating in context.""" |
1241 | - |
1242 | - context = zope.interface.Attribute("The context the source is bound to.") |
1243 | - factory = zope.interface.Attribute("The source factory.") |
1244 | - |
1245 | - |
1246 | -class INamedSource(zope.interface.Interface): |
1247 | - """A marker interface to register named source for.""" |
1248 | - |
1249 | - |
1250 | -class IToken(zope.interface.Interface): |
1251 | - """A string representing a token that uniquely identifies a value.""" |
1252 | - |
1253 | - |
1254 | -# Policies |
1255 | - |
1256 | -class ITokenPolicy(zope.interface.Interface): |
1257 | - """The token policy maps values and tokens.""" |
1258 | - |
1259 | - def getValue(source, token): |
1260 | - """Return a token for the value.""" |
1261 | - |
1262 | - def getToken(value): |
1263 | - """Return a token for the value.""" |
1264 | - |
1265 | - |
1266 | -class IContextualTokenPolicy(zope.interface.Interface): |
1267 | - """The contextua token policy maps values and tokens. |
1268 | - |
1269 | - It allows access to the context. |
1270 | - |
1271 | - """ |
1272 | - |
1273 | - def getValue(context, source, token): |
1274 | - """Return a token for the value.""" |
1275 | - |
1276 | - def getToken(context, value): |
1277 | - """Return a token for the value.""" |
1278 | - |
1279 | - |
1280 | -class ITermPolicy(zope.interface.Interface): |
1281 | - """The term policy creates terms and provides data for terms.""" |
1282 | - |
1283 | - def createTerm(source, value, title, token, request): |
1284 | - """Create and return a term object.""" |
1285 | - |
1286 | - def getTitle(value): |
1287 | - """Return a title for the value. |
1288 | - |
1289 | - The return value should not be localized; that is the |
1290 | - responsibility of the user. The title may be an |
1291 | - internationalized message value. |
1292 | - |
1293 | - """ |
1294 | - |
1295 | - |
1296 | -class IContextualTermPolicy(zope.interface.Interface): |
1297 | - """The contextual term policy creates terms and provides data for terms. |
1298 | - |
1299 | - It allows access to the context. |
1300 | - |
1301 | - """ |
1302 | - |
1303 | - def createTerm(context, source, value, title, token, request): |
1304 | - """Create and return a term object.""" |
1305 | - |
1306 | - def getTitle(context, value): |
1307 | - """Return a title for the value. |
1308 | - |
1309 | - The return value should not be localized; that is the |
1310 | - responsibility of the user. The title may be an |
1311 | - internationalized message value. |
1312 | - |
1313 | - """ |
1314 | - |
1315 | - |
1316 | -class IValuePolicy(zope.interface.Interface): |
1317 | - """The value policy retrieves and filters values for a source.""" |
1318 | - |
1319 | - def getValues(): |
1320 | - """Return the values for the source.""" |
1321 | - |
1322 | - def filterValue(value): |
1323 | - """Determine whether the value should be filtered out or not.""" |
1324 | - |
1325 | - |
1326 | -class IContextualValuePolicy(zope.interface.Interface): |
1327 | - """The contextual value policy retrieves and filters values for a source |
1328 | - within context. |
1329 | - |
1330 | - """ |
1331 | - |
1332 | - def getValues(context): |
1333 | - """Return the values for the source in the given context.""" |
1334 | - |
1335 | - def filterValue(context, value): |
1336 | - """Return the values for the source in the given context.""" |
1337 | - |
1338 | -# Standard combined policies |
1339 | - |
1340 | -class ISourcePolicy(ITokenPolicy, ITermPolicy, IValuePolicy): |
1341 | - pass |
1342 | - |
1343 | - |
1344 | -class IContextualSourcePolicy( |
1345 | - ITokenPolicy, IContextualTermPolicy, IContextualValuePolicy): |
1346 | - pass |
1347 | |
1348 | === removed file 'src/zc/sourcefactory/mapping.py' |
1349 | --- src/zc/sourcefactory/mapping.py 2010-03-01 20:29:16 +0000 |
1350 | +++ src/zc/sourcefactory/mapping.py 1970-01-01 00:00:00 +0000 |
1351 | @@ -1,78 +0,0 @@ |
1352 | -############################################################################## |
1353 | -# |
1354 | -# Copyright (c) 2006-2007 Zope Corporation and Contributors. |
1355 | -# All Rights Reserved. |
1356 | -# |
1357 | -# This software is subject to the provisions of the Zope Public License, |
1358 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
1359 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
1360 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
1361 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
1362 | -# FOR A PARTICULAR PURPOSE. |
1363 | -# |
1364 | -############################################################################## |
1365 | -"""A source proxy providing a mapping between values |
1366 | - |
1367 | -""" |
1368 | -__docformat__ = "reStructuredText" |
1369 | - |
1370 | -import zope.interface |
1371 | -import zope.schema.interfaces |
1372 | - |
1373 | - |
1374 | -class ValueMappingSourceContextBinder(object): |
1375 | - |
1376 | - zope.interface.implements(zope.schema.interfaces.IContextSourceBinder) |
1377 | - |
1378 | - def __init__(self, base, map): |
1379 | - self.base = base |
1380 | - self.map = map |
1381 | - |
1382 | - def __call__(self, context): |
1383 | - source = self.base(context) |
1384 | - return ValueMappingSource(source, self.map) |
1385 | - |
1386 | - |
1387 | -class ValueMappingSource(object): |
1388 | - |
1389 | - zope.interface.implements(zope.schema.interfaces.IIterableSource) |
1390 | - |
1391 | - def __init__(self, base, map): |
1392 | - self.base = base |
1393 | - self._mapping_cache = {} |
1394 | - self.map = map |
1395 | - |
1396 | - def mapReverse(self, mapped_value): |
1397 | - if mapped_value in self._mapping_cache: |
1398 | - return self._mapping_cache[mapped_value] |
1399 | - |
1400 | - # Not found in cache, continue to look for the mapped value in |
1401 | - # the rest of the iterator |
1402 | - if not hasattr(self, '_cache_iterator'): |
1403 | - self._cache_iterator = iter(self.base) |
1404 | - for original_value in self._cache_iterator: |
1405 | - original_mapped_value = self.map(original_value) |
1406 | - self._mapping_cache[original_mapped_value] = original_value |
1407 | - if mapped_value == original_mapped_value: |
1408 | - return original_value |
1409 | - raise KeyError(mapped_value) |
1410 | - |
1411 | - def __contains__(self, value): |
1412 | - try: |
1413 | - self.mapReverse(value) |
1414 | - except KeyError: |
1415 | - return False |
1416 | - else: |
1417 | - return True |
1418 | - |
1419 | - def __iter__(self): |
1420 | - for item in self.base: |
1421 | - yield self.map(item) |
1422 | - |
1423 | - def __len__(self): |
1424 | - return len(self.base) |
1425 | - |
1426 | - def __nonzero__(self): |
1427 | - for dummy in self.base: |
1428 | - return True |
1429 | - return False |
1430 | |
1431 | === removed file 'src/zc/sourcefactory/mapping.txt' |
1432 | --- src/zc/sourcefactory/mapping.txt 2010-03-01 20:29:16 +0000 |
1433 | +++ src/zc/sourcefactory/mapping.txt 1970-01-01 00:00:00 +0000 |
1434 | @@ -1,68 +0,0 @@ |
1435 | -Mapping source values |
1436 | -===================== |
1437 | - |
1438 | -Sometimes a source provides the right choice of objects, but the actual values |
1439 | -we want to talk about are properties or computed views on those objects. The |
1440 | -`mapping proxy source` helps us to map a source to a different value space. |
1441 | - |
1442 | -We start out with a source: |
1443 | - |
1444 | - >>> source = [1,2,3,4,5] |
1445 | - |
1446 | -and we provide a method that maps the values of the original source to the |
1447 | -values we want to see (we map the numbers to the characters in the english |
1448 | -alphabet): |
1449 | - |
1450 | - >>> map = lambda x: chr(x+96) |
1451 | - |
1452 | -Now we can create a mapped source: |
1453 | - |
1454 | - >>> from zc.sourcefactory.mapping import ValueMappingSource |
1455 | - >>> mapped_source = ValueMappingSource(source, map) |
1456 | - >>> list(mapped_source) |
1457 | - ['a', 'b', 'c', 'd', 'e'] |
1458 | - >>> len(mapped_source) |
1459 | - 5 |
1460 | - >>> 'a' in mapped_source |
1461 | - True |
1462 | - >>> 1 in mapped_source |
1463 | - False |
1464 | - |
1465 | -You can also use context-dependent sources: |
1466 | - |
1467 | - >>> def bindSource(context): |
1468 | - ... return [1,2,3,4,5] |
1469 | - >>> from zc.sourcefactory.mapping import ValueMappingSourceContextBinder |
1470 | - >>> binder = ValueMappingSourceContextBinder(bindSource, map) |
1471 | - >>> bound_source = binder(object()) |
1472 | - >>> list(bound_source) |
1473 | - ['a', 'b', 'c', 'd', 'e'] |
1474 | - >>> len(bound_source) |
1475 | - 5 |
1476 | - >>> 'a' in bound_source |
1477 | - True |
1478 | - >>> 1 in bound_source |
1479 | - False |
1480 | - |
1481 | - |
1482 | -Scaling |
1483 | -------- |
1484 | - |
1485 | -Sometimes the number of items available through a source is very large. So |
1486 | -large that you only want to access them if absolutely neccesary. One such |
1487 | -occasion is with truth-testing a source. By default Python will call |
1488 | -__nonzero__ to get the boolean value of an object, but if that isn't available |
1489 | -__len__ is called to see what it returns. That might be very expensive, so we |
1490 | -want to make sure it isn't called. |
1491 | - |
1492 | - >>> class ExpensiveSource(object): |
1493 | - ... def __len__(self): |
1494 | - ... raise RuntimeError("oops, don't want to call __len__") |
1495 | - ... |
1496 | - ... def __iter__(self): |
1497 | - ... return iter(xrange(999999)) |
1498 | - |
1499 | - >>> expensive_source = ExpensiveSource() |
1500 | - >>> mapped_source = ValueMappingSource(expensive_source, map) |
1501 | - >>> bool(mapped_source) |
1502 | - True |
1503 | |
1504 | === removed file 'src/zc/sourcefactory/named.py' |
1505 | --- src/zc/sourcefactory/named.py 2010-03-01 20:29:16 +0000 |
1506 | +++ src/zc/sourcefactory/named.py 1970-01-01 00:00:00 +0000 |
1507 | @@ -1,42 +0,0 @@ |
1508 | -############################################################################## |
1509 | -# |
1510 | -# Copyright (c) 2006-2007 Zope Corporation and Contributors. |
1511 | -# All Rights Reserved. |
1512 | -# |
1513 | -# This software is subject to the provisions of the Zope Public License, |
1514 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
1515 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
1516 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
1517 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
1518 | -# FOR A PARTICULAR PURPOSE. |
1519 | -# |
1520 | -############################################################################## |
1521 | -"""Named source binder |
1522 | - |
1523 | -""" |
1524 | -__docformat__ = "reStructuredText" |
1525 | - |
1526 | -import zope.interface |
1527 | -import zope.schema.interfaces |
1528 | - |
1529 | -import zc.sourcefactory.interfaces |
1530 | - |
1531 | - |
1532 | -class NamedSource(object): |
1533 | - """Factory for named sources. |
1534 | - |
1535 | - This is a generic thin wrapper to look up sources by name. |
1536 | - """ |
1537 | - |
1538 | - zope.interface.implements(zope.schema.interfaces.IContextSourceBinder) |
1539 | - |
1540 | - def __init__(self, name): |
1541 | - self.name = name |
1542 | - |
1543 | - def __call__(self, context): |
1544 | - factory = zope.component.getUtility( |
1545 | - zc.sourcefactory.interfaces.INamedSource, name=self.name) |
1546 | - source = factory() |
1547 | - if zope.schema.interfaces.IContextSourceBinder.providedBy(source): |
1548 | - source = source(context) |
1549 | - return source |
1550 | |
1551 | === removed file 'src/zc/sourcefactory/policies.py' |
1552 | --- src/zc/sourcefactory/policies.py 2010-03-01 20:29:16 +0000 |
1553 | +++ src/zc/sourcefactory/policies.py 1970-01-01 00:00:00 +0000 |
1554 | @@ -1,186 +0,0 @@ |
1555 | -############################################################################## |
1556 | -# |
1557 | -# Copyright (c) 2006-2007 Zope Corporation and Contributors. |
1558 | -# All Rights Reserved. |
1559 | -# |
1560 | -# This software is subject to the provisions of the Zope Public License, |
1561 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
1562 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
1563 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
1564 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
1565 | -# FOR A PARTICULAR PURPOSE. |
1566 | -# |
1567 | -############################################################################## |
1568 | -"""Implementations of the basic policy components. |
1569 | - |
1570 | -""" |
1571 | -__docformat__ = "reStructuredText" |
1572 | - |
1573 | - |
1574 | -from zope.dublincore import interfaces as dublincoreinterfaces |
1575 | -import zc.sourcefactory.browser.source |
1576 | -import zc.sourcefactory.interfaces |
1577 | -import zope.component |
1578 | -import zope.intid.interfaces |
1579 | - |
1580 | -# Term policies |
1581 | - |
1582 | -class BasicTermPolicy(object): |
1583 | - """A basic term policy. |
1584 | - |
1585 | - createTerm creates a FactoredTerm object. |
1586 | - |
1587 | - getTitle uses IDCDescriptiveProperties.title and falls back to |
1588 | - `str`-representation of the value. |
1589 | - """ |
1590 | - |
1591 | - zope.interface.implements(zc.sourcefactory.interfaces.ITermPolicy) |
1592 | - |
1593 | - def createTerm(self, source, value, title, token, request): |
1594 | - return zc.sourcefactory.browser.source.FactoredTerm( |
1595 | - value, title, token) |
1596 | - |
1597 | - def getTitle(self, value): |
1598 | - try: |
1599 | - md = dublincoreinterfaces.IDCDescriptiveProperties(value) |
1600 | - except TypeError: |
1601 | - md = None |
1602 | - |
1603 | - if md: |
1604 | - title = md.title |
1605 | - else: |
1606 | - title = unicode(value) |
1607 | - return title |
1608 | - |
1609 | - |
1610 | -class BasicContextualTermPolicy(BasicTermPolicy): |
1611 | - """A basic contextual term policy. |
1612 | - |
1613 | - All methods are deferred to the BasicTermPolicy by removing the context |
1614 | - argument. |
1615 | - |
1616 | - """ |
1617 | - |
1618 | - zope.interface.implements(zc.sourcefactory.interfaces.ITermPolicy) |
1619 | - |
1620 | - def createTerm(self, context, source, value, title, token, request): |
1621 | - return super(BasicContextualTermPolicy, self).createTerm( |
1622 | - source, value, title, token, request) |
1623 | - |
1624 | - def getTitle(self, context, value): |
1625 | - return super(BasicContextualTermPolicy, self).getTitle(value) |
1626 | - |
1627 | - |
1628 | -# Token policies |
1629 | - |
1630 | -class BasicTokenPolicy(object): |
1631 | - """A basic token policy. |
1632 | - |
1633 | - getToken adapts the value to IToken |
1634 | - |
1635 | - getValue iterates over the source comparing the tokens of the values to the |
1636 | - token. |
1637 | - """ |
1638 | - |
1639 | - zope.interface.implements(zc.sourcefactory.interfaces.ITokenPolicy) |
1640 | - |
1641 | - def getValue(self, source, token): |
1642 | - for value in source: |
1643 | - if source.factory.getToken(value) == token: |
1644 | - return value |
1645 | - raise KeyError, "No value with token '%s'" % token |
1646 | - |
1647 | - def getToken(self, value): |
1648 | - return zc.sourcefactory.interfaces.IToken(value) |
1649 | - |
1650 | - |
1651 | -class BasicContextualTokenPolicy(BasicTokenPolicy): |
1652 | - """A basic contextual token policy. |
1653 | - |
1654 | - This implements a fallback to the context-free token policy but satisfies |
1655 | - the contextual interfaces. |
1656 | - |
1657 | - """ |
1658 | - |
1659 | - zope.interface.implements(zc.sourcefactory.interfaces.IContextualTokenPolicy) |
1660 | - |
1661 | - def getValue(self, context, source, token): |
1662 | - for value in source: |
1663 | - if source.factory.getToken(context, value) == token: |
1664 | - return value |
1665 | - raise KeyError, "No value with token '%s'" % token |
1666 | - |
1667 | - def getToken(self, context, value): |
1668 | - return super(BasicContextualTokenPolicy, self).getToken(value) |
1669 | - |
1670 | - |
1671 | -class IntIdTokenPolicy(object): |
1672 | - """A token policy based on intids.""" |
1673 | - |
1674 | - zope.interface.implements(zc.sourcefactory.interfaces.ITokenPolicy) |
1675 | - |
1676 | - def getValue(self, source, token): |
1677 | - iid = int(token) |
1678 | - value = self.intids.getObject(iid) |
1679 | - if value in self.source: |
1680 | - return value |
1681 | - else: |
1682 | - raise LookupError("no value matching token: %r" % token) |
1683 | - |
1684 | - def getToken(self, value): |
1685 | - return str(self.intids.getId(value)) |
1686 | - |
1687 | - # We can't use zope.cachedescriptors.property.Lazy for this since |
1688 | - # the source factory exists across the entire process, and is used |
1689 | - # across different requests. Using Lazy for this would result in |
1690 | - # the wrong ZODB connection being used in most threads. |
1691 | - # |
1692 | - @property |
1693 | - def intids(self): |
1694 | - return zope.component.getUtility( |
1695 | - zope.intid.interfaces.IIntIds) |
1696 | - |
1697 | - |
1698 | -# Value policies |
1699 | - |
1700 | -class BasicValuePolicy(object): |
1701 | - """An abstract basic value policy. |
1702 | - |
1703 | - `getValues()` is not implemented. |
1704 | - |
1705 | - The filter allows all values. |
1706 | - """ |
1707 | - |
1708 | - zope.interface.implements(zc.sourcefactory.interfaces.IValuePolicy) |
1709 | - |
1710 | - def filterValue(self, value): |
1711 | - return True |
1712 | - |
1713 | -class BasicContextualValuePolicy(BasicValuePolicy): |
1714 | - """An abstract basic value policy. |
1715 | - |
1716 | - `getValues()` is not implemented. |
1717 | - |
1718 | - The filter allows all values. |
1719 | - """ |
1720 | - |
1721 | - zope.interface.implements( |
1722 | - zc.sourcefactory.interfaces.IContextualValuePolicy) |
1723 | - |
1724 | - def filterValue(self, context, value): |
1725 | - return True |
1726 | - |
1727 | - |
1728 | -# Standard combined policies |
1729 | - |
1730 | -class BasicSourcePolicy(BasicValuePolicy, BasicTokenPolicy, BasicTermPolicy): |
1731 | - pass |
1732 | - |
1733 | - |
1734 | -class BasicContextualSourcePolicy( |
1735 | - BasicContextualValuePolicy, BasicContextualTokenPolicy, BasicContextualTermPolicy): |
1736 | - pass |
1737 | - |
1738 | - |
1739 | -class IntIdSourcePolicy(BasicValuePolicy, IntIdTokenPolicy, BasicTermPolicy): |
1740 | - pass |
1741 | |
1742 | === removed file 'src/zc/sourcefactory/source.py' |
1743 | --- src/zc/sourcefactory/source.py 2010-03-01 20:29:16 +0000 |
1744 | +++ src/zc/sourcefactory/source.py 1970-01-01 00:00:00 +0000 |
1745 | @@ -1,76 +0,0 @@ |
1746 | -############################################################################## |
1747 | -# |
1748 | -# Copyright (c) 2006-2007 Zope Corporation and Contributors. |
1749 | -# All Rights Reserved. |
1750 | -# |
1751 | -# This software is subject to the provisions of the Zope Public License, |
1752 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
1753 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
1754 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
1755 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
1756 | -# FOR A PARTICULAR PURPOSE. |
1757 | -# |
1758 | -############################################################################## |
1759 | -"""Source that uses the policies from the source factory. |
1760 | - |
1761 | -""" |
1762 | -__docformat__ = "reStructuredText" |
1763 | - |
1764 | - |
1765 | -import zope.interface |
1766 | -import zope.schema.interfaces |
1767 | - |
1768 | -import zc.sourcefactory.interfaces |
1769 | - |
1770 | - |
1771 | -class FactoredSource(object): |
1772 | - """An iterable source that was created from a source factory.""" |
1773 | - |
1774 | - zope.interface.implements(zc.sourcefactory.interfaces.IFactoredSource) |
1775 | - |
1776 | - factory = None |
1777 | - |
1778 | - def __init__(self, factory): |
1779 | - self.factory = factory |
1780 | - |
1781 | - def __iter__(self): |
1782 | - return self._get_filtered_values() |
1783 | - |
1784 | - def __len__(self): |
1785 | - # This is potentially expensive! |
1786 | - return len(list(self._get_filtered_values())) |
1787 | - |
1788 | - def __nonzero__(self): |
1789 | - for dummy in self._get_filtered_values(): |
1790 | - return True |
1791 | - return False |
1792 | - |
1793 | - def __contains__(self, value): |
1794 | - # This is potentially expensive! |
1795 | - return value in self._get_filtered_values() |
1796 | - |
1797 | - def _get_filtered_values(self): |
1798 | - for value in self.factory.getValues(): |
1799 | - if not self.factory.filterValue(value): |
1800 | - continue |
1801 | - yield value |
1802 | - |
1803 | - |
1804 | -class FactoredContextualSource(FactoredSource): |
1805 | - """An iterable context-aware source that was created from a source factory. |
1806 | - """ |
1807 | - |
1808 | - zope.interface.implements(zc.sourcefactory.interfaces.IContextualSource) |
1809 | - |
1810 | - context = None |
1811 | - |
1812 | - def __init__(self, factory, context): |
1813 | - self.factory = factory |
1814 | - self.context = context |
1815 | - self.__parent__ = context |
1816 | - |
1817 | - def _get_filtered_values(self): |
1818 | - for value in self.factory.getValues(self.context): |
1819 | - if not self.factory.filterValue(self.context, value): |
1820 | - continue |
1821 | - yield value |
1822 | |
1823 | === removed file 'src/zc/sourcefactory/tests.py' |
1824 | --- src/zc/sourcefactory/tests.py 2010-03-01 20:29:16 +0000 |
1825 | +++ src/zc/sourcefactory/tests.py 1970-01-01 00:00:00 +0000 |
1826 | @@ -1,41 +0,0 @@ |
1827 | -############################################################################## |
1828 | -# |
1829 | -# Copyright (c) 2006 Zope Corporation. All Rights Reserved. |
1830 | -# |
1831 | -# This software is subject to the provisions of the Zope Visible Source |
1832 | -# License, Version 1.0 (ZVSL). A copy of the ZVSL should accompany this |
1833 | -# distribution. |
1834 | -# |
1835 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
1836 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
1837 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
1838 | -# FOR A PARTICULAR PURPOSE. |
1839 | -# |
1840 | -############################################################################## |
1841 | -"""Unit tests |
1842 | - |
1843 | -""" |
1844 | -__docformat__ = "reStructuredText" |
1845 | - |
1846 | -import os.path |
1847 | -import unittest |
1848 | - |
1849 | -from zope.testing import doctest |
1850 | -import zope.app.testing.functional |
1851 | -from zope.app.testing.functional import FunctionalDocFileSuite |
1852 | - |
1853 | -here = os.path.realpath(os.path.dirname(__file__)) |
1854 | - |
1855 | -SourceFactoryLayer = zope.app.testing.functional.ZCMLLayer( |
1856 | - os.path.join(here, "ftesting.zcml"), __name__, "SourceFactoryLayer") |
1857 | - |
1858 | - |
1859 | -def test_suite(): |
1860 | - suite = unittest.TestSuite() |
1861 | - suite.addTest(doctest.DocFileSuite('README.txt')) |
1862 | - suite.addTest(doctest.DocFileSuite('mapping.txt')) |
1863 | - suite.addTest(doctest.DocFileSuite('constructors.txt')) |
1864 | - adapters = FunctionalDocFileSuite('adapters.txt') |
1865 | - adapters.layer = SourceFactoryLayer |
1866 | - suite.addTest(adapters) |
1867 | - return suite |
1868 | |
1869 | === removed directory 'src/zodbcode' |
1870 | === removed file 'src/zodbcode/DEPENDENCIES.cfg' |
1871 | --- src/zodbcode/DEPENDENCIES.cfg 2009-04-23 15:12:18 +0000 |
1872 | +++ src/zodbcode/DEPENDENCIES.cfg 1970-01-01 00:00:00 +0000 |
1873 | @@ -1,5 +0,0 @@ |
1874 | -persistent |
1875 | -transaction |
1876 | -zope.interface |
1877 | -# ZODB.utils and ZODB.tests.utils are used by the tests |
1878 | -ZODB |
1879 | |
1880 | === removed file 'src/zodbcode/__init__.py' |
1881 | --- src/zodbcode/__init__.py 2009-04-23 15:12:18 +0000 |
1882 | +++ src/zodbcode/__init__.py 1970-01-01 00:00:00 +0000 |
1883 | @@ -1,2 +0,0 @@ |
1884 | -# |
1885 | -# This file is necessary to make this directory a package. |
1886 | |
1887 | === removed file 'src/zodbcode/class_.py' |
1888 | --- src/zodbcode/class_.py 2009-04-23 15:12:18 +0000 |
1889 | +++ src/zodbcode/class_.py 1970-01-01 00:00:00 +0000 |
1890 | @@ -1,436 +0,0 @@ |
1891 | -############################################################################## |
1892 | -# |
1893 | -# Copyright (c) 2002 Zope Corporation and Contributors. |
1894 | -# All Rights Reserved. |
1895 | -# |
1896 | -# This software is subject to the provisions of the Zope Public License, |
1897 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
1898 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
1899 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
1900 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
1901 | -# FOR A PARTICULAR PURPOSE. |
1902 | -# |
1903 | -############################################################################## |
1904 | -"""Persistent Classes.""" |
1905 | - |
1906 | -__metaclass__ = type |
1907 | - |
1908 | -from zope.interface import implements |
1909 | -from persistent.cPersistence import UPTODATE, CHANGED, GHOST |
1910 | -from persistent.interfaces import IPersistent |
1911 | -from zodbcode.function import PersistentFunction |
1912 | - |
1913 | -import time |
1914 | - |
1915 | -# XXX There is a lot of magic here to give classes and instances |
1916 | -# separate sets of attributes. This code should be documented, as it |
1917 | -# it quite delicate, and it should be move to a separate module. |
1918 | - |
1919 | -class SimpleDescriptor(object): |
1920 | - |
1921 | - missing = object() |
1922 | - |
1923 | - def __init__(self, value): |
1924 | - self._value = value |
1925 | - |
1926 | - def __get__(self, obj, cls): |
1927 | - if self._value is self.missing: |
1928 | - raise AttributeError |
1929 | - return self._value |
1930 | - |
1931 | - def __set__(self, obj, value): |
1932 | - self._value = value |
1933 | - |
1934 | - def __delete__(self, obj): |
1935 | - if self._value is self.missing: |
1936 | - raise AttributeError |
1937 | - del self._value |
1938 | - |
1939 | -class ExtClassDescr: |
1940 | - """Maintains seperate class and instance descriptors for an attribute. |
1941 | - |
1942 | - This allows a class to provide methods and attributes without |
1943 | - intefering with normal use of instances. The class and its |
1944 | - instances can each have methods with the same name. |
1945 | - |
1946 | - This does interfere with introspection on the class. |
1947 | - """ |
1948 | - |
1949 | - def __init__(self, name, instdescr): |
1950 | - self.name = name |
1951 | - self.instdescr = instdescr |
1952 | - |
1953 | - def __get__(self, obj, cls): |
1954 | - if obj is None: |
1955 | - return self.clsget(cls) |
1956 | - else: |
1957 | - return self.instdescr.__get__(obj, cls) |
1958 | - |
1959 | - def __set__(self, obj, val): |
1960 | - if obj is None: |
1961 | - self.clsset(val) |
1962 | - else: |
1963 | - if self.instdescr is None: |
1964 | - raise AttributeError(self.name) |
1965 | - return self.instdescr.__set__(obj, val) |
1966 | - |
1967 | - def __delete__(self, obj): |
1968 | - if self.instdescr is None: |
1969 | - raise AttributeError(self.name) |
1970 | - return self.instdescr.__delete__(obj) |
1971 | - |
1972 | - # subclass should override |
1973 | - |
1974 | - def clsget(self, cls): |
1975 | - pass |
1976 | - |
1977 | - def clsset(self, val): |
1978 | - pass |
1979 | - |
1980 | - def clsdelete(self): |
1981 | - pass |
1982 | - |
1983 | -class MethodMixin: |
1984 | - |
1985 | - def __init__(self, name, descr, func): |
1986 | - if not hasattr(descr, "__get__"): |
1987 | - # If the object defined in the metaclass is not a descriptor, |
1988 | - # create one for it. |
1989 | - descr = SimpleDescriptor(descr) |
1990 | - super(MethodMixin, self).__init__(name, descr) |
1991 | - self.func = func |
1992 | - |
1993 | - def clsget(self, cls): |
1994 | - def f(*args, **kwargs): |
1995 | - try: |
1996 | - return self.func(cls, *args, **kwargs) |
1997 | - except TypeError: |
1998 | - print `self.func`, `cls`, `args`, `kwargs` |
1999 | - raise |
2000 | - return f |
2001 | - |
2002 | -class DataMixin: |
2003 | - |
2004 | - def __init__(self, name, descr, val): |
2005 | - if not hasattr(descr, "__get__"): |
2006 | - # If the object defined in the metaclass is not a descriptor, |
2007 | - # create one for it. |
2008 | - descr = SimpleDescriptor(descr) |
2009 | - super(DataMixin, self).__init__(name, descr) |
2010 | - self.val = val |
2011 | - |
2012 | - def clsget(self, cls): |
2013 | - return self.val |
2014 | - |
2015 | - def clsset(self, val): |
2016 | - self.val = val |
2017 | - |
2018 | - def clsdelete(self): |
2019 | - del self.val |
2020 | - |
2021 | -class ExtClassMethodDescr(MethodMixin, ExtClassDescr): |
2022 | - pass |
2023 | - |
2024 | -class ExtClassDataDescr(DataMixin, ExtClassDescr): |
2025 | - pass |
2026 | - |
2027 | -class ExtClassHookDataDescr(ExtClassDataDescr): |
2028 | - # Calls a hook when clsset() is called. |
2029 | - |
2030 | - def __init__(self, name, descr, val, hook): |
2031 | - super(ExtClassHookDataDescr, self).__init__(name, descr, val) |
2032 | - self.hook = hook |
2033 | - |
2034 | - def clsset(self, val): |
2035 | - self.val = val |
2036 | - self.hook() |
2037 | - |
2038 | -# The next three classes conspire to make a PersistentFunction |
2039 | -# behave like a method when found in a class's __dict__. |
2040 | - |
2041 | -class PersistentMethod: |
2042 | - """Make PersistentFunctions into methods.""" |
2043 | - def __init__(self, klass, inst, func): |
2044 | - self.im_class = klass |
2045 | - self.im_self = inst |
2046 | - self.im_func = func |
2047 | - |
2048 | - def __repr__(self): |
2049 | - if self.im_self is None: |
2050 | - fmt = "<persistent unbound method %s.%s>" |
2051 | - else: |
2052 | - fmt = "<persistent bound method %%s.%%s of %s>" % (self.im_self,) |
2053 | - return fmt % (self.im_class.__name__, self.im_func.__name__) |
2054 | - |
2055 | - def __call__(self, *args, **kwargs): |
2056 | - if self.im_self is None: |
2057 | - if not isinstance(args[0], self.im_class): |
2058 | - raise TypeError("unbound method %s() must be called " |
2059 | - "with %s instance as first argument (" |
2060 | - "got %s instead)" % (self.im_func.__name__, |
2061 | - self.im_class.__name__, |
2062 | - type(args[0]).__name__)) |
2063 | - else: |
2064 | - return self.im_func(self.im_self, *args, **kwargs) |
2065 | - |
2066 | -class PersistentDescriptor: |
2067 | - |
2068 | - def __init__(self, objclass, func): |
2069 | - self.__name__ = func.__name__ |
2070 | - self.__doc__ = func.__doc__ |
2071 | - self.__objclass__ = objclass |
2072 | - self._func = func |
2073 | - # Delegate __getstate__ and __setstate__ to the persistent func. |
2074 | - # The patch module will use these methods to update persistent |
2075 | - # methods in place. |
2076 | - self.__getstate__ = func.__getstate__ |
2077 | - self.__setstate__ = func.__setstate__ |
2078 | - |
2079 | - def __repr__(self): |
2080 | - return "<persistent descriptor %s.%s>" % (self.__objclass__.__name__, |
2081 | - self.__name__) |
2082 | - |
2083 | - def __get__(self, object, klass=None): |
2084 | - if object is None: |
2085 | - return PersistentMethod(klass or self.__objclass__, None, |
2086 | - self._func) |
2087 | - else: |
2088 | - return PersistentMethod(klass or self.__objclass__, object, |
2089 | - self._func) |
2090 | - |
2091 | - |
2092 | -_missing = object() |
2093 | - |
2094 | -def findattr(cls, attr, default): |
2095 | - """Walk the mro of cls to find attr.""" |
2096 | - for c in cls.__mro__: |
2097 | - o = c.__dict__.get(attr, _missing) |
2098 | - if o is not _missing: |
2099 | - return o |
2100 | - return default |
2101 | - |
2102 | -class StateChangeDataDescr(ExtClassDataDescr): |
2103 | - # A data descriptor for _p_changed. |
2104 | - pass |
2105 | - |
2106 | -class PersistentClassMetaClass(type): |
2107 | - |
2108 | - # An attempt to make persistent classes look just like other |
2109 | - # persistent objects by providing class attributes and methods |
2110 | - # that behave like the persistence machinery. |
2111 | - |
2112 | - # The chief limitation of this approach is that class.attr won't |
2113 | - # always behave the way it does for normal classes |
2114 | - |
2115 | - # A persistent class can never be a ghost, because there are too |
2116 | - # many places where Python will attempt to inspect the class |
2117 | - # without using getattr(). As a result, it would be impossible to |
2118 | - # guarantee that the class would be unghostified at the right |
2119 | - # time. It's really difficult to guarantee this property without |
2120 | - # help from the connection, because a ghost can't be unghosted |
2121 | - # until after the connection sets its _p_jar. |
2122 | - |
2123 | - # The hack solution is to have a hook for _p_jar that activates |
2124 | - # the object the first time it is set. |
2125 | - |
2126 | - #implements(IPersistent) |
2127 | - __implements__ = IPersistent |
2128 | - |
2129 | - # A class is normally created in the UPTODATE state, but when a |
2130 | - # new ghost is created for it the serialization machinery passes |
2131 | - # GHOST instead of UPTODATE. See __getnewargs__(). |
2132 | - |
2133 | - def __new__(meta, name, bases, dict, state=UPTODATE): |
2134 | - |
2135 | - if "__dict__" in dict: |
2136 | - del dict["__dict__"] |
2137 | - cls = super(PersistentClassMetaClass, meta).__new__( |
2138 | - meta, name, bases, dict) |
2139 | - cls._pc_init = False |
2140 | - |
2141 | - # helper functions |
2142 | - def extend_attr(attr, v): |
2143 | - prev = findattr(cls, attr, SimpleDescriptor.missing) |
2144 | - setattr(cls, attr, ExtClassDataDescr(attr, prev, v)) |
2145 | - |
2146 | - def extend_meth(attr, m): |
2147 | - prev = findattr(cls, attr, SimpleDescriptor.missing) |
2148 | - setattr(cls, attr, ExtClassMethodDescr(attr, prev, m)) |
2149 | - |
2150 | - extend_attr("_p_oid", None) |
2151 | - extend_attr("_p_atime", time.time() % 86400) |
2152 | - extend_attr("_p_state", state) |
2153 | - extend_attr("_p_changed", None) |
2154 | - extend_meth("_p_activate", meta._p_activate) |
2155 | - extend_meth("_p_deactivate", meta._p_deactivate) |
2156 | - # XXX _p_invalidate |
2157 | - |
2158 | - # Create a descriptor that calls _p_activate() when _p_jar is set. |
2159 | - inst_jar_descr = findattr(cls, "_p_jar", None) |
2160 | - setattr(cls, "_p_jar", |
2161 | - ExtClassHookDataDescr("_p_jar", inst_jar_descr, None, |
2162 | - getattr(cls, "_p_activate"))) |
2163 | - |
2164 | - for k, v in dict.items(): |
2165 | - if isinstance(v, PersistentFunction): |
2166 | - setattr(cls, k, PersistentDescriptor(cls, v)) |
2167 | - |
2168 | - # A class could define any of these attributes, thus we |
2169 | - # need to create extended descriptors so that the class |
2170 | - # and its instances have separate versions. |
2171 | - extend_meth("__getstate__", meta.__getstate__) |
2172 | - extend_meth("__setstate__", meta.__setstate__) |
2173 | - |
2174 | - # Don't need this with interface geddon |
2175 | - # extend_attr("__implements__", meta.__implements__) |
2176 | - |
2177 | - cls._pc_init = True |
2178 | - return cls |
2179 | - |
2180 | - def __getattribute__(cls, name): |
2181 | - # XXX I'm not sure I understand this code any more. |
2182 | - super_meth = super(PersistentClassMetaClass, cls).__getattribute__ |
2183 | - |
2184 | - # If we are initializing the class, don't trying to check variables |
2185 | - # like _p_state, since they may not be initialized. |
2186 | - if not super_meth("_pc_init"): |
2187 | - return super_meth(name) |
2188 | - if (name[0] != "_" or |
2189 | - not (name.startswith("_p_") or name.startswith("_pc_") or |
2190 | - name == "__dict__")): |
2191 | - if cls._p_state == GHOST: |
2192 | - cls._p_activate() |
2193 | - cls._p_atime = int(time.time() % 86400) |
2194 | - return super_meth(name) |
2195 | - |
2196 | - # XXX There needs to be an _p_changed flag so that classes get |
2197 | - # registered with the txn when they are modified. |
2198 | - |
2199 | - def __setattr__(cls, attr, val): |
2200 | - if not attr.startswith("_pc_") and cls._pc_init: |
2201 | - descr = cls.__dict__.get(attr) |
2202 | - if descr is not None: |
2203 | - set = getattr(descr, "__set__", None) |
2204 | - if set is not None: |
2205 | - set(None, val) |
2206 | -## cls._p_changed = True |
2207 | - return |
2208 | - super(PersistentClassMetaClass, cls).__setattr__(attr, val) |
2209 | - |
2210 | - def __delattr__(cls, attr): |
2211 | - if attr.startswith('_p_'): |
2212 | - # XXX what should happen with these? |
2213 | - return |
2214 | - super(PersistentClassMetaClass, cls).__delattr__(attr) |
2215 | - |
2216 | - def __repr__(cls): |
2217 | - return "<persistent class %s.%s>" % (cls.__module__, |
2218 | - cls.__name__) |
2219 | - |
2220 | - # It should be possible for getstate / setstate to deal with |
2221 | - # arbitrary class attributes. That goal is hard to achieve, |
2222 | - # because there are several funny descriptors that need to |
2223 | - # be handled specially. |
2224 | - |
2225 | - def __getstate__(cls): |
2226 | - dict = {} |
2227 | - |
2228 | - for k in cls.__dict__.keys(): |
2229 | - v = getattr(cls, k) |
2230 | - if isinstance(v, PersistentMethod): |
2231 | - dict[k] = v.im_func |
2232 | - continue |
2233 | - if (k in ["__module__", "__weakref__", "__dict__"] |
2234 | - or k.startswith("_p_") or k.startswith("_pc_")): |
2235 | - continue |
2236 | - # XXX The following test isn't right because overriding |
2237 | - # must be allowed, but I haven't figured that out yet. |
2238 | - # __getstate__ and __setstate__ might be overridden |
2239 | - # __implements__ might be overridden |
2240 | - if k in ["__getstate__", "__setstate__", "__implements__"]: |
2241 | - continue |
2242 | - dict[k] = v |
2243 | - return dict |
2244 | - |
2245 | - def __setstate__(cls, dict): |
2246 | - for k, v in dict.items(): |
2247 | - if isinstance(v, PersistentFunction): |
2248 | - setattr(cls, k, PersistentDescriptor(cls, v)) |
2249 | - else: |
2250 | - setattr(cls, k, v) |
2251 | - |
2252 | - # XXX Should the object get marked as a ghost when it is, in fact, |
2253 | - # not a ghost? The most obvious answer is no. But if we don't |
2254 | - # then we need some other attribute that can be used to handle |
2255 | - # invalidations of classes and make _p_activate() work as expected. |
2256 | - # Need to decide on a good answer. |
2257 | - |
2258 | - def _p_deactivate(cls): |
2259 | - # do nothing but mark the state change for now |
2260 | - cls._p_state = GHOST |
2261 | - |
2262 | - def _p_activate(cls): |
2263 | - # The logic here is: |
2264 | - # If the class hasn't finished executing __new__(), don't |
2265 | - # try to load its state. |
2266 | - # If the class has a jar but no oid, it's a new object |
2267 | - # and doesn't have state in the database. |
2268 | - |
2269 | - if cls._p_state == GHOST and cls._pc_init: |
2270 | - dm = cls._p_jar |
2271 | - if dm is not None and cls._p_oid: |
2272 | - cls._p_state = CHANGED |
2273 | - try: |
2274 | - # XXX Make sure the object is in the cache before |
2275 | - # calling setstate(). |
2276 | - dm._cache[cls._p_oid] = cls |
2277 | - dm.setstate(cls) |
2278 | - finally: |
2279 | - # XXX Should really put in special inconsistent state |
2280 | - cls._p_state = UPTODATE |
2281 | - else: |
2282 | - print id(cls), "dm", dm, "oid", cls._p_oid |
2283 | - |
2284 | - # Methods below here are not wrapped to be class-only attributes. |
2285 | - # They are available as methods of classes using this metaclass. |
2286 | - |
2287 | - def __getnewargs__(cls): |
2288 | - # XXX This should really be _p_getnewargs() or something like that. |
2289 | - |
2290 | - # If the class is later loaded and unghostified, the arguments |
2291 | - # passed to __new__() won't have an __module__. It seems that |
2292 | - # the module gets set to zodb.code.class_ in that case, which |
2293 | - # is wrong. |
2294 | - return (cls.__name__, cls.__bases__, |
2295 | - {"__module__": cls.__module__}, GHOST) |
2296 | - |
2297 | - def _p_newstate(cls, acls): |
2298 | - # Update a class's __dict__ in place. Must use setattr and |
2299 | - # delattr because __dict__ is a read-only proxy. |
2300 | - # XXX This doesn't handle __methods__ correctly. |
2301 | - |
2302 | - # XXX I'm not sure how this is supposed to handle the |
2303 | - # ExtClassDataDescrs. As a hack, I'm deleting _p_oid |
2304 | - # and _p_jar from the keys dict, because I know they |
2305 | - # will be descrs and they won't change as a result of |
2306 | - # update. It appears that if the new class has a descr |
2307 | - # that isn't set on the class, it will stomp on the old |
2308 | - # class's value. Not sure if this is a problem in general. |
2309 | - |
2310 | - def getkeys(cls): |
2311 | - L = [n for n in cls.__dict__.keys() |
2312 | - if (not (n.startswith("__") and n.endswith("__")) |
2313 | - and not n.startswith("_p_")) |
2314 | - ] |
2315 | - d = {} |
2316 | - for elt in L: |
2317 | - d[elt] = True |
2318 | - return d |
2319 | - oldnames = getkeys(cls) |
2320 | - newnames = getkeys(acls) |
2321 | - for name in oldnames: |
2322 | - if not name in newnames: |
2323 | - delattr(cls, name) |
2324 | - for name in newnames: |
2325 | - setattr(cls, name, acls.__dict__[name]) |
2326 | - |
2327 | |
2328 | === removed file 'src/zodbcode/function.py' |
2329 | --- src/zodbcode/function.py 2009-04-23 15:12:18 +0000 |
2330 | +++ src/zodbcode/function.py 1970-01-01 00:00:00 +0000 |
2331 | @@ -1,201 +0,0 @@ |
2332 | -############################################################################## |
2333 | -# |
2334 | -# Copyright (c) 2002 Zope Corporation and Contributors. |
2335 | -# All Rights Reserved. |
2336 | -# |
2337 | -# This software is subject to the provisions of the Zope Public License, |
2338 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
2339 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
2340 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
2341 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
2342 | -# FOR A PARTICULAR PURPOSE. |
2343 | -# |
2344 | -############################################################################## |
2345 | -"""Persistent functions.""" |
2346 | - |
2347 | -import dis |
2348 | -import new |
2349 | -import sys |
2350 | -# in 2.3, this will be spelled new.function and new.code |
2351 | -from types import FunctionType as function, CodeType as code |
2352 | - |
2353 | -from persistent import Persistent |
2354 | - |
2355 | -_STORE_GLOBAL = chr(dis.opname.index("STORE_GLOBAL")) |
2356 | - |
2357 | -def has_side_effect(func): |
2358 | - # will find this as an opcode or oparg |
2359 | - return _STORE_GLOBAL in func.func_code.co_code |
2360 | - |
2361 | -class CodeWrapper: |
2362 | - """Package a code object so that it can be pickled.""" |
2363 | - |
2364 | - nested = 0 |
2365 | - |
2366 | - def __init__(self, co): |
2367 | - consts = co.co_consts |
2368 | - nested = [(i, c) for i, c in zip(range(len(consts)), consts) |
2369 | - if isinstance(c, code)] |
2370 | - if nested: |
2371 | - self.nested = 1 |
2372 | - L = list(consts) |
2373 | - for i, c in nested: |
2374 | - L[i] = CodeWrapper(c) |
2375 | - consts = tuple(L) |
2376 | - |
2377 | - # args stores the arguments to new.code in order |
2378 | - self.args = [co.co_argcount, |
2379 | - co.co_nlocals, |
2380 | - co.co_stacksize, |
2381 | - co.co_flags, |
2382 | - co.co_code, |
2383 | - consts, |
2384 | - co.co_names, |
2385 | - co.co_varnames, |
2386 | - co.co_filename, |
2387 | - co.co_name, |
2388 | - co.co_firstlineno, |
2389 | - co.co_lnotab, |
2390 | - co.co_freevars, |
2391 | - co.co_cellvars] |
2392 | - |
2393 | - def ascode(self): |
2394 | - if self.nested: |
2395 | - L = list(self.args[5]) |
2396 | - for i, elt in zip(range(len(L)), L): |
2397 | - if isinstance(elt, CodeWrapper): |
2398 | - L[i] = elt.ascode() |
2399 | - self.args[5] = tuple(L) |
2400 | - return new.code(*self.args) |
2401 | - |
2402 | -def get_code_args(co): |
2403 | - """Return args from code object suitable for passing to constructor.""" |
2404 | - |
2405 | -class PersistentFunction(Persistent): |
2406 | - |
2407 | - def __init__(self, func, module): |
2408 | - # Use _pf_ as the prefix to minimize the possibility that |
2409 | - # these attribute names will conflict with function attributes |
2410 | - # found in user code. It would have been nice to use _p_ |
2411 | - # since it's already an reserved attribute prefix, but the |
2412 | - # base persistent getattr function does not unghostify an |
2413 | - # object on refences to _p_ attributes. |
2414 | - self._pf_func = func |
2415 | - self._v_side_effect = has_side_effect(func) |
2416 | - self._pf_module = module |
2417 | - self._pf_code = {} |
2418 | - # Python doesn't provide enough rope to recreate a closure. The |
2419 | - # cell objects are opaque which means Python code can't extra |
2420 | - # the objects from them or recreate them on unpickling. In |
2421 | - # principle this code be fixed with C code, but it should be |
2422 | - # done in Python, not Zope. |
2423 | - if func.func_code.co_freevars: |
2424 | - raise TypeError("persistent function can not have free variables") |
2425 | - |
2426 | - def __repr__(self): |
2427 | - return "<PersistentFunction %s.%s>" % (self._pf_module.__name__, |
2428 | - self._pf_func.func_name) |
2429 | - |
2430 | - # We need attribute hooks to handle access to _pf_ attributes in a |
2431 | - # special way. All other attributes should be looked up on |
2432 | - # _pf_func. |
2433 | - |
2434 | - def __getattr__(self, attr): |
2435 | - # If it wasn't found in __dict__, then it must be a function |
2436 | - # attribute. |
2437 | - if attr == '_pf_func': |
2438 | - raise AttributeError(attr) |
2439 | - return getattr(self._pf_func, attr) |
2440 | - |
2441 | - def __setattr__(self, attr, value): |
2442 | - if not self._p_setattr(attr, value): |
2443 | - # the persistence machinery didn't handle this attribute, |
2444 | - # it must be ours |
2445 | - if attr.startswith('_pf_'): |
2446 | - self.__dict__[attr] = value |
2447 | - if attr == "_pf_func": |
2448 | - self._v_side_effect = has_side_effect(self._pf_func) |
2449 | - else: |
2450 | - setattr(self._pf_func, attr, value) |
2451 | - if not attr.startswith('_v_'): |
2452 | - self._p_changed = 1 |
2453 | - |
2454 | - def __delattr__(self, attr): |
2455 | - if not self._p_delattr(attr): |
2456 | - # the persistence machinery didn't handle this attribute, |
2457 | - # it must be ours |
2458 | - if attr.startswith('_pf_'): |
2459 | - del self.__dict__[attr] |
2460 | - else: |
2461 | - delattr(self._pf_func, attr) |
2462 | - if not attr.startswith('_v_'): |
2463 | - self._p_changed = 1 |
2464 | - |
2465 | - def __call__(self, *args, **kwargs): |
2466 | - # We must make sure that _module is loaded when func is |
2467 | - # executed because the function may reference a global |
2468 | - # variable and that global variable must be in the module's |
2469 | - # __dict__. We can't use a PersistentDict because the |
2470 | - # interpreter requires that globals be a real dict. |
2471 | - self._pf_module._p_activate() |
2472 | - |
2473 | - # XXX What if the function module is deactivated while the |
2474 | - # function is executing? It seems like we need to expose |
2475 | - # refcounts at the Python level to guarantee that this will |
2476 | - # work. |
2477 | - |
2478 | - try: |
2479 | - return self._pf_func(*args, **kwargs) |
2480 | - finally: |
2481 | - # If the func has a side-effect, the module must be marked |
2482 | - # as changed. We use the conservative approximation that |
2483 | - # any function with a STORE_GLOBAL opcode has a |
2484 | - # side-effect, regardless of whether a a particular call |
2485 | - # of the function actually executes STORE_GLOBAL. |
2486 | - |
2487 | - # XXX Is this sufficient? |
2488 | - if self._v_side_effect: |
2489 | - self._pf_module._p_changed = True |
2490 | - |
2491 | - def __getstate__(self): |
2492 | - # If func_dict is empty, store None to avoid creating a dict |
2493 | - # unnecessarily when the function is unpickled |
2494 | - # XXX new.function doesn't accept a closure |
2495 | - func = self._pf_func |
2496 | - func_state = func.func_defaults, func.func_dict or None |
2497 | - |
2498 | - # Store the code separately from the function |
2499 | - code = func.func_code |
2500 | - |
2501 | - # The code object is can only be reused in an interpreter |
2502 | - # running the same version of Python and with the same |
2503 | - # __debug__ value. Store code in a dict keyed by these two values. |
2504 | - |
2505 | - key = sys.version_info, __debug__ |
2506 | - if key not in self._pf_code: |
2507 | - self._pf_code[key] = CodeWrapper(code) |
2508 | - |
2509 | - return func_state, self._pf_code, self._pf_module |
2510 | - |
2511 | - def __setstate__(self, (func, code, mod)): |
2512 | - self._pf_code = code |
2513 | - self._pf_module = mod |
2514 | - |
2515 | - # recreate the code object |
2516 | - code = None |
2517 | - key = sys.version_info, __debug__ |
2518 | - cowrap = self._pf_code.get(key, None) |
2519 | - if cowrap is None: |
2520 | - assert False, "not implemented yet" |
2521 | - else: |
2522 | - code = cowrap.ascode() |
2523 | - |
2524 | - func_defaults, func_dict = func |
2525 | - if func_defaults: |
2526 | - func = new.function(code, mod.__dict__, None, func_defaults) |
2527 | - else: |
2528 | - func = new.function(code, mod.__dict__) |
2529 | - if func_dict: |
2530 | - func.func_dict.update(func_dict) |
2531 | - self._pf_func = func |
2532 | - self._v_side_effect = has_side_effect(func) |
2533 | |
2534 | === removed file 'src/zodbcode/interfaces.py' |
2535 | --- src/zodbcode/interfaces.py 2009-04-23 15:12:18 +0000 |
2536 | +++ src/zodbcode/interfaces.py 1970-01-01 00:00:00 +0000 |
2537 | @@ -1,54 +0,0 @@ |
2538 | -############################################################################## |
2539 | -# |
2540 | -# Copyright (c) 2002 Zope Corporation and Contributors. |
2541 | -# All Rights Reserved. |
2542 | -# |
2543 | -# This software is subject to the provisions of the Zope Public License, |
2544 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
2545 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
2546 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
2547 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
2548 | -# FOR A PARTICULAR PURPOSE. |
2549 | -# |
2550 | -############################################################################## |
2551 | -"""Persistent Module Interfaces |
2552 | - |
2553 | -$Id$ |
2554 | -""" |
2555 | -from zope.interface import Interface, Attribute |
2556 | - |
2557 | -class IPersistentModuleImportRegistry(Interface): |
2558 | - |
2559 | - def findModule(name): |
2560 | - """Return module registered under name or None.""" |
2561 | - |
2562 | - def modules(): |
2563 | - """Return a list of module names in the registry.""" |
2564 | - |
2565 | -class IPersistentModuleUpdateRegistry(IPersistentModuleImportRegistry): |
2566 | - |
2567 | - def setModule(name, module): |
2568 | - """Register module under name. |
2569 | - |
2570 | - Raises ValueError if module is already registered. |
2571 | - """ |
2572 | - |
2573 | - def delModule(name): |
2574 | - """Unregister module registered under name. |
2575 | - |
2576 | - Raises KeyError in module is not registered. |
2577 | - """ |
2578 | - |
2579 | -class IPersistentModuleManager(Interface): |
2580 | - |
2581 | - def new(name, source): |
2582 | - """Create and register a new named module from source.""" |
2583 | - |
2584 | - def update(src): |
2585 | - """Update the source of the existing module.""" |
2586 | - |
2587 | - def remove(): |
2588 | - """Unregister the module and forget about it.""" |
2589 | - |
2590 | - name = Attribute("Absolute module name") |
2591 | - source = Attribute("Module source string") |
2592 | |
2593 | === removed file 'src/zodbcode/module.py' |
2594 | --- src/zodbcode/module.py 2009-04-23 15:12:18 +0000 |
2595 | +++ src/zodbcode/module.py 1970-01-01 00:00:00 +0000 |
2596 | @@ -1,343 +0,0 @@ |
2597 | -############################################################################## |
2598 | -# |
2599 | -# Copyright (c) 2002 Zope Corporation and Contributors. |
2600 | -# All Rights Reserved. |
2601 | -# |
2602 | -# This software is subject to the provisions of the Zope Public License, |
2603 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
2604 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
2605 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
2606 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
2607 | -# FOR A PARTICULAR PURPOSE. |
2608 | -# |
2609 | -############################################################################## |
2610 | -"""Persistent Module.""" |
2611 | - |
2612 | -__metaclass__ = type |
2613 | - |
2614 | -from zope.interface import implements |
2615 | - |
2616 | -from persistent import Persistent |
2617 | -from persistent.cPersistence import GHOST |
2618 | -from zodbcode.interfaces import IPersistentModuleManager |
2619 | -from zodbcode.interfaces \ |
2620 | - import IPersistentModuleImportRegistry, IPersistentModuleUpdateRegistry |
2621 | -from zodbcode.patch import NameFinder, convert |
2622 | - |
2623 | -# builtins are explicitly assigned when a module is unpickled |
2624 | -import __builtin__ |
2625 | - |
2626 | -# Modules aren't picklable by default, but we'd like them to be |
2627 | -# pickled just like classes (by name). |
2628 | -import copy_reg |
2629 | - |
2630 | -def _pickle_module(mod): |
2631 | - return _unpickle_module, (mod.__name__,) |
2632 | - |
2633 | -def _unpickle_module(modname): |
2634 | - mod = __import__(modname) |
2635 | - if "." in modname: |
2636 | - parts = modname.split(".")[1:] |
2637 | - for part in parts: |
2638 | - mod = getattr(mod, part) |
2639 | - return mod |
2640 | - |
2641 | -copy_reg.pickle(type(copy_reg), _pickle_module, _unpickle_module) |
2642 | - |
2643 | -# XXX Is this comment still relevant? |
2644 | -# |
2645 | -# There seems to be something seriously wrong with a module pickle |
2646 | -# that contains objects pickled via save_global(). These objects are |
2647 | -# pickled using references to the module. It appears that unpickling the |
2648 | -# object in the module causes the persistence machinery to fail. |
2649 | -# |
2650 | -# My suspicion is that the assignment to po_state before trying to |
2651 | -# load the state confuses things. The first call to setstate attempts |
2652 | -# to reference an attribute of the module. That getattr() fails because |
2653 | -# the module is not a ghost, but does have any empty dict. Since |
2654 | -# that getattr() fails, its state can't be unpickled. |
2655 | -# |
2656 | -# Not sure what to do about this. |
2657 | - |
2658 | -class PersistentModule(Persistent): |
2659 | - |
2660 | - def __init__(self, name): |
2661 | - self.__name__ = name |
2662 | - |
2663 | - def __repr__(self): |
2664 | - return "<%s %s>" % (self.__class__.__name__, self.__name__) |
2665 | - |
2666 | - # XXX need getattr &c. hooks to update _p_changed? |
2667 | - # XXX what about code that modifies __dict__ directly? |
2668 | - # XXX one example is a function that rebinds a global |
2669 | - |
2670 | - def __getstate__(self): |
2671 | - d = self.__dict__.copy() |
2672 | - try: |
2673 | - del d["__builtins__"] |
2674 | - except KeyError: |
2675 | - pass |
2676 | - return d |
2677 | - |
2678 | - def __setstate__(self, state): |
2679 | - state["__builtins__"] = __builtin__ |
2680 | - self.__dict__.update(state) |
2681 | - |
2682 | -class PersistentPackage(PersistentModule): |
2683 | - # XXX Is it okay that these packages don't have __path__? |
2684 | - |
2685 | - # A PersistentPackage can exist in a registry without a manager. |
2686 | - # It only gets a manager if someone creates an __init__ module for |
2687 | - # the package. |
2688 | - |
2689 | - def __init__(self, name): |
2690 | - self.__name__ = name |
2691 | - |
2692 | -__persistent_module_registry__ = "__persistent_module_registry__" |
2693 | - |
2694 | -def newModule(registry, name, source): |
2695 | - """Return a manager object for a newly created module.""" |
2696 | - mgr = PersistentModuleManager(registry) |
2697 | - mgr.new(name, source) |
2698 | - return mgr |
2699 | - |
2700 | - |
2701 | -def compileModule(module, registry, source): |
2702 | - # Try to prevent compilation errors from files without trailing newlines. |
2703 | - if source and source[-1] != "\n": |
2704 | - source += "\n" |
2705 | - module._p_changed = True |
2706 | - moddict = module.__dict__ |
2707 | - old_names = NameFinder(module) |
2708 | - moddict[__persistent_module_registry__] = registry |
2709 | - # XXX need to be able to replace sys.std{in,out,err} at this point |
2710 | - exec source in moddict |
2711 | - # XXX and restore them here. |
2712 | - del moddict[__persistent_module_registry__] |
2713 | - new_names = NameFinder(module) |
2714 | - replacements = new_names.replacements(old_names) |
2715 | - convert(module, replacements) |
2716 | - |
2717 | -class PersistentModuleManager(Persistent): |
2718 | - |
2719 | - implements(IPersistentModuleManager) |
2720 | - |
2721 | - def __init__(self, registry): |
2722 | - self._registry = registry |
2723 | - self._module = None |
2724 | - self.name = None |
2725 | - self.source = None |
2726 | - |
2727 | - def new(self, name, source): |
2728 | - """Return a new module from a name and source text.""" |
2729 | - if self._module is not None: |
2730 | - raise ValueError("module already exists") |
2731 | - if "." in name: |
2732 | - parent = self._new_package(name) |
2733 | - else: |
2734 | - parent = None |
2735 | - self._module = PersistentModule(name) |
2736 | - try: |
2737 | - self._registry.setModule(name, self._module) |
2738 | - except ValueError: |
2739 | - self._module = None |
2740 | - raise |
2741 | - self.name = name |
2742 | - try: |
2743 | - self.update(source) |
2744 | - except: |
2745 | - self._registry.delModule(name) |
2746 | - raise |
2747 | - if parent is not None: |
2748 | - modname = name.split(".")[-1] |
2749 | - setattr(parent, modname, self._module) |
2750 | - |
2751 | - def update(self, source): |
2752 | - # Try to prevent compilation errors from files without trailing |
2753 | - # newlines. |
2754 | - compileModule(self._module, self._registry, source) |
2755 | - self.source = source |
2756 | - |
2757 | - def remove(self): |
2758 | - self._registry.delModule(self._module.__name__) |
2759 | - self._module = None |
2760 | - |
2761 | - def _new_package(self, name): |
2762 | - parent = self._get_parent(name) |
2763 | - modname = name.split(".")[-1] |
2764 | - if modname == "__init__": |
2765 | - self._module = parent |
2766 | - return None |
2767 | - else: |
2768 | - self._module = PersistentModule(name) |
2769 | - return parent |
2770 | - |
2771 | - def _get_parent(self, name): |
2772 | - # If a module is being created in a package, automatically |
2773 | - # create parent packages that do no already exist. |
2774 | - parts = name.split(".")[:-1] |
2775 | - parent = None |
2776 | - for i in range(len(parts)): |
2777 | - if parts[i] == "__init__": |
2778 | - raise ValueError("__init__ can not be a package") |
2779 | - pname = ".".join(parts[:i+1]) |
2780 | - package = self._registry.findModule(pname) |
2781 | - if package is None: |
2782 | - package = PersistentPackage(pname) |
2783 | - self._registry.setModule(pname, package) |
2784 | - if parent is not None: |
2785 | - setattr(parent, parts[i], package) |
2786 | - elif not isinstance(package, PersistentPackage): |
2787 | - raise ValueError("%s is module" % pname) |
2788 | - parent = package |
2789 | - return parent |
2790 | - |
2791 | -class PersistentModuleImporter: |
2792 | - """An import hook that loads persistent modules. |
2793 | - |
2794 | - The importer cooperates with other objects to make sure imports of |
2795 | - persistent modules work correctly. The default importer depends |
2796 | - on finding a persistent module registry in the globals passed to |
2797 | - __import__(). It looks for the name __persistent_module_registry__. |
2798 | - A PersistentModuleManager places its registry in the globals used |
2799 | - to exec module source. |
2800 | - |
2801 | - It is important that the registry be activated before it is used |
2802 | - to handle imports. If a ghost registry is used for importing, a |
2803 | - circular import occurs. The second import occurs when the |
2804 | - machinery searches for the class of the registry. It will re-use |
2805 | - the registry and fail, because the registry will be marked as |
2806 | - changed but not yet have its state loaded. |
2807 | - XXX There ought to be a way to deal with this. |
2808 | - """ |
2809 | - |
2810 | - # The import hook doesn't use sys.modules, because Zope might want |
2811 | - # to have placeful registries. That is, a particular module might |
2812 | - # execute in a context where there is more than one persistent |
2813 | - # module registry active. In this case, it isn't safe to use |
2814 | - # sys.modules, because each registry could have a different binding |
2815 | - # for a particular name. |
2816 | - |
2817 | - _saved_import = None |
2818 | - |
2819 | - def install(self): |
2820 | - if self._saved_import is not None: |
2821 | - raise TypeError("Already installed!") |
2822 | - self._saved_import = __builtin__.__import__ |
2823 | - __builtin__.__import__ = self.__import__ |
2824 | - |
2825 | - def uninstall(self): |
2826 | - if self._saved_import is None: |
2827 | - raise TypeError("Not installed!") |
2828 | - __builtin__.__import__ = self._saved_import |
2829 | - self._saved_import = None |
2830 | - |
2831 | - def _import(self, registry, name, parent, fromlist): |
2832 | - mod = None |
2833 | - if parent is not None: |
2834 | - fullname = "%s.%s" % (parent, name) |
2835 | - mod = registry.findModule(fullname) |
2836 | - if mod is None: |
2837 | - parent = None |
2838 | - if mod is None: # no parent or didn't find in parent |
2839 | - mod = registry.findModule(name) |
2840 | - if mod is None: |
2841 | - return None |
2842 | - if fromlist: |
2843 | - if isinstance(mod, PersistentPackage): |
2844 | - self._import_fromlist(registry, mod, fromlist) |
2845 | - return mod |
2846 | - else: |
2847 | - i = name.find(".") |
2848 | - if i == -1: |
2849 | - return mod |
2850 | - name = name[:i] |
2851 | - if parent: |
2852 | - name = "%s.%s" % (parent, name) |
2853 | - top = registry.findModule(name) |
2854 | - assert top is not None, "No package for module %s" % name |
2855 | - return top |
2856 | - |
2857 | - def _import_fromlist(self, registry, mod, fromlist): |
2858 | - for name in fromlist: |
2859 | - if not hasattr(mod, name): |
2860 | - fullname = "%s.%s" % (mod.__name__, name) |
2861 | - self._import(registry, fullname, None, []) |
2862 | - |
2863 | - def __import__(self, name, globals={}, locals={}, fromlist=[]): |
2864 | - registry = globals.get(__persistent_module_registry__) |
2865 | - if registry is not None: |
2866 | - mod = self._import(registry, name, self._get_parent(globals), |
2867 | - fromlist) |
2868 | - if mod is not None: |
2869 | - return mod |
2870 | - return self._saved_import(name, globals, locals, fromlist) |
2871 | - |
2872 | - def _get_parent(self, globals): |
2873 | - name = globals.get("__name__") |
2874 | - if name is None or "." not in name: |
2875 | - return None |
2876 | - i = name.rfind(".") |
2877 | - return name[:i] |
2878 | - |
2879 | -class PersistentModuleRegistry(Persistent): |
2880 | - """A collection of persistent modules. |
2881 | - |
2882 | - The registry is similar in purpose to sys.modules. A persistent |
2883 | - module manager stores its modules in a registry, and the importer |
2884 | - looks for them there. |
2885 | - """ |
2886 | - |
2887 | - implements(IPersistentModuleImportRegistry, |
2888 | - IPersistentModuleUpdateRegistry) |
2889 | - |
2890 | - def __init__(self): |
2891 | - self._modules = {} |
2892 | - |
2893 | - def findModule(self, name): |
2894 | - assert self._p_changed is not None |
2895 | - return self._modules.get(name) |
2896 | - |
2897 | - def setModule(self, name, module): |
2898 | - if name in self._modules: |
2899 | - # The name is already in use. |
2900 | - # XXX should raise a better error |
2901 | - raise ValueError(name) |
2902 | - self._p_changed = True |
2903 | - self._modules[name] = module |
2904 | - |
2905 | - def delModule(self, name): |
2906 | - self._p_changed = True |
2907 | - del self._modules[name] |
2908 | - |
2909 | - def modules(self): |
2910 | - """Return a list of the modules in the registry.""" |
2911 | - return self._modules.keys() |
2912 | - |
2913 | -class ManagedRegistry(PersistentModuleRegistry): |
2914 | - """A collection of persistent modules and their managers. |
2915 | - |
2916 | - An extension of the persistent module registry that also collects |
2917 | - the managers. For persistent modules to be useful, the managers |
2918 | - must be stored in the database. This registry stores managers |
2919 | - as well as their modules, so that all objects related to the modules |
2920 | - in the registry are reachable from the registry. |
2921 | - """ |
2922 | - |
2923 | - def __init__(self): |
2924 | - super(ManagedRegistry, self).__init__() |
2925 | - self._mgrs = {} |
2926 | - |
2927 | - def newModule(self, name, source): |
2928 | - mgr = PersistentModuleManager(self) |
2929 | - mgr.new(name, source) |
2930 | - self._p_changed = True |
2931 | - self._mgrs[name] = mgr |
2932 | - |
2933 | - def updateModule(self, name, source): |
2934 | - self._mgrs[name].update(source) |
2935 | - |
2936 | - def removeModule(self, name): |
2937 | - self._mgrs[name].remove() |
2938 | - self._p_changed = True |
2939 | - del self._mgrs[name] |
2940 | |
2941 | === removed file 'src/zodbcode/module.txt' |
2942 | --- src/zodbcode/module.txt 2009-04-23 15:12:18 +0000 |
2943 | +++ src/zodbcode/module.txt 1970-01-01 00:00:00 +0000 |
2944 | @@ -1,300 +0,0 @@ |
2945 | -================== |
2946 | -Persistent Modules |
2947 | -================== |
2948 | - |
2949 | -Document Overview |
2950 | ------------------ |
2951 | - |
2952 | -This document seeks to capture technical information about persistent modules |
2953 | -to guide and document their design. |
2954 | - |
2955 | -Goals |
2956 | ------ |
2957 | - |
2958 | -These goals largely come from Zope 3. It would be worth while considering |
2959 | -other applications. |
2960 | - |
2961 | -- Persistent modules are used to support management of software using the |
2962 | - ZODB. |
2963 | - |
2964 | -- Software can be updated using network clients, such as web browsers and |
2965 | - file-synchonozation tools. |
2966 | - |
2967 | -- Application-server clusters can be updated transactionally without requiring |
2968 | - server restarts. |
2969 | - |
2970 | -- Persistent modules leverage a familiar model, modules, for managing Python |
2971 | - software. |
2972 | - |
2973 | -- Persistent modules can be synchronized to a file-system using the Zope |
2974 | - file-system synchronization framework. Persistent modules are synchronized |
2975 | - for purposes including: |
2976 | - |
2977 | - o Use of traditional tools such as editors and code-analysis tools |
2978 | - |
2979 | - o Revision control |
2980 | - |
2981 | - Ideally, the file-system representation would consist of a Python source |
2982 | - file. |
2983 | - |
2984 | -Use cases |
2985 | ---------- |
2986 | - |
2987 | -- Create classes and functions that implement Zope 3 components. |
2988 | - |
2989 | - o Utility, Adapter, View, and service classes and factories. |
2990 | - |
2991 | - o Content components, which are typically persistent and/or |
2992 | - pickleable. |
2993 | - |
2994 | -- Define interfaces, including schema |
2995 | - |
2996 | -- Import classes, functions, and interfaces from other modules. |
2997 | - |
2998 | -- Import classes, functions, and interfaces from other persistent objects. For |
2999 | - example, an adapter registration object might have a direct reference to a |
3000 | - persistent-module-defined class. |
3001 | - |
3002 | -- Change module source |
3003 | - |
3004 | - - Changes are reflected in module state |
3005 | - |
3006 | - - Changes are reflected in objects imported into other modules. |
3007 | - |
3008 | -- Synchronize modules with a file-system representation. |
3009 | - |
3010 | -Edge cases |
3011 | ----------- |
3012 | - |
3013 | - ??? |
3014 | - |
3015 | -Fundamental dilema |
3016 | ------------------- |
3017 | - |
3018 | -Python modules were not designed to change at run time. The source of a |
3019 | -Python module normally doesn't change while a Python program is running. |
3020 | -There is a crude reload tool that allows modules to be manually reloaded to |
3021 | -handle source changes. |
3022 | - |
3023 | -Python modules contain mutable state. A module has a dictionary that may be |
3024 | -mutated by application code. It may contain mutable data that is modified at |
3025 | -run time. This is typeically used to implement global registries. |
3026 | - |
3027 | -When a module is reloaded, it is reexecuted with a dictionary that includes |
3028 | -the results of the previous execution. |
3029 | - |
3030 | -Programs using the ZODB may be said to have logical lifetimes that exceed the |
3031 | -lifetimes of individual processes. In addition, the program might exist as |
3032 | -multiple individual processes with overlapping run-times. |
3033 | - |
3034 | -The lifetime of a persistent program is long enough that it is likely that |
3035 | -module source code will change during the life time of the program. |
3036 | - |
3037 | -Issues |
3038 | ------- |
3039 | - |
3040 | -Should the state of a module be represented soley by the module source? |
3041 | - |
3042 | -Consider the possibilities: |
3043 | - |
3044 | -A. Module state is represented soley by it's source. |
3045 | - |
3046 | -- This would be a departure from the behavior of standard Python modules. |
3047 | - Standard Python modules retain a module dictionary that is not overwritten |
3048 | - by reloads. Python modules may be mutated from outside and may contain |
3049 | - mutable data structures that are modified at run time. |
3050 | - |
3051 | - OTOH, a regular module's state is not persistent or shared accross |
3052 | - processes. |
3053 | - |
3054 | - For standard Python modules, one could view the module source as an |
3055 | - expression of the initial state of the module. (This isn't quite right |
3056 | - either, since some modules are written in such a way that they anticipate |
3057 | - module reloads.) |
3058 | - |
3059 | -- Deleting variables from a module's source that have been imported by other |
3060 | - modules or objects will cause the imported values to become disconnected |
3061 | - from the module's source. Even if the variables are added back later, the |
3062 | - previously-imported values will be disconnected. |
3063 | - |
3064 | - It is tempting to introduce a data structure to record imports make from a |
3065 | - module. For example, suppose module M1 imports X from M2. It's tempting to |
3066 | - record that fact in M2, so that we disallow M2 to be removed or to be |
3067 | - changed in such a way that M2 no-longer defines X. Unfortunately, that |
3068 | - would introduce state that isn't captured by my M2's source. |
3069 | - |
3070 | -- Persistent modules could only be used for software. You wouldn't be able to |
3071 | - use them to store mutable data, such as registries or counters, that are |
3072 | - updated outside of the execution of the module source. |
3073 | - |
3074 | -B. Module state isn't represented soley by it's source. |
3075 | - |
3076 | - - It would become possible to allow mutable data, such as registries in |
3077 | - persistent modules. |
3078 | - |
3079 | - - It could be very difficult to see what a module's state is. If a module |
3080 | - contained mutable data, you'd need some way to get to that data so you |
3081 | - could inspect and manipulate it. |
3082 | - |
3083 | - - When a module is synchronized to the file system, you'd need to syncronize |
3084 | - it's source and you'd also need to synchronize it's contents in some |
3085 | - way. Synchronization of the contents could be done using an XML pickle, but |
3086 | - management of the data using file-system-based tools would be cumbersome. |
3087 | - |
3088 | - You'd end up with data duplicated between the two representations. It |
3089 | - would be cumbersome to manage the duplicated data in a consistent way. |
3090 | - |
3091 | -C. Module state is represented soley by it's source, but allow additional meta |
3092 | - data. |
3093 | - |
3094 | - This is the same as option A, except we support meta-data management. The |
3095 | - meta data could include dependency information. We'd keep track of external |
3096 | - usage (import) of module variables to influence whether deletion of the |
3097 | - module or defined variables is allowed, or whether to issue warnings when |
3098 | - variables are deleted. |
3099 | - |
3100 | - Note that the management of the meta data need not be the responsibility of |
3101 | - the module. This could be done via some application-defined facility, in |
3102 | - which case, the module facility would need to provide an api for |
3103 | - implimenting hooks for managing this information. |
3104 | - |
3105 | -Special cases |
3106 | -------------- |
3107 | - |
3108 | -This section contains examples that may introduce challenges for persistent |
3109 | -modules or that might motivate or highlight issues described above, |
3110 | - |
3111 | -- Persistent classes |
3112 | - |
3113 | - Persistent classes include data that are not represented by the class |
3114 | - sources. A class caches slot definitions inherited from base classes. This |
3115 | - is information that is only indirectly represented by it's source. |
3116 | - Similarly, a class manages a collection of it's subclasses. This allows a |
3117 | - class to invalidate cached slots in subclasses when a new slot definition is |
3118 | - assigned (via a setattr). The cached slots and collection of subclasses is |
3119 | - not part of a persistent class' state. It isn't saved in the database, but |
3120 | - is recomputed when the class is loaded into memory or when it's subclasses |
3121 | - are loaded into memory. |
3122 | - |
3123 | - Consider two persistent modules, M1, which defines class C1, and M2, which |
3124 | - defines class C2. C2 subclasses C1. C1 defines a __getitem__ slot, which |
3125 | - is inherited and cached by C2. |
3126 | - |
3127 | - Suppose we have a process, P1, which has M1 and M2 in memory. C2 in P1 has |
3128 | - a (cached) __getitem__ slot filled with the definition inherited from C1 in |
3129 | - P1. C1 in P1 has C2 in it's collection of subclasses. In P1, we modify M1, |
3130 | - by editing and recompiling its source. When we recompile M1's source, we'll |
3131 | - update the state of C1 by calling it's __setstate__ method, passing the new |
3132 | - class dictionary. The __setstate__ method will, in turn, use setattr to |
3133 | - assign the values from the new dictionary. If we set a slot attribute, the |
3134 | - __setattribute__ method in C1 will notify each of it's subclasses that the |
3135 | - slot has changed. Now, suppose that we've added a __len__ slot definition |
3136 | - when we modified the source. When we set the __len__ attribute in C1, C2 |
3137 | - will be notified that there is a new slot definition for __len__. |
3138 | - |
3139 | - Suppose we have a process P2, which also has M1 and M2 loaded into memory. |
3140 | - As in P1, C2 in P2 caches the __getitem__ slot and C1 in P2 has C2 in P2 in |
3141 | - it's collection of subclasses. Now, when M1 in P1 is modified and the |
3142 | - corresponding transaction is committed, an invalidation for M1 and all of |
3143 | - the persistent objects it defines, including C1, is sent to all other |
3144 | - processes. When P2 gets the invalidation for C1, it invalidates C1. It |
3145 | - happens that persistent classes are not allowed to be ghosts. When a |
3146 | - persistent class is invalidated, it immediately reloads it's state, rather |
3147 | - than converting itself into a ghost. When C2's state is reloaded in P2, we |
3148 | - assign it's attributes from the new class dictionary. When we assign slots, |
3149 | - we notify it's subclasses, including C2 in P2. |
3150 | - |
3151 | - Suppose we have a process P3, that only has M1 in memory. In P3, M2 is not |
3152 | - in memory, nor are any of it's subobjects. In P3, C2 is not in the |
3153 | - collection of subclasses of C1, because C2 is not in memory and the |
3154 | - collection of subclasses is volatile data for C1. When we modify C1 in P1 |
3155 | - and commit the transaction, the state of C1 in P3 will be updated, but the |
3156 | - state of C2 is not affected in P3, because it's not in memory. |
3157 | - |
3158 | - Finally, consider a process, P4 that has M2, but not M1 in memory. M2 is |
3159 | - not a ghost, so C2 is in memory. Now, since C2 is in memory, C1 must be in |
3160 | - memory, even though M1 is not in memory, because C2 has a reference to C1. |
3161 | - Further, C1 cannot be a ghost, because persistent classes are not allowed to |
3162 | - be ghosts. When we commit the transation in P1 that updates M1, an |
3163 | - invalidation for C1 is sent to P4 and C1 is updated. When C1 is updated, |
3164 | - it's subclasses (in P4), including C2 are notified, so that their cached |
3165 | - slot definitions are updated. |
3166 | - |
3167 | - When we modify M1, all copies in memory of C1 and C2 are updated properly, |
3168 | - even though the data they cache is not cached persistently. This works, and |
3169 | - only works, because persistent classes are never ghosts. If a class could |
3170 | - be a ghost, then invalidating it would have not effect and non-ghost |
3171 | - dependent classes would not be updated. |
3172 | - |
3173 | -- Persistent interfaces |
3174 | - |
3175 | - Like classes, Zope interfaces cache certain information. An interface |
3176 | - maintains a set of all of the interfaces that it extends. In addition, |
3177 | - interfaces maintain a collection of all of their sub-interfaces. The |
3178 | - collection of subinterfaces is used to notify sub=interfaces when an |
3179 | - interface changes. |
3180 | - |
3181 | - (Interfaces are a special case of a more general class of objects, called |
3182 | - "specifications", that include both interfaces and interface declareations. |
3183 | - Similar caching is performed for other specifications and related data |
3184 | - structures. To simplify the discussion, however, we'll limit ourselves to |
3185 | - interfaces.) |
3186 | - |
3187 | - When designing persistent interfaces, we have alternative approaches to |
3188 | - consider: |
3189 | - |
3190 | - A. We could take the same approach as that taken with persistent classes. |
3191 | - We would not save cached data persistently. We would compute it as |
3192 | - objects are moved into memory. |
3193 | - |
3194 | - To take this approach, we'd need to also make persistent interfaces |
3195 | - non-ghostifiable. This is necessary to properly propigate object |
3196 | - changes. |
3197 | - |
3198 | - One could argue that non-ghostifiability if classes is a necessary wart |
3199 | - forced on us by details of Python classes that are beyond our control, |
3200 | - and that we should avoid creating new kinds of objects that require |
3201 | - non-ghostifiability. |
3202 | - |
3203 | - B. We could store the cached data persistently. For example, we could store |
3204 | - the set of extended interfaces and the set of subinterfaces in persistent |
3205 | - dictionaries. |
3206 | - |
3207 | - A significant disadvantage of this approach is that persistent interfaces |
3208 | - would accumulate state is that not refelcted in their source code, |
3209 | - however, it's worth noting that, while the dependency and cache data |
3210 | - cannot be derived from a single module source, it *can* be derived from |
3211 | - the sources of all of the modules in the system. We can implement |
3212 | - persistent interface in such a way that execution of module code causes |
3213 | - all dependcies among module-defined interfaces to be recomputed |
3214 | - correctly. |
3215 | - |
3216 | - (This is, to me, Jim, an interesting case: state that can be computed |
3217 | - during deserialization from other serialized state. This should not be |
3218 | - surprising, as we are essentially talking about cached data used for |
3219 | - optimization purposes.) |
3220 | - |
3221 | -Proposals |
3222 | ---------- |
3223 | - |
3224 | -- A module's state must be reprersented, directly or indirectly, by it's |
3225 | - source. The state may also include information, such as caching data, that |
3226 | - is derivable from it's source-represented state. |
3227 | - |
3228 | - It is unclear if or how we will enforce this. Perhaps it will be just a |
3229 | - guideline. The module-synchronization adapters used in Zope will only |
3230 | - synchronize the module source. If a module defines state that is not |
3231 | - represented by or derivable from it's source, then that data will be lost in |
3232 | - synchronization. Of course, applications that don't use the synchronization |
3233 | - framework would be unaffected by this limitation. Alternatively, one could |
3234 | - develop custom module-synchronization adapters that handled extra module |
3235 | - data, however, development of such adapters will be outside the scope of the |
3236 | - Zope project. |
3237 | - |
3238 | -Notes |
3239 | ------ |
3240 | - |
3241 | -- When we invalidate a persistent class, we need to delete all of the |
3242 | - attributes defined by it's old dictionary that are not defined by the new |
3243 | - class dictionary. |
3244 | - |
3245 | |
3246 | === removed file 'src/zodbcode/patch.py' |
3247 | --- src/zodbcode/patch.py 2009-04-23 15:12:18 +0000 |
3248 | +++ src/zodbcode/patch.py 1970-01-01 00:00:00 +0000 |
3249 | @@ -1,468 +0,0 @@ |
3250 | -############################################################################## |
3251 | -# |
3252 | -# Copyright (c) 2002 Zope Corporation and Contributors. |
3253 | -# All Rights Reserved. |
3254 | -# |
3255 | -# This software is subject to the provisions of the Zope Public License, |
3256 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
3257 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
3258 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
3259 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
3260 | -# FOR A PARTICULAR PURPOSE. |
3261 | -# |
3262 | -############################################################################## |
3263 | -"""Patch references to auto-persistent objects in a module. |
3264 | - |
3265 | -When a persistent module is compiled, all classes and functions should |
3266 | -be converted to persistent classes and functions. When a module is |
3267 | -updated, it is compiled and its persistent functions and classes are |
3268 | -updated in place so that clients of the module see the update. |
3269 | - |
3270 | -The specific semantics of the convert and update-in-place operations |
3271 | -are still being determined. Here are some rough notes: |
3272 | - |
3273 | -- Classes and functions are not converted in place. New objects are |
3274 | - created to replace the builtin functions and classes. |
3275 | - |
3276 | -- Every function object is converted to a PersistentFunction. |
3277 | - |
3278 | -- Every class is converted to a new class that is created by calling |
3279 | - the PersistentClassMetaClass with the name, bases, and dict of the |
3280 | - class being converted. |
3281 | - |
3282 | -- The conversion operation must preserve object identity. If an |
3283 | - object created by a def or class statement is referenced elsewhere |
3284 | - in the module, all references must be replaced with references to |
3285 | - the converted object. |
3286 | - |
3287 | -Implementation notes |
3288 | --------------------- |
3289 | - |
3290 | -The conversion operation is implemented using a pickler. It wasn't |
3291 | -possible to use the copy module, because it isn't possible to extend |
3292 | -the copy module in a safe way. The copy module depends on module globals. |
3293 | - |
3294 | -The pickler uses a Wrapper object that creates the appropriate new |
3295 | -object or updates an old one when it is unpickled. The wrapper also |
3296 | -causes parts of the wrapped object's state to be traversed by the |
3297 | -pickler, for example the func_defaults of a function object. This |
3298 | -traversal is necessary because references to convertable objects could |
3299 | -be contained in the state and must be updated to refer to the new |
3300 | -objects. |
3301 | - |
3302 | -What semantics do we want for update-in-place in the presence of aliases? |
3303 | - |
3304 | -Semantics based on per-namespace updates don't work in the presence of |
3305 | -aliases. If an update changes an alias, then the old binding will be |
3306 | -updated with the state of the new binding. |
3307 | - |
3308 | -Semantics based on containing namespaces seem to work. The outermost |
3309 | -namespace that contains a name is updated in place. Aliases are |
3310 | -simple rebinding operations that do not update in place. |
3311 | - |
3312 | -The containment approach seems to have a problem with bound methods, |
3313 | -where an instance can stash a copy of a bound method created via an |
3314 | -alias. When the class is updated, the alias changes, but the bound |
3315 | -method isn't. Then the bound method can invoke an old method on a new |
3316 | -object, which may not be legal. It might sufficient to outlaw this case. |
3317 | - |
3318 | -Open issues |
3319 | ------------ |
3320 | - |
3321 | -Can we handle metaclasses within this framework? That is, what if an |
3322 | -object's type is not type, but a subclass of type. |
3323 | - |
3324 | -How do we handle things like staticmethods? We'd like the code to be |
3325 | -able to use them, but Python doesn't expose an introspection on them. |
3326 | - |
3327 | -What if the same object is bound to two different names in the same |
3328 | -namespace? For example:: |
3329 | - |
3330 | - x = lambda: 1 |
3331 | - y = x |
3332 | - |
3333 | -If the module is updated to:: |
3334 | - |
3335 | - x = lambda: 1 |
3336 | - y = lambda: 2 |
3337 | - |
3338 | -What are the desired semantics? |
3339 | -""" |
3340 | - |
3341 | -__metaclass__ = type |
3342 | - |
3343 | -from copy_reg import dispatch_table |
3344 | -from cStringIO import StringIO |
3345 | -import pickle |
3346 | -import sys |
3347 | -from types import * |
3348 | - |
3349 | -from zodbcode.class_ import PersistentClassMetaClass, PersistentDescriptor |
3350 | -from zodbcode.function import PersistentFunction |
3351 | - |
3352 | -class Wrapper: |
3353 | - """Implement pickling reduce protocol for update-able object. |
3354 | - |
3355 | - The Pickler creates a Wrapper instance and uses it as the reduce |
3356 | - function. The Unpickler calls the instance to recreate the |
3357 | - object. |
3358 | - """ |
3359 | - __safe_for_unpickling__ = True |
3360 | - |
3361 | - def __init__(self, obj, module, replace=None): |
3362 | - self._obj = obj |
3363 | - self._module = module |
3364 | - self._replace = replace |
3365 | - |
3366 | - def __call__(self, *args): |
3367 | - new = self.unwrap(*args) |
3368 | - if self._replace is not None: |
3369 | - # XXX Hack: Use _p_newstate for persistent classes, because |
3370 | - # a persistent class's persistent state is a fairly limited |
3371 | - # subset of the dict and we really want to replace everything. |
3372 | - if hasattr(self._replace, "_p_newstate"): |
3373 | - self._replace._p_newstate(new) |
3374 | - else: |
3375 | - self._replace.__setstate__(new.__getstate__()) |
3376 | - return self._replace |
3377 | - else: |
3378 | - return new |
3379 | - |
3380 | -class FunctionWrapper(Wrapper): |
3381 | - |
3382 | - def unwrap(self, defaults, dict): |
3383 | - self._obj.func_defaults = defaults |
3384 | - self._obj.func_dict.update(dict) |
3385 | - return PersistentFunction(self._obj, self._module) |
3386 | - |
3387 | -class TypeWrapper(Wrapper): |
3388 | - |
3389 | - def unwrap(self, bases, dict): |
3390 | - return PersistentClassMetaClass(self._obj.__name__, bases, dict) |
3391 | - |
3392 | -def registerWrapper(atype, wrapper, unwrap_args, getstate=None): |
3393 | - """Register a patch wrapper for an external object type.""" |
3394 | - Pickler.dispatch[atype] = Pickler.save_external |
3395 | - Pickler.external[atype] = wrapper, unwrap_args, getstate |
3396 | - |
3397 | -marker = object() |
3398 | - |
3399 | -_module_cache = {} |
3400 | - |
3401 | -def whichmodule(func, funcname): |
3402 | - """Return a likely candidate for the module that defines obj, |
3403 | - where context is the name of the module in which obj was found. |
3404 | - |
3405 | - Use a trick suggested by Guido to make sure we found the right |
3406 | - module: Compare the function's globals with the module's globals. |
3407 | - You've found the right module only when they match. |
3408 | - """ |
3409 | - mod = getattr(func, "__module__", None) |
3410 | - if mod is not None: |
3411 | - return mod |
3412 | - mod = _module_cache.get(func) |
3413 | - if mod is not None: |
3414 | - return mod |
3415 | - for name, module in sys.modules.items(): |
3416 | - if module is None: |
3417 | - continue # skip dummy package entries |
3418 | - if getattr(module, funcname, None) is func: |
3419 | - if module.__dict__ is func.func_globals: |
3420 | - break |
3421 | - else: |
3422 | - name = '__main__' |
3423 | - _module_cache[func] = name |
3424 | - return name |
3425 | - |
3426 | - |
3427 | -class Pickler(pickle.Pickler): |
3428 | - |
3429 | - dispatch = pickle.Pickler.dispatch.copy() |
3430 | - |
3431 | - def __init__(self, file, module, memo, replacements): |
3432 | - # The pickler must be created in binary mode, because |
3433 | - # it pickles instances using the OBJ code. The text-mode |
3434 | - # pickler uses a different strategy that explicitly |
3435 | - # stores the name of the instance's class which defeats |
3436 | - # the desire to replace references to classes with |
3437 | - # persistent classes. |
3438 | - pickle.Pickler.__init__(self, file, protocol=1) |
3439 | - |
3440 | - self._pmemo = memo |
3441 | - self._wrapped = {} # set of objects already wrapped |
3442 | - self._module = module |
3443 | - self._module_name = module.__name__ |
3444 | - self._repl = replacements |
3445 | - self._builtins = module.__builtins__ |
3446 | - |
3447 | - def wrap(self, wrapperclass, obj): |
3448 | - return wrapperclass(obj, self._module, self._repl.get(id(obj))) |
3449 | - |
3450 | - def persistent_id(self, obj, force=False): |
3451 | - if (isinstance(obj, Wrapper) |
3452 | - or isinstance(obj, ModuleType) |
3453 | - or obj is self._builtins |
3454 | - or force): |
3455 | - oid = id(obj) |
3456 | - self._pmemo[oid] = obj |
3457 | - return oid |
3458 | - else: |
3459 | - # If the object is a real persistent object, patch it by |
3460 | - # persistent id, too. This case is specifically intended |
3461 | - # to catch persistent classes imported from other modules. |
3462 | - # They are classes, but can't be pickled as globals because |
3463 | - # pickle looks in sys.modules and the persistent import |
3464 | - # doesn't use sys.modules. |
3465 | - |
3466 | - # If we find a class, pickle it via save_type() |
3467 | - if isinstance(obj, PersistentClassMetaClass): |
3468 | - return None |
3469 | - |
3470 | - # XXX Is this safe in all cases? |
3471 | - oid = getattr(obj, "_p_oid", marker) |
3472 | - if oid is marker: |
3473 | - return None |
3474 | - elif oid is None: |
3475 | - # It's a persistent object, but it's newly created. |
3476 | - oid = object() |
3477 | - descr = getattr(oid, "__get__", None) |
3478 | - if descr is not None: |
3479 | - return None |
3480 | - self._pmemo[oid] = obj |
3481 | - return oid |
3482 | - |
3483 | - def save_type(self, atype): |
3484 | - if atype.__module__ == self._module_name: |
3485 | - self.save_reduce(self.wrap(TypeWrapper, atype), |
3486 | - (atype.__bases__, atype.__dict__), |
3487 | - obj=atype) |
3488 | - else: |
3489 | - if isinstance(atype, PersistentClassMetaClass): |
3490 | - self.save_pers(self.persistent_id(atype, True)) |
3491 | - else: |
3492 | - self.save_global(atype) |
3493 | - |
3494 | - dispatch[TypeType] = save_type |
3495 | - dispatch[ClassType] = save_type |
3496 | - dispatch[type] = save_type |
3497 | - dispatch[PersistentClassMetaClass] = save_type |
3498 | - |
3499 | - def save_function(self, func): |
3500 | - modname = whichmodule(func, func.__name__) |
3501 | - if modname == self._module_name or modname == "__main__": |
3502 | - self.save_reduce(self.wrap(FunctionWrapper, func), |
3503 | - (func.func_defaults, func.func_dict), |
3504 | - obj=func) |
3505 | - else: |
3506 | - self.save_global(func) |
3507 | - |
3508 | - dispatch[FunctionType] = save_function |
3509 | - |
3510 | - external = {} |
3511 | - |
3512 | - def save_external(self, obj): |
3513 | - # XXX Will this object always have an __module__? |
3514 | - if obj.__module__ == self._module_name: |
3515 | - # Save an external type registered through registerWrapper |
3516 | - objtype = type(obj) |
3517 | - wrapper, unwrap_args, getstate = self.external[objtype] |
3518 | - if getstate is not None: |
3519 | - self.save_reduce(self.wrap(wrapper, obj), unwrap_args(obj), |
3520 | - getstate(obj), |
3521 | - obj=obj) |
3522 | - else: |
3523 | - self.save_reduce(self.wrap(wrapper, obj), unwrap_args(obj), |
3524 | - obj=obj) |
3525 | - else: |
3526 | - # In general, we don't know how to pickle this object, |
3527 | - # so pickle it by reference to the original. |
3528 | - self.save_pers(self.persistent_id(obj, True)) |
3529 | - |
3530 | - # New-style classes don't have real dicts. They have dictproxies. |
3531 | - # There's no official way to spell the dictproxy type, so we have |
3532 | - # to get it by using type() on an example. |
3533 | - dispatch[type(Wrapper.__dict__)] = pickle.Pickler.save_dict |
3534 | - |
3535 | - def save(self, obj, ignore=None): |
3536 | - # Override the save() implementation from pickle.py, because |
3537 | - # we don't ever want to invoke __reduce__() on builtin types |
3538 | - # that aren't picklable. Instead, we'd like to pickle all of |
3539 | - # those objects using the persistent_id() mechanism. There's |
3540 | - # no need to cover every type with this pickler, because it |
3541 | - # isn't being used for persistent just to create a copy. |
3542 | - |
3543 | - # The ignored parameter is for compatible with Python 2.2, |
3544 | - # which has the old inst_persistent_id feature. |
3545 | - pid = self.persistent_id(obj) |
3546 | - if pid is not None: |
3547 | - self.save_pers(pid) |
3548 | - return |
3549 | - |
3550 | - d = id(obj) |
3551 | - t = type(obj) |
3552 | - if (t is TupleType) and (len(obj) == 0): |
3553 | - if self.bin: |
3554 | - self.save_empty_tuple(obj) |
3555 | - else: |
3556 | - self.save_tuple(obj) |
3557 | - return |
3558 | - |
3559 | - if d in self.memo: |
3560 | - self.write(self.get(self.memo[d][0])) |
3561 | - return |
3562 | - |
3563 | - try: |
3564 | - f = self.dispatch[t] |
3565 | - except KeyError: |
3566 | - try: |
3567 | - issc = issubclass(t, TypeType) |
3568 | - except TypeError: # t is not a class |
3569 | - issc = 0 |
3570 | - if issc: |
3571 | - self.save_global(obj) |
3572 | - return |
3573 | - |
3574 | - try: |
3575 | - reduce = dispatch_table[t] |
3576 | - except KeyError: |
3577 | - self.save_pers(self.persistent_id(obj, True)) |
3578 | - return |
3579 | - else: |
3580 | - tup = reduce(obj) |
3581 | - |
3582 | - if type(tup) is StringType: |
3583 | - self.save_global(obj, tup) |
3584 | - return |
3585 | - if type(tup) is not TupleType: |
3586 | - raise pickle.PicklingError("Value returned by %s must be a " |
3587 | - "tuple" % reduce) |
3588 | - |
3589 | - l = len(tup) |
3590 | - if (l != 2) and (l != 3): |
3591 | - raise pickle.PicklingError("tuple returned by %s must " |
3592 | - "contain only two or three " |
3593 | - "elements" % reduce) |
3594 | - |
3595 | - callable = tup[0] |
3596 | - arg_tup = tup[1] |
3597 | - if l > 2: |
3598 | - state = tup[2] |
3599 | - else: |
3600 | - state = None |
3601 | - |
3602 | - if type(arg_tup) is not TupleType and arg_tup is not None: |
3603 | - raise pickle.PicklingError("Second element of tuple " |
3604 | - "returned by %s must be a " |
3605 | - "tuple" % reduce) |
3606 | - |
3607 | - self.save_reduce(callable, arg_tup, state, obj=obj) |
3608 | - return |
3609 | - |
3610 | - f(self, obj) |
3611 | - |
3612 | - def save_reduce(self, callable, arg_tup, state = None, obj = None): |
3613 | - write = self.write |
3614 | - save = self.save |
3615 | - |
3616 | - save(callable) |
3617 | - save(arg_tup) |
3618 | - write(pickle.REDUCE) |
3619 | - |
3620 | - if obj is not None: |
3621 | - memo_len = len(self.memo) |
3622 | - self.write(self.put(memo_len)) |
3623 | - self.memo[id(obj)] = (memo_len, obj) |
3624 | - |
3625 | - if state is not None: |
3626 | - save(state) |
3627 | - write(pickle.BUILD) |
3628 | - |
3629 | -class Unpickler(pickle.Unpickler): |
3630 | - |
3631 | - def __init__(self, file, pmemo): |
3632 | - pickle.Unpickler.__init__(self, file) |
3633 | - self._pmemo = pmemo |
3634 | - |
3635 | - def persistent_load(self, oid): |
3636 | - return self._pmemo[oid] |
3637 | - |
3638 | -class NameFinder: |
3639 | - """Find a canonical name for each update-able object.""" |
3640 | - |
3641 | - # XXX should we try to handle descriptors? If it looks like a |
3642 | - # descriptor, try calling it and passing the class object? |
3643 | - |
3644 | - classTypes = { |
3645 | - TypeType: True, |
3646 | - ClassType: True, |
3647 | - PersistentClassMetaClass: True, |
3648 | - } |
3649 | - |
3650 | - types = { |
3651 | - FunctionType: True, |
3652 | - PersistentFunction: True, |
3653 | - PersistentDescriptor: True, |
3654 | - } |
3655 | - types.update(classTypes) |
3656 | - |
3657 | - def __init__(self, module): |
3658 | - self._names = {} # map object ids to (canonical name, obj) pairs |
3659 | - self.walkModule(module) |
3660 | - |
3661 | - def names(self): |
3662 | - return [n for n, o in self._names.itervalues()] |
3663 | - |
3664 | - def _walk(self, obj, name, fmt): |
3665 | - classes = [] |
3666 | - for k, v in obj.__dict__.items(): |
3667 | - aType = type(v) |
3668 | - anId = id(v) |
3669 | - if aType in self.types and not anId in self._names: |
3670 | - self._names[anId] = fmt % (name, k), v |
3671 | - if aType in self.classTypes: |
3672 | - classes.append((v, k)) |
3673 | - for _klass, _name in classes: |
3674 | - self.walkClass(_klass, fmt % (name, _name)) |
3675 | - |
3676 | - def walkModule(self, mod): |
3677 | - self._walk(mod, "", "%s%s") |
3678 | - |
3679 | - def walkClass(self, klass, name): |
3680 | - self._walk(klass, name, "%s.%s") |
3681 | - |
3682 | - def replacements(self, aFinder): |
3683 | - """Return a dictionary of replacements. |
3684 | - |
3685 | - self and aFinder are two NameFinder instances. Return a dict |
3686 | - of all the objects in the two that share the same name. The |
3687 | - keys are the ids in self and the values are the objects in |
3688 | - aFinder. |
3689 | - """ |
3690 | - temp = {} |
3691 | - result = {} |
3692 | - for anId, (name, obj) in self._names.iteritems(): |
3693 | - temp[name] = anId |
3694 | - for anId, (name, obj) in aFinder._names.iteritems(): |
3695 | - if name in temp: |
3696 | - result[temp[name]] = obj |
3697 | - return result |
3698 | - |
3699 | -def convert(module, replacements): |
3700 | - """Convert object to persistent objects in module. |
3701 | - |
3702 | - Use replacements dictionary to determine which objects to update |
3703 | - in place. |
3704 | - """ |
3705 | - f = StringIO() |
3706 | - memo = {} |
3707 | - p = Pickler(f, module, memo, replacements) |
3708 | - moddict = module.__dict__ |
3709 | - p.dump(moddict) |
3710 | - f.seek(0) |
3711 | - u = Unpickler(f, memo) |
3712 | - newdict = u.load() |
3713 | - module.__dict__.clear() |
3714 | - module.__dict__.update(newdict) |
3715 | - |
3716 | -if __name__ == "__main__": |
3717 | - pass |
3718 | |
3719 | === removed directory 'src/zodbcode/tests' |
3720 | === removed file 'src/zodbcode/tests/__init__.py' |
3721 | --- src/zodbcode/tests/__init__.py 2009-04-23 15:12:18 +0000 |
3722 | +++ src/zodbcode/tests/__init__.py 1970-01-01 00:00:00 +0000 |
3723 | @@ -1,2 +0,0 @@ |
3724 | -# |
3725 | -# This file is necessary to make this directory a package. |
3726 | |
3727 | === removed file 'src/zodbcode/tests/_pmtest.py' |
3728 | --- src/zodbcode/tests/_pmtest.py 2009-04-23 15:12:18 +0000 |
3729 | +++ src/zodbcode/tests/_pmtest.py 1970-01-01 00:00:00 +0000 |
3730 | @@ -1,25 +0,0 @@ |
3731 | -############################################################################## |
3732 | -# |
3733 | -# Copyright (c) 2003 Zope Corporation and Contributors. |
3734 | -# All Rights Reserved. |
3735 | -# |
3736 | -# This software is subject to the provisions of the Zope Public License, |
3737 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
3738 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
3739 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
3740 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
3741 | -# FOR A PARTICULAR PURPOSE. |
3742 | -# |
3743 | -############################################################################## |
3744 | -"""A simple module""" |
3745 | - |
3746 | -# XXX why aren't modules pickleable? |
3747 | -# import os |
3748 | -# from xml import sax |
3749 | - |
3750 | -a = 1 |
3751 | -b = 2 |
3752 | -c = 3 |
3753 | - |
3754 | -def f(x): |
3755 | - return a * x ** 2 + b * x + c |
3756 | |
3757 | === removed file 'src/zodbcode/tests/atestmodule.py' |
3758 | --- src/zodbcode/tests/atestmodule.py 2009-04-23 15:12:18 +0000 |
3759 | +++ src/zodbcode/tests/atestmodule.py 1970-01-01 00:00:00 +0000 |
3760 | @@ -1,53 +0,0 @@ |
3761 | -############################################################################## |
3762 | -# |
3763 | -# Copyright (c) 2003 Zope Corporation and Contributors. |
3764 | -# All Rights Reserved. |
3765 | -# |
3766 | -# This software is subject to the provisions of the Zope Public License, |
3767 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
3768 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
3769 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
3770 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
3771 | -# FOR A PARTICULAR PURPOSE. |
3772 | -# |
3773 | -############################################################################## |
3774 | -"""A module used to test persistent module patching.""" |
3775 | - |
3776 | -from ZODB.utils import * |
3777 | - |
3778 | -def aFunc(): |
3779 | - def nestedFunc(): |
3780 | - return aFunc |
3781 | - return 1 |
3782 | - |
3783 | -class Foo(object): |
3784 | - def meth(self): |
3785 | - return 0 |
3786 | - |
3787 | - class Nested(object): |
3788 | - def bar(self): |
3789 | - return 1 |
3790 | - |
3791 | -# put aFunc inside a function to be sure it is found |
3792 | -foo = (aFunc,) |
3793 | - |
3794 | -class Bar: |
3795 | - def bar(self, x): |
3796 | - return 2 * x |
3797 | - |
3798 | - static = staticmethod(aFunc) |
3799 | - alias = aFunc |
3800 | - |
3801 | - classbar = classmethod(bar) |
3802 | - |
3803 | -class Sub(Bar): |
3804 | - pass |
3805 | - |
3806 | -def anotherFunc(): |
3807 | - class NotFound: |
3808 | - pass |
3809 | - |
3810 | - |
3811 | -# import a module that won't be imported by something else: |
3812 | -from zodbcode.tests import tobeimportedbyatestmodule |
3813 | - |
3814 | |
3815 | === removed file 'src/zodbcode/tests/test_class.py' |
3816 | --- src/zodbcode/tests/test_class.py 2009-04-23 15:12:18 +0000 |
3817 | +++ src/zodbcode/tests/test_class.py 1970-01-01 00:00:00 +0000 |
3818 | @@ -1,215 +0,0 @@ |
3819 | -############################################################################## |
3820 | -# |
3821 | -# Copyright (c) 2002 Zope Corporation and Contributors. |
3822 | -# All Rights Reserved. |
3823 | -# |
3824 | -# This software is subject to the provisions of the Zope Public License, |
3825 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
3826 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
3827 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
3828 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
3829 | -# FOR A PARTICULAR PURPOSE. |
3830 | -# |
3831 | -############################################################################## |
3832 | -import unittest |
3833 | - |
3834 | -from zodbcode.tests.test_module import TestBase |
3835 | - |
3836 | -import transaction |
3837 | -from persistent.cPersistence import CHANGED, UPTODATE |
3838 | - |
3839 | -class TestClass(TestBase): |
3840 | - |
3841 | - # TODO |
3842 | - # test classes with getstate and setstate |
3843 | - # make sure class invalidation works correctly |
3844 | - |
3845 | - class_with_init = """class Foo: |
3846 | - def __init__(self, arg): |
3847 | - self.var = arg""" "\n" |
3848 | - |
3849 | - def _load_path(self, path): |
3850 | - # Load an object from a new connection given a database path. |
3851 | - tm = transaction.TransactionManager() |
3852 | - root = self.db.open(transaction_manager=tm).root() |
3853 | - obj = root |
3854 | - for part in path.split("."): |
3855 | - try: |
3856 | - obj = obj[part] |
3857 | - except TypeError: |
3858 | - obj = getattr(obj, part) |
3859 | - return obj |
3860 | - |
3861 | - def _load_name(self, name): |
3862 | - # Load a class from a new connection given a dotted name |
3863 | - i = name.rfind(".") |
3864 | - module = name[:i] |
3865 | - klass = name[i+1:] |
3866 | - # The following depends entirely on the internals of the |
3867 | - # implementation. |
3868 | - return self._load_path("registry._mgrs.%s._module.%s" |
3869 | - % (module, klass)) |
3870 | - |
3871 | - def testClassWithInit(self): |
3872 | - self.registry.newModule("testclass", self.class_with_init) |
3873 | - transaction.commit() |
3874 | - import testclass |
3875 | - x = testclass.Foo(12) |
3876 | - self.assertEqual(x.var, 12) |
3877 | - |
3878 | - Foo2 = self._load_name("testclass.Foo") |
3879 | - y = Foo2(12) |
3880 | - self.assertEqual(y.var, 12) |
3881 | - |
3882 | - class_and_instance = """class Foo: |
3883 | - def __init__(self, arg): |
3884 | - self.var = arg |
3885 | - |
3886 | - # The class must have a getinitargs because the instance |
3887 | - # will be pickled during module conversion. |
3888 | - |
3889 | - def __getinitargs__(self): |
3890 | - return self.var, |
3891 | - |
3892 | -y = Foo(11) |
3893 | -x = Foo(12)""" "\n" |
3894 | - |
3895 | - def testClassAndInstance(self): |
3896 | - self.registry.newModule("testclass", self.class_and_instance) |
3897 | - transaction.commit() |
3898 | - import testclass |
3899 | - self.assertEqual(testclass.x.var, 12) |
3900 | - |
3901 | - Foo2 = self._load_name("testclass.Foo") |
3902 | - self.assertEqual(Foo2(12).var, 12) |
3903 | - x = self._load_name("testclass.x") |
3904 | - self.assertEqual(x.var, 12) |
3905 | - y = self._load_name("testclass.y") |
3906 | - self.assertEqual(y.var, 11) |
3907 | - |
3908 | - self.assert_(not hasattr(x, "_p_oid")) |
3909 | - self.assert_(not hasattr(y, "_p_oid")) |
3910 | - x._p_oid = 1234 |
3911 | - y._p_oid = 4321 |
3912 | - |
3913 | - class_interface = """class Foo: |
3914 | - __implements__ = 1""" + "\n" |
3915 | - |
3916 | - def testClassInterface(self): |
3917 | - # this doesn't do a proper zope interface, but we're really |
3918 | - # only concerned about handling of the __implements__ attribute. |
3919 | - self.registry.newModule("testclass", self.class_interface) |
3920 | - transaction.commit() |
3921 | - import testclass |
3922 | - obj = testclass.Foo() |
3923 | - self.assertEqual(obj.__implements__, 1) |
3924 | - |
3925 | - cross_module_import = "from testclass import Foo" |
3926 | - |
3927 | - def testCrossModuleImport(self): |
3928 | - self.registry.newModule("testclass", self.class_with_init) |
3929 | - transaction.commit() |
3930 | - self.registry.newModule("another", self.cross_module_import) |
3931 | - transaction.commit() |
3932 | - |
3933 | - update_in_place1 = """class Foo: |
3934 | - def meth(self, arg): |
3935 | - return arg * 3""" "\n" |
3936 | - |
3937 | - update_in_place2 = """class Foo: |
3938 | - def meth(self, arg): |
3939 | - return arg + 3""" "\n" |
3940 | - |
3941 | - def testUpdateInPlace(self): |
3942 | - self.registry.newModule("testclass", self.update_in_place1) |
3943 | - transaction.commit() |
3944 | - import testclass |
3945 | - inst = testclass.Foo() |
3946 | - self.assertEqual(inst.meth(4), 12) |
3947 | - |
3948 | - Foo2 = self._load_name("testclass.Foo") |
3949 | - inst2 = Foo2() |
3950 | - self.assertEqual(inst2.meth(4), 12) |
3951 | - |
3952 | - self.registry.updateModule("testclass", self.update_in_place2) |
3953 | - transaction.commit() |
3954 | - self.assertEqual(inst.meth(4), 7) |
3955 | - |
3956 | - # The old instance's connection hasn't processed the |
3957 | - # invalidation yet. |
3958 | - self.assertEqual(inst2.meth(4), 12) |
3959 | - self.assertEqual(Foo2().meth(4), 12) |
3960 | - inst2.__class__._p_jar.sync() |
3961 | - self.assertEqual(inst2.meth(4), 7) |
3962 | - self.assertEqual(Foo2().meth(4), 7) |
3963 | - |
3964 | - parent1 = """class Foo(object): |
3965 | - def meth(self, arg): |
3966 | - return arg * 2""" "\n" |
3967 | - |
3968 | - parent2 = """class Foo(object): |
3969 | - def meth(self, arg): |
3970 | - return arg // 2""" "\n" |
3971 | - |
3972 | - child = """import parent |
3973 | - |
3974 | -class Bar(parent.Foo): |
3975 | - def meth(self, arg): |
3976 | - return super(Bar, self).meth(arg) + 5""" "\n" |
3977 | - |
3978 | - def testInheritanceAcrossModules(self): |
3979 | - self.registry.newModule("parent", self.parent1) |
3980 | - self.registry.newModule("child", self.child) |
3981 | - transaction.commit() |
3982 | - import child |
3983 | - self.assertEqual(child.Bar().meth(3), 3*2+5) |
3984 | - self.registry.updateModule("parent", self.parent2) |
3985 | - transaction.commit() |
3986 | - self.assertEqual(child.Bar().meth(3), 3//2+5) |
3987 | - |
3988 | - Bar = self._load_name("child.Bar") |
3989 | - self.assertEqual(Bar().meth(3), 3//2+5) |
3990 | - |
3991 | - persist = """from persistent import Persistent |
3992 | -class Foo(Persistent): |
3993 | - pass""" "\n" |
3994 | - |
3995 | - def testPersistentSubclass(self): |
3996 | - self.registry.newModule("persist", self.persist) |
3997 | - transaction.commit() |
3998 | - import persist |
3999 | - # Verify that the instances are persistent and that the |
4000 | - # _p_ namespace is separate. |
4001 | - obj = persist.Foo() |
4002 | - foo_oid = persist.Foo._p_oid |
4003 | - self.assertEqual(obj._p_oid, None) |
4004 | - obj._p_oid = 1 |
4005 | - self.assertEqual(obj._p_oid, 1) |
4006 | - self.assertEqual(persist.Foo._p_oid, foo_oid) |
4007 | - |
4008 | - save_persist = """from persist import Foo |
4009 | -x = Foo() |
4010 | -""" |
4011 | - |
4012 | - def testSavePersistentSubclass(self): |
4013 | - self.registry.newModule("persist", self.persist) |
4014 | - transaction.commit() |
4015 | - import persist |
4016 | - self.registry.newModule("save_persist", self.save_persist) |
4017 | - transaction.commit() |
4018 | - import save_persist |
4019 | - |
4020 | - def XXXtestUpdateClassAttribute(self): |
4021 | - self.registry.newModule("parent", self.parent1) |
4022 | - transaction.commit() |
4023 | - import parent |
4024 | - parent.Foo.attr = 2 |
4025 | - self.assertEqual(parent.Foo._p_state, CHANGED) |
4026 | - transaction.commit() |
4027 | - self.assertEqual(parent.Foo._p_state, UPTODATE) |
4028 | - |
4029 | - Foo = self._load_name("parent.Foo") |
4030 | - self.assertEqual(Foo.attr, 2) |
4031 | - |
4032 | -def test_suite(): |
4033 | - return unittest.makeSuite(TestClass) |
4034 | |
4035 | === removed file 'src/zodbcode/tests/test_module.py' |
4036 | --- src/zodbcode/tests/test_module.py 2009-04-23 15:12:18 +0000 |
4037 | +++ src/zodbcode/tests/test_module.py 1970-01-01 00:00:00 +0000 |
4038 | @@ -1,444 +0,0 @@ |
4039 | -############################################################################## |
4040 | -# |
4041 | -# Copyright (c) 2002 Zope Corporation and Contributors. |
4042 | -# All Rights Reserved. |
4043 | -# |
4044 | -# This software is subject to the provisions of the Zope Public License, |
4045 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
4046 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
4047 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
4048 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
4049 | -# FOR A PARTICULAR PURPOSE. |
4050 | -# |
4051 | -############################################################################## |
4052 | -import os |
4053 | -import pickle |
4054 | -import unittest |
4055 | - |
4056 | -from persistent.dict import PersistentDict |
4057 | -from persistent import UPTODATE |
4058 | -import transaction |
4059 | - |
4060 | -import ZODB.tests.util |
4061 | -from zodbcode import tests # import this package, to get at __file__ reliably |
4062 | -from zodbcode.module \ |
4063 | - import ManagedRegistry, PersistentModuleImporter, PersistentPackage |
4064 | - |
4065 | -# snippets of source code used by testModules |
4066 | -foo_src = """\ |
4067 | -import string |
4068 | -x = 1 |
4069 | -def f(y): |
4070 | - return x + y |
4071 | -""" |
4072 | -quux_src = """\ |
4073 | -from foo import x |
4074 | -def f(y): |
4075 | - return x + y |
4076 | -""" |
4077 | -side_effect_src = """\ |
4078 | -x = 1 |
4079 | -def inc(): |
4080 | - global x |
4081 | - x += 1 |
4082 | - return x |
4083 | -""" |
4084 | -builtin_src = """\ |
4085 | -x = 1, 2, 3 |
4086 | -def f(): |
4087 | - return len(x) |
4088 | -""" |
4089 | -nested_src = """\ |
4090 | -def f(x): |
4091 | - def g(y): |
4092 | - def z(z): |
4093 | - return x + y + z |
4094 | - return x + y |
4095 | - return g |
4096 | -""" |
4097 | - |
4098 | -nested_err_src = nested_src + """\ |
4099 | -g = f(3) |
4100 | -""" |
4101 | - |
4102 | -closure_src = """\ |
4103 | -def f(x): |
4104 | - def g(y): |
4105 | - return x + y |
4106 | - return g |
4107 | - |
4108 | -inc = f(1) |
4109 | -""" |
4110 | - |
4111 | -class TestPersistentModuleImporter(PersistentModuleImporter): |
4112 | - |
4113 | - def __init__(self, registry): |
4114 | - self._registry = registry |
4115 | - self._registry._p_activate() |
4116 | - |
4117 | - def __import__(self, name, globals={}, locals={}, fromlist=[]): |
4118 | - mod = self._import(self._registry, name, self._get_parent(globals), |
4119 | - fromlist) |
4120 | - if mod is not None: |
4121 | - return mod |
4122 | - return self._saved_import(name, globals, locals, fromlist) |
4123 | - |
4124 | -class TestBase(unittest.TestCase): |
4125 | - |
4126 | - def setUp(self): |
4127 | - self.db = ZODB.tests.util.DB() |
4128 | - self.root = self.db.open().root() |
4129 | - self.registry = ManagedRegistry() |
4130 | - self.importer = TestPersistentModuleImporter(self.registry) |
4131 | - self.importer.install() |
4132 | - self.root["registry"] = self.registry |
4133 | - transaction.commit() |
4134 | - _dir, _file = os.path.split(tests.__file__) |
4135 | - self._pmtest = os.path.join(_dir, "_pmtest.py") |
4136 | - |
4137 | - def tearDown(self): |
4138 | - # just in case |
4139 | - transaction.abort() |
4140 | - self.db.close() |
4141 | - self.importer.uninstall() |
4142 | - |
4143 | - def sameModules(self, registry): |
4144 | - m1 = self.registry.modules() |
4145 | - m1.sort() |
4146 | - m2 = registry.modules() |
4147 | - m2.sort() |
4148 | - self.assertEqual(m1, m2) |
4149 | - |
4150 | - def useNewConnection(self): |
4151 | - # load modules using a separate connection to test that |
4152 | - # modules can be recreated from the database |
4153 | - cn = self.db.open() |
4154 | - reg = cn.root()["registry"] |
4155 | - self.sameModules(reg) |
4156 | - for name in reg.modules(): |
4157 | - mod = reg.findModule(name) |
4158 | - mod._p_activate() |
4159 | - self.assertEqual(mod._p_state, UPTODATE) |
4160 | - for obj in mod.__dict__.values(): |
4161 | - if hasattr(obj, "_p_activate"): |
4162 | - obj._p_activate() |
4163 | - # XXX somehow objects are getting registered here, but not |
4164 | - # modified. need to figure out what is going wrong, but for |
4165 | - # now just abort the transaction. |
4166 | - ##assert not cn._registered |
4167 | - transaction.abort() |
4168 | - cn.close() |
4169 | - |
4170 | -class TestModule(TestBase): |
4171 | - |
4172 | - def testModule(self): |
4173 | - self.registry.newModule("pmtest", open(self._pmtest).read()) |
4174 | - transaction.commit() |
4175 | - self.assert_(self.registry.findModule("pmtest")) |
4176 | - import pmtest |
4177 | - pmtest._p_deactivate() |
4178 | - self.assertEqual(pmtest.a, 1) |
4179 | - pmtest.f(4) |
4180 | - self.useNewConnection() |
4181 | - |
4182 | - def testUpdateFunction(self): |
4183 | - self.registry.newModule("pmtest", "def f(x): return x") |
4184 | - transaction.commit() |
4185 | - import pmtest |
4186 | - self.assertEqual(pmtest.f(3), 3) |
4187 | - copy = pmtest.f |
4188 | - self.registry.updateModule("pmtest", "def f(x): return x + 1") |
4189 | - transaction.commit() |
4190 | - pmtest._p_deactivate() |
4191 | - self.assertEqual(pmtest.f(3), 4) |
4192 | - self.assertEqual(copy(3), 4) |
4193 | - self.useNewConnection() |
4194 | - |
4195 | - def testUpdateClass(self): |
4196 | - self.registry.newModule("pmtest", src) |
4197 | - transaction.commit() |
4198 | - import pmtest |
4199 | - inst = pmtest.Foo() |
4200 | - v0 = inst.x |
4201 | - v1 = inst.m() |
4202 | - v2 = inst.n() |
4203 | - self.assertEqual(v1 - 1, v2) |
4204 | - self.assertEqual(v0 + 1, v1) |
4205 | - self.registry.updateModule("pmtest", src2) |
4206 | - transaction.commit() |
4207 | - self.assertRaises(AttributeError, getattr, inst, "n") |
4208 | - self.useNewConnection() |
4209 | - |
4210 | - def testModules(self): |
4211 | - self.registry.newModule("foo", foo_src) |
4212 | - # quux has a copy of foo.x |
4213 | - self.registry.newModule("quux", quux_src) |
4214 | - # bar has a reference to foo |
4215 | - self.registry.newModule("bar", "import foo") |
4216 | - # baz has reference to f and copy of x, |
4217 | - # remember the the global x in f is looked up in foo |
4218 | - self.registry.newModule("baz", "from foo import *") |
4219 | - import foo, bar, baz, quux |
4220 | - self.assert_(foo._p_oid is None) |
4221 | - transaction.commit() |
4222 | - self.assert_(foo._p_oid) |
4223 | - self.assert_(bar._p_oid) |
4224 | - self.assert_(baz._p_oid) |
4225 | - self.assert_(quux._p_oid) |
4226 | - self.assertEqual(foo.f(4), 5) |
4227 | - self.assertEqual(bar.foo.f(4), 5) |
4228 | - self.assertEqual(baz.f(4), 5) |
4229 | - self.assertEqual(quux.f(4), 5) |
4230 | - self.assert_(foo.f is bar.foo.f) |
4231 | - self.assert_(foo.f is baz.f) |
4232 | - foo.x = 42 |
4233 | - self.assertEqual(quux.f(4), 5) |
4234 | - transaction.commit() |
4235 | - self.assertEqual(quux.f(4), 5) |
4236 | - foo._p_deactivate() |
4237 | - # foo is deactivated, which means its dict is empty when f() |
4238 | - # is activated, how do we guarantee that foo is also |
4239 | - # activated? |
4240 | - self.assertEqual(baz.f(4), 46) |
4241 | - self.assertEqual(bar.foo.f(4), 46) |
4242 | - self.assertEqual(foo.f(4), 46) |
4243 | - self.useNewConnection() |
4244 | - |
4245 | - def testFunctionAttrs(self): |
4246 | - self.registry.newModule("foo", foo_src) |
4247 | - import foo |
4248 | - A = foo.f.attr = "attr" |
4249 | - self.assertEqual(foo.f.attr, A) |
4250 | - transaction.commit() |
4251 | - self.assertEqual(foo.f.attr, A) |
4252 | - foo.f._p_deactivate() |
4253 | - self.assertEqual(foo.f.attr, A) |
4254 | - del foo.f.attr |
4255 | - self.assertRaises(AttributeError, getattr, foo.f, "attr") |
4256 | - foo.f.func_code |
4257 | - self.useNewConnection() |
4258 | - |
4259 | - def testFunctionSideEffects(self): |
4260 | - self.registry.newModule("effect", side_effect_src) |
4261 | - import effect |
4262 | - effect.inc() |
4263 | - transaction.commit() |
4264 | - effect.inc() |
4265 | - self.assert_(effect._p_changed) |
4266 | - self.useNewConnection() |
4267 | - |
4268 | - def testBuiltins(self): |
4269 | - self.registry.newModule("test", builtin_src) |
4270 | - transaction.commit() |
4271 | - import test |
4272 | - self.assertEqual(test.f(), len(test.x)) |
4273 | - test._p_deactivate() |
4274 | - self.assertEqual(test.f(), len(test.x)) |
4275 | - self.useNewConnection() |
4276 | - |
4277 | - def testNested(self): |
4278 | - self.assertRaises(TypeError, |
4279 | - self.registry.newModule, "nested", nested_err_src) |
4280 | - self.registry.newModule("nested", nested_src) |
4281 | - transaction.commit() |
4282 | - import nested |
4283 | - g = nested.f(3) |
4284 | - self.assertEqual(g(4), 7) |
4285 | - |
4286 | - def testLambda(self): |
4287 | - # test a lambda that contains another lambda as a default |
4288 | - self.registry.newModule("test", |
4289 | - "f = lambda x, y = lambda: 1: x + y()") |
4290 | - transaction.commit() |
4291 | - import test |
4292 | - self.assertEqual(test.f(1), 2) |
4293 | - self.useNewConnection() |
4294 | - |
4295 | - def testClass(self): |
4296 | - self.registry.newModule("foo", src) |
4297 | - transaction.commit() |
4298 | - import foo |
4299 | - obj = foo.Foo() |
4300 | - obj.m() |
4301 | - self.root["m"] = obj |
4302 | - transaction.commit() |
4303 | - foo._p_deactivate() |
4304 | - o = foo.Foo() |
4305 | - i = o.m() |
4306 | - j = o.m() |
4307 | - self.assertEqual(i + 1, j) |
4308 | - self.useNewConnection() |
4309 | - |
4310 | - def testPackage(self): |
4311 | - self.registry.newModule("A.B.C", "def f(x): return x") |
4312 | - transaction.commit() |
4313 | - |
4314 | - import A.B.C |
4315 | - self.assert_(isinstance(A, PersistentPackage)) |
4316 | - self.assertEqual(A.B.C.f("A"), "A") |
4317 | - |
4318 | - self.assertRaises(ValueError, self.registry.newModule, |
4319 | - "A.B", "def f(x): return x + 1") |
4320 | - |
4321 | - self.registry.newModule("A.B.D", "def f(x): return x") |
4322 | - transaction.commit() |
4323 | - |
4324 | - from A.B import D |
4325 | - self.assert_(hasattr(A.B.D, "f")) |
4326 | - self.useNewConnection() |
4327 | - |
4328 | - def testPackageInit(self): |
4329 | - self.registry.newModule("A.B.C", "def f(x): return x") |
4330 | - transaction.commit() |
4331 | - |
4332 | - import A.B.C |
4333 | - |
4334 | - self.registry.newModule("A.B.__init__", "x = 2") |
4335 | - transaction.commit() |
4336 | - |
4337 | - import A.B |
4338 | - self.assert_(hasattr(A.B, "C")) |
4339 | - self.assertEqual(A.B.x, 2) |
4340 | - |
4341 | - self.assertRaises(ValueError, self.registry.newModule, |
4342 | - "A.__init__.D", "x = 2") |
4343 | - self.useNewConnection() |
4344 | - |
4345 | - def testPackageRelativeImport(self): |
4346 | - self.registry.newModule("A.B.C", "def f(x): return x") |
4347 | - transaction.commit() |
4348 | - |
4349 | - self.registry.newModule("A.Q", "from B.C import f") |
4350 | - transaction.commit() |
4351 | - |
4352 | - import A.Q |
4353 | - self.assertEqual(A.B.C.f, A.Q.f) |
4354 | - |
4355 | - self.registry.updateModule("A.Q", "import B.C") |
4356 | - transaction.commit() |
4357 | - |
4358 | - self.assertEqual(A.B.C.f, A.Q.B.C.f) |
4359 | - |
4360 | - try: |
4361 | - import A.B.Q |
4362 | - except ImportError: |
4363 | - pass |
4364 | - self.useNewConnection() |
4365 | - |
4366 | - def testImportAll(self): |
4367 | - self.registry.newModule("A.B.C", |
4368 | - """__all__ = ["a", "b"]; a, b, c = 1, 2, 3""") |
4369 | - transaction.commit() |
4370 | - |
4371 | - d = {} |
4372 | - exec "from A.B.C import *" in d |
4373 | - self.assertEqual(d['a'], 1) |
4374 | - self.assertEqual(d['b'], 2) |
4375 | - self.assertRaises(KeyError, d.__getitem__, "c") |
4376 | - |
4377 | - self.registry.newModule("A.B.D", "from C import *") |
4378 | - transaction.commit() |
4379 | - |
4380 | - import A.B.D |
4381 | - self.assert_(hasattr(A.B.D, "a")) |
4382 | - self.assert_(hasattr(A.B.D, "b")) |
4383 | - self.assert_(not hasattr(A.B.D, "c")) |
4384 | - |
4385 | - self.registry.newModule("A.__init__", """__all__ = ["B", "F"]""") |
4386 | - transaction.commit() |
4387 | - |
4388 | - self.registry.newModule("A.F", "spam = 1") |
4389 | - transaction.commit() |
4390 | - |
4391 | - import A |
4392 | - self.assertEqual(A.F.spam, 1) |
4393 | - self.useNewConnection() |
4394 | - |
4395 | -class TestModuleReload(unittest.TestCase): |
4396 | - """Test reloading of modules""" |
4397 | - |
4398 | - def setUp(self): |
4399 | - self.db = ZODB.tests.util.DB() |
4400 | - self.open() |
4401 | - _dir, _file = os.path.split(tests.__file__) |
4402 | - self._pmtest = os.path.join(_dir, "_pmtest.py") |
4403 | - |
4404 | - def tearDown(self): |
4405 | - transaction.abort() |
4406 | - self.close() |
4407 | - self.db.close() |
4408 | - |
4409 | - def open(self): |
4410 | - # open a new db and importer from the storage |
4411 | - self.root = self.db.open().root() |
4412 | - self.registry = self.root.get("registry") |
4413 | - if self.registry is None: |
4414 | - self.root["registry"] = self.registry = ManagedRegistry() |
4415 | - self.importer = TestPersistentModuleImporter(self.registry) |
4416 | - self.importer.install() |
4417 | - transaction.commit() |
4418 | - |
4419 | - def close(self): |
4420 | - self.importer.uninstall() |
4421 | - self.root._p_jar.close() |
4422 | - |
4423 | - def testModuleReload(self): |
4424 | - self.registry.newModule("pmtest", open(self._pmtest).read()) |
4425 | - transaction.commit() |
4426 | - import pmtest |
4427 | - pmtest._p_deactivate() |
4428 | - self.assertEqual(pmtest.a, 1) |
4429 | - pmtest.f(4) |
4430 | - self.close() |
4431 | - pmtest._p_deactivate() |
4432 | - self.open() |
4433 | - del pmtest |
4434 | - import pmtest |
4435 | - |
4436 | - def testClassReload(self): |
4437 | - self.registry.newModule("foo", src) |
4438 | - transaction.commit() |
4439 | - import foo |
4440 | - obj = foo.Foo() |
4441 | - obj.m() |
4442 | - self.root["d"] = d = PersistentDict() |
4443 | - d["m"] = obj |
4444 | - transaction.commit() |
4445 | - self.close() |
4446 | - foo._p_deactivate() |
4447 | - self.open() |
4448 | - del foo |
4449 | - import foo |
4450 | - |
4451 | - def testModulePicklability(self): |
4452 | - from zodbcode.tests import test_module |
4453 | - s = pickle.dumps(test_module) |
4454 | - m = pickle.loads(s) |
4455 | - self.assertEqual(m, test_module) |
4456 | - |
4457 | -def test_suite(): |
4458 | - s = unittest.TestSuite() |
4459 | - for klass in TestModule, TestModuleReload: |
4460 | - s.addTest(unittest.makeSuite(klass)) |
4461 | - return s |
4462 | - |
4463 | -src = """\ |
4464 | -class Foo(object): |
4465 | - def __init__(self): |
4466 | - self.x = id(self) |
4467 | - def m(self): |
4468 | - self.x += 1 |
4469 | - return self.x |
4470 | - def n(self): |
4471 | - self.x -= 1 |
4472 | - return self.x |
4473 | -""" |
4474 | - |
4475 | -src2 = """\ |
4476 | -class Foo(object): |
4477 | - def __init__(self): |
4478 | - self.x = 0 |
4479 | - def m(self): |
4480 | - self.x += 10 |
4481 | - return self.x |
4482 | -""" |
4483 | |
4484 | === removed file 'src/zodbcode/tests/test_patch.py' |
4485 | --- src/zodbcode/tests/test_patch.py 2009-04-23 15:12:18 +0000 |
4486 | +++ src/zodbcode/tests/test_patch.py 1970-01-01 00:00:00 +0000 |
4487 | @@ -1,77 +0,0 @@ |
4488 | -############################################################################## |
4489 | -# |
4490 | -# Copyright (c) 2003 Zope Corporation and Contributors. |
4491 | -# All Rights Reserved. |
4492 | -# |
4493 | -# This software is subject to the provisions of the Zope Public License, |
4494 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
4495 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
4496 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
4497 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
4498 | -# FOR A PARTICULAR PURPOSE. |
4499 | -# |
4500 | -############################################################################## |
4501 | -from zodbcode.patch import NameFinder, convert |
4502 | -from zodbcode.tests import atestmodule |
4503 | - |
4504 | -import unittest |
4505 | -from types import FunctionType as function |
4506 | - |
4507 | -class TestNameFinder(unittest.TestCase): |
4508 | - |
4509 | - def testNameFinder(self): |
4510 | - nf = NameFinder(atestmodule) |
4511 | - names = nf.names() |
4512 | - for name in ("Foo", "Bar", "aFunc", "anotherFunc", |
4513 | - "Foo.meth", "Foo.Nested", "Bar.bar", |
4514 | - "Foo.Nested.bar"): |
4515 | - self.assert_(name in names) |
4516 | - for name in ("aFunc.nestedFunc", "anotherFunc.NotFound"): |
4517 | - self.assert_(name not in names) |
4518 | - |
4519 | -class TestPatch(unittest.TestCase): |
4520 | - |
4521 | - def setUp(self): |
4522 | - self.olddict = atestmodule.__dict__.copy() |
4523 | - |
4524 | - def tearDown(self): |
4525 | - atestmodule.__dict__.clear() |
4526 | - atestmodule.__dict__.update(self.olddict) |
4527 | - |
4528 | - def testPatch(self): |
4529 | - # verify obvious facts of object identity |
4530 | - self.assert_(atestmodule.Bar is atestmodule.Sub.__bases__[0]) |
4531 | - self.assert_(atestmodule.aFunc is atestmodule.foo[0]) |
4532 | - |
4533 | - moddict = self.olddict |
4534 | - convert(atestmodule, {}) |
4535 | - newdict = atestmodule.__dict__ |
4536 | - |
4537 | - L1 = moddict.keys() |
4538 | - L2 = newdict.keys() |
4539 | - L1.sort() |
4540 | - L2.sort() |
4541 | - self.assertEqual(L1, L2) |
4542 | - |
4543 | - self.assertEqual(atestmodule.__dict__, atestmodule.aFunc.func_globals) |
4544 | - |
4545 | - # make sure object identity is maintained by patch |
4546 | - Bar = newdict["Bar"] |
4547 | - Bar_as_base = newdict["Sub"].__bases__[0] |
4548 | - self.assert_(Bar is Bar_as_base) |
4549 | - |
4550 | - self.assert_(newdict["aFunc"] is newdict["foo"][0]) |
4551 | - |
4552 | - # The patch should not touch modules, functions, etc. that |
4553 | - # are imported from other modules. |
4554 | - import ZODB.utils |
4555 | - for name in ZODB.utils.__all__: |
4556 | - obj = getattr(ZODB.utils, name) |
4557 | - if isinstance(obj, type) or isinstance(obj, function): |
4558 | - self.assert_(obj is newdict[name]) |
4559 | - |
4560 | -def test_suite(): |
4561 | - s = unittest.TestSuite() |
4562 | - for c in TestNameFinder, TestPatch: |
4563 | - s.addTest(unittest.makeSuite(c)) |
4564 | - return s |
4565 | |
4566 | === removed file 'src/zodbcode/tests/tobeimportedbyatestmodule.py' |
4567 | --- src/zodbcode/tests/tobeimportedbyatestmodule.py 2009-04-23 15:12:18 +0000 |
4568 | +++ src/zodbcode/tests/tobeimportedbyatestmodule.py 1970-01-01 00:00:00 +0000 |
4569 | @@ -1,22 +0,0 @@ |
4570 | -############################################################################## |
4571 | -# |
4572 | -# Copyright (c) 2004 Zope Corporation and Contributors. |
4573 | -# All Rights Reserved. |
4574 | -# |
4575 | -# This software is subject to the provisions of the Zope Public License, |
4576 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
4577 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
4578 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
4579 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
4580 | -# FOR A PARTICULAR PURPOSE. |
4581 | -# |
4582 | -############################################################################## |
4583 | -"""This module exists soley to e imported by atestmodule |
4584 | - |
4585 | -$Id: tobeimportedbyatestmodule.py 25177 2004-06-02 13:17:31Z jim $ |
4586 | -""" |
4587 | - |
4588 | -x = 1 |
4589 | - |
4590 | -class C: |
4591 | - pass |
4592 | |
4593 | === removed directory 'src/zope/app/basicskin' |
4594 | === removed file 'src/zope/app/basicskin/__init__.py' |
4595 | --- src/zope/app/basicskin/__init__.py 2010-03-01 20:29:16 +0000 |
4596 | +++ src/zope/app/basicskin/__init__.py 1970-01-01 00:00:00 +0000 |
4597 | @@ -1,23 +0,0 @@ |
4598 | -############################################################################## |
4599 | -# |
4600 | -# Copyright (c) 2006 Zope Corporation and Contributors. |
4601 | -# All Rights Reserved. |
4602 | -# |
4603 | -# This software is subject to the provisions of the Zope Public License, |
4604 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
4605 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
4606 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
4607 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
4608 | -# FOR A PARTICULAR PURPOSE. |
4609 | -# |
4610 | -############################################################################## |
4611 | -"""Basic skin |
4612 | - |
4613 | -$Id: __init__.py 106669 2009-12-16 22:42:40Z hannosch $ |
4614 | -""" |
4615 | -__docformat__ = 'restructuredtext' |
4616 | -from zope.publisher.interfaces.browser import IDefaultBrowserLayer |
4617 | - |
4618 | -class IBasicSkin(IDefaultBrowserLayer): |
4619 | - """Basic skin that simply only contains the default layer and |
4620 | - nothing else""" |
4621 | |
4622 | === removed file 'src/zope/app/basicskin/arrowup.gif' |
4623 | Binary files src/zope/app/basicskin/arrowup.gif 2009-04-23 15:12:18 +0000 and src/zope/app/basicskin/arrowup.gif 1970-01-01 00:00:00 +0000 differ |
4624 | === removed file 'src/zope/app/basicskin/configure.zcml' |
4625 | --- src/zope/app/basicskin/configure.zcml 2009-04-23 15:12:18 +0000 |
4626 | +++ src/zope/app/basicskin/configure.zcml 1970-01-01 00:00:00 +0000 |
4627 | @@ -1,44 +0,0 @@ |
4628 | -<zope:configure |
4629 | - xmlns:zope="http://namespaces.zope.org/zope" |
4630 | - xmlns="http://namespaces.zope.org/browser"> |
4631 | - |
4632 | - <zope:interface |
4633 | - interface=".IBasicSkin" |
4634 | - type="zope.publisher.interfaces.browser.IBrowserSkinType" |
4635 | - name="Basic" |
4636 | - /> |
4637 | - |
4638 | - <page |
4639 | - name="standard_macros" |
4640 | - for="*" |
4641 | - class=".standardmacros.StandardMacros" |
4642 | - allowed_interface="zope.interface.common.mapping.IItemMapping" |
4643 | - permission="zope.Public" /> |
4644 | - |
4645 | - <page |
4646 | - name="view_macros" |
4647 | - for="*" |
4648 | - permission="zope.View" |
4649 | - template="view_macros.pt" /> |
4650 | - |
4651 | - <page |
4652 | - name="dialog_macros" |
4653 | - for="*" |
4654 | - permission="zope.View" |
4655 | - template="dialog_macros.pt" /> |
4656 | - |
4657 | - <resource |
4658 | - name="zopetopBasic.css" |
4659 | - file="zopetopbasic.css" /> |
4660 | - |
4661 | - <resource |
4662 | - name="zopetopWidgets.css" |
4663 | - file="zopetopwidgets.css" /> |
4664 | - |
4665 | - <resource |
4666 | - name="zopetopStructure.css" |
4667 | - file="zopetopstructure.css" /> |
4668 | - |
4669 | - <resource name="arrowUp.gif" file="arrowup.gif"/> |
4670 | - |
4671 | -</zope:configure> |
4672 | |
4673 | === removed file 'src/zope/app/basicskin/dialog_macros.pt' |
4674 | --- src/zope/app/basicskin/dialog_macros.pt 2009-04-23 15:12:18 +0000 |
4675 | +++ src/zope/app/basicskin/dialog_macros.pt 1970-01-01 00:00:00 +0000 |
4676 | @@ -1,16 +0,0 @@ |
4677 | -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
4678 | - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
4679 | -<html metal:define-macro="dialog" i18n:domain="zope"> |
4680 | -<head metal:use-macro="context/@@standard_macros/head" /> |
4681 | - |
4682 | -<body> |
4683 | - <span metal:use-macro="context/@@standard_macros/breadcrumbs" /> |
4684 | - |
4685 | - <div metal:define-slot="body"> |
4686 | - <p>Body here</p> |
4687 | - </div> |
4688 | - |
4689 | - <div metal:use-macro="context/@@standard_macros/footer" /> |
4690 | -</body> |
4691 | -</html> |
4692 | - |
4693 | |
4694 | === removed file 'src/zope/app/basicskin/document_icon.gif' |
4695 | Binary files src/zope/app/basicskin/document_icon.gif 2009-04-23 15:12:18 +0000 and src/zope/app/basicskin/document_icon.gif 1970-01-01 00:00:00 +0000 differ |
4696 | === removed file 'src/zope/app/basicskin/folder_icon.gif' |
4697 | Binary files src/zope/app/basicskin/folder_icon.gif 2009-04-23 15:12:18 +0000 and src/zope/app/basicskin/folder_icon.gif 1970-01-01 00:00:00 +0000 differ |
4698 | === removed file 'src/zope/app/basicskin/standardmacros.py' |
4699 | --- src/zope/app/basicskin/standardmacros.py 2009-04-23 15:12:18 +0000 |
4700 | +++ src/zope/app/basicskin/standardmacros.py 1970-01-01 00:00:00 +0000 |
4701 | @@ -1,51 +0,0 @@ |
4702 | -############################################################################## |
4703 | -# |
4704 | -# Copyright (c) 2002 Zope Corporation and Contributors. |
4705 | -# All Rights Reserved. |
4706 | -# |
4707 | -# This software is subject to the provisions of the Zope Public License, |
4708 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
4709 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
4710 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
4711 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
4712 | -# FOR A PARTICULAR PURPOSE. |
4713 | -# |
4714 | -############################################################################## |
4715 | -"""Standard macros for page templates in the ZMI |
4716 | - |
4717 | -The macros are drawn from various different page templates. |
4718 | - |
4719 | -$Id: standardmacros.py 67630 2006-04-27 00:54:03Z jim $ |
4720 | -""" |
4721 | -__docformat__ = 'restructuredtext' |
4722 | -import zope.interface |
4723 | - |
4724 | -from zope.component import getMultiAdapter |
4725 | -from zope.publisher.browser import BrowserView |
4726 | - |
4727 | -class Macros(object): |
4728 | - zope.interface.implements(zope.interface.common.mapping.IItemMapping) |
4729 | - |
4730 | - macro_pages = () |
4731 | - aliases = { |
4732 | - 'view': 'page', |
4733 | - 'dialog': 'page', |
4734 | - 'addingdialog': 'page' |
4735 | - } |
4736 | - |
4737 | - def __getitem__(self, key): |
4738 | - key = self.aliases.get(key, key) |
4739 | - context = self.context |
4740 | - request = self.request |
4741 | - for name in self.macro_pages: |
4742 | - page = getMultiAdapter((context, request), name=name) |
4743 | - try: |
4744 | - v = page[key] |
4745 | - except KeyError: |
4746 | - pass |
4747 | - else: |
4748 | - return v |
4749 | - raise KeyError(key) |
4750 | - |
4751 | -class StandardMacros(BrowserView, Macros): |
4752 | - macro_pages = ('view_macros', 'dialog_macros') |
4753 | |
4754 | === removed directory 'src/zope/app/basicskin/tests' |
4755 | === removed file 'src/zope/app/basicskin/tests/__init__.py' |
4756 | --- src/zope/app/basicskin/tests/__init__.py 2009-04-23 15:12:18 +0000 |
4757 | +++ src/zope/app/basicskin/tests/__init__.py 1970-01-01 00:00:00 +0000 |
4758 | @@ -1,2 +0,0 @@ |
4759 | -# |
4760 | -# This file is necessary to make this directory a package. |
4761 | |
4762 | === removed file 'src/zope/app/basicskin/tests/test.gif' |
4763 | Binary files src/zope/app/basicskin/tests/test.gif 2009-04-23 15:12:18 +0000 and src/zope/app/basicskin/tests/test.gif 1970-01-01 00:00:00 +0000 differ |
4764 | === removed file 'src/zope/app/basicskin/tests/test_standardmacros.py' |
4765 | --- src/zope/app/basicskin/tests/test_standardmacros.py 2010-03-01 20:29:16 +0000 |
4766 | +++ src/zope/app/basicskin/tests/test_standardmacros.py 1970-01-01 00:00:00 +0000 |
4767 | @@ -1,120 +0,0 @@ |
4768 | -############################################################################## |
4769 | -# |
4770 | -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. |
4771 | -# All Rights Reserved. |
4772 | -# |
4773 | -# This software is subject to the provisions of the Zope Public License, |
4774 | -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
4775 | -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
4776 | -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
4777 | -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
4778 | -# FOR A PARTICULAR PURPOSE. |
4779 | -# |
4780 | -############################################################################## |
4781 | -"""Basic skin standard macros |
4782 | - |
4783 | -$Id: test_standardmacros.py 106671 2009-12-16 22:56:40Z hannosch $ |
4784 | -""" |
4785 | -import unittest |
4786 | - |
4787 | -from zope.component import getGlobalSiteManager |
4788 | -from zope.component.testing import PlacelessSetup |
4789 | -from zope.interface import implements, Interface |
4790 | -from zope.publisher.browser import TestRequest |
4791 | -from zope.publisher.interfaces.browser import IBrowserView |
4792 | -from zope.publisher.interfaces.browser import IDefaultBrowserLayer |
4793 | - |
4794 | -from zope.app.basicskin.standardmacros import Macros |
4795 | - |
4796 | - |
4797 | -class ViewWithMacros(object): |
4798 | - implements(IBrowserView) |
4799 | - |
4800 | - def __init__(self, context, request): |
4801 | - self.context = context |
4802 | - self.request = request |
4803 | - |
4804 | - def __call__(self): |
4805 | - pass |
4806 | - |
4807 | - def __getitem__(self, key): |
4808 | - return self.pages[key] |
4809 | - |
4810 | - pages = {} |
4811 | - |
4812 | -class I(Interface): pass |
4813 | - |
4814 | -class C(object): |
4815 | - implements(I) |
4816 | - |
4817 | -class page1(ViewWithMacros): |
4818 | - pages = {'foo':'page1_foo', |
4819 | - 'bar':'page1_bar'} |
4820 | - |
4821 | -class collides_with_page1(ViewWithMacros): |
4822 | - pages = {'foo':'collides_with_page1_foo', |
4823 | - 'baz':'collides_with_page1_baz'} |
4824 | - |
4825 | -class works_with_page1(ViewWithMacros): |
4826 | - pages = {'fish':'works_with_page1_fish', |
4827 | - 'tree':'works_with_page1_tree'} |
4828 | - |
4829 | -def createMacrosInstance(pages): |
4830 | - |
4831 | - class T(Macros): |
4832 | - aliases = {'afoo': 'foo', 'abar': 'bar'} |
4833 | - |
4834 | - def __init__(self, context, request): |
4835 | - self.context = context |
4836 | - self.request = request |
4837 | - macro_pages = pages |
4838 | - return T(C(), TestRequest()) |
4839 | - |
4840 | - |
4841 | -def browserView(for_, name, factory): |
4842 | - gsm = getGlobalSiteManager() |
4843 | - for_ = (for_, ) + (IDefaultBrowserLayer,) |
4844 | - gsm.registerAdapter(factory, for_, Interface, name, event=False) |
4845 | - |
4846 | - |
4847 | -class Test(PlacelessSetup, unittest.TestCase): |
4848 | - |
4849 | - def setUp(self): |
4850 | - PlacelessSetup.setUp(self) |
4851 | - browserView(I, 'page1', page1) |
4852 | - browserView(I, 'collides_with_page1', collides_with_page1) |
4853 | - browserView(I, 'works_with_page1', works_with_page1) |
4854 | - |
4855 | - def testSinglePage(self): |
4856 | - macros = createMacrosInstance(('page1',)) |
4857 | - self.assertEqual(macros['foo'], 'page1_foo') |
4858 | - self.assertEqual(macros['bar'], 'page1_bar') |
4859 | - self.assertRaises(KeyError, macros.__getitem__, 'fish') |
4860 | - |
4861 | - def testConcordentPages(self): |
4862 | - macros = createMacrosInstance(('page1', 'works_with_page1')) |
4863 | - self.assertEqual(macros['foo'], 'page1_foo') |
4864 | - self.assertEqual(macros['bar'], 'page1_bar') |
4865 | - self.assertEqual(macros['fish'], 'works_with_page1_fish') |
4866 | - self.assertEqual(macros['tree'], 'works_with_page1_tree') |
4867 | - self.assertRaises(KeyError, macros.__getitem__, 'pants') |
4868 | - |
4869 | - def testConflictingPages(self): |
4870 | - macros = createMacrosInstance(('page1', 'collides_with_page1')) |
4871 | - self.assertEqual(macros['foo'], 'page1_foo') |
4872 | - self.assertEqual(macros['bar'], 'page1_bar') |
4873 | - self.assertEqual(macros['baz'], 'collides_with_page1_baz') |
4874 | - self.assertRaises(KeyError, macros.__getitem__, 'pants') |
4875 | - |
4876 | - def testMacroAliases(self): |
4877 | - macros = createMacrosInstance(('page1', 'collides_with_page1')) |
4878 | - self.assertEqual(macros['afoo'], 'page1_foo') |
4879 | - self.assertEqual(macros['abar'], 'page1_bar') |
4880 | - |
4881 | - |
4882 | -def test_suite(): |
4883 | - loader = unittest.TestLoader() |
4884 | - return loader.loadTestsFromTestCase(Test) |
4885 | - |
4886 | -if __name__=='__main__': |
4887 | - unittest.TextTestRunner().run(test_suite()) |
4888 | |
4889 | === removed file 'src/zope/app/basicskin/view_macros.pt' |
4890 | --- src/zope/app/basicskin/view_macros.pt 2009-04-23 15:12:18 +0000 |
4891 | +++ src/zope/app/basicskin/view_macros.pt 1970-01-01 00:00:00 +0000 |
4892 | @@ -1,48 +0,0 @@ |
4893 | -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
4894 | - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
4895 | -<html metal:define-macro="page" i18n:domain="zope"> |
4896 | -<head metal:define-macro="head"> |
4897 | - <title |
4898 | - metal:define-slot="title" |
4899 | - tal:content="options/getTitle|view/getTitle|context/getTitle|default" |
4900 | - >Zope</title> |
4901 | - <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> |
4902 | - <link href="/@@/zopetopBasic.css" rel="stylesheet" type="text/css" |
4903 | - tal:attributes="href string:/@@/zopetopBasic.css" /> |
4904 | - <link href="/@@/zopetopWidgets.css" rel="stylesheet" type="text/css" |
4905 | - tal:attributes="href string:/@@/zopetopWidgets.css" /> |
4906 | - <link href="/@@/zopetopStructure.css" rel="stylesheet" type="text/css" |
4907 | - tal:attributes="href string:/@@/zopetopStructure.css" /> |
4908 | - <div metal:define-slot="headers"> |
4909 | - </div> |
4910 | -</head> |
4911 | -<body> |
4912 | - |
4913 | - <table metal:define-macro="zmi_tabs"><tr> |
4914 | - <td tal:repeat="view context/@@view_get_menu/zmi_views"> |
4915 | - <a href="" tal:attributes="href view/action" |
4916 | - tal:content="view/title" |
4917 | - i18n:translate=""> |
4918 | - label</a> |
4919 | - <tal:block condition="not: repeat/view/end">'</tal:block> |
4920 | - </td> |
4921 | - </tr></table> |
4922 | - |
4923 | - <div metal:define-slot="body"> |
4924 | - <p>Body here</p> |
4925 | - </div> |
4926 | - |
4927 | - <div metal:define-macro="logged_user"> |
4928 | - <p i18n:translate="">User: |
4929 | - <span tal:replace="request/principal/title" |
4930 | - i18n:name="user_title">User</span> |
4931 | - </p> |
4932 | - </div> |
4933 | - |
4934 | - <div metal:define-macro="footer"> |
4935 | - <p i18n:translate="">Powered by Zope</p> |
4936 | - </div> |
4937 | - |
4938 | -</body> |
4939 | -</html> |
4940 | - |
4941 | |
4942 | === removed file 'src/zope/app/basicskin/zmi_stylesheet.css' |
4943 | --- src/zope/app/basicskin/zmi_stylesheet.css 2009-04-23 15:12:18 +0000 |
4944 | +++ src/zope/app/basicskin/zmi_stylesheet.css 1970-01-01 00:00:00 +0000 |
4945 | @@ -1,45 +0,0 @@ |
4946 | -body { |
4947 | - font-family: sans-serif; |
4948 | - color: Black; |
4949 | - background-color: White; |
4950 | -} |
4951 | - |
4952 | -h1 { |
4953 | - font-size: x-large; |
4954 | - font-weight: bold; |
4955 | -} |
4956 | - |
4957 | -h2 { |
4958 | - font-size: large; |
4959 | - font-weight: bold; |
4960 | -} |
4961 | - |
4962 | -h3 { |
4963 | - font-size: large; |
4964 | - font-weight: bold; |
4965 | - font-style: italic; |
4966 | -} |
4967 | - |
4968 | -h4 { |
4969 | - font-weight: bold; |
4970 | - font-style: italic; |
4971 | -} |
4972 | - |
4973 | -h5 { |
4974 | - font-size: small; |
4975 | - font-weight: bold; |
4976 | -} |
4977 | - |
4978 | -h6 { |
4979 | - font-size: small; |
4980 | - font-weight: bold; |
4981 | - font-style: italic; |
4982 | -} |
4983 | - |
4984 | -img { |
4985 | - border: none; |
4986 | -} |
4987 | - |
4988 | -caption { |
4989 | - font-weight: bold; |
4990 | -} |
4991 | |
4992 | === removed file 'src/zope/app/basicskin/zopetopbasic.css' |
4993 | --- src/zope/app/basicskin/zopetopbasic.css 2009-04-23 15:12:18 +0000 |
4994 | +++ src/zope/app/basicskin/zopetopbasic.css 1970-01-01 00:00:00 +0000 |
4995 | @@ -1,183 +0,0 @@ |
4996 | -/***************************************************************************** |
4997 | - * |
4998 | - * Copyright (c) 2001, 2002 Zope Corporation and Contributors. |
4999 | - * All Rights Reserved. |
5000 | - * |
The diff has been truncated for viewing.
Approved as part of https:/ /code.launchpad .net/~sidnei/ landscape/ reduce- deps/+merge/ 29236