[Subversion] / PEAK / src / peak / util / imports.py |
No default branch
Bookmark a link to HEAD:
(view)
(download)
(as text)
Fixed some 'whenImported()' hooks firing early, which could cause problems in some lazy import situations.
Fix double-reload caused by "double-layered laziness". Apparently Python can sometimes import a module into one of our "lazy module" objects without our noticing that it has done so. Fix this by checking to see if module has any contents before reloading it. This fixes the problems using Zope with PEAK that were reported by Wayne Larsen, and replaces the quick hack I gave on the mailing list.
Fixes for lazy imports and whenImported(). Previously, a direct import of a lazily imported module whose parent package wasn't imported (lazily or otherwise) could cause an error. Also, setting an attribute of a lazy module didn't necessarily trigger the module to be imported. Finally, whenImported() doesn't create lazy modules until the module's parent is loaded (except for top-level packages). This reduces unnecessary clutter in 'sys.modules', and avoids giving the impression that such modules are actually present in the system until at least their parent package exists.
Change 'importString()' for better compatibility with import hooks (such as imputil).
Fixed 'peak.util.imports.whenImported()' function, so you can now register functions to be called when another module is imported. This should be useful for declaring adapters for external types, e.g. adapting Zope interfaces to IConfigKey, without causing the external type to be imported unless it's actually used.
Normalized whitespace.
Re-documented/undeprecated ':' in import strings. Editing peak.ini and elsewhere, I realized that it *really* helps in understanding an import string. It may not be necessary for the computer to interpret it, but it helps us humans figure out what module file we need to look for.
Fixed the mysterious "UML tests fail on Linux" bug. Apparently, under the old 'importString()' algorithm, specifying a trailing ':' works on Windows but not Linux. (Which is *really* weird, since in theory '__import__()' shouldn't behave differently. I think it might have something to do with an empty string being a valid directory name on Unix and not on Windows.) Anyway, I still need to track down and kill all the remaining ':' usage in import strings, but now at least the test suite works.
Cleaned up import string syntax; ':' is still recognized, but is now undocumented and deprecated. We now use a "'getattr()' first and '__import__()' second" algorithm similar to that used by ZConfig. While it is still subject to ambiguity (it believes what a module puts inside of itself over what 'sys.modules' says), it is also more robust. Our old algorithm was subject to quirkyness that this one should not be.
Added 'whenImported(modulename,hookFunc)' API. This should be useful for setting up lazily-activated initializers for third-party packages such as Zope, Twisted, and the Python 'logging' package. Meanwhile, it helped clean up the kludgy "reloader" mechanism I had in there to make 'declareModule()' work. 'declareModule()' now just sets up a hook via the 'whenImported' mechanism to work its magic, instead of using a custom reloader. Custom reloaders for lazy modules are now in fact disallowed; the new mechanism is more flexible and usable by multiple callers. Errors are also now more standardized: 'AlreadyRead' is used whenever the issue is that something has already been read/imported.
REINSTALL WARNING: a package was removed from setup.py on this change, so be sure to *delete* your PEAK installation from 'site-packages' before reinstalling. Also be sure to update your checkout with 'cvs update -dPA'. Change notes: * It's now possible to use 'config.declareModule()' to patch third-party (i.e. non-PEAK) modules, and also to pre-declare inheritance or patch data for modules inherited via package inheritance. This was done to make PEAK/Zope reusage/patching easier, and also to ease patching of large generated-code models (like UML and CWM). * The patches to add "Pythonic features" to UML models are now in a separate module, 'peak.metamodels.core_addons', so that they can be shared amongst all UML versions. This was made possible by the new 'declareModule()' function. * Cleaned up and removed the now-unnecessary subpackage of UML13 that was there just to provide a home for the patches that can now be applied by "remote control", so to speak. * 'lazyModule()' now has an extra parameter that can be used to hook the initial loading of a module. This was added so that 'declareModule()' can patch modules when they are loaded.
Package inheritance support: 'config.setupModule()' now automatically munges the '__path__' of inheriting packages for you. Also, '__bases__' can now contain '/'-separated relative or absolute paths to the desired base modules (i.e. you don't have to import them yourself). Last, but not least, you can now inherit from modules that don't call 'setupModule()'! This means that you can now re-use code from non-PEAK packages and totally bend them to your will! As long as their code is 1) pure Python, and 2) available from a .py or .pyc file on disk, that is. Documented these new features, updated tests and other misc. code to match.
Added 'relativePath' parameter to 'lazyModule()' to support relative imports for module inheritance (package inheritance, actually). Documented 'lazyModule()' and removed the now-unused 'lazyImport' class.
Fixed import utilities so that by default, they import from the top-level package namespace, rather than from within 'peak.util'.
Fixed repeat loads & orphaned modules caused if module is already loaded
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.)
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
cvs-admin@eby-sarna.com Powered by ViewCVS 1.0-dev |
ViewCVS and CVS Help |