rennat / pynliner

Python CSS-to-inline-styles conversion tool for HTML using BeautifulSoup and cssutils
http://pythonhosted.org/pynliner/
181 stars 93 forks source link

regression parsing .btn-large [class^="icon-"], results in exception raised #42

Closed ghost closed 8 years ago

ghost commented 8 years ago

Version 0.7.0 raises an exception parsing .btn-large [class^="icon-"], This did not occur in previous versions.

Test case:

# py.test pyliner_test.py

import pytest
import textwrap
from pynliner import fromString as inlinecss

def no_whitespace(text):
    return ''.join(text.split())

def test_email():
    expected = textwrap.dedent("""\
        tbd
        """)

    input = textwrap.dedent("""\
        <!DOCTYPE html>
            <html>
              <head>
                <style type="text/css">
            body {
              margin: 0;
              font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
              font-size: 14px;
              line-height: 20px;
              color: #333333;
              background-color: #ffffff;
              max-width: 600px;
            }
            .btn-large [class^="icon-"],
            .btn-large [class*=" icon-"] {
              margin-top: 4px;
            }
                </style>

              </head>
              <body>
                <p>hello world</p>
              </body>
            </html>""")

    result = inlinecss(input)

    assert no_whitespace(str(result)) == no_whitespace(str(expected))

Output:

$ py.test  pynliner_bug_test.py
============================================================== test session starts ===============================================================
platform linux2 -- Python 2.7.9, pytest-2.9.1, py-1.4.31, pluggy-0.3.1
rootdir: /home/vagrant/synced/symqe-bugfix-BIZ-493-semicolons-are-invading-car-ops-URLs, inifile:
collected 1 items

pynliner_bug_test.py F

==================================================================== FAILURES ====================================================================
___________________________________________________________________ test_email ___________________________________________________________________

    def test_email():
        expected = textwrap.dedent("""\

            """)

        input = textwrap.dedent("""\
            <!DOCTYPE html>
                <html>
                  <head>
                    <style type="text/css">
                body {
                  margin: 0;
                  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
                  font-size: 14px;
                  line-height: 20px;
                  color: #333333;
                  background-color: #ffffff;
                  max-width: 600px;
                }
                .btn-large [class^="icon-"],
                .btn-large [class*=" icon-"] {
                  margin-top: 4px;
                }
                    </style>

                  </head>
                  <body>
                    <p>hello world</p>
                  </body>
                </html>""")

>       result = inlinecss(input)

pynliner_bug_test.py:42:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../env/lib/python2.7/site-packages/pynliner/__init__.py:272: in fromString
    return Pynliner(log).from_string(string).run()
../../env/lib/python2.7/site-packages/pynliner/__init__.py:126: in run
    self._apply_styles()
../../env/lib/python2.7/site-packages/pynliner/__init__.py:219: in _apply_styles
    for element in select(self.soup, selector.selectorText):
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

soup = <!DOCTYPE html>\n\n<html>\n<head>\n\n</head>\n<body>\n<p>hello world</p>\n</body>\n</html>, selector = '.btn-large [class^'

    def select(soup, selector):
        """
        soup should be a BeautifulSoup instance; selector is a CSS selector
        specifying the elements you want to retrieve.
        """
        handle_token = True
        current_context = [(soup, [])]
        operator = None
        while selector:
            if handle_token:
                # Get the rightmost token
                handle_token = False
                match = re.search('([_0-9a-zA-Z-#.:*"\'\[\\]=]+)$', selector)
                if not match:
>                   raise Exception("No match was found. We're done or something is broken")
E                   Exception: No match was found. We're done or something is broken

../../env/lib/python2.7/site-packages/pynliner/soupselect.py:109: Exception
============================================================ 1 failed in 0.70 seconds ============================================================
rennat commented 8 years ago

Good catch! I'll have time to look into it in about 7 hours

rennat commented 8 years ago

The latest release, 0.7.1, takes care of this and adds better testing for attribute selectors. @elkcip does this fix your issue?

ghost commented 8 years ago

Wow, thanks for the quick response! I will try it out tomorrow. On Thu, Apr 7, 2016 at 9:17 PM Tanner Netterville notifications@github.com wrote:

The latest release, 0.7.1, takes care of this and adds better testing for attribute selectors. @elkcip https://github.com/elkcip does this fix your issue?

— You are receiving this because you were mentioned.

Reply to this email directly or view it on GitHub https://github.com/rennat/pynliner/issues/42#issuecomment-207178491

ghost commented 8 years ago

Tried 0.7.1 and it fixes the issue. Thanks again for the quick response!

Pete

On Thu, Apr 7, 2016 at 9:17 PM, Tanner Netterville <notifications@github.com

wrote:

The latest release, 0.7.1, takes care of this and adds better testing for attribute selectors. @elkcip https://github.com/elkcip does this fix your issue?

— You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub https://github.com/rennat/pynliner/issues/42#issuecomment-207178491

Pete mobile: 651-233-3978