summaryrefslogtreecommitdiff
path: root/pystache/loader.py
blob: d4a7e5310ff4022dc27cb3e5bd57c63d817861b8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# coding: utf-8

"""
This module provides a Loader class for locating and reading templates.

"""

import os
import sys

from pystache import common
from pystache import defaults
from pystache.locator import Locator


# We make a function so that the current defaults take effect.
# TODO: revisit whether this is necessary.

def _make_to_unicode():
    def to_unicode(s, encoding=None):
        """
        Raises a TypeError exception if the given string is already unicode.

        """
        if encoding is None:
            encoding = defaults.STRING_ENCODING
        return unicode(s, encoding, defaults.DECODE_ERRORS)
    return to_unicode


class Loader(object):

    """
    Loads the template associated to a name or user-defined object.

    All load_*() methods return the template as a unicode string.

    """

    def __init__(self, file_encoding=None, extension=None, to_unicode=None,
                 search_dirs=None):
        """
        Construct a template loader instance.

        Arguments:

          extension: the template file extension, without the leading dot.
            Pass False for no extension (e.g. to use extensionless template
            files).  Defaults to the package default.

          file_encoding: the name of the encoding to use when converting file
            contents to unicode.  Defaults to the package default.

          search_dirs: the list of directories in which to search when loading
            a template by name or file name.  Defaults to the package default.

          to_unicode: the function to use when converting strings of type
            str to unicode.  The function should have the signature:

              to_unicode(s, encoding=None)

            It should accept a string of type str and an optional encoding
            name and return a string of type unicode.  Defaults to calling
            Python's built-in function unicode() using the package string
            encoding and decode errors defaults.

        """
        if extension is None:
            extension = defaults.TEMPLATE_EXTENSION

        if file_encoding is None:
            file_encoding = defaults.FILE_ENCODING

        if search_dirs is None:
            search_dirs = defaults.SEARCH_DIRS

        if to_unicode is None:
            to_unicode = _make_to_unicode()

        self.extension = extension
        self.file_encoding = file_encoding
        # TODO: unit test setting this attribute.
        self.search_dirs = search_dirs
        self.to_unicode = to_unicode

    def _make_locator(self):
        return Locator(extension=self.extension)

    def unicode(self, s, encoding=None):
        """
        Convert a string to unicode using the given encoding, and return it.

        This function uses the underlying to_unicode attribute.

        Arguments:

          s: a basestring instance to convert to unicode.  Unlike Python's
            built-in unicode() function, it is okay to pass unicode strings
            to this function.  (Passing a unicode string to Python's unicode()
            with the encoding argument throws the error, "TypeError: decoding
            Unicode is not supported.")

          encoding: the encoding to pass to the to_unicode attribute.
            Defaults to None.

        """
        if isinstance(s, unicode):
            return unicode(s)

        return self.to_unicode(s, encoding)

    def read(self, path, encoding=None):
        """
        Read the template at the given path, and return it as a unicode string.

        """
        b = common.read(path)

        if encoding is None:
            encoding = self.file_encoding

        return self.unicode(b, encoding)

    def load_file(self, file_name):
        """
        Find and return the template with the given file name.

        Arguments:

          file_name: the file name of the template.

        """
        locator = self._make_locator()

        path = locator.find_file(file_name, self.search_dirs)

        return self.read(path)

    def load_name(self, name):
        """
        Find and return the template with the given template name.

        Arguments:

          name: the name of the template.

        """
        locator = self._make_locator()

        path = locator.find_name(name, self.search_dirs)

        return self.read(path)

    # TODO: unit-test this method.
    def load_object(self, obj):
        """
        Find and return the template associated to the given object.

        Arguments:

          obj: an instance of a user-defined class.

          search_dirs: the list of directories in which to search.

        """
        locator = self._make_locator()

        path = locator.find_object(obj, self.search_dirs)

        return self.read(path)