[Subversion] / PEAK / src / peak / config / api_impl.py |
No default branch
Bookmark a link to HEAD:
(view)
(download)
(as text)
Fix 'config.registeredProtocol()' not working on root components.
Recreate checkins lost when hard drive died (1 of 4); see: http://www.eby-sarna.com/pipermail/source-changes/2004q3/001807.html for original log info.
Remove items that were deprecated during alpha 3 development. If you've got code that breaks with this version, check HISTORY.txt for replacements, or ask on the mailing list.
MAJOR API REFACTORING for 'peak.config', to support iterating over configuration keys, 'n2' navigability of properties, and much more. Many APIs are now DEPRECATED or renamed; please see CHANGES.txt for a complete description. A few highlights: - 'config.lookup()' replaces 'findUtility' and 'getProperty' - 'config.iterValues()' replaces 'findUtilities' - 'config.iterKeys()' finds keys in a specific namespace - NEW: 'config.parentProviding()' and 'config.parentsProviding()' APIs to find parent components that support a protocol. - NEW: You can now use 'peak n2 config:' to explore the default property namespace. For example 'ls -l peak.naming.schemes' will list all defined naming schemes. Please see CHANGES.txt for the list of deprecated or removed APIs.
Finished switchover to using protocols.advise() API to declare interfaces.
Fixed property/utility lookups no longer working for peak.model objects.
Paramegeddon! Adjusted API signatures so that all calls that have a context component, have it as the first parameter. Changed functions, methods, and classes are: * binding.acquireComponent() * binding.lookupComponent() * config.getProperty() * config.findUtility() * config.findUtilities() * config.PropertyMap.getValueFor() * config.IConfigSource._getConfigData() * config.PropertySet() * naming.lookup() * naming.parseURL() Also, renamed 'config.LazyLoader' -> 'config.LazyRule' to reduce confusion with 'storage.LazyLoader', which has a very different purpose/function.
More "root" cleanups. 'config.makeRoot()' can now take an 'iniFiles' argument listing file paths (or '(modulename,filename)' tuples) to load; it defaults to '[('peak','peak.ini')]', providing the default behavior we know and love. :) If you create a binding.Component with a parent of 'None', it will now believe you and make itself a root. The default value of parentComponent is now 'NOT_GIVEN', so that if you don't specify a parent, the object will be "undecided" until it really needs to know who its parent is (at which point it will be 'None' if it hasn't been "adopted" in the meantime). Interface docs and tests have been updated to reflect/take advantage of this. (Specifically, the tests used to use 'getParentComponent()' to force a root to acknowledge its orphan status; now they can just *tell* it.) Finally, I removed the use of weak references from the assembly events system. If you created an object, intending that it register itself with some kind of registry, it could get GC'd before the assembly event kicked in, unless you specifically held onto a reference until then. Since components that don't need assembly events don't register for them, it seems harmless to use simple references rather than weak ones.
Replaced 'config.Application' class with 'config.makeRoot()' function. (There's still a 'ConfigurationRoot' class behind the scenes, but it's no longer part of the public API.)
"As We Planned-it of the APES, The Final Chapter". Removed AppConfig/SysConfig classes and APIs. Renamed 'instancePerApp()' to 'provideInstance()' (since it now just provides a single instance), and added 'instancePerComponent()' (which provides a fresh instance per target component). Some files have whitespace-only changes.
Plan-it of the APES, phase 1. Configuration APIs now require an explicit context argument. There is a 'config.IConfigurationRoot' interface, that is currently implemented by AppConfig and SystemConfig. There is also a 'NullConfigRoot' object that implements it by giving "invalid root" errors. Right now, however, you'll never see that message because 'iterParents' still goes to the special config objects once a root is reached. That'll be changed in the next phase.
Fixed needing to break encapsulation of EigenCells in order to supply a default value. 'EigenCell.get()' can now be given a function that will be called to suppy a default value for the cell in the event that it hasn't had a value set yet, and has not been read. This cleans up code in the singleton accessors for the "system configuration" and "reactor" services.
Implemented the Global/Local -> System/App renaming of configuration APIs, as per the proposal at: http://www.eby-sarna.com/pipermail/transwarp/2003-March/000341.html
Moved remaining utility/property functions from binding -> config. This should make it a little easier to finish tutorial chapter 2... ;) Seriously, these functions aren't really about binding, even though they're called by certain attribute bindings. They're about finding configuration data.
PropertyName -> peak.api; Improved lazy import facility * naming.PropertyName is now simply PropertyName; it never really had much to do with naming in the first place, doesn't depend on anything else, and needs to be accessible in all major subpackages and in end-user API calls. So now it's in-line in the peak.api module. * Added a 'lazyModule(moduleName)' function to peak.util.imports. This new "next generation" way of creating a lazily-loaded module actually creates an object that *will be* the real module in sys.modules, and once loaded will be indistinguishable from an ordinary Python module. (Well, under Python 2.3 the type() will be different, but you can't have everything.) I was getting really fed up of tracing into lazyImport.__getattr__ during debugging sessions, so I was inspired to come up with something that would only have code overhead when it's first touched. Subclassing ModuleType, adding a __getattribute__ method, and clever use of the Python 'reload()' function saved the day. * This now completes all the non-documentation items I want for 0.5a1, although I may "work ahead" a little on the features list, especially if Ty keeps pressing for SQL type maps and LDAP schemas. ;) (In truth, I'd like those and some of the other database features Real Soon Now myself.)
Arbitrary Python objects are now treated as stand-alone component roots by all APIs that accept a component for looking up configuration data, utilities, etc.
*Really* fixed the local/global config startup recursion loop. Config objects now perform their "setup" operation lazily, upon the first attempt to get configuration data from them. By the time this happens, the default local and global config objects will already be registered, so all system invariants should be in effect. Fixing this now allows the addition of Ty's requested PEAK_CONFIG environment variable load operation; so you can now specify PEAK_CONFIG to point to an additional config file, similar to "peak.ini", that can do any necessary site-, user-, or application-specific setups. Since that file can include others (and those still others) without limit, PEAK_CONFIG names only one file.
* Added 'binding.Constant(key, value)', which allows you to specify a constant value to be used as a property or utility in that component subtree. * Added storage.get/begin/commit/abortTransaction() APIs for ease of use in short scripts. Defined a default provider for ITransactionService in peak.ini that provides each component root with its own TransactionService instance. It's easily replaceable with other allocation strategies, if it should be needed. I may change this later to a per-root strategy, since the current strategy requires creating localConfigs for each component root. We'll see what actual use has to say about the best way of doing it. * Fixed a problem with local/global config object startup that could cause "phantom" configuration objects to appear via recursion of getLocal() or getGlobal(). * Got rid of binding.meta.assertInterfaces, which is no longer needed because the Interface package now correctly handles metaclass instances. * Got rid of Singleton, since it's not used for anything and I could neither think of any use cases nor remember why I added it in the first place! * Made it possible for CachingProviders to cache per-localConfig as well as per-object. This is handy for implementing per-hierarchy services, like the TransactionService provider mentioned above. * Misc. TODO updates.
First phase refactoring of configuration loading. Removed rule factories, as the only thing they do is help avoid specifying a wildcard to both the rule object and the property map. Generalized loadEnviron to loadMapping, and added an 'asPrefix()' method to PropertyName objects so that it's easy to turn either 'eniron' or 'environ.*' into 'environ.' for adding onto the front of loaded configuation keys.
Reversed parameter order for both findUtility and getProperty. Now the name or interface comes first, and the (now optional) target component second. This means that when writing short scripts or using PEAK at an interpreter prompt, it won't be necessary to pass config.getLocal() into either function just to get access to a global utility or property. I'd like to make lookupComponent and certain other functions follow this same pattern, but there are some hitches to doing so right away. I'll take another stab at it later. Also, I added '!' and ':' to the allowable characters in a property name, since cygwin Python puts things like '!C:' into os.environ.keys(). Last, but not least, I added an 'onJoinTxn()' method to TransactionComponent, as I'm about to need it in order to implement transaction operations on ManagedConnection objects.
Simplified naming system creation mechanisms. URL contexts and parsers are now looked up as properties in 'peak.naming.schemes.*'. Object factories and state factories can be specified as keyword arguments to an InitialContext, and then "inherited" by child contexts. Also, moved config.Property -> naming.PropertyName. Still need to convert IInitialContextFactory from a utility to a property. Also, we need a way for scheme address parsers to be asked what schemes they support; right now I've hacked URL contexts to assume their parser supports anything. :(
Properties and utilities are unified at last! Both properties and utilities are now handled by the __instance_provides__ and __class_provides__ attributes of component classes. This simplified the code and interfaces for both PropertyMap and for registering dynamic utility providers. Property names now have an additional syntax form: 'some.prop?' which is used as a default value that is checked after 'some.prop', 'some.*', and 'some.prop' (a second time). This is handled transparently for you by way of the 'setDefault()' method of 'IPropertyMap', so effectively it's an implementation detail. Documentation is still a little sketchy, but it should now be straightforward to get the naming system using properties and utilities in a harmonious way. ALSO: Fixed config.getLocal() to ensure it's working with a root component. binding.New() can now use an import string instead of a class/type/callable. The object referenced by the import string will be loaded and called as though the object itself had been used. GlobalConfig and LocalConfig now have 'setup()' methods that can be overridden to create default rule and provider registrations. This'll be handy for making LocalConfig register a default transaction service provider, for example.
Moved all PEAK API exceptions to 'peak.exceptions' module, because it was getting pretty darn inconvenient to keep importing them across subpackages. 'from peak.api import exceptions' or 'from peak import exceptions' can be used to access them. It's worth the trouble of referring to 'exceptions.SomeException', because it allows the names to be shorter (no need for Exception or Error in the name) and makes the exceptions globally available. Added 'binding.iterParents()', which walks from a component up through its root parent, into the local and global configuration objects, if available. It's now used in getProperty() and findUtilities(). Synchronized interface of 'binding.findUtility()' and 'config.getProperty()'. Now both take an optional 'default' argument which will be returned if the sought item is not found, or, if a default is not supplied and the item isn't found, an 'exceptions.NameNotFound' error is raised. (findUtility() used to return 'None' to mean not-found). Fixed a bug in 'binding.lookupComponent()' for looking up utilities (which also caused 'bindTo(ISomething)' to not work correctly). Added a 'config.Property' class, a subclass of 'str', which parses and validates property names, as well as handling wildcard iteration. It also implements enough of 'IInterface' to allow it to be used as a key in an EigenRegistry. There's a new interface 'config.IConfigKey', which is implemented by both Interface objects and Property objects, so everything that can be used as a configuration key now implements it. This is another step towards unification of configuration properties (keyed by name) and utilities (keyed by Interface). After a few more passes, I should be able to eliminate the rest of the parallel logic that exists to process both Utilities and Properties. Fixed a typo in 'storage.TransactionComponent' which would have caused it to raise an error upon joining a transaction.
Fixed a problem with wildcard handling. Added IRuleFactory to make it easier for IRules to be instantiated per property map. Created a 'LoadingRule' factory for rules that load configuration data on-demand, and a 'loadEnviron' rule to test it with. Added unit test for the 'loadEnviron' rule, and code in the default GlobalConfig to add an "environ.*" rule based on loadEnviron. Also changed the default PropertyMap implementation to allow setting property values for "None", which is to say an assumed global property scope under the owner of the map.
Finished out the rest of the PropertyMap implementation. It turns out we need to distinguish between "rules" (which compute a property value for a specific target) and "defaults" (which compute a property value irrespective of the target object). Updated interfaces to reflect this. Reworked PropertyMap algorithms to properly handle delayed locking of eigenstate for missing rules/defaults that are loaded by a higher-level wildcard rule or default. Added scope management to the IPropertyMap interface and implementation; i.e. when you set a value you must specify the intended target object, so that IPropertyMaps which manage properties per-target can do so, and ones that don't support it can raise a fuss if they're asked to do it.
Added basic property-related APIs -- they should work fine except that they'll never find any IPropertyMap utilities to use! :) (IPropertyMap implementations are up next...) I also moved the config API implementation out of the 'api' module and into a separate 'api_impl' module to avoid crowding the 'api' module with details, plus I cleaned up the code a little and added a few docstrings.
cvs-admin@eby-sarna.com Powered by ViewCVS 1.0-dev |
ViewCVS and CVS Help |