OLD | NEW |
(Empty) | |
| 1 # coding: utf-8 |
| 2 |
| 3 """ |
| 4 This module provides a Locator class for finding template files. |
| 5 |
| 6 """ |
| 7 |
| 8 import os |
| 9 import re |
| 10 import sys |
| 11 |
| 12 from pystache.common import TemplateNotFoundError |
| 13 from pystache import defaults |
| 14 |
| 15 |
| 16 class Locator(object): |
| 17 |
| 18 def __init__(self, extension=None): |
| 19 """ |
| 20 Construct a template locator. |
| 21 |
| 22 Arguments: |
| 23 |
| 24 extension: the template file extension, without the leading dot. |
| 25 Pass False for no extension (e.g. to use extensionless template |
| 26 files). Defaults to the package default. |
| 27 |
| 28 """ |
| 29 if extension is None: |
| 30 extension = defaults.TEMPLATE_EXTENSION |
| 31 |
| 32 self.template_extension = extension |
| 33 |
| 34 def get_object_directory(self, obj): |
| 35 """ |
| 36 Return the directory containing an object's defining class. |
| 37 |
| 38 Returns None if there is no such directory, for example if the |
| 39 class was defined in an interactive Python session, or in a |
| 40 doctest that appears in a text file (rather than a Python file). |
| 41 |
| 42 """ |
| 43 if not hasattr(obj, '__module__'): |
| 44 return None |
| 45 |
| 46 module = sys.modules[obj.__module__] |
| 47 |
| 48 if not hasattr(module, '__file__'): |
| 49 # TODO: add a unit test for this case. |
| 50 return None |
| 51 |
| 52 path = module.__file__ |
| 53 |
| 54 return os.path.dirname(path) |
| 55 |
| 56 def make_template_name(self, obj): |
| 57 """ |
| 58 Return the canonical template name for an object instance. |
| 59 |
| 60 This method converts Python-style class names (PEP 8's recommended |
| 61 CamelCase, aka CapWords) to lower_case_with_underscords. Here |
| 62 is an example with code: |
| 63 |
| 64 >>> class HelloWorld(object): |
| 65 ... pass |
| 66 >>> hi = HelloWorld() |
| 67 >>> |
| 68 >>> locator = Locator() |
| 69 >>> locator.make_template_name(hi) |
| 70 'hello_world' |
| 71 |
| 72 """ |
| 73 template_name = obj.__class__.__name__ |
| 74 |
| 75 def repl(match): |
| 76 return '_' + match.group(0).lower() |
| 77 |
| 78 return re.sub('[A-Z]', repl, template_name)[1:] |
| 79 |
| 80 def make_file_name(self, template_name, template_extension=None): |
| 81 """ |
| 82 Generate and return the file name for the given template name. |
| 83 |
| 84 Arguments: |
| 85 |
| 86 template_extension: defaults to the instance's extension. |
| 87 |
| 88 """ |
| 89 file_name = template_name |
| 90 |
| 91 if template_extension is None: |
| 92 template_extension = self.template_extension |
| 93 |
| 94 if template_extension is not False: |
| 95 file_name += os.path.extsep + template_extension |
| 96 |
| 97 return file_name |
| 98 |
| 99 def _find_path(self, search_dirs, file_name): |
| 100 """ |
| 101 Search for the given file, and return the path. |
| 102 |
| 103 Returns None if the file is not found. |
| 104 |
| 105 """ |
| 106 for dir_path in search_dirs: |
| 107 file_path = os.path.join(dir_path, file_name) |
| 108 if os.path.exists(file_path): |
| 109 return file_path |
| 110 |
| 111 return None |
| 112 |
| 113 def _find_path_required(self, search_dirs, file_name): |
| 114 """ |
| 115 Return the path to a template with the given file name. |
| 116 |
| 117 """ |
| 118 path = self._find_path(search_dirs, file_name) |
| 119 |
| 120 if path is None: |
| 121 raise TemplateNotFoundError('File %s not found in dirs: %s' % |
| 122 (repr(file_name), repr(search_dirs))) |
| 123 |
| 124 return path |
| 125 |
| 126 def find_file(self, file_name, search_dirs): |
| 127 """ |
| 128 Return the path to a template with the given file name. |
| 129 |
| 130 Arguments: |
| 131 |
| 132 file_name: the file name of the template. |
| 133 |
| 134 search_dirs: the list of directories in which to search. |
| 135 |
| 136 """ |
| 137 return self._find_path_required(search_dirs, file_name) |
| 138 |
| 139 def find_name(self, template_name, search_dirs): |
| 140 """ |
| 141 Return the path to a template with the given name. |
| 142 |
| 143 Arguments: |
| 144 |
| 145 template_name: the name of the template. |
| 146 |
| 147 search_dirs: the list of directories in which to search. |
| 148 |
| 149 """ |
| 150 file_name = self.make_file_name(template_name) |
| 151 |
| 152 return self._find_path_required(search_dirs, file_name) |
| 153 |
| 154 def find_object(self, obj, search_dirs, file_name=None): |
| 155 """ |
| 156 Return the path to a template associated with the given object. |
| 157 |
| 158 """ |
| 159 if file_name is None: |
| 160 # TODO: should we define a make_file_name() method? |
| 161 template_name = self.make_template_name(obj) |
| 162 file_name = self.make_file_name(template_name) |
| 163 |
| 164 dir_path = self.get_object_directory(obj) |
| 165 |
| 166 if dir_path is not None: |
| 167 search_dirs = [dir_path] + search_dirs |
| 168 |
| 169 path = self._find_path_required(search_dirs, file_name) |
| 170 |
| 171 return path |
OLD | NEW |