zope.app.appsetup

Zope app setup helper
Download

zope.app.appsetup Ranking & Summary

Advertisement

  • Rating:
  • License:
  • ZPL
  • Publisher Name:
  • Zope Corporation and Contributors
  • Publisher web site:
  • http://zope org

zope.app.appsetup Tags


zope.app.appsetup Description

Zope app setup helper zope.app.appsetup is a module that provides application setup helpers for the Zope3 appserver.Bootstrap helpersThe bootstrap helpers provide a number of functions that help with bootstrapping.The bootStrapSubscriber function makes sure that there is a root object. It subscribes to DatabaseOpened events: >>> from zope.app.appsetup import bootstrap >>> import zope.processlifetime >>> from ZODB.tests import util >>> db = util.DB() >>> bootstrap.bootStrapSubscriber(zope.processlifetime.DatabaseOpened(db))The subscriber makes sure that there is a root folder: >>> from zope.app.publication.zopepublication import ZopePublication >>> conn = db.open() >>> root = conn.root() >>> sm = root.getSiteManager() >>> conn.close()A DatabaseOpenedWithRoot is generated with the database. >>> from zope.component.eventtesting import getEvents >>> = getEvents(zope.processlifetime.IDatabaseOpenedWithRoot) >>> event.database is db TrueGenerally, startup code that expects the root object and site to have been created will want to subscribe to this event, not IDataBaseOpenedEvent.The subscriber generates the event whether or not the root had to be set up: >>> bootstrap.bootStrapSubscriber(zope.processlifetime.DatabaseOpened(db)) >>> = getEvents(zope.processlifetime.IDatabaseOpenedWithRoot) >>> event.database is db TrueCheck the Security PolicyWhen the security policy got refactored to be really pluggable, the inclusion of the security policy configuration was moved to the very top level, to site.zcml. This happened in r24770, after ZopeX3 3.0 was released, but before 3.1.Now the maintainers of existing 3.0 sites need to manually update their site.zcml to include securitypolicy.zcml while upgrading to 3.1. See also http://www.zope.org/Collectors/Zope3-dev/381 . >>> from zope.testing.loggingsupport import InstalledHandler >>> handler = InstalledHandler('zope.app.appsetup')If the security policy is unset from the default ParanoidSecurityPolicy, we get a warning: >>> from zope.app.appsetup.bootstrap import checkSecurityPolicy >>> event = object() >>> checkSecurityPolicy(event) >>> print handler zope.app.appsetup WARNING Security policy is not configured. Please make sure that securitypolicy.zcml is included in site.zcml immediately before principals.zcmlHowever, if any non-default security policy is installed, no warning is emitted: >>> from zope.security.management import setSecurityPolicy >>> defaultPolicy = setSecurityPolicy(object()) >>> handler.clear() >>> checkSecurityPolicy(event) >>> print handler < BLANKLINE >Clean up: >>> handler.uninstall()Debug consoleThe debug console lets you have a Python prompt with the full Zope environment loaded (which includes the ZCML configuration, as well as an open database connection).Let's define a helper to run the debug script and trap SystemExit exceptions that would otherwise hide the output >>> import sys >>> from zope.app.appsetup import debug >>> def run(*args): ... sys.argv = 'debug' ... sys.stderr = sys.stdout ... try: ... debug.main(args) ... except SystemExit, e: ... print "(exited with status %d)" % e.codeIf you call the script with no arguments, it displays a brief error message on stderr >>> run() Error: please specify a configuration file For help, use debug -h (exited with status 2)We need to pass a ZConfig configuration file as an argument >>> run('-C', 'test.conf') The application root is known as `root`.Now you have the root object from the open database available as a global variable named 'root' in the __main__ module: >>> main_module = sys.modules >>> main_module.root # doctest: +ELLIPSIS < zope.site.folder.Folder object at ... >and we have asked Python to enter interactive mode by setting the PYTHONINSPECT environment variable >>> import os >>> os.environ.get('PYTHONINSPECT') 'true'We have to do extra work to honor the PYTHONSTARTUP environment variable: >>> pythonstartup = os.path.join(os.path.dirname(debug.__file__), ... 'testdata', 'pythonstartup') >>> os.environ = pythonstartup >>> run('-C', 'test.conf') The application root is known as `root`.You can see that our pythonstartup file was executed because it changed the prompt >>> sys.ps1 'debug > 'Product-specific configurationThe product module of this package provides a very simple way to deal with what has traditionally been called "product configuration", where "product" refers to the classic Zope 2 notion of a product.The configuration schema for the application server allows named < product-config > sections to be added to the configuration file, and product code can use the API provided by the module to retrieve configuration sections for given names.There are two public functions in the module that should be used in normal operations, and additional functions and a class that can be used to help with testing: >>> from zope.app.appsetup import productLet's look at the helper class first, since we'll use it in describing the public (application) interface. We'll follow that with the functions for normal operation, then the remaining test-support functions.Faux configuration objectThe FauxConfiguration class constructs objects that behave like the ZConfig section objects to the extent needed for the product configuration API. These will be used here, and may also be used to create configurations for testing components that consume such configuration.The constructor requires two arguments: the name of the section, and a mapping of keys to values that the section should provide. Let's create a simple example: >>> one = product.FauxConfiguration("one", {}) >>> one.getSectionName() 'one' >>> one.mapping {}Providing a non-empty set of key/value pairs trivially behaves as expected: >>> two = product.FauxConfiguration("two", {"abc": "def"}) >>> two.getSectionName() 'two' >>> two.mapping {'abc': 'def'}Application APIThere are two functions in the application interface for this module. One is used by the configuration provider, and the other is used by the consumer.The provider's API takes a sequence of configuration objects that conform to the behaviors exhibited by the default ZConfig section objects. Since the FauxConfiguration class provides these behaviors, we can easily see how this can be used: >>> product.setProductConfigurations()Now that we've established some configuration, we want to be able to use it. We do this using the getProductConfiguration() function. This function takes a name and returns a matching configuration section if there is one, of None if not: >>> product.getProductConfiguration("one") {} >>> product.getProductConfiguration("not-there") is None TrueNote that for a section that exists, only the internal mapping is provided, not the containing section object. This is a historical wart; we'll just need to live with it until new APIs are introduced.Setting the configuration a second time will overwrite the prior configuration; sections previously available will no longer be: >>> product.setProductConfigurations() >>> product.getProductConfiguration("one") is None TrueThe new sections are available, as expected: >>> product.getProductConfiguration("two") {'abc': 'def'}Test support functionsAdditional functions are provided that make it easier to manage configuration state in testing.The first can be used to provide configuration for a single name. The function takes a name and either a configuration mapping or None as arguments. If None is provided as the second argument, any configuration settings for the name are removed, if present. If the second argument is not None, it will be used as the return value for getProductConfiguration for the given name. >>> product.setProductConfiguration("first", None) >>> print product.getProductConfiguration("first") None >>> product.setProductConfiguration("first", {"key": "value1"}) >>> product.getProductConfiguration("first") {'key': 'value1'} >>> product.setProductConfiguration("first", {"key": "value2"}) >>> product.getProductConfiguration("first") {'key': 'value2'} >>> product.setProductConfiguration("first", {"alt": "another"}) >>> product.getProductConfiguration("first") {'alt': 'another'} >>> product.setProductConfiguration("second", {"you": "there"}) >>> product.getProductConfiguration("first") {'alt': 'another'} >>> product.getProductConfiguration("second") {'you': 'there'} >>> product.setProductConfiguration("first", None) >>> print product.getProductConfiguration("first") NoneThe other two functions work in concert, saving and restoring the entirety of the configuration state.Our current configuration includes data for the "second" key, and none for the "first" key: >>> print product.getProductConfiguration("first") None >>> print product.getProductConfiguration("second") {'you': 'there'}Let's save this state: >>> state = product.saveConfiguration()Now let's replace the kitchen sink: >>> product.setProductConfigurations() >>> print product.getProductConfiguration("first") None >>> print product.getProductConfiguration("second") None >>> product.getProductConfiguration("x") {'a': 'b'} >>> product.getProductConfiguration("y") {'c': 'd'}The saved configuration state can be restored: >>> product.restoreConfiguration(state) >>> print product.getProductConfiguration("x") None >>> print product.getProductConfiguration("y") None >>> print product.getProductConfiguration("first") None >>> print product.getProductConfiguration("second") {'you': 'there'}There's an additional function that can be used to load product configuration from a file object; only product configuration components are accepted. The function returns a mapping of names to configuration objects suitable for passing to setProductConfiguration. Using this with setProductConfigurations would require constructing FauxConfiguration objects.Let's create some sample configuration text: >>> product_config = ''' ... < product-config product1 > ... key1 product1-value1 ... key2 product1-value2 ... < /product-config > ... ... < product-config product2 > ... key1 product2-value1 ... key3 product2-value2 ... < /product-config > ... '''We can now load the configuration using the loadConfiguration function: >>> import StringIO >>> import pprint >>> sio = StringIO.StringIO(product_config) >>> config = product.loadConfiguration(sio) >>> pprint.pprint(config, width=1) {'product1': {'key1': 'product1-value1', 'key2': 'product1-value2'}, 'product2': {'key1': 'product2-value1', 'key3': 'product2-value2'}}Extensions that provide product configurations can be used as well: >>> product_config = ''' ... %import zope.app.appsetup.testproduct ... ... < testproduct foobar > ... < /testproduct > ... ... ... key1 value1 ... key2 value2 ... < /testproduct > ... ''' >>> sio = StringIO.StringIO(product_config) >>> config = product.loadConfiguration(sio) >>> pprint.pprint(config, width=1) {'barfoo': {'key1': 'value1', 'key2': 'value2', 'product-name': 'barfoo'}, 'foobar': {'product-name': 'foobar'}} Requirements: · Python What's New in This Release: · Added stacking of storages for layer/test level setup separation in derived ZODBLayers.


zope.app.appsetup Related Software