From 89eae3cc302909811cd269bde7a9a80ac17ab747 Mon Sep 17 00:00:00 2001
From: Mike Bayer <mike_mp@zzzcomputing.com>
Date: Fri, 5 Mar 2010 18:47:56 +0000
Subject: [PATCH] - Windows paths are handled correctly if a Template   is
 passed only an absolute filename (i.e. with c:   drive etc.)  and no URI -
 the URI is converted   to a forward-slash path and module_directory   is
 treated as a windows path.  [ticket:128]

---
 CHANGES               |  6 ++++
 mako/template.py      | 76 +++++++++++++++++++++++--------------------
 test/test_template.py | 63 +++++++++++++++++++++++++++++++++++
 3 files changed, 110 insertions(+), 35 deletions(-)

diff --git a/CHANGES b/CHANGES
index 06d7643..eb38534 100644
--- a/CHANGES
+++ b/CHANGES
@@ -44,6 +44,12 @@
   no longer get doubly-rendered in the body() scope,
   and now allow local variable assignment without
   breakage.  [ticket:109]
+
+- Windows paths are handled correctly if a Template
+  is passed only an absolute filename (i.e. with c: 
+  drive etc.)  and no URI - the URI is converted
+  to a forward-slash path and module_directory
+  is treated as a windows path.  [ticket:128]
   
 0.2.6
 
diff --git a/mako/template.py b/mako/template.py
index 9104683..b7c5419 100644
--- a/mako/template.py
+++ b/mako/template.py
@@ -57,7 +57,9 @@ class Template(object):
             self.uri = uri
         elif filename:
             self.module_id = re.sub(r'\W', "_", filename)
-            self.uri = filename
+            drive, path = os.path.splitdrive(filename)
+            path = os.path.normpath(path).replace(os.path.sep, "/")
+            self.uri = path
         else:
             self.module_id = "memory:" + hex(id(self))
             self.uri = self.module_id
@@ -101,43 +103,14 @@ class Template(object):
                     u = u[1:]
                 path = os.path.abspath(
                         os.path.join(
-                            module_directory.replace('/', os.path.sep), 
-                            u + ".py"
+                            os.path.normpath(module_directory), 
+                            os.path.normpath(u) + ".py"
                             )
                         )
             else:
-                path = None    
-            if path is not None:
-                util.verify_directory(os.path.dirname(path))
-                filemtime = os.stat(filename)[stat.ST_MTIME]
-                if not os.path.exists(path) or \
-                            os.stat(path)[stat.ST_MTIME] < filemtime:
-                    _compile_module_file(
-                                self, 
-                                open(filename, 'rb').read(), 
-                                filename, 
-                                path)
-                module = imp.load_source(self.module_id, path, open(path, 'rb'))
-                del sys.modules[self.module_id]
-                if module._magic_number != codegen.MAGIC_NUMBER:
-                    _compile_module_file(
-                                self, 
-                                open(filename, 'rb').read(), 
-                                filename, 
-                                path)
-                    module = imp.load_source(self.module_id, path, open(path, 'rb'))
-                    del sys.modules[self.module_id]
-                ModuleInfo(module, path, self, filename, None, None)
-            else:
-                # template filename and no module directory, compile code
-                # in memory
-                (code, module) = _compile_text(
-                                    self, 
-                                    open(filename, 'rb').read(), 
-                                    filename)
-                self._source = None
-                self._code = code
-                ModuleInfo(module, None, self, filename, code, None)
+                path = None
+                
+            module = self._compile_from_file(path, filename)
         else:
             raise exceptions.RuntimeException(
                                 "Template requires text or filename")
@@ -153,6 +126,39 @@ class Template(object):
         self.cache_url = cache_url
         self.cache_enabled = cache_enabled
     
+    def _compile_from_file(self, path, filename):
+        if path is not None:
+            util.verify_directory(os.path.dirname(path))
+            filemtime = os.stat(filename)[stat.ST_MTIME]
+            if not os.path.exists(path) or \
+                        os.stat(path)[stat.ST_MTIME] < filemtime:
+                _compile_module_file(
+                            self, 
+                            open(filename, 'rb').read(), 
+                            filename, 
+                            path)
+            module = imp.load_source(self.module_id, path, open(path, 'rb'))
+            del sys.modules[self.module_id]
+            if module._magic_number != codegen.MAGIC_NUMBER:
+                _compile_module_file(
+                            self, 
+                            open(filename, 'rb').read(), 
+                            filename, 
+                            path)
+                module = imp.load_source(self.module_id, path, open(path, 'rb'))
+                del sys.modules[self.module_id]
+            ModuleInfo(module, path, self, filename, None, None)
+        else:
+            # template filename and no module directory, compile code
+            # in memory
+            code, module = _compile_text(
+                                self, 
+                                open(filename, 'rb').read(), 
+                                filename)
+            self._source = None
+            self._code = code
+            ModuleInfo(module, None, self, filename, code, None)
+        return module
     @property
     def source(self):
         """return the template source code for this Template."""
diff --git a/test/test_template.py b/test/test_template.py
index c738012..4b5b94a 100644
--- a/test/test_template.py
+++ b/test/test_template.py
@@ -678,6 +678,69 @@ class ModuleDirTest(TemplateTest):
             os.path.join(module_base, 'subdir', 'foo', 'modtest.html.py')
         )
 
+class FilenameToURITest(TemplateTest):
+    def test_windows_paths(self):
+        """test that windows filenames are handled appropriately by Template."""
+        
+        current_path = os.path
+        import ntpath
+        os.path = ntpath
+        try:
+            class NoCompileTemplate(Template):
+                def _compile_from_file(self, path, filename):
+                    self.path = path
+                    return Template("foo bar").module
+                    
+            t1 = NoCompileTemplate(
+                                    filename="c:\\foo\\template.html", 
+                                    module_directory="c:\\modules\\")
+            
+            eq_(t1.uri, "/foo/template.html")
+            eq_(t1.path, "c:\\modules\\foo\\template.html.py")
+
+            t1 = NoCompileTemplate(
+                                    filename="c:\\path\\to\\templates\\template.html", 
+                                    uri = "/bar/template.html",
+                                    module_directory="c:\\modules\\")
+            
+            eq_(t1.uri, "/bar/template.html")
+            eq_(t1.path, "c:\\modules\\bar\\template.html.py")
+
+        finally:
+            os.path = current_path
+
+    def test_posix_paths(self):
+        """test that posixs filenames are handled appropriately by Template."""
+
+        current_path = os.path
+        import posixpath
+        os.path = posixpath
+        try:
+            class NoCompileTemplate(Template):
+                def _compile_from_file(self, path, filename):
+                    self.path = path
+                    return Template("foo bar").module
+
+            t1 = NoCompileTemplate(
+                                    filename="/var/www/htdocs/includes/template.html", 
+                                    module_directory="/var/lib/modules")
+
+            eq_(t1.uri, "/var/www/htdocs/includes/template.html")
+            eq_(t1.path, "/var/lib/modules/var/www/htdocs/includes/template.html.py")
+
+            t1 = NoCompileTemplate(
+                                    filename="/var/www/htdocs/includes/template.html", 
+                                    uri = "/bar/template.html",
+                                    module_directory="/var/lib/modules")
+
+            eq_(t1.uri, "/bar/template.html")
+            eq_(t1.path, "/var/lib/modules/bar/template.html.py")
+
+        finally:
+            os.path = current_path
+        
+    
+    
 class ModuleTemplateTest(TemplateTest):
     def test_module_roundtrip(self):
         lookup = TemplateLookup()
-- 
GitLab