[Subversion] / PEAK / src / peak / naming / names.py |
No default branch
Bookmark a link to HEAD:
(view)
(download)
(as text)
The 'logging.logger:' URL scheme has been simplified to 'logger:'. Please convert your scripts and configuration files, as the longer form will go away in the alpha 4 development cycle. Also, fix 'peak help logs' breaking due to a missing 'mdl_typeCode' on 'naming.CompositeName'.
Added 'naming.Indirect(key)', a 'binding.IComponentKey' that can be used to do an indirect lookup via another 'IComponentKey' (such as a name). Using 'naming.Indirect()', you can replace code like this:: socket = binding.Obtain( lambda self: self.lookupComponent(self.socketURL), adaptTo = [IListeningSocket] ) with code like this:: socket = binding.Obtain( naming.Indirect('socketURL'), adaptTo = [IListeningSocket] )
Removed all uses of deprecated binding APIs.
'naming.IBasicContext.lookup()' and 'naming.lookup()' now accept a 'default' argument, similar to that used by 'lookupComponent()' and most other lookup-like APIs in PEAK. This change was made so that component lookups don't need to rely on catching 'exceptions.NameNotFound' errors to tell them when to use the default value. This could hide 'NameNotFound' errors that were actually from a broken component somewhere in the lookup process. (In general, it's probably a bad idea to have an exception that's used for both control flow and real errors!) Also, removed most trapping of 'NameNotFound' errors throughout PEAK, except for those in N2, which I'll leave for Ty. :) Last, but not least, cleaned up documentation of related interfaces/methods.
Got rid of worst remaining 'isinstance()' occurrences in binding and naming; updated TODO.
Misc. peak.binding cleanups and DEPRECATIONS, as follows: - The following 'binding' forms are now deprecated, and will go away before 0.5 beta is released: 'bindToProperty(x,y)' -- use 'bindTo(PropertyName(x),default=y)' 'bindToParent()' -- use 'bindTo("..")' 'bindToSelf()' -- use 'bindTo(".")' 'bindToUtilities()' -- no replacement; let me know if you're using this. - 'naming.IName' is now derived from 'binding.IComponentKey', so names and addresses must now support the 'findComponent()' method. All PEAK name and address types provide support for this. - The 'lookup()' method of 'binding.IComponentKey' is now called 'findComponent()', to better distinguish it from 'lookup()' in 'naming.IBasicContext', which does something very different. - 'binding.bindTo()' and 'binding.bindSequence()' now pre-adapt their arguments to 'IComponentKey', to speed lookups at runtime, and to ensure that errors due to an unusable parameter type occur at class creation time instead of waiting until lookup time.
Drafted rough equivalents to "var" and "in". Refactored model and publishing traverals to use a name class (LocationPath) that knows how to do traversal. Moved Zope request subclasses to a separate module, so that you don't have to have Zope installed just to use templates (important for testing!). Made 'peak.naming' name classes (compound/composite and any derivative thereof) support 'adapt(stringOrUnicode,nameClass)' by parsing.
Got rid of the 'adaptTo' requirement for retrieving objects from naming contexts. Note that if you have defined any URL schemes that do not also define a naming context class, you will need to revise them. Specifically, you need to add a 'defaultFactory' attribute referencing the name of the class of object that the URL should retrieve, and you need to have that class declare that it (not its instances) provide 'naming.IObjectFactory', and add a 'getObjectInstance()' classmethod to do the dirty work. If your URL scheme references a subclass of ManagedConnection, you don't need to do the object factory stuff, however, as it's already done for you in the ManagedConnection base. All you need is the 'defaultFactory' attribute. Also, if you defined any adapter declarations for your URLs to the target class, you should get rid of them.
'peak.naming' no longer automatically converts all addresses to the addressed objects. You must specifically request the interface you want by adapting the retrieved object to that interface. This can be done by supplying an 'adaptTo=ISomething' keyword argument to the attribute binding definition or your 'lookupComponent()' call. The naming system no longer has 'objectFactories' and 'stateFactories'; these have been replaced with adaptation. Writable naming contexts must have a 'serializationProtocol' attribute specifying what interface an object should be adapted to before attempting to store it in that context. The naming system no longer processes the 'creationName' keyword argument; this is now considered the sole responsibility of 'peak.binding'. The 'IComponent.lookupComponent()' method still accepts the keyword argument, and attribute bindings still handle the creation name transparently. It is just not available via naming system APIs, and naming contexts no longer have to deal with it. Also, removed 'naming.ParsedURL'; it was deprecated as of 0.5 alpha 2. (Note: 'smtp:' URLs are currently broken, in that we don't have an interface to adapt them to for retrieval, and I didn't want to create an SMTP naming context, since what we want to do with SMTP is still up in the air.)
Finished switchover to using protocols.advise() API to declare interfaces.
And so we bid a fond farewell to introspection as well. 'isImplementedBy' is now a thing of the past. Refactored anything that used it, to now use adapt(), which has now opened up a lot of extension possibilities in places that were previously not extensible without modifying PEAK core code. See below. Also, the interface module has been refactored to support 'classProvides()' in a clean and kludge-free fashion, along with support for faster adaptation of old and new-style classes (by caching lookups, and by safely adding '__conform__' methods to classic classes), and the ability for classes to manage their own "implements" information. The core interface code is now quite elegant in the way it uses its own adaptation system as the basis for implementing adaptation. :) 'binding.Acquire()' now accepts a 'default' value argument, and 'binding.New()' no longer accepts the 'bindToOwner' flag. There is a new 'binding.IComponentKey' interface that is used to implement 'IComponent.lookupComponent()'. Now you can implement this interface, or create an adapter for it, in order to make an object usable as an argument to 'binding.lookupComponent()' - and therefore usable as a key for 'binding.bindTo()' or 'binding.bindToSequence()'. Not that it's necessarily very useful to do so; you're probably better off simply creating a naming scheme. But it might be useful for lookups done in the context of classes, since naming schemes aren't usable there. (It was actually added in order to factor out all the type testing that 'lookupComponent' used to do, so it doesn't matter if it's useful for much else.) PEAK has been refactored to avoid the use of 'isImplementedBy()' and similar introspection, in favor of 'adapt()'. As a result, some 'peak.naming' interfaces have changed. This should not affect you if you are only subclassing PEAK-provided naming components and not implementing these interfaces "from scratch". However, the various 'isAddress', 'isAddressClass', 'isResolver', and 'isName' APIs have also been removed, as they were based on 'isImplementedBy()'. The ability to use 'isImplementedBy()' with interfaces declared by PEAK is REMOVED. You can still use 'isImplementedBy()' with Zope interfaces, of course, but we recommend you switch to 'adapt()', which will work with both PEAK and Zope interfaces.
Added sensible defaults for most 'mdl_' attributes and methods, so that it's easier to create types that can be used as a structural feature's 'referencedType'.
Removed regular expression support from URL.Base; it was only there for ease of migration while I was switching all of PEAK's URL classes over to the new parsing framework. Since use of regular expressions for URL syntax is now deprecated (so that URLs can be formattable as well as parseable), there's no reason to keep this in URL.Base. Added the ability for other name types (composite and compound) to be used as structural feature types (e.g. for URL fields), and for compound name types to generate a corresponding composite name type. Changed LDAP urls to use this ability, which means the LDAP 'basedn' field is now always a composite name.
Integrated syntax-driven processing into 'peak.model', including addition of 'toString' and 'mdl_toString' methods. By defining a 'mdl_syntax' rule in any peak.model.Type subclass, you can get automatic rule-driven conversion to and from strings, including the parsing of nested field contents.
Repoint 'ParsedURL' -> 'URL.Base'; this will let existing 'ParsedURL' subclasses continue to work for a while, until 'ParsedURL' is removed in alpha 3.
Began work on replacing 'naming.ParsedURL' with a structure type using 'peak.model'. See 'CHANGES.txt' for a summary of how your ParsedURL subclasses must be changed. There is a further refactoring coming, however, to support simpler parsing mechanisms for complex URL syntaxes, and to support URLs generating a "canonical form" body part. This will be important for robust comparison of URLs, path manipulation, etc.
Removed unused imports, found by Martijn Faassen's clever 'importchecker' script. (http://www.zope.org/Members/faassen/importchecker)
Began documenting naming system interfaces that were previously opaque.
Normalized whitespace.
Fixed minor bugs found by playing around with the nis: and config: contexts in Ty's "namespace navigator" tool. One was a problem with parsing empty composite names, and the other was that a string name could creep into a situation where it should first have been converted to a compound name.
More doc and code cleanup for peak.naming, including updates to "nis:" context. The "nis:" context has been updated to use the latest in hierarchical namespace features, and is now simpler and clearer as an example than ever before -- while also serving as an example of some of the newer techniques. Also, moved name arithmetic functions out of naming.names and into their own module, since they just clutter up the module.
More docs and code cleanup for 'peak.naming'. Moved syntax-related classes to a separate module, 'naming.syntax'. Renamed 'Syntax' class to 'PathSyntax', to distinguish from the 'URLSyntax' helper that I'll be adding later. Got rid of legacy names for NameContext/AddressContext classes, and made NameContext and AddressContext accessible via the API, so context implementers don't have to import from peak.naming.contexts. (If you're using the naming system at all, it's pretty much guaranteed that something's going to import those classes, so we might as well put them in the API.)
Hierarchical contexts and composite namespaces work now. I had to refactor some of the context base class internals to get this to work reasonably, and there are now some new methods that can be overridden. In the simple case, overriding '_contextNNS()' lets you handle per-context NNS pointers. (And in the really simple case, you can ignore it altogether.) If you want to support explicit NNS pointers, you can override _get_nns(), _bind_nns(), and _unbind_nns() as well. The rules of name arithmetic have changed slightly; any addition that previously returned a composite name will now return a compound name, if it is possible to do so without changing the meaning of the returned name. Similarly, the parser for nesting a compound name inside a composite name, will return just a compound name if possible/appropriate. There are new 'naming.isBoundary()' and 'naming.crossesBoundary()' APIs that can be used to check if a name is a terminal namespace boundary, or crosses namespace boundaries, respectively. The name parsing tests have been updated for arithmetic and parsing changes, and also to use the new naming.parseURL() function instead of performing partial retrievals on the names. Finally, a new 'config:' URL scheme has been added, as a demo of the finished hierarchy and composite name support. For example, 'config:environ.TMP' refers to a 'PropertyContext()' for that property namespace, but 'config:environ.TMP/' returns the value of 'environ.TMP'. Similarly, 'naming.lookup("config:environ")["TMP/"]' returns the value, while 'naming.lookup("config:environ")["TMP"]' is just another naming context.
Fix to ensure that compound names embedded in a CompositeName are formatted without error.
Made it possible for CompositeName subclasses to use a separator other than '/'. This will be handy for URLs whose compound name syntax includes slashes, and thus want a different namespace delimiter.
Made 'body' part of a URL's state, if the only content of the URL is a scheme and body. This is true for import URLs, lockfile URLs, and generic URLs, at the least. This means such URLs should now compare and hash correctly, not to mention create authorities properly.
Major refactoring of naming system base classes for contexts and names. Enhancements include "name subtraction", smart resolution algorithms for both name-based and address-based contexts, improved syntax objects, URL-compatible syntax for CompositeName objects, with the ability to nest the parsing of a CompositeName's first element to a specific compound name syntax. Lots more tests, ability to specify a field of a URL as a hierarchical name object, simplified subclassing API for ParsedURL and naming contexts, and ParsedURLs can now have attribute bindings. All this stuff really needs a *lot* of documentation, but my brain is too fried to even think about trying to write it prior to this checkin.
Starting implementation of "name arithmetic". Composite and compound names can now be added to each other or themselves, with correct handling of namespace boundaries. (Well, the test cases work correctly, but I need to add some more of them.) Got rid of the 'isComposite/isCompound/isURL' flags, and replaced them with a 'nameKind' enumeration. The base 'Name' class is now 'AbstractName', since it's not a useful thing to instantiate.
Beginning of refactoring to support naming authorities, absolute addresses, etc. This is just a few small fixups; the main changes will be coming later in the refactoring to make "Address = Parameters + Name", and to move most of the "name arithmetic" into the name and address classes. It should then end up pretty easy to do most of the things people will want to do with new naming or address systems. One of the first changes here is to make AbstractContext -> NameContext, and GenericURLContext -> AddressContext. Nameless, contextless addresses will use AddressContext, and anything which contains a name will implement an address class, and a context based on NameContext. All of these names may change before the refactoring is done, which is why I've left in aliases to the old names for now.
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.)
Fixed some problems stringifying URLs.
Removing excessive DWIMishness from peak.naming, part 1: Made ParsedURLs accept a scheme and body, instead of trying to guess from a string what they should do. It's now the *sole* responsibility of naming.toName() to determine whether a string should be treated as a URL, and then only if it's told to make that determination. Next up: refactor naming context base classes to have unambiguous rules for how they parse and process names.
Added automatic URL-unquoting for ParsedURL classes that use a regex pattern for parsing. It can be overridden for specific regex fields using a 'dont_unquote' attribute. Misc. fixes to various name parsers, with new test cases added to cover the problems found.
Removed OpaqueURL and refactored ParsedURL for simpler creation of URL classes. This may need another pass or two to get everything completely cleaned up. Added a test suite for peak.naming to do parse tests on a variety of the built-in URL classes, which really needs a lot more test examples. The URL classes also need better parse error messages. Last, but not least, we may need a way to map from URLs back to their strings, if they are created from arguments instead of a string. But that's probably lower priority.
Reformatted peak.running.clusters docstring to structured text for better HappyDoc output. Defined the rule for 'peak.running.cluster._filename' in peak.ini instead of in the code. Renamed PropSet to PropertySet, and made it possible to go from a PropertyName to a PropertySet by calling '.of()' (e.g. 'PropertyName("foo").of(anObj)'. PropertySets can now reproduce in various ways, e.g.: c = PropertyName('peak.running.cluster').of(None) # -> PropertySet c._host['two.baz.com'] # ('even','prime','weird') c._groups() # ('odd','even','prime','weird','qux') But none of this is documented yet and possibly subject to change. :) (Especially since we're probably going to change how the cluster namespace works anyhow!) Ideally, it should be easy to go from a property name to its value or to a property set, and to go from a property set to a value in some namespace. Of course, it's somewhat questionable whether we'll be doing this for that many properties in the first place! And this is all going to go "full circle" once properties have a naming context that can be used to look them up in. I worry a bit about creeping TMTOWTDI-ism in all this. :(
Reverted the ability to omit schemes/bodies from parsed URLs, since that might violate the IName interface contract for URLs! Fixed a problem with _defaultScheme support. Made some notes in TODO about issues in the naming system that need review/investigation.
Simplified getURLContext() so it doesn't need a starting context. Made ParsedURL's support a '_defaultScheme' for use when a name doesn't include a scheme. Added 'formatString' support to ParsedURLs so they can display themselves differently from OpaqueURLs. Changed fromURL() method so that ParsedURL's don't have to keep the scheme and body parameters if they don't want to.
Fixed PropertyName.isDefault() bug. Made it possible to matchPatterns() on default names, thus allowing property defaults to be used to compute non-defaults.
Standardized call signature for metaclass.__new__ methods as __new__(meta, name, bases, ...) to make it easier to find metaclass __new__ methods (as opposed to class __new__ methods). Eliminated a metaclass __new__ that wasn't needed (replaced with an __init__). There are now only two PEAK metaclasses that use __new__: structType and Singleton. Neither is particularly likely to need mixing with Persistent.__class__, so we should be able to steer clear of any danger that might come about from Persistent.__class__ being somewhere other than at the end of the __bases__ list. Whew! I think that finally concludes the integration of Persistent into the model.Element base class; so now it should be possible to create Element subclasses and store the instances in Racks.
Re-org/refactoring of many items from the TODO list for 0.5, including: * moved peak.binding.imports -> peak.util.imports, added importSuite() * Decided not to do binding.Acquire, it should just be a documented idiom * Moved LDAP and lockfile URLs to peak.storage.LDAP and peak.running.lockfiles, respectively * Moved factories.getObjectInstance -> spi, updated peak.ini to load naming.spi as the provider. * Consolidated naming.references into naming.names * Made ParsedURLs compile their pattern strings, and automatically make their 'fromX()' methods classmethods (and the same is true for other 'struct' types. * Refactored cursors and connections out into distinct SQLCursor/LDAPCursor types, based on a common AbstractCursor. * Added TooManyResults/TooFewResults errors to peak.exceptions
Completed configuration files refactoring. Configuration files now can have [Load Settings From] and [Provide Utilities] sections, and property sections can now define rules instead of just values. Property values are eval()'d at rule access time rather than configuration loading time, and they have access to 'propertyMap', 'propertyName', and 'targetObj' locals, as well as the full peak.api.* and config_components' globals. "Load Settings From" sections can access a potentially infinite variety of sources for loading configuration data; the sources are defined using the 'peak.config.loaders.*' property namespace, and thus can be meta-configured even in the same configuration file. Builtin loader types are 'file' and 'mapping'. GlobalConfig no longer has any hard-wired configuration steps; everything is now in the peak.ini file. Subclasses of GlobalConfig need only perform 'self.config_filenames.append(fname)' before calling GlobalConfig's 'setup()' method, to cause additional config files to be loaded after 'peak.ini'. Everything that is configurable in PEAK, is now (in principle) configurable via property files.
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.
Added a basic configuration file format, and used it to replace the schemes dictionary in peak.naming.factories, by adding a "peak.ini" global configuration file for PEAK builtins. This means that the factories subpackage is pretty much useless now; the URL classes can easily move anywhere now, like to the same modules as the implementations. It should now be easy to add lots of address schemes to PEAK. Also, subclasses of GlobalConfig can change the list of filenames used to load configuration settings, and thus perhaps read a ~.peakrc or /etc/peak.ini file, or an app-specific global configuration file. The file format is very primitive right now: ConfigParser with eval() of the settings done at file load time. Ultimately, this should move to a true lazy evaluation mode, and there are some syntactic sugar features that should be added. For right now, however, all we need are constant expressions. Last, but not least, fixed a bug in the fromURL() method of ParsedURLs.
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.
Fixed GenericURLContext parser kludge by adding a supportsScheme() method to OpaqueURL/ParsedURL.
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. :(
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.
Made ParsedURL objects implement IAddress by default, with a default retrieve() that returns None (causing fallback to other object factories, if available).
Fixed up struct's constructor calling patterns to be a bit more sensible, and adjusted naming classes accordingly.
Another pass at simplifying peak.naming. Added GenericURLContext so it's not necessary to implement a context if a URL scheme is just an object address. Simplified approach to specify factory objects for such schenes, also, but in a rather hackish way for now. A proper fix for this will have to wait until I've stripped out a few more things, fixed up the interfaces a bit, and maybe begun to integrate with the configuration system. :(
Fixed some class/type problems with NamingExceptions; refactored URL classes to use the new 'struct' class as a base type.
Another typo
fix typo
Changed default name parsing arguments to match the new strategy of making CompositeNames the "complex things should be possible" branch. :) toName() now accepts URLs by default, and converts strings to flat CompoundName objects by default.
Fixed a couple of minor errors in formatting of URLs and exceptions. Most of the stuff in the 'names' module now seems to be working correctly, from manual testing in IDLE. I should probably write some automated tests next.
Fixed things up enough that 'import peak.naming' doesn't throw any exceptions. :) Specifically, I reincorporated exceptions into the interfaces module, fixed up dangling uppercase module names, and fixed a problem with Syntax objects failing to compile a regular expression for a "flat" naming syntax.
Fix up some imports XXX: names can't import exceptions, since that gets the global exceptions module. Trying to import peak.naming.exceptions doesn't seem to work because that imports naming.__init__ which imports names.py. Hrm...
Added Parsed URL support, default object/URL context factories, and support for TW.Utils.Import to import relative to a particular package.
Refactored to separate "operation" and "naming resolution" objects from context objects. This will probably become meaningless since Ty and I just worked out how to implement federation in a much cleaner way than JNDI does it. So tomorrow I'll be ripping out most of this and starting over... But it will get rid of crap like CannotProceedException and all the enormous complexity of composite name management for things that don't need composite names.
Misc. consistency cleanups.
Fleshed out NamingException classes. Renamed the API for 'getInitialContext()' to 'InitialContext()' for more similarity to JNDI API. Fleshed out federation handling in AbstractContext to include compound name parsing for local name parts, and full CPE handling. Misc. interface fixups/cleanups. Dropped 'InitialContexts' module for now. Added stubs for the last needed SPI functions. Dropped "hook"-setting functions from SPI, because YAGNI, and you can always monkeypatch instead.
Added Names module, with support for CompositeNames, CompoundNames, OpaqueURLs, Syntax objects, and the 'toName()' function.
cvs-admin@eby-sarna.com Powered by ViewCVS 1.0-dev |
ViewCVS and CVS Help |