Merge lp:~sidnei/zope3/reduce-deps into lp:~landscape/zope3/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
Reviewer Review Type Date Requested Status
Sidnei da Silva (community) Approve
Review via email: mp+29237@code.launchpad.net

Description of the change

Reduce deps

To post a comment you must log in.
Revision history for this message
Sidnei da Silva (sidnei) wrote :
review: Approve

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'
4623Binary 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'
4695Binary 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'
4697Binary 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'
4763Binary 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.

Subscribers

People subscribed via source and target branches

to all changes: