Repository: peterbe/premailer

Issue:
Reusing premailer instances does not work
The README contains a [nice section](https://github.com/peterbe/premailer#if-execution-speed-is-on-your-mind) on speeding up premailer by reusing premailer instances. This, however, [throws an exception](https://github.com/peterbe/premailer/blob/master/premailer/premailer.py#L319) on subsequent iterations because the instance's internal `html` attribute was already set on the first iteration.

Possible solutions:
 **a)** Refactor code to allow for multiple runs
 **b)** Remove problematic section from documentation

Discussion:
coveralls: 
[![Coverage Status](https://coveralls.io/builds/21793245/badge)](https://coveralls.io/builds/21793245)

Coverage remained the same at 100.0% when pulling **6cd4c888807b5c173d649b60f31ec07f62e47f6e on viernullvier:instance-reuse** into **350af2440ccc9598d01841d1a22a8e5236da85a1 on peterbe:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/21793245/badge)](https://coveralls.io/builds/21793245)

Coverage remained the same at 100.0% when pulling **6cd4c888807b5c173d649b60f31ec07f62e47f6e on viernullvier:instance-reuse** into **350af2440ccc9598d01841d1a22a8e5236da85a1 on peterbe:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/21793245/badge)](https://coveralls.io/builds/21793245)

Coverage remained the same at 100.0% when pulling **6cd4c888807b5c173d649b60f31ec07f62e47f6e on viernullvier:instance-reuse** into **350af2440ccc9598d01841d1a22a8e5236da85a1 on peterbe:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/21793245/badge)](https://coveralls.io/builds/21793245)

Coverage remained the same at 100.0% when pulling **6cd4c888807b5c173d649b60f31ec07f62e47f6e on viernullvier:instance-reuse** into **350af2440ccc9598d01841d1a22a8e5236da85a1 on peterbe:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/21793245/badge)](https://coveralls.io/builds/21793245)

Coverage remained the same at 100.0% when pulling **6cd4c888807b5c173d649b60f31ec07f62e47f6e on viernullvier:instance-reuse** into **350af2440ccc9598d01841d1a22a8e5236da85a1 on peterbe:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/21793245/badge)](https://coveralls.io/builds/21793245)

Coverage remained the same at 100.0% when pulling **6cd4c888807b5c173d649b60f31ec07f62e47f6e on viernullvier:instance-reuse** into **350af2440ccc9598d01841d1a22a8e5236da85a1 on peterbe:master**.


Patch:
diff --git a/premailer/premailer.py b/premailer/premailer.py
index 344a6ad..37fd743 100644
--- a/premailer/premailer.py
+++ b/premailer/premailer.py
@@ -311,18 +311,18 @@ class Premailer(object):
         return rules, leftover
 
     def transform(self, html=None, pretty_print=True, **kwargs):
-        """change the self.html and return it with CSS turned into style
+        """change the html and return it with CSS turned into style
         attributes.
         """
-        if html is not None:
-            if self.html is not None:
-                raise TypeError("Can't pass html argument twice")
-            self.html = html
-        elif self.html is None:
+        if html is not None and self.html is not None:
+            raise TypeError("Can't pass html argument twice")
+        elif html is None and self.html is None:
             raise TypeError("must pass html as first argument")
-        if hasattr(self.html, "getroottree"):
+        elif html is None:
+            html = self.html
+        if hasattr(html, "getroottree"):
             # skip the next bit
-            root = self.html.getroottree()
+            root = html.getroottree()
             page = root
             tree = root
         else:
@@ -330,7 +330,7 @@ class Premailer(object):
                 parser = etree.XMLParser(ns_clean=False, resolve_entities=False)
             else:
                 parser = etree.HTMLParser()
-            stripped = self.html.strip()
+            stripped = html.strip()
             tree = etree.fromstring(stripped, parser).getroottree()
             page = tree.getroot()
             # lxml inserts a doctype if none exists, so only include it in
@@ -379,6 +379,7 @@ class Premailer(object):
                 css_body = self._load_external(href)
 
             these_rules, these_leftover = self._parse_style_rules(css_body, index)
+
             index += 1
             rules.extend(these_rules)
             parent_of_element = element.getparent()
@@ -522,7 +523,7 @@ class Premailer(object):
                         continue
                     parent.attrib[attr] = urljoin(self.base_url, url)
 
-        if hasattr(self.html, "getroottree"):
+        if hasattr(html, "getroottree"):
             return root
         else:
             kwargs.setdefault("method", self.method)


Test patch:
diff --git a/premailer/tests/test_premailer.py b/premailer/tests/test_premailer.py
index f0ef4ac..0ff7a37 100644
--- a/premailer/tests/test_premailer.py
+++ b/premailer/tests/test_premailer.py
@@ -215,6 +215,68 @@ class Tests(unittest.TestCase):
         p = Premailer()
         assert_raises(TypeError, p.transform)
 
+    def test_instance_reuse(self):
+        """test whether the premailer instance can be reused"""
+
+        html_1 = """<html>
+        <head>
+        <title>Title</title>
+        <style type="text/css">
+        h1, h2 { color:red; }
+        strong {
+            text-decoration:none
+            }
+        </style>
+        </head>
+        <body>
+        <h1>Hi!</h1>
+        <p><strong>Yes!</strong></p>
+        </body>
+        </html>"""
+
+        html_2 = """<html>
+        <head>
+        <title>Another Title</title>
+        <style type="text/css">
+        h1, h2 { color:blue; }
+        strong {
+            text-decoration:underline
+            }
+        </style>
+        </head>
+        <body>
+        <h1>Hello!</h1>
+        <p><strong>Nope!</strong></p>
+        </body>
+        </html>"""
+
+        expect_html_1 = """<html>
+        <head>
+        <title>Title</title>
+        </head>
+        <body>
+        <h1 style="color:red">Hi!</h1>
+        <p><strong style="text-decoration:none">Yes!</strong></p>
+        </body>
+        </html>"""
+
+        expect_html_2 = """<html>
+        <head>
+        <title>Another Title</title>
+        </head>
+        <body>
+        <h1 style="color:blue">Hello!</h1>
+        <p><strong style="text-decoration:underline">Nope!</strong></p>
+        </body>
+        </html>"""
+
+        p = Premailer()
+        result_html_1 = p.transform(html_1)
+        result_html_2 = p.transform(html_2)
+
+        compare_html(expect_html_1, result_html_1)
+        compare_html(expect_html_2, result_html_2)
+
     def test_remove_classes(self):
         """test the simplest case"""