| 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() |
|---|