[3] | 1 | # $Id: ImportHooks.py,v 1.27 2007/11/16 18:28:47 tavis_rudd Exp $ |
---|
| 2 | |
---|
| 3 | """Provides some import hooks to allow Cheetah's .tmpl files to be imported |
---|
| 4 | directly like Python .py modules. |
---|
| 5 | |
---|
| 6 | To use these: |
---|
| 7 | import Cheetah.ImportHooks |
---|
| 8 | Cheetah.ImportHooks.install() |
---|
| 9 | |
---|
| 10 | Meta-Data |
---|
| 11 | ================================================================================ |
---|
| 12 | Author: Tavis Rudd <tavis@damnsimple.com> |
---|
| 13 | License: This software is released for unlimited distribution under the |
---|
| 14 | terms of the MIT license. See the LICENSE file. |
---|
| 15 | Version: $Revision: 1.27 $ |
---|
| 16 | Start Date: 2001/03/30 |
---|
| 17 | Last Revision Date: $Date: 2007/11/16 18:28:47 $ |
---|
| 18 | """ |
---|
| 19 | __author__ = "Tavis Rudd <tavis@damnsimple.com>" |
---|
| 20 | __revision__ = "$Revision: 1.27 $"[11:-2] |
---|
| 21 | |
---|
| 22 | import sys |
---|
| 23 | import os.path |
---|
| 24 | import types |
---|
| 25 | import __builtin__ |
---|
| 26 | import new |
---|
| 27 | import imp |
---|
| 28 | from threading import RLock |
---|
| 29 | import string |
---|
| 30 | import traceback |
---|
| 31 | from Cheetah import ImportManager |
---|
| 32 | from Cheetah.ImportManager import DirOwner |
---|
| 33 | from Cheetah.Compiler import Compiler |
---|
| 34 | from Cheetah.convertTmplPathToModuleName import convertTmplPathToModuleName |
---|
| 35 | |
---|
| 36 | _installed = False |
---|
| 37 | |
---|
| 38 | ################################################## |
---|
| 39 | ## HELPER FUNCS |
---|
| 40 | |
---|
| 41 | _cacheDir = [] |
---|
| 42 | def setCacheDir(cacheDir): |
---|
| 43 | global _cacheDir |
---|
| 44 | _cacheDir.append(cacheDir) |
---|
| 45 | |
---|
| 46 | ################################################## |
---|
| 47 | ## CLASSES |
---|
| 48 | |
---|
| 49 | class CheetahDirOwner(DirOwner): |
---|
| 50 | _lock = RLock() |
---|
| 51 | _acquireLock = _lock.acquire |
---|
| 52 | _releaseLock = _lock.release |
---|
| 53 | |
---|
| 54 | templateFileExtensions = ('.tmpl',) |
---|
| 55 | |
---|
| 56 | def getmod(self, name): |
---|
| 57 | self._acquireLock() |
---|
| 58 | try: |
---|
| 59 | mod = DirOwner.getmod(self, name) |
---|
| 60 | if mod: |
---|
| 61 | return mod |
---|
| 62 | |
---|
| 63 | for ext in self.templateFileExtensions: |
---|
| 64 | tmplPath = os.path.join(self.path, name + ext) |
---|
| 65 | if os.path.exists(tmplPath): |
---|
| 66 | try: |
---|
| 67 | return self._compile(name, tmplPath) |
---|
| 68 | except: |
---|
| 69 | # @@TR: log the error |
---|
| 70 | exc_txt = traceback.format_exc() |
---|
| 71 | exc_txt =' '+(' \n'.join(exc_txt.splitlines())) |
---|
| 72 | raise ImportError( |
---|
| 73 | 'Error while compiling Cheetah module' |
---|
| 74 | ' %(name)s, original traceback follows:\n%(exc_txt)s'%locals()) |
---|
| 75 | ## |
---|
| 76 | return None |
---|
| 77 | |
---|
| 78 | finally: |
---|
| 79 | self._releaseLock() |
---|
| 80 | |
---|
| 81 | def _compile(self, name, tmplPath): |
---|
| 82 | ## @@ consider adding an ImportError raiser here |
---|
| 83 | code = str(Compiler(file=tmplPath, moduleName=name, |
---|
| 84 | mainClassName=name)) |
---|
| 85 | if _cacheDir: |
---|
| 86 | __file__ = os.path.join(_cacheDir[0], |
---|
| 87 | convertTmplPathToModuleName(tmplPath)) + '.py' |
---|
| 88 | try: |
---|
| 89 | open(__file__, 'w').write(code) |
---|
| 90 | except OSError: |
---|
| 91 | ## @@ TR: need to add some error code here |
---|
| 92 | traceback.print_exc(file=sys.stderr) |
---|
| 93 | __file__ = tmplPath |
---|
| 94 | else: |
---|
| 95 | __file__ = tmplPath |
---|
| 96 | co = compile(code+'\n', __file__, 'exec') |
---|
| 97 | |
---|
| 98 | mod = imp.new_module(name) |
---|
| 99 | mod.__file__ = co.co_filename |
---|
| 100 | if _cacheDir: |
---|
| 101 | mod.__orig_file__ = tmplPath # @@TR: this is used in the WebKit |
---|
| 102 | # filemonitoring code |
---|
| 103 | mod.__co__ = co |
---|
| 104 | return mod |
---|
| 105 | |
---|
| 106 | |
---|
| 107 | ################################################## |
---|
| 108 | ## FUNCTIONS |
---|
| 109 | |
---|
| 110 | def install(templateFileExtensions=('.tmpl',)): |
---|
| 111 | """Install the Cheetah Import Hooks""" |
---|
| 112 | |
---|
| 113 | global _installed |
---|
| 114 | if not _installed: |
---|
| 115 | CheetahDirOwner.templateFileExtensions = templateFileExtensions |
---|
| 116 | import __builtin__ |
---|
| 117 | if type(__builtin__.__import__) == types.BuiltinFunctionType: |
---|
| 118 | global __oldimport__ |
---|
| 119 | __oldimport__ = __builtin__.__import__ |
---|
| 120 | ImportManager._globalOwnerTypes.insert(0, CheetahDirOwner) |
---|
| 121 | #ImportManager._globalOwnerTypes.append(CheetahDirOwner) |
---|
| 122 | global _manager |
---|
| 123 | _manager=ImportManager.ImportManager() |
---|
| 124 | _manager.setThreaded() |
---|
| 125 | _manager.install() |
---|
| 126 | |
---|
| 127 | def uninstall(): |
---|
| 128 | """Uninstall the Cheetah Import Hooks""" |
---|
| 129 | global _installed |
---|
| 130 | if not _installed: |
---|
| 131 | import __builtin__ |
---|
| 132 | if type(__builtin__.__import__) == types.MethodType: |
---|
| 133 | __builtin__.__import__ = __oldimport__ |
---|
| 134 | global _manager |
---|
| 135 | del _manager |
---|
| 136 | |
---|
| 137 | if __name__ == '__main__': |
---|
| 138 | install() |
---|