Edgewall Software

Ticket #485: template-encoding-bugfix.diff

File template-encoding-bugfix.diff, 6.1 KB (added by hodgestar, 12 years ago)

Invasive patch that opens files loaded via the template loader as unicode. Undecided whether this is a good approach.

  • genshi/template/loader.py

     
    1414"""Template loading and caching."""
    1515
    1616import os
     17import codecs
    1718try:
    1819    import threading
    1920except ImportError:
     
    2122
    2223from genshi.template.base import TemplateError
    2324from genshi.util import LRUCache
     25from genshi.compat import StringIO
    2426
    2527__all__ = ['TemplateLoader', 'TemplateNotFound', 'directory', 'package',
    2628           'prefixed']
     
    120122        """Whether templates should be reloaded when the underlying file is
    121123        changed"""
    122124
    123         self.default_encoding = default_encoding
     125        if default_encoding is None:
     126            self.default_encoding = "utf-8"
     127        else:
     128            self.default_encoding = default_encoding
    124129        self.default_class = default_class or MarkupTemplate
    125130        self.variable_lookup = variable_lookup
    126131        self.allow_exec = allow_exec
     
    183188
    184189        filename = os.path.normpath(filename)
    185190        cachekey = filename
     191        if encoding is None:
     192            encoding = self.default_encoding
    186193
    187194        self._lock.acquire()
    188195        try:
     
    220227                if isinstance(loadfunc, basestring):
    221228                    loadfunc = directory(loadfunc)
    222229                try:
    223                     filepath, filename, fileobj, uptodate = loadfunc(filename)
     230                    filepath, filename, fileobj, uptodate = loadfunc(filename,
     231                                                                     encoding)
    224232                except IOError:
    225233                    continue
    226234                else:
     
    233241                            # search path
    234242                            filename = filepath
    235243                        tmpl = self._instantiate(cls, fileobj, filepath,
    236                                                  filename, encoding=encoding)
     244                                                 filename)
    237245                        if self.callback:
    238246                            self.callback(tmpl)
    239247                        self._cache[cachekey] = tmpl
     
    248256        finally:
    249257            self._lock.release()
    250258
    251     def _instantiate(self, cls, fileobj, filepath, filename, encoding=None):
     259    def _instantiate(self, cls, fileobj, filepath, filename):
    252260        """Instantiate and return the `Template` object based on the given
    253261        class and parameters.
    254262       
     
    262270        :param filepath: the absolute path to the template file
    263271        :param filename: the path to the template file relative to the search
    264272                         path
    265         :param encoding: the encoding of the template to load; defaults to the
    266                          ``default_encoding`` of the loader instance
    267273        :return: the loaded `Template` instance
    268274        :rtype: `Template`
    269275        """
    270         if encoding is None:
    271             encoding = self.default_encoding
     276        # encoding here is always None because the encoding has already
     277        # been handled by opening the file using codec.open(...) under
     278        # Python 2.x or open(...) under Python 3.x.
    272279        return cls(fileobj, filepath=filepath, filename=filename, loader=self,
    273                    encoding=encoding, lookup=self.variable_lookup,
     280                   encoding=None, lookup=self.variable_lookup,
    274281                   allow_exec=self.allow_exec)
    275282
    276283    @staticmethod
     
    281288        :return: the loader function to load templates from the given directory
    282289        :rtype: ``function``
    283290        """
    284         def _load_from_directory(filename):
     291        def _load_from_directory(filename, encoding):
    285292            filepath = os.path.join(path, filename)
    286             fileobj = open(filepath, 'rU')
     293            fileobj = codecs.open(filepath, 'rU', encoding=encoding)
    287294            mtime = os.path.getmtime(filepath)
    288295            def _uptodate():
    289296                return mtime == os.path.getmtime(filepath)
     
    300307        :rtype: ``function``
    301308        """
    302309        from pkg_resources import resource_stream
    303         def _load_from_package(filename):
     310        def _load_from_package(filename, encoding):
    304311            filepath = os.path.join(path, filename)
    305             return filepath, filename, resource_stream(name, filepath), None
     312            # TODO: read file iteratively
     313            bytes_stream = resource_stream(name, filepath)
     314            file_stream = StringIO(bytes_stream.read().decode(encoding))
     315            return filepath, filename, file_stream, None
    306316        return _load_from_package
    307317
    308318    @staticmethod
     
    314324        request to the delegate.
    315325       
    316326        >>> load = prefixed(
    317         ...     app1 = lambda filename: ('app1', filename, None, None),
    318         ...     app2 = lambda filename: ('app2', filename, None, None)
     327        ...     app1 = lambda filename, enc: ('app1', filename, None, None),
     328        ...     app2 = lambda filename, enc: ('app2', filename, None, None)
    319329        ... )
    320         >>> print(load('app1/foo.html'))
     330        >>> print(load('app1/foo.html', 'utf-8'))
    321331        ('app1', 'app1/foo.html', None, None)
    322         >>> print(load('app2/bar.html'))
     332        >>> print(load('app2/bar.html', 'utf-8'))
    323333        ('app2', 'app2/bar.html', None, None)
    324334       
    325335        :param delegates: mapping of path prefixes to loader functions
    326336        :return: the loader function
    327337        :rtype: ``function``
    328338        """
    329         def _dispatch_by_prefix(filename):
     339        def _dispatch_by_prefix(filename, encoding):
    330340            for prefix, delegate in delegates.items():
    331341                if filename.startswith(prefix):
    332342                    if isinstance(delegate, basestring):
    333343                        delegate = directory(delegate)
    334344                    filepath, _, fileobj, uptodate = delegate(
    335                         filename[len(prefix):].lstrip('/\\')
     345                        filename[len(prefix):].lstrip('/\\'),
     346                        encoding
    336347                    )
    337348                    return filepath, filename, fileobj, uptodate
    338349            raise TemplateNotFound(filename, list(delegates.keys()))