diff -Nru cssutils-1.0.2/debian/changelog cssutils-1.0.2/debian/changelog --- cssutils-1.0.2/debian/changelog 2022-10-10 14:15:39.000000000 +0000 +++ cssutils-1.0.2/debian/changelog 2023-02-23 11:01:02.000000000 +0000 @@ -1,3 +1,11 @@ +cssutils (1.0.2-7) unstable; urgency=medium + + * Team upload + * Apply upstream patch for 2to3 conversion (Closes: #1026728) + * Fix test regressions with Python 3.11 + + -- Benjamin Drung Thu, 23 Feb 2023 12:01:02 +0100 + cssutils (1.0.2-6) unstable; urgency=medium * Team upload. diff -Nru cssutils-1.0.2/debian/patches/Execute-lib2to3-on-src-examples.-Ref-2.patch cssutils-1.0.2/debian/patches/Execute-lib2to3-on-src-examples.-Ref-2.patch --- cssutils-1.0.2/debian/patches/Execute-lib2to3-on-src-examples.-Ref-2.patch 1970-01-01 00:00:00.000000000 +0000 +++ cssutils-1.0.2/debian/patches/Execute-lib2to3-on-src-examples.-Ref-2.patch 2023-02-23 10:59:45.000000000 +0000 @@ -0,0 +1,19680 @@ +From: "Jason R. Coombs" +Date: Mon, 8 Mar 2021 21:51:42 -0500 +Subject: Execute lib2to3 on src, examples. Ref #2. + +python -m lib2to3 --no-diffs -nw src examples + +Origin: https://github.com/jaraco/cssutils/commit/e1e07731fe7c6bd6f830149e6b980f693270314d +--- + examples/build.py | 6 +- + examples/codec.py | 4 +- + examples/cssencodings.py | 40 +- + examples/customlog.py | 6 +- + examples/imports.py | 22 +- + examples/minify.py | 8 +- + examples/parse.py | 16 +- + examples/properties_with_same_name.py | 44 +- + examples/selectors_tolower.py | 20 +- + examples/serialize.py | 50 +- + examples/style.py | 14 +- + examples/styledeclaration.py | 34 +- + examples/testutil.py | 36 +- + src/cssutils/__init__.py | 56 +- + src/cssutils/_codec2.py | 56 +- + src/cssutils/_fetch.py | 26 +- + src/cssutils/_fetchgae.py | 14 +- + src/cssutils/codec.py | 8 +- + src/cssutils/css/__init__.py | 40 +- + src/cssutils/css/csscharsetrule.py | 34 +- + src/cssutils/css/csscomment.py | 14 +- + src/cssutils/css/cssfontfacerule.py | 44 +- + src/cssutils/css/cssimportrule.py | 70 +- + src/cssutils/css/cssmediarule.py | 54 +- + src/cssutils/css/cssnamespacerule.py | 44 +- + src/cssutils/css/csspagerule.py | 84 +- + src/cssutils/css/cssrule.py | 72 +- + src/cssutils/css/cssrulelist.py | 2 +- + src/cssutils/css/cssstyledeclaration.py | 76 +- + src/cssutils/css/cssstylerule.py | 60 +- + src/cssutils/css/cssstylesheet.py | 98 +- + src/cssutils/css/cssunknownrule.py | 51 +- + src/cssutils/css/cssvalue.py | 142 +-- + src/cssutils/css/cssvariablesdeclaration.py | 64 +- + src/cssutils/css/cssvariablesrule.py | 46 +- + src/cssutils/css/marginrule.py | 38 +- + src/cssutils/css/property.py | 94 +- + src/cssutils/css/selector.py | 146 +-- + src/cssutils/css/selectorlist.py | 30 +- + src/cssutils/css/value.py | 252 ++--- + src/cssutils/cssproductions.py | 18 +- + src/cssutils/errorhandler.py | 8 +- + src/cssutils/helper.py | 26 +- + src/cssutils/parse.py | 6 +- + src/cssutils/prodparser.py | 100 +- + src/cssutils/profiles.py | 60 +- + src/cssutils/sac.py | 109 +- + src/cssutils/script.py | 86 +- + src/cssutils/scripts/__init__.py | 2 +- + src/cssutils/scripts/csscapture.py | 6 +- + src/cssutils/scripts/csscombine.py | 8 +- + src/cssutils/scripts/cssparse.py | 10 +- + src/cssutils/serialize.py | 256 ++--- + src/cssutils/settings.py | 4 +- + src/cssutils/stylesheets/__init__.py | 8 +- + src/cssutils/stylesheets/medialist.py | 24 +- + src/cssutils/stylesheets/mediaquery.py | 30 +- + src/cssutils/stylesheets/stylesheet.py | 4 +- + src/cssutils/tests/basetest.py | 40 +- + src/cssutils/tests/test_codec.py | 152 +-- + src/cssutils/tests/test_csscharsetrule.py | 54 +- + src/cssutils/tests/test_csscomment.py | 40 +- + src/cssutils/tests/test_cssfontfacerule.py | 102 +- + src/cssutils/tests/test_cssimportrule.py | 272 ++--- + src/cssutils/tests/test_cssmediarule.py | 250 ++--- + src/cssutils/tests/test_cssnamespacerule.py | 180 ++-- + src/cssutils/tests/test_csspagerule.py | 264 ++--- + src/cssutils/tests/test_cssproperties.py | 4 +- + src/cssutils/tests/test_cssrule.py | 42 +- + src/cssutils/tests/test_cssrulelist.py | 2 +- + src/cssutils/tests/test_cssstyledeclaration.py | 346 +++--- + src/cssutils/tests/test_cssstylerule.py | 112 +- + src/cssutils/tests/test_cssstylesheet.py | 150 +-- + src/cssutils/tests/test_cssunknownrule.py | 108 +- + src/cssutils/tests/test_cssutils.py | 94 +- + src/cssutils/tests/test_cssvariablesdeclaration.py | 94 +- + src/cssutils/tests/test_cssvariablesrule.py | 74 +- + src/cssutils/tests/test_encutils/__init__.py | 70 +- + src/cssutils/tests/test_errorhandler.py | 32 +- + src/cssutils/tests/test_helper.py | 56 +- + src/cssutils/tests/test_marginrule.py | 44 +- + src/cssutils/tests/test_medialist.py | 120 +-- + src/cssutils/tests/test_mediaquery.py | 94 +- + src/cssutils/tests/test_parse.py | 226 ++-- + src/cssutils/tests/test_prodparser.py | 66 +- + src/cssutils/tests/test_profiles.py | 22 +- + src/cssutils/tests/test_properties.py | 16 +- + src/cssutils/tests/test_property.py | 160 +-- + src/cssutils/tests/test_scripts_csscombine.py | 2 +- + src/cssutils/tests/test_selector.py | 552 +++++----- + src/cssutils/tests/test_selectorlist.py | 64 +- + src/cssutils/tests/test_serialize.py | 336 +++--- + src/cssutils/tests/test_settings.py | 4 +- + src/cssutils/tests/test_stylesheet.py | 8 +- + src/cssutils/tests/test_tokenize2.py | 1129 ++++++++++---------- + src/cssutils/tests/test_util.py | 318 +++--- + src/cssutils/tests/test_value.py | 706 ++++++------ + src/cssutils/tests/test_x.py | 6 +- + src/cssutils/tokenize2.py | 38 +- + src/cssutils/util.py | 157 +-- + src/encutils/__init__.py | 100 +- + 101 files changed, 4742 insertions(+), 4744 deletions(-) + +diff --git a/examples/build.py b/examples/build.py +index 29acc20..7e7bb27 100644 +--- a/examples/build.py ++++ b/examples/build.py +@@ -18,7 +18,7 @@ atom|title { + color: #000 !important + } + ''' +-EXPERR = u'Property: Found valid "CSS Level 2.1" value: red [4:19: color]\nProperty: Found valid "CSS Level 2.1" value: #fff [4:30: background]\nProperty: Found valid "CSS Level 2.1" value: #000 [1:30: color]\nProperty: Found valid "CSS Level 2.1" value: url(images/example3.gif) [4:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(./images/example3.gif) [5:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(import/images2/example2.gif) [6:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(./import/images2/example2.gif) [7:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(import/images2/../../images/example3.gif) [8:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(images2/example2.gif) [4:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(http://example.com/images/example.gif) [5:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(//example.com/images/example.gif) [6:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(/images/example.gif) [7:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(images2/example.gif) [8:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(./images2/example.gif) [9:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(../images/example.gif) [10:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(./../images/example.gif) [11:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(images/example.gif) [4:2: background-image]\n' ++EXPERR = 'Property: Found valid "CSS Level 2.1" value: red [4:19: color]\nProperty: Found valid "CSS Level 2.1" value: #fff [4:30: background]\nProperty: Found valid "CSS Level 2.1" value: #000 [1:30: color]\nProperty: Found valid "CSS Level 2.1" value: url(images/example3.gif) [4:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(./images/example3.gif) [5:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(import/images2/example2.gif) [6:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(./import/images2/example2.gif) [7:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(import/images2/../../images/example3.gif) [8:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(images2/example2.gif) [4:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(http://example.com/images/example.gif) [5:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(//example.com/images/example.gif) [6:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(/images/example.gif) [7:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(images2/example.gif) [8:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(./images2/example.gif) [9:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(../images/example.gif) [10:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(./../images/example.gif) [11:2: background]\nProperty: Found valid "CSS Level 2.1" value: url(images/example.gif) [4:2: background-image]\n' + + def main(): + # -*- coding: utf-8 -*- +@@ -26,7 +26,7 @@ def main(): + import logging + cssutils.log.setLevel(logging.DEBUG) + +- css = u'''/* a comment with umlaut ä */ ++ css = '''/* a comment with umlaut ä */ + @namespace html "http://www.w3.org/1999/xhtml"; + @variables { BG: #fff } + html|a { color:red; background: var(BG) }''' +@@ -50,7 +50,7 @@ def main(): + sheet.add('@import "sheets/import.css";') + + # cssutils.ser.prefs.resolveVariables = True # default since 0.9.7b2 +- print sheet.cssText ++ print(sheet.cssText) + + def _test(): + import doctest # replace M with your module's name +diff --git a/examples/codec.py b/examples/codec.py +index 2af8d03..7ff7bf4 100644 +--- a/examples/codec.py ++++ b/examples/codec.py +@@ -5,5 +5,5 @@ import cssutils + + cssText = codecs.open('../sheets/cases.css', encoding='css').read() + sheet = cssutils.parseString(cssText) +-print sheet +-print sheet.cssText +\ No newline at end of file ++print(sheet) ++print(sheet.cssText) +diff --git a/examples/cssencodings.py b/examples/cssencodings.py +index 82c43ae..711e050 100644 +--- a/examples/cssencodings.py ++++ b/examples/cssencodings.py +@@ -7,11 +7,11 @@ example css is in default UTF-8 encoding + from cssutils import CSSParser + + EXPOUT = '''cssText in different encodings, depending on the console some\n chars may look broken but are actually not\n\n@charset "ascii";\n/* some umlauts \\E4 \\F6 \\FC and EURO sign \\20AC */\na:before {\n content: "\\E4 "\n }\n\n@charset "iso-8859-1";\n/* some umlauts \xe4\xf6\xfc and EURO sign \\20AC */\na:before {\n content: "\xe4"\n }\n\n@charset "iso-8859-15";\n/* some umlauts \xe4\xf6\xfc and EURO sign \xa4 */\na:before {\n content: "\xe4"\n }\n\n@charset "utf-8";\n/* some umlauts \xc3\xa4\xc3\xb6\xc3\xbc and EURO sign \xe2\x82\xac */\na:before {\n content: "\xc3\xa4"\n }\n\n/* some umlauts \xc3\xa4\xc3\xb6\xc3\xbc and EURO sign \xe2\x82\xac */\na:before {\n content: "\xc3\xa4"\n }\n''' +-EXPERR = u'Property: Found valid "CSS Level 2.1" value: "\xe4" [4:8: content]\n' ++EXPERR = 'Property: Found valid "CSS Level 2.1" value: "\xe4" [4:8: content]\n' + + + def main(): +- css = u''' ++ css = ''' + /* some umlauts äöü and EURO sign € */ + a:before { + content: "ä"; +@@ -20,30 +20,30 @@ def main(): + p = CSSParser() + sheet = p.parseString(css) + +- print """cssText in different encodings, depending on the console some +- chars may look broken but are actually not""" +- print +- ++ print("""cssText in different encodings, depending on the console some ++ chars may look broken but are actually not""") ++ print() ++ + sheet.encoding = 'ascii' +- print sheet.cssText +- print +- ++ print(sheet.cssText) ++ print() ++ + sheet.encoding = 'iso-8859-1' +- print sheet.cssText +- print +- ++ print(sheet.cssText) ++ print() ++ + sheet.encoding = 'iso-8859-15' +- print sheet.cssText +- print +- ++ print(sheet.cssText) ++ print() ++ + sheet.encoding = 'utf-8' +- print sheet.cssText +- print +- ++ print(sheet.cssText) ++ print() ++ + # results in default UTF-8 encoding without @charset rule + sheet.encoding = None +- print sheet.cssText ++ print(sheet.cssText) + + + if __name__ == '__main__': +- main() +\ No newline at end of file ++ main() +diff --git a/examples/customlog.py b/examples/customlog.py +index 123944d..da577c1 100644 +--- a/examples/customlog.py ++++ b/examples/customlog.py +@@ -1,12 +1,12 @@ +-import logging, StringIO ++import logging, io + + EXPOUT = "" +-EXPERR = u"Property: Unknown Property name. [1:5: x]\nHTTPError opening url=http://cthedot.de/x: 404 Not Found\nCSSImportRule: While processing imported style sheet href=http://cthedot.de/x: IOError('Cannot read Stylesheet.',)\nCSSStylesheet: CSSImportRule not allowed here. [1:13: @import]\n" ++EXPERR = "Property: Unknown Property name. [1:5: x]\nHTTPError opening url=http://cthedot.de/x: 404 Not Found\nCSSImportRule: While processing imported style sheet href=http://cthedot.de/x: IOError('Cannot read Stylesheet.',)\nCSSStylesheet: CSSImportRule not allowed here. [1:13: @import]\n" + + def main(): + import cssutils + +- mylog = StringIO.StringIO() ++ mylog = io.StringIO() + h = logging.StreamHandler(mylog) + h.setFormatter(logging.Formatter('%(levelname)s %(message)s')) + #cssutils.log.addHandler(h) +diff --git a/examples/imports.py b/examples/imports.py +index 4b8258a..ef045b2 100644 +--- a/examples/imports.py ++++ b/examples/imports.py +@@ -3,7 +3,7 @@ import cssutils + import os.path + import xml.dom + +-EXPOUT = u'''@charset "iso-8859-1"; ++EXPOUT = '''@charset "iso-8859-1"; + @import "1inherit-iso.css"; + + ############################## +@@ -22,7 +22,7 @@ EXPOUT = u'''@charset "iso-8859-1"; + + + ''' +-EXPERR = u'' ++EXPERR = '' + + + def main(): +@@ -30,19 +30,19 @@ def main(): + def p(s, l=0): + c = '#=-'[l] * (30 - l*10) + for r in s.cssRules.rulesOfType(cssutils.css.CSSRule.IMPORT_RULE): +- print c +- print r.href +- print c +- print r.styleSheet.cssText +- print ++ print(c) ++ print(r.href) ++ print(c) ++ print(r.styleSheet.cssText) ++ print() + p(r.styleSheet, l=l+1) +- print ++ print() + + s = cssutils.parseFile(os.path.join('sheets', '1import.css')) +- print s.cssText +- print ++ print(s.cssText) ++ print() + + p(s) + + if __name__ == '__main__': +- main() +\ No newline at end of file ++ main() +diff --git a/examples/minify.py b/examples/minify.py +index fa7a069..62333ba 100644 +--- a/examples/minify.py ++++ b/examples/minify.py +@@ -1,7 +1,7 @@ +-import logging, StringIO ++import logging, io + + EXPOUT = "@variables{c:#0f0}a{color:var(c)}\na{color:#0f0}\n" +-EXPERR = u'Property: Found valid "CSS Level 2.1" value: #0f0 [6:9: color]\n' ++EXPERR = 'Property: Found valid "CSS Level 2.1" value: #0f0 [6:9: color]\n' + + def main(): + import cssutils +@@ -19,11 +19,11 @@ def main(): + + cssutils.ser.prefs.useMinified() + cssutils.ser.prefs.resolveVariables = False +- print s.cssText ++ print(s.cssText) + + # reset + cssutils.ser.prefs.resolveVariables = True +- print s.cssText ++ print(s.cssText) + + + if __name__ == '__main__': +diff --git a/examples/parse.py b/examples/parse.py +index e1525cf..f781659 100644 +--- a/examples/parse.py ++++ b/examples/parse.py +@@ -3,7 +3,7 @@ import cssutils + import xml.dom + + EXPOUT = '''\n--- source CSS ---\n/* This is a comment */\n body {\n background: white;\n top: red;\n x: 1;\n }\n a { y }\n \n\n--- simple parsing ---\n/* This is a comment */\nbody {\n background: white;\n top: red;\n x: 1\n }\n\n--- CSSParser(raiseExceptions=True) ---\n:::RAISED::: Property: No ":" after name found: y [7:10: ]\n''' +-EXPERR = u'Property: Invalid value for "CSS Level 2.1" property: red [4:9: top]\nProperty: Unknown Property name. [5:9: x]\nProperty: No ":" after name found: y [7:10: ]\nProperty: No property value found: y [7:10: ]\nCSSStyleDeclaration: Syntax Error in Property: y \nProperty: Invalid value for "CSS Level 2.1" property: red [4:9: top]\nProperty: Unknown Property name. [5:9: x]\n' ++EXPERR = 'Property: Invalid value for "CSS Level 2.1" property: red [4:9: top]\nProperty: Unknown Property name. [5:9: x]\nProperty: No ":" after name found: y [7:10: ]\nProperty: No property value found: y [7:10: ]\nCSSStyleDeclaration: Syntax Error in Property: y \nProperty: Invalid value for "CSS Level 2.1" property: red [4:9: top]\nProperty: Unknown Property name. [5:9: x]\n' + + + def main(): +@@ -16,19 +16,19 @@ def main(): + } + a { y } + ''' +- print "\n--- source CSS ---" +- print css ++ print("\n--- source CSS ---") ++ print(css) + +- print "\n--- simple parsing ---" ++ print("\n--- simple parsing ---") + c1 = cssutils.parseString(css) +- print c1.cssText ++ print(c1.cssText) + +- print "\n--- CSSParser(raiseExceptions=True) ---" ++ print("\n--- CSSParser(raiseExceptions=True) ---") + p = cssutils.CSSParser(raiseExceptions=True) + try: + c2 = p.parseString(css) +- except xml.dom.DOMException, e: +- print ":::RAISED:::", e ++ except xml.dom.DOMException as e: ++ print(":::RAISED:::", e) + + if __name__ == '__main__': + main() +\ No newline at end of file +diff --git a/examples/properties_with_same_name.py b/examples/properties_with_same_name.py +index 3418cf3..a2c87b4 100644 +--- a/examples/properties_with_same_name.py ++++ b/examples/properties_with_same_name.py +@@ -2,39 +2,39 @@ + """ + import cssutils + +-print "\n**SameNamePropertyList is replaced with style.getProperties() from 0.9.4**" ++print("\n**SameNamePropertyList is replaced with style.getProperties() from 0.9.4**") + cssutils.ser.prefs.keepComments = False # remove for now + + cssText=''' background: white url(paper.png) scroll; /* for all UAs */ + background: white url(ledger.png) fixed; /* for UAs that do fixed backgrounds */ + ''' +-print "\n>>> # cssText" +-print cssText ++print("\n>>> # cssText") ++print(cssText) + + +-print ">>> style = cssutils.css.CSSStyleDeclaration(cssText=cssText)" ++print(">>> style = cssutils.css.CSSStyleDeclaration(cssText=cssText)") + style = cssutils.css.CSSStyleDeclaration(cssText=cssText) +-print '>>> print style.cssText' +-print style.cssText ++print('>>> print style.cssText') ++print(style.cssText) + +-print "\n>>> cssutils.ser.prefs.keepAllProperties = True # output all values" ++print("\n>>> cssutils.ser.prefs.keepAllProperties = True # output all values") + cssutils.ser.prefs.keepAllProperties = True # output all values +-print '>>> style.cssText # with keepAllProperties==True:' +-print style.cssText +-print ++print('>>> style.cssText # with keepAllProperties==True:') ++print(style.cssText) ++print() + +-print ">>> # NEW METHOD getProperties" +-print ">>> proplist = style.getProperties('background', all=True)" ++print(">>> # NEW METHOD getProperties") ++print(">>> proplist = style.getProperties('background', all=True)") + proplist = style.getProperties('background', all=True) +-print ">>> proplist\n", proplist +-print ">>> for prop in proplist: print '\\t', prop.value" +-for prop in proplist: print "\t", prop.value +-print ++print(">>> proplist\n", proplist) ++print(">>> for prop in proplist: print '\\t', prop.value") ++for prop in proplist: print("\t", prop.value) ++print() + +-print ">>> # overwrite the current property, to overwrite all iterate over proplist" +-print ">>> style.setProperty('background', 'red')" ++print(">>> # overwrite the current property, to overwrite all iterate over proplist") ++print(">>> style.setProperty('background', 'red')") + style.setProperty('background', 'red') +-print ">>> style.getPropertyValue('background')" +-print style.getPropertyValue('background') +-print ">>> style.cssText" +-print style.cssText ++print(">>> style.getPropertyValue('background')") ++print(style.getPropertyValue('background')) ++print(">>> style.cssText") ++print(style.cssText) +diff --git a/examples/selectors_tolower.py b/examples/selectors_tolower.py +index feef86e..8c18df3 100644 +--- a/examples/selectors_tolower.py ++++ b/examples/selectors_tolower.py +@@ -1,11 +1,11 @@ + import cssutils + from cssutils import css, stylesheets + +-EXPOUT = u'''--- ORIGINAL ---\n@charset "ascii";\n @namespace PREfix "uri";\n SOME > WeIrD + selector ~ used here {color: green}\n PREfix|name {color: green}\n \n\n--- SELECTORS TO LOWER CASE (does not simply work for PREfix|name!) ---\n--- CHANGE PREFIX (prefix is not really part of selectorText, URI is! ---\n\n@charset "ascii";\n@namespace lower-case_prefix "uri";\nsome > weird + selector ~ used here {\n color: green\n }\nlower-case_prefix|name {\n color: green\n }\n''' +-EXPERR = u'Property: Found valid "CSS Level 2.1" value: green [3:46: color]\nProperty: Found valid "CSS Level 2.1" value: green [4:22: color]\n' ++EXPOUT = '''--- ORIGINAL ---\n@charset "ascii";\n @namespace PREfix "uri";\n SOME > WeIrD + selector ~ used here {color: green}\n PREfix|name {color: green}\n \n\n--- SELECTORS TO LOWER CASE (does not simply work for PREfix|name!) ---\n--- CHANGE PREFIX (prefix is not really part of selectorText, URI is! ---\n\n@charset "ascii";\n@namespace lower-case_prefix "uri";\nsome > weird + selector ~ used here {\n color: green\n }\nlower-case_prefix|name {\n color: green\n }\n''' ++EXPERR = 'Property: Found valid "CSS Level 2.1" value: green [3:46: color]\nProperty: Found valid "CSS Level 2.1" value: green [4:22: color]\n' + + def main(): +- examplecss = u"""@charset "ascii"; ++ examplecss = """@charset "ascii"; + @namespace PREfix "uri"; + SOME > WeIrD + selector ~ used here {color: green} + PREfix|name {color: green} +@@ -14,18 +14,18 @@ def main(): + import logging + sheet = cssutils.CSSParser(loglevel=logging.DEBUG).parseString(examplecss) + +- print "--- ORIGINAL ---" +- print examplecss +- print ++ print("--- ORIGINAL ---") ++ print(examplecss) ++ print() + +- print "--- SELECTORS TO LOWER CASE (does not simply work for PREfix|name!) ---" ++ print("--- SELECTORS TO LOWER CASE (does not simply work for PREfix|name!) ---") + sheet.cssRules[2].selectorText = sheet.cssRules[2].selectorText.lower() + +- print "--- CHANGE PREFIX (prefix is not really part of selectorText, URI is! ---" ++ print("--- CHANGE PREFIX (prefix is not really part of selectorText, URI is! ---") + sheet.cssRules[1].prefix = 'lower-case_prefix' + +- print +- print sheet.cssText ++ print() ++ print(sheet.cssText) + + if __name__ == '__main__': + main() +\ No newline at end of file +diff --git a/examples/serialize.py b/examples/serialize.py +index 713c374..1401d6e 100644 +--- a/examples/serialize.py ++++ b/examples/serialize.py +@@ -12,49 +12,49 @@ a { + }''' + + sheet = cssutils.parseString(css) +-print "\nORIGINAL CSS:" +-print css +-print "------------" ++print("\nORIGINAL CSS:") ++print(css) ++print("------------") + +-print repr(cssutils.ser.prefs) ++print(repr(cssutils.ser.prefs)) + +-print "\nCSS Serialized" +-print sheet.cssText ++print("\nCSS Serialized") ++print(sheet.cssText) + +-print "\nCSS Serialized with ``keepAllProperties`` = False" ++print("\nCSS Serialized with ``keepAllProperties`` = False") + cssutils.ser.prefs.keepAllProperties = False +-print sheet.cssText ++print(sheet.cssText) + +-print "\nCSS Serialized with ``defaultPropertyName`` = True" ++print("\nCSS Serialized with ``defaultPropertyName`` = True") + cssutils.ser.prefs.defaultPropertyName = True +-print sheet.cssText ++print(sheet.cssText) + +-print "\nCSS Serialized with ``defaultPropertyName`` = False" ++print("\nCSS Serialized with ``defaultPropertyName`` = False") + cssutils.ser.prefs.defaultPropertyName = False +-print sheet.cssText ++print(sheet.cssText) + + +-print '\nBUT: Reading value programmatic uses normalized property' +-print ' name and results in actual value only:' +-print '\t.getPropertyValue("color") ==', +-print sheet.cssRules[1].style.getPropertyValue('color') +-print '\t.getPropertyValue("c\\olor") ==', +-print sheet.cssRules[1].style.getPropertyValue('c\olor') +-print '\t.getPropertyValue("c\\o\\l\\o\\r") ==', +-print sheet.cssRules[1].style.getPropertyValue('c\\o\\l\\o\\r') +-print ++print('\nBUT: Reading value programmatic uses normalized property') ++print(' name and results in actual value only:') ++print('\t.getPropertyValue("color") ==', end=' ') ++print(sheet.cssRules[1].style.getPropertyValue('color')) ++print('\t.getPropertyValue("c\\olor") ==', end=' ') ++print(sheet.cssRules[1].style.getPropertyValue('c\olor')) ++print('\t.getPropertyValue("c\\o\\l\\o\\r") ==', end=' ') ++print(sheet.cssRules[1].style.getPropertyValue('c\\o\\l\\o\\r')) ++print() + +-print '\nCSS Serialized with indent = 2*" ", importHrefFormat="string", lineNumbers=True' ++print('\nCSS Serialized with indent = 2*" ", importHrefFormat="string", lineNumbers=True') + cssutils.ser.prefs.indent = 2*' ' + # used to set indentation string, default is 4*' ' + cssutils.ser.prefs.importHrefFormat = 'string' + # or 'uri', defaults to the format used in parsed stylesheet + cssutils.ser.prefs.lineNumbers = True +-print sheet.cssText ++print(sheet.cssText) + +-print '\nCSS Serialized with useMinified()' ++print('\nCSS Serialized with useMinified()') + cssutils.ser.prefs.useMinified() +-print sheet.cssText ++print(sheet.cssText) + + # OUTPUTS + #1: @import "example.css"; +diff --git a/examples/style.py b/examples/style.py +index 9c64223..bb887cb 100644 +--- a/examples/style.py ++++ b/examples/style.py +@@ -19,15 +19,15 @@ sys.path.append(os.path.join(os.path.dirname(__file__), 'lib')) + try: + import pkg_resources + pkg_resources.require('lxml') +-except pkg_resources.DistributionNotFound, e: ++except pkg_resources.DistributionNotFound as e: + pass + + try: + from lxml import etree + from lxml.builder import E + from lxml.cssselect import CSSSelector +-except ImportError, e: +- print 'You need lxml for this example:', e ++except ImportError as e: ++ print('You need lxml for this example:', e) + sys.exit(1) + + +@@ -138,8 +138,8 @@ def render2style(document, view): + - add style into @style attribute + - add style into @title attribute (for debugging) + """ +- for element, style in view.items(): +- v = style.getCssText(separator=u'') ++ for element, style in list(view.items()): ++ v = style.getCssText(separator='') + element.set('style', v) + element.set('title', v) + +@@ -154,8 +154,8 @@ def render2content(document, view, css): + e = etree.Element('style', {'type': 'text/css'}) + e.text = css + document.find('head').append(e) +- for element, style in view.items(): +- v = style.getCssText(separator=u'') ++ for element, style in list(view.items()): ++ v = style.getCssText(separator='') + element.text = v + + def show(text, name, encoding='utf-8'): +diff --git a/examples/styledeclaration.py b/examples/styledeclaration.py +index 46d2918..86c9281 100644 +--- a/examples/styledeclaration.py ++++ b/examples/styledeclaration.py +@@ -1,14 +1,14 @@ + import cssutils + + def show(style): +- print "style.length ==", style.length +- print "style.item(0) ==", style.item(0) +- print "style.item(1) ==", style.item(1) +- print "style.getProperties('color', all=True) == [" ++ print("style.length ==", style.length) ++ print("style.item(0) ==", style.item(0)) ++ print("style.item(1) ==", style.item(1)) ++ print("style.getProperties('color', all=True) == [") + for x in style.getProperties('color', all=True): +- print "\t", x.cssText +- print "\t]" +- print "style.getPropertyValue('color') ==", style.getPropertyValue('color'), '\n' ++ print("\t", x.cssText) ++ print("\t]") ++ print("style.getPropertyValue('color') ==", style.getPropertyValue('color'), '\n') + + + styledeclaration = ''' +@@ -19,34 +19,34 @@ c\olor: green !important; + c\olor: blue; + FONT-FAMILY: serif; + ''' +-print "\nGiven styledeclaration:" +-print styledeclaration +-print "------------" ++print("\nGiven styledeclaration:") ++print(styledeclaration) ++print("------------") + +-print "setting cssText" ++print("setting cssText") + style = cssutils.css.CSSStyleDeclaration(cssText=styledeclaration) + show(style) + +-print "------------" ++print("------------") + + # overwrite in any case +-print "style.setProperty('color', 'yellow','!important')" ++print("style.setProperty('color', 'yellow','!important')") + style.setProperty('color', 'yellow','!important') + show(style) + + # overwrite in any case, even !important +-print "style.setProperty('color', 'red')" ++print("style.setProperty('color', 'red')") + style.setProperty('color', 'red') + show(style) + +-print "------------" ++print("------------") + + # overwrite in any case, even !important +-print "style.setProperty('color', 'green', '!important')" ++print("style.setProperty('color', 'green', '!important')") + style.setProperty('color', 'green', '!important') + show(style) + + # overwrite in any case, even !important +-print "style.setProperty('color', 'blue')" ++print("style.setProperty('color', 'blue')") + style.setProperty('color', 'blue') + show(style) +diff --git a/examples/testutil.py b/examples/testutil.py +index 284ab7f..256f4de 100644 +--- a/examples/testutil.py ++++ b/examples/testutil.py +@@ -11,7 +11,7 @@ __all__ = ['TestUtil'] + + import logging + import os +-import StringIO ++import io + import sys + + import cssutils +@@ -46,7 +46,7 @@ class TestUtil(object): + self._out = OutReplacement()#StringIO() + sys.stdout = self._out + +- self._err = StringIO.StringIO() ++ self._err = io.StringIO() + hdlr = logging.StreamHandler(self._err) + cssutils.log._log.addHandler(hdlr) + +@@ -59,11 +59,11 @@ class TestUtil(object): + + ok = (out == expo and err == expe) + if not ok: +- print ++ print() + if out != expo: +- print '### out:\n%r\n### != expout:\n%r\n' % (out, expo) ++ print('### out:\n%r\n### != expout:\n%r\n' % (out, expo)) + else: +- print '### err:\n%r\n### != experr:\n%r\n' % (err, expe) ++ print('### err:\n%r\n### != experr:\n%r\n' % (err, expe)) + return ok + + modules = 0 +@@ -77,20 +77,20 @@ def mod(module): + ok = t.end(module.EXPOUT, module.EXPERR) + if not ok: + errors += 1 +- print '---', ok, ':', os.path.basename(module.__file__) +- print +- ++ print('---', ok, ':', os.path.basename(module.__file__)) ++ print() ++ + def main(): + if PY2x: +- print "DOCTESTS:::::::::::::" ++ print("DOCTESTS:::::::::::::") + # doctests + import website + import doctest + doctest.testmod(website) +- print +- print 80*'-' +- print +- print ++ print() ++ print(80*'-') ++ print() ++ print() + + global modules, errors + +@@ -111,13 +111,13 @@ def main(): + import minify + mod(minify) + +- print +- print 80*'-' +- print 'Ran %i tests (%i errors).' % (modules, errors) ++ print() ++ print(80*'-') ++ print('Ran %i tests (%i errors).' % (modules, errors)) + if PY2x: +- print '**Check doctest results above!**' ++ print('**Check doctest results above!**') + else: +- print 'doctests do not work in Python 3 (yet?)!' ++ print('doctests do not work in Python 3 (yet?)!') + + + if __name__ == '__main__': +diff --git a/src/cssutils/__init__.py b/src/cssutils/__init__.py +index 4a2d773..b169d2c 100644 +--- a/src/cssutils/__init__.py ++++ b/src/cssutils/__init__.py +@@ -101,25 +101,25 @@ import sys + if sys.version_info < (2,6): + bytes = str + +-import codec ++from . import codec + import os.path +-import urllib +-import urlparse ++import urllib.request, urllib.parse, urllib.error ++import urllib.parse + import xml.dom + + # order of imports is important (partly circular) + from . import util +-import errorhandler ++from . import errorhandler + log = errorhandler.ErrorHandler() + +-import css +-import stylesheets +-from parse import CSSParser ++from . import css ++from . import stylesheets ++from .parse import CSSParser + +-from serialize import CSSSerializer ++from .serialize import CSSSerializer + ser = CSSSerializer() + +-from profiles import Profiles ++from .profiles import Profiles + profile = Profiles(log=log) + + # used by Selector defining namespace prefix '*' +@@ -180,7 +180,7 @@ class DOMImplementationCSS(object): + return minidom.DOMImplementation().createDocumentType(*args, **kwargs) + + def hasFeature(self, feature, version): +- return (feature.lower(), unicode(version)) in self._features ++ return (feature.lower(), str(version)) in self._features + + xml.dom.registerDOMImplementation('cssutils', DOMImplementationCSS) + +@@ -298,16 +298,16 @@ def resolveImports(sheet, target=None): + + def getReplacer(targetbase): + "Return a replacer which uses base to return adjusted URLs" +- basesch, baseloc, basepath, basequery, basefrag = urlparse.urlsplit(targetbase) ++ basesch, baseloc, basepath, basequery, basefrag = urllib.parse.urlsplit(targetbase) + basepath, basepathfilename = os.path.split(basepath) + + def replacer(uri): +- scheme, location, path, query, fragment = urlparse.urlsplit(uri) +- if not scheme and not location and not path.startswith(u'/'): ++ scheme, location, path, query, fragment = urllib.parse.urlsplit(uri) ++ if not scheme and not location and not path.startswith('/'): + # relative + path, filename = os.path.split(path) + combined = os.path.normpath(os.path.join(basepath, path, filename)) +- return urllib.pathname2url(combined) ++ return urllib.request.pathname2url(combined) + else: + # keep anything absolute + return uri +@@ -318,30 +318,30 @@ def resolveImports(sheet, target=None): + if rule.type == rule.CHARSET_RULE: + pass + elif rule.type == rule.IMPORT_RULE: +- log.info(u'Processing @import %r' % rule.href, neverraise=True) ++ log.info('Processing @import %r' % rule.href, neverraise=True) + + if rule.hrefFound: + # add all rules of @import to current sheet +- target.add(css.CSSComment(cssText=u'/* START @import "%s" */' ++ target.add(css.CSSComment(cssText='/* START @import "%s" */' + % rule.href)) + + try: + # nested imports + importedSheet = resolveImports(rule.styleSheet) +- except xml.dom.HierarchyRequestErr, e: +- log.warn(u'@import: Cannot resolve target, keeping rule: %s' ++ except xml.dom.HierarchyRequestErr as e: ++ log.warn('@import: Cannot resolve target, keeping rule: %s' + % e, neverraise=True) + target.add(rule) + else: + # adjust relative URI references +- log.info(u'@import: Adjusting paths for %r' % rule.href, ++ log.info('@import: Adjusting paths for %r' % rule.href, + neverraise=True) + replaceUrls(importedSheet, + getReplacer(rule.href), + ignoreImportRules=True) + + # might have to wrap rules in @media if media given +- if rule.media.mediaText == u'all': ++ if rule.media.mediaText == 'all': + mediaproxy = None + else: + keepimport = False +@@ -354,18 +354,18 @@ def resolveImports(sheet, target=None): + keepimport = True + break + if keepimport: +- log.warn(u'Cannot combine imported sheet with' +- u' given media as other rules then' +- u' comments or stylerules found %r,' +- u' keeping %r' % (r, ++ log.warn('Cannot combine imported sheet with' ++ ' given media as other rules then' ++ ' comments or stylerules found %r,' ++ ' keeping %r' % (r, + rule.cssText), + neverraise=True) + target.add(rule) + continue + + # wrap in @media if media is not `all` +- log.info(u'@import: Wrapping some rules in @media ' +- u' to keep media: %s' ++ log.info('@import: Wrapping some rules in @media ' ++ ' to keep media: %s' + % rule.media.mediaText, neverraise=True) + mediaproxy = css.CSSMediaRule(rule.media.mediaText) + +@@ -381,7 +381,7 @@ def resolveImports(sheet, target=None): + + else: + # keep @import as it is +- log.error(u'Cannot get referenced stylesheet %r, keeping rule' ++ log.error('Cannot get referenced stylesheet %r, keeping rule' + % rule.href, neverraise=True) + target.add(rule) + +@@ -392,4 +392,4 @@ def resolveImports(sheet, target=None): + + + if __name__ == '__main__': +- print __doc__ ++ print(__doc__) +diff --git a/src/cssutils/_codec2.py b/src/cssutils/_codec2.py +index d0ae617..3204736 100644 +--- a/src/cssutils/_codec2.py ++++ b/src/cssutils/_codec2.py +@@ -154,9 +154,9 @@ def detectencoding_unicode(input, final=False): + specifies whether more data will be available in later calls or not. If + ``final`` is true, ``detectencoding_unicode()`` will never return ``None``. + """ +- prefix = u'@charset "' ++ prefix = '@charset "' + if input.startswith(prefix): +- pos = input.find(u'"', len(prefix)) ++ pos = input.find('"', len(prefix)) + if pos >= 0: + return (input[len(prefix):pos], True) + elif final or not prefix.startswith(input): +@@ -176,13 +176,13 @@ def _fixencoding(input, encoding, final=False): + specifies whether more data will be available in later calls or not. + If ``final`` is true, ``_fixencoding()`` will never return ``None``. + """ +- prefix = u'@charset "' ++ prefix = '@charset "' + if len(input) > len(prefix): + if input.startswith(prefix): +- pos = input.find(u'"', len(prefix)) ++ pos = input.find('"', len(prefix)) + if pos >= 0: + if encoding.replace("_", "-").lower() == "utf-8-sig": +- encoding = u"utf-8" ++ encoding = "utf-8" + return prefix + encoding + input[pos:] + # we haven't seen the end of the encoding name yet => fall through + else: +@@ -203,7 +203,7 @@ def decode(input, errors="strict", encoding=None, force=True): + if (explicit and not force) or encoding is None: # Take the encoding from the input + encoding = _encoding + (input, consumed) = codecs.getdecoder(encoding)(input, errors) +- return (_fixencoding(input, unicode(encoding), True), consumed) ++ return (_fixencoding(input, str(encoding), True), consumed) + + + def encode(input, errors="strict", encoding=None): +@@ -211,9 +211,9 @@ def encode(input, errors="strict", encoding=None): + if encoding is None: + encoding = detectencoding_unicode(input, True)[0] + if encoding.replace("_", "-").lower() == "utf-8-sig": +- input = _fixencoding(input, u"utf-8", True) ++ input = _fixencoding(input, "utf-8", True) + else: +- input = _fixencoding(input, unicode(encoding), True) ++ input = _fixencoding(input, str(encoding), True) + if encoding == "css": + raise ValueError("css not allowed as encoding name") + encoder = codecs.getencoder(encoding) +@@ -247,7 +247,7 @@ if hasattr(codecs, "IncrementalDecoder"): + # Store ``errors`` somewhere else, + # because we have to hide it in a property + self._errors = errors +- self.buffer = u"".encode() ++ self.buffer = "".encode() + self.headerfixed = False + + def iterdecode(self, input): +@@ -272,7 +272,7 @@ if hasattr(codecs, "IncrementalDecoder"): + (encoding, explicit) = detectencoding_str(input, final) + if encoding is None: # no encoding determined yet + self.buffer = input # retry the complete input on the next call +- return u"" # no encoding determined yet, so no output ++ return "" # no encoding determined yet, so no output + elif encoding == "css": + raise ValueError("css not allowed as encoding name") + if (explicit and not self.force) or self.encoding is None: # Take the encoding from the input +@@ -288,18 +288,18 @@ if hasattr(codecs, "IncrementalDecoder"): + encoding = self.encoding + if encoding.replace("_", "-").lower() == "utf-8-sig": + encoding = "utf-8" +- newoutput = _fixencoding(output, unicode(encoding), final) ++ newoutput = _fixencoding(output, str(encoding), final) + if newoutput is None: + # retry fixing the @charset rule (but keep the decoded stuff) + self.buffer = output +- return u"" ++ return "" + self.headerfixed = True + return newoutput + + def reset(self): + codecs.IncrementalDecoder.reset(self) + self.decoder = None +- self.buffer = u"".encode() ++ self.buffer = "".encode() + self.headerfixed = False + + def _geterrors(self): +@@ -340,14 +340,14 @@ if hasattr(codecs, "IncrementalEncoder"): + # Store ``errors`` somewhere else, + # because we have to hide it in a property + self._errors = errors +- self.buffer = u"" ++ self.buffer = "" + + def iterencode(self, input): + for part in input: + result = self.encode(part, False) + if result: + yield result +- result = self.encode(u"", True) ++ result = self.encode("", True) + if result: + yield result + +@@ -359,7 +359,7 @@ if hasattr(codecs, "IncrementalEncoder"): + encoding = self.encoding + if encoding.replace("_", "-").lower() == "utf-8-sig": + encoding = "utf-8" +- newinput = _fixencoding(input, unicode(encoding), final) ++ newinput = _fixencoding(input, str(encoding), final) + if newinput is None: # @charset rule incomplete => Retry next time + self.buffer = input + return "" +@@ -373,9 +373,9 @@ if hasattr(codecs, "IncrementalEncoder"): + info = codecs.lookup(self.encoding) + encoding = self.encoding + if self.encoding.replace("_", "-").lower() == "utf-8-sig": +- input = _fixencoding(input, u"utf-8", True) ++ input = _fixencoding(input, "utf-8", True) + self.encoder = info.incrementalencoder(self._errors) +- self.buffer = u"" ++ self.buffer = "" + else: + self.buffer = input + return "" +@@ -384,7 +384,7 @@ if hasattr(codecs, "IncrementalEncoder"): + def reset(self): + codecs.IncrementalEncoder.reset(self) + self.encoder = None +- self.buffer = u"" ++ self.buffer = "" + + def _geterrors(self): + return self._errors +@@ -420,7 +420,7 @@ class StreamWriter(codecs.StreamWriter): + self.streamwriter = None + self.encoding = encoding + self._errors = errors +- self.buffer = u"" ++ self.buffer = "" + + def encode(self, input, errors='strict'): + li = len(input) +@@ -432,7 +432,7 @@ class StreamWriter(codecs.StreamWriter): + encoding = self.encoding + if encoding.replace("_", "-").lower() == "utf-8-sig": + encoding = "utf-8" +- newinput = _fixencoding(input, unicode(encoding), False) ++ newinput = _fixencoding(input, str(encoding), False) + if newinput is None: # @charset rule incomplete => Retry next time + self.buffer = input + return ("", 0) +@@ -446,8 +446,8 @@ class StreamWriter(codecs.StreamWriter): + self.streamwriter = codecs.getwriter(self.encoding)(self.stream, self._errors) + encoding = self.encoding + if self.encoding.replace("_", "-").lower() == "utf-8-sig": +- input = _fixencoding(input, u"utf-8", True) +- self.buffer = u"" ++ input = _fixencoding(input, "utf-8", True) ++ self.buffer = "" + else: + self.buffer = input + return ("", 0) +@@ -478,7 +478,7 @@ class StreamReader(codecs.StreamReader): + if self.encoding is None or not self.force: + (encoding, explicit) = detectencoding_str(input, False) + if encoding is None: # no encoding determined yet +- return (u"", 0) # no encoding determined yet, so no output ++ return ("", 0) # no encoding determined yet, so no output + elif encoding == "css": + raise ValueError("css not allowed as encoding name") + if (explicit and not self.force) or self.encoding is None: # Take the encoding from the input +@@ -489,11 +489,11 @@ class StreamReader(codecs.StreamReader): + encoding = self.encoding + if encoding.replace("_", "-").lower() == "utf-8-sig": + encoding = "utf-8" +- newoutput = _fixencoding(output, unicode(encoding), False) ++ newoutput = _fixencoding(output, str(encoding), False) + if newoutput is not None: + self.streamreader = streamreader + return (newoutput, consumed) +- return (u"", 0) # we will create a new streamreader on the next call ++ return ("", 0) # we will create a new streamreader on the next call + return self.streamreader.decode(input, errors) + + def _geterrors(self): +@@ -558,7 +558,7 @@ else: + if len(input) < 3 and codecs.BOM_UTF8.startswith(input): + # not enough data to decide if this is a BOM + # => try again on the next call +- return (u"", 0) ++ return ("", 0) + self.decode = codecs.utf_8_decode + return utf8sig_decode(input, errors) + +@@ -579,6 +579,6 @@ codecs.register(search_function) + def cssescape(exc): + if not isinstance(exc, UnicodeEncodeError): + raise TypeError("don't know how to handle %r" % exc) +- return (u"".join(u"\\%06x" % ord(c) for c in exc.object[exc.start:exc.end]), exc.end) ++ return ("".join("\\%06x" % ord(c) for c in exc.object[exc.start:exc.end]), exc.end) + + codecs.register_error("cssescape", cssescape) +diff --git a/src/cssutils/_fetch.py b/src/cssutils/_fetch.py +index e9096ee..822d987 100644 +--- a/src/cssutils/_fetch.py ++++ b/src/cssutils/_fetch.py +@@ -6,8 +6,8 @@ __version__ = '$Id: tokenize2.py 1547 2008-12-10 20:42:26Z cthedot $' + import cssutils + from cssutils import VERSION + import encutils +-import errorhandler +-import urllib2 ++from . import errorhandler ++import urllib.request, urllib.error, urllib.parse + + log = errorhandler.ErrorHandler() + +@@ -18,28 +18,28 @@ def _defaultFetcher(url): + Returns ``(encoding, string)`` or ``None`` + """ + try: +- request = urllib2.Request(url) ++ request = urllib.request.Request(url) + request.add_header('User-agent', + 'cssutils %s (http://www.cthedot.de/cssutils/)' % VERSION) +- res = urllib2.urlopen(request) +- except urllib2.HTTPError, e: ++ res = urllib.request.urlopen(request) ++ except urllib.error.HTTPError as e: + # http error, e.g. 404, e can be raised +- log.warn(u'HTTPError opening url=%s: %s %s' % ++ log.warn('HTTPError opening url=%s: %s %s' % + (url, e.code, e.msg), error=e) +- except urllib2.URLError, e: ++ except urllib.error.URLError as e: + # URLError like mailto: or other IO errors, e can be raised +- log.warn(u'URLError, %s' % e.reason, error=e) +- except OSError, e: ++ log.warn('URLError, %s' % e.reason, error=e) ++ except OSError as e: + # e.g if file URL and not found + log.warn(e, error=OSError) +- except ValueError, e: ++ except ValueError as e: + # invalid url, e.g. "1" +- log.warn(u'ValueError, %s' % e.args[0], error=ValueError) ++ log.warn('ValueError, %s' % e.args[0], error=ValueError) + else: + if res: + mimeType, encoding = encutils.getHTTPInfo(res) +- if mimeType != u'text/css': +- log.error(u'Expected "text/css" mime type for url=%r but found: %r' % ++ if mimeType != 'text/css': ++ log.error('Expected "text/css" mime type for url=%r but found: %r' % + (url, mimeType), error=ValueError) + content = res.read() + if hasattr(res, 'close'): +diff --git a/src/cssutils/_fetchgae.py b/src/cssutils/_fetchgae.py +index 7760ac6..fb708e9 100644 +--- a/src/cssutils/_fetchgae.py ++++ b/src/cssutils/_fetchgae.py +@@ -6,8 +6,8 @@ __version__ = '$Id: tokenize2.py 1547 2008-12-10 20:42:26Z cthedot $' + # raises ImportError of not on GAE + from google.appengine.api import urlfetch + import cgi +-import errorhandler +-import util ++from . import errorhandler ++from . import util + + log = errorhandler.ErrorHandler() + +@@ -46,8 +46,8 @@ def _defaultFetcher(url): + #from google.appengine.api import urlfetch + try: + r = urlfetch.fetch(url, method=urlfetch.GET) +- except urlfetch.Error, e: +- log.warn(u'Error opening url=%r: %s' % (url, e), ++ except urlfetch.Error as e: ++ log.warn('Error opening url=%r: %s' % (url, e), + error=IOError) + else: + if r.status_code == 200: +@@ -58,11 +58,11 @@ def _defaultFetcher(url): + encoding = params['charset'] + except KeyError: + encoding = None +- if mimetype != u'text/css': +- log.error(u'Expected "text/css" mime type for url %r but found: %r' % ++ if mimetype != 'text/css': ++ log.error('Expected "text/css" mime type for url %r but found: %r' % + (url, mimetype), error=ValueError) + return encoding, r.content + else: + # TODO: 301 etc +- log.warn(u'Error opening url=%r: HTTP status %s' % ++ log.warn('Error opening url=%r: HTTP status %s' % + (url, r.status_code), error=IOError) +diff --git a/src/cssutils/codec.py b/src/cssutils/codec.py +index c694e1f..03ee076 100644 +--- a/src/cssutils/codec.py ++++ b/src/cssutils/codec.py +@@ -7,10 +7,10 @@ __version__ = '$Id: util.py 1114 2008-03-05 13:22:59Z cthedot $' + import sys + + if sys.version_info < (3,): +- from _codec2 import * ++ from ._codec2 import * + # for tests +- from _codec2 import _fixencoding ++ from ._codec2 import _fixencoding + else: +- from _codec3 import * ++ from ._codec3 import * + # for tests +- from _codec3 import _fixencoding ++ from ._codec3 import _fixencoding +diff --git a/src/cssutils/css/__init__.py b/src/cssutils/css/__init__.py +index 4cc4a90..d70a630 100644 +--- a/src/cssutils/css/__init__.py ++++ b/src/cssutils/css/__init__.py +@@ -57,24 +57,24 @@ __all__ = [ + __docformat__ = 'restructuredtext' + __version__ = '$Id$' + +-from cssstylesheet import * +-from cssrulelist import * +-from cssrule import * +-from csscomment import * +-from csscharsetrule import * +-from cssfontfacerule import * +-from cssimportrule import * +-from cssmediarule import * +-from cssnamespacerule import * +-from csspagerule import * +-from marginrule import * +-from cssstylerule import * +-from cssvariablesrule import * +-from cssunknownrule import * +-from selector import * +-from selectorlist import * +-from cssstyledeclaration import * +-from cssvariablesdeclaration import * +-from property import * ++from .cssstylesheet import * ++from .cssrulelist import * ++from .cssrule import * ++from .csscomment import * ++from .csscharsetrule import * ++from .cssfontfacerule import * ++from .cssimportrule import * ++from .cssmediarule import * ++from .cssnamespacerule import * ++from .csspagerule import * ++from .marginrule import * ++from .cssstylerule import * ++from .cssvariablesrule import * ++from .cssunknownrule import * ++from .selector import * ++from .selectorlist import * ++from .cssstyledeclaration import * ++from .cssvariablesdeclaration import * ++from .property import * + #from cssvalue import * +-from value import * ++from .value import * +diff --git a/src/cssutils/css/csscharsetrule.py b/src/cssutils/css/csscharsetrule.py +index fa6b7c4..1e0e9dc 100644 +--- a/src/cssutils/css/csscharsetrule.py ++++ b/src/cssutils/css/csscharsetrule.py +@@ -4,7 +4,7 @@ __docformat__ = 'restructuredtext' + __version__ = '$Id$' + + import codecs +-import cssrule ++from . import cssrule + import cssutils + import xml.dom + +@@ -57,14 +57,14 @@ class CSSCharsetRule(cssrule.CSSRule): + self._readonly = readonly + + def __repr__(self): +- return u"cssutils.css.%s(encoding=%r)" % ( +- self.__class__.__name__, ++ return "cssutils.css.%s(encoding=%r)" % ( ++ self.__class__.__name__, + self.encoding) + + def __str__(self): +- return u"" % ( +- self.__class__.__name__, +- self.encoding, ++ return "" % ( ++ self.__class__.__name__, ++ self.encoding, + id(self)) + + def _getCssText(self): +@@ -95,7 +95,7 @@ class CSSCharsetRule(cssrule.CSSRule): + + if self._type(self._nexttoken(tokenizer)) != self._prods.CHARSET_SYM: + wellformed = False +- self._log.error(u'CSSCharsetRule must start with "@charset "', ++ self._log.error('CSSCharsetRule must start with "@charset "', + error=xml.dom.InvalidModificationErr) + + encodingtoken = self._nexttoken(tokenizer) +@@ -103,21 +103,21 @@ class CSSCharsetRule(cssrule.CSSRule): + encoding = self._stringtokenvalue(encodingtoken) + if self._prods.STRING != encodingtype or not encoding: + wellformed = False +- self._log.error(u'CSSCharsetRule: no encoding found; %r.' % ++ self._log.error('CSSCharsetRule: no encoding found; %r.' % + self._valuestr(cssText)) + + semicolon = self._tokenvalue(self._nexttoken(tokenizer)) + EOFtype = self._type(self._nexttoken(tokenizer)) +- if u';' != semicolon or EOFtype not in ('EOF', None): ++ if ';' != semicolon or EOFtype not in ('EOF', None): + wellformed = False +- self._log.error(u'CSSCharsetRule: Syntax Error: %r.' % ++ self._log.error('CSSCharsetRule: Syntax Error: %r.' % + self._valuestr(cssText)) + + if wellformed: + self.encoding = encoding + + cssText = property(fget=_getCssText, fset=_setCssText, +- doc=u"(DOM) The parsable textual representation.") ++ doc="(DOM) The parsable textual representation.") + + def _setEncoding(self, encoding): + """ +@@ -138,22 +138,22 @@ class CSSCharsetRule(cssrule.CSSRule): + + if not encodingtoken or unexpected or\ + self._prods.IDENT != self._type(encodingtoken): +- self._log.error(u'CSSCharsetRule: Syntax Error in encoding value ' +- u'%r.' % encoding) ++ self._log.error('CSSCharsetRule: Syntax Error in encoding value ' ++ '%r.' % encoding) + else: + try: + codecs.lookup(encoding) + except LookupError: +- self._log.error(u'CSSCharsetRule: Unknown (Python) encoding %r.' ++ self._log.error('CSSCharsetRule: Unknown (Python) encoding %r.' + % encoding) + else: + self._encoding = encoding.lower() + + encoding = property(lambda self: self._encoding, _setEncoding, +- doc=u"(DOM)The encoding information used in this @charset rule.") ++ doc="(DOM)The encoding information used in this @charset rule.") + + type = property(lambda self: self.CHARSET_RULE, +- doc=u"The type of this rule, as defined by a CSSRule " +- u"type constant.") ++ doc="The type of this rule, as defined by a CSSRule " ++ "type constant.") + + wellformed = property(lambda self: bool(self.encoding)) +diff --git a/src/cssutils/css/csscomment.py b/src/cssutils/css/csscomment.py +index 311df0f..0f706e9 100644 +--- a/src/cssutils/css/csscomment.py ++++ b/src/cssutils/css/csscomment.py +@@ -7,7 +7,7 @@ __all__ = ['CSSComment'] + __docformat__ = 'restructuredtext' + __version__ = '$Id$' + +-import cssrule ++from . import cssrule + import cssutils + import xml.dom + +@@ -31,12 +31,12 @@ class CSSComment(cssrule.CSSRule): + self._readonly = readonly + + def __repr__(self): +- return u"cssutils.css.%s(cssText=%r)" % ( ++ return "cssutils.css.%s(cssText=%r)" % ( + self.__class__.__name__, + self.cssText) + + def __str__(self): +- return u"" % ( ++ return "" % ( + self.__class__.__name__, + self.cssText, + id(self)) +@@ -70,18 +70,18 @@ class CSSComment(cssrule.CSSRule): + if not commenttoken or\ + self._type(commenttoken) != self._prods.COMMENT or\ + unexpected: +- self._log.error(u'CSSComment: Not a CSSComment: %r' % ++ self._log.error('CSSComment: Not a CSSComment: %r' % + self._valuestr(cssText), + error=xml.dom.InvalidModificationErr) + else: + self._cssText = self._tokenvalue(commenttoken) + + cssText = property(_getCssText, _setCssText, +- doc=u"The parsable textual representation of this rule.") ++ doc="The parsable textual representation of this rule.") + + type = property(lambda self: self.COMMENT, +- doc=u"The type of this rule, as defined by a CSSRule " +- u"type constant.") ++ doc="The type of this rule, as defined by a CSSRule " ++ "type constant.") + + # constant but needed: + wellformed = property(lambda self: True) +diff --git a/src/cssutils/css/cssfontfacerule.py b/src/cssutils/css/cssfontfacerule.py +index 621bcb8..dbc3142 100644 +--- a/src/cssutils/css/cssfontfacerule.py ++++ b/src/cssutils/css/cssfontfacerule.py +@@ -7,8 +7,8 @@ __all__ = ['CSSFontFaceRule'] + __docformat__ = 'restructuredtext' + __version__ = '$Id$' + +-from cssstyledeclaration import CSSStyleDeclaration +-import cssrule ++from .cssstyledeclaration import CSSStyleDeclaration ++from . import cssrule + import cssutils + import xml.dom + +@@ -41,7 +41,7 @@ class CSSFontFaceRule(cssrule.CSSRule): + """ + super(CSSFontFaceRule, self).__init__(parentRule=parentRule, + parentStyleSheet=parentStyleSheet) +- self._atkeyword = u'@font-face' ++ self._atkeyword = '@font-face' + + if style: + self.style = style +@@ -51,12 +51,12 @@ class CSSFontFaceRule(cssrule.CSSRule): + self._readonly = readonly + + def __repr__(self): +- return u"cssutils.css.%s(style=%r)" % ( ++ return "cssutils.css.%s(style=%r)" % ( + self.__class__.__name__, + self.style.cssText) + + def __str__(self): +- return u"" % ( ++ return "" % ( + self.__class__.__name__, + self.style.cssText, + self.valid, +@@ -86,7 +86,7 @@ class CSSFontFaceRule(cssrule.CSSRule): + tokenizer = self._tokenize2(cssText) + attoken = self._nexttoken(tokenizer, None) + if self._type(attoken) != self._prods.FONT_FACE_SYM: +- self._log.error(u'CSSFontFaceRule: No CSSFontFaceRule found: %s' % ++ self._log.error('CSSFontFaceRule: No CSSFontFaceRule found: %s' % + self._valuestr(cssText), + error=xml.dom.InvalidModificationErr) + else: +@@ -96,10 +96,10 @@ class CSSFontFaceRule(cssrule.CSSRule): + beforetokens, brace = self._tokensupto2(tokenizer, + blockstartonly=True, + separateEnd=True) +- if self._tokenvalue(brace) != u'{': ++ if self._tokenvalue(brace) != '{': + ok = False +- self._log.error(u'CSSFontFaceRule: No start { of style ' +- u'declaration found: %r' ++ self._log.error('CSSFontFaceRule: No start { of style ' ++ 'declaration found: %r' + % self._valuestr(cssText), brace) + + # parse stuff before { which should be comments and S only +@@ -117,16 +117,16 @@ class CSSFontFaceRule(cssrule.CSSRule): + + val, type_ = self._tokenvalue(braceorEOFtoken),\ + self._type(braceorEOFtoken) +- if val != u'}' and type_ != 'EOF': ++ if val != '}' and type_ != 'EOF': + ok = False +- self._log.error(u'CSSFontFaceRule: No "}" after style ' +- u'declaration found: %r' ++ self._log.error('CSSFontFaceRule: No "}" after style ' ++ 'declaration found: %r' + % self._valuestr(cssText)) + + nonetoken = self._nexttoken(tokenizer) + if nonetoken: + ok = False +- self._log.error(u'CSSFontFaceRule: Trailing content found.', ++ self._log.error('CSSFontFaceRule: Trailing content found.', + token=nonetoken) + + if 'EOF' == type_: +@@ -142,8 +142,8 @@ class CSSFontFaceRule(cssrule.CSSRule): + self.style = newStyle + + cssText = property(_getCssText, _setCssText, +- doc=u"(DOM) The parsable textual representation of this " +- u"rule.") ++ doc="(DOM) The parsable textual representation of this " ++ "rule.") + + def _setStyle(self, style): + """ +@@ -151,19 +151,19 @@ class CSSFontFaceRule(cssrule.CSSRule): + a CSSStyleDeclaration or string + """ + self._checkReadonly() +- if isinstance(style, basestring): ++ if isinstance(style, str): + self._style = CSSStyleDeclaration(cssText=style, parentRule=self) + else: + style._parentRule = self + self._style = style + + style = property(lambda self: self._style, _setStyle, +- doc=u"(DOM) The declaration-block of this rule set, " +- u"a :class:`~cssutils.css.CSSStyleDeclaration`.") ++ doc="(DOM) The declaration-block of this rule set, " ++ "a :class:`~cssutils.css.CSSStyleDeclaration`.") + + type = property(lambda self: self.FONT_FACE_RULE, +- doc=u"The type of this rule, as defined by a CSSRule " +- u"type constant.") ++ doc="The type of this rule, as defined by a CSSRule " ++ "type constant.") + + def _getValid(self): + needed = ['font-family', 'src'] +@@ -177,8 +177,8 @@ class CSSFontFaceRule(cssrule.CSSRule): + return not bool(needed) + + valid = property(_getValid, +- doc=u"CSSFontFace is valid if properties `font-family` " +- u"and `src` are set and all properties are valid.") ++ doc="CSSFontFace is valid if properties `font-family` " ++ "and `src` are set and all properties are valid.") + + # constant but needed: + wellformed = property(lambda self: True) +diff --git a/src/cssutils/css/cssimportrule.py b/src/cssutils/css/cssimportrule.py +index 59fe256..a83a561 100644 +--- a/src/cssutils/css/cssimportrule.py ++++ b/src/cssutils/css/cssimportrule.py +@@ -4,10 +4,10 @@ __all__ = ['CSSImportRule'] + __docformat__ = 'restructuredtext' + __version__ = '$Id$' + +-import cssrule ++from . import cssrule + import cssutils + import os +-import urlparse ++import urllib.parse + import xml.dom + + class CSSImportRule(cssrule.CSSRule): +@@ -37,7 +37,7 @@ class CSSImportRule(cssrule.CSSRule): + """ + super(CSSImportRule, self).__init__(parentRule=parentRule, + parentStyleSheet=parentStyleSheet) +- self._atkeyword = u'@import' ++ self._atkeyword = '@import' + self._styleSheet = None + + # string or uri used for reserialization +@@ -55,7 +55,7 @@ class CSSImportRule(cssrule.CSSRule): + self.media = mediaText + else: + # must be all for @import +- self.media = cssutils.stylesheets.MediaList(mediaText=u'all') ++ self.media = cssutils.stylesheets.MediaList(mediaText='all') + # 2. name + self.name = name + # 3. href and styleSheet +@@ -68,7 +68,7 @@ class CSSImportRule(cssrule.CSSRule): + mediaText = self.media.mediaText + else: + mediaText = None +- return u"cssutils.css.%s(href=%r, mediaText=%r, name=%r)" % ( ++ return "cssutils.css.%s(href=%r, mediaText=%r, name=%r)" % ( + self.__class__.__name__, + self.href, + self.media.mediaText, +@@ -79,14 +79,14 @@ class CSSImportRule(cssrule.CSSRule): + mediaText = self.media.mediaText + else: + mediaText = None +- return u""\ ++ return ""\ + % (self.__class__.__name__, + self.href, + mediaText, + self.name, + id(self)) + +- _usemedia = property(lambda self: self.media.mediaText not in (u'', u'all'), ++ _usemedia = property(lambda self: self.media.mediaText not in ('', 'all'), + doc="if self.media is used (or simply empty)") + + def _getCssText(self): +@@ -112,7 +112,7 @@ class CSSImportRule(cssrule.CSSRule): + tokenizer = self._tokenize2(cssText) + attoken = self._nexttoken(tokenizer, None) + if self._type(attoken) != self._prods.IMPORT_SYM: +- self._log.error(u'CSSImportRule: No CSSImportRule found: %s' % ++ self._log.error('CSSImportRule: No CSSImportRule found: %s' % + self._valuestr(cssText), + error=xml.dom.InvalidModificationErr) + else: +@@ -144,7 +144,7 @@ class CSSImportRule(cssrule.CSSRule): + else: + new['wellformed'] = False + self._log.error( +- u'CSSImportRule: Unexpected string.', token) ++ 'CSSImportRule: Unexpected string.', token) + return expected + + def _uri(expected, seq, token, tokenizer=None): +@@ -158,7 +158,7 @@ class CSSImportRule(cssrule.CSSRule): + else: + new['wellformed'] = False + self._log.error( +- u'CSSImportRule: Unexpected URI.', token) ++ 'CSSImportRule: Unexpected URI.', token) + return expected + + def _ident(expected, seq, token, tokenizer=None): +@@ -170,10 +170,10 @@ class CSSImportRule(cssrule.CSSRule): + + last = mediatokens.pop() # retrieve ; + lastval, lasttyp = self._tokenvalue(last), self._type(last) +- if lastval != u';' and lasttyp not in ('EOF', ++ if lastval != ';' and lasttyp not in ('EOF', + self._prods.STRING): + new['wellformed'] = False +- self._log.error(u'CSSImportRule: No ";" found: %s' % ++ self._log.error('CSSImportRule: No ";" found: %s' % + self._valuestr(cssText), token=token) + + newMedia = cssutils.stylesheets.MediaList(parentRule=self) +@@ -183,7 +183,7 @@ class CSSImportRule(cssrule.CSSRule): + seq.append(newMedia, 'media') + else: + new['wellformed'] = False +- self._log.error(u'CSSImportRule: Invalid MediaList: %s' % ++ self._log.error('CSSImportRule: Invalid MediaList: %s' % + self._valuestr(cssText), token=token) + + if lasttyp == self._prods.STRING: +@@ -193,18 +193,18 @@ class CSSImportRule(cssrule.CSSRule): + return 'EOF' # ';' is token "last" + else: + new['wellformed'] = False +- self._log.error(u'CSSImportRule: Unexpected ident.', token) ++ self._log.error('CSSImportRule: Unexpected ident.', token) + return expected + + def _char(expected, seq, token, tokenizer=None): + # final ; + val = self._tokenvalue(token) +- if expected.endswith(';') and u';' == val: ++ if expected.endswith(';') and ';' == val: + return 'EOF' + else: + new['wellformed'] = False + self._log.error( +- u'CSSImportRule: Unexpected char.', token) ++ 'CSSImportRule: Unexpected char.', token) + return expected + + # import : IMPORT_SYM S* [STRING|URI] +@@ -226,12 +226,12 @@ class CSSImportRule(cssrule.CSSRule): + # post conditions + if not new['href']: + ok = False +- self._log.error(u'CSSImportRule: No href found: %s' % ++ self._log.error('CSSImportRule: No href found: %s' % + self._valuestr(cssText)) + + if expected != 'EOF': + ok = False +- self._log.error(u'CSSImportRule: No ";" found: %s' % ++ self._log.error('CSSImportRule: No ";" found: %s' % + self._valuestr(cssText)) + + # set all +@@ -246,7 +246,7 @@ class CSSImportRule(cssrule.CSSRule): + self.media = new['media'] + else: + # must be all for @import +- self.media = cssutils.stylesheets.MediaList(mediaText=u'all') ++ self.media = cssutils.stylesheets.MediaList(mediaText='all') + + # needs new self.media + self.href = new['href'] +@@ -278,7 +278,7 @@ class CSSImportRule(cssrule.CSSRule): + # use cwd instead + parentHref = cssutils.helper.path2url(os.getcwd()) + '/' + +- fullhref = urlparse.urljoin(parentHref, self.href) ++ fullhref = urllib.parse.urljoin(parentHref, self.href) + + # all possible exceptions are ignored + try: +@@ -306,9 +306,9 @@ class CSSImportRule(cssrule.CSSRule): + encodingOverride=encodingOverride, + encoding=encoding) + +- except (OSError, IOError, ValueError), e: +- self._log.warn(u'CSSImportRule: While processing imported ' +- u'style sheet href=%s: %r' ++ except (OSError, IOError, ValueError) as e: ++ self._log.warn('CSSImportRule: While processing imported ' ++ 'style sheet href=%s: %r' + % (self.href, e), neverraise=True) + + else: +@@ -319,7 +319,7 @@ class CSSImportRule(cssrule.CSSRule): + + _href = None # needs to be set + href = property(lambda self: self._href, _setHref, +- doc=u"Location of the style sheet to be imported.") ++ doc="Location of the style sheet to be imported.") + + def _setMedia(self, media): + """ +@@ -327,7 +327,7 @@ class CSSImportRule(cssrule.CSSRule): + a :class:`~cssutils.stylesheets.MediaList` or string + """ + self._checkReadonly() +- if isinstance(media, basestring): ++ if isinstance(media, str): + self._media = cssutils.stylesheets.MediaList(mediaText=media, + parentRule=self) + else: +@@ -348,12 +348,12 @@ class CSSImportRule(cssrule.CSSRule): + self._media, 'media', None, None) + + media = property(lambda self: self._media, _setMedia, +- doc=u"(DOM) A list of media types for this rule " +- u"of type :class:`~cssutils.stylesheets.MediaList`.") ++ doc="(DOM) A list of media types for this rule " ++ "of type :class:`~cssutils.stylesheets.MediaList`.") + +- def _setName(self, name=u''): ++ def _setName(self, name=''): + """Raises xml.dom.SyntaxErr if name is not a string.""" +- if name is None or isinstance(name, basestring): ++ if name is None or isinstance(name, str): + # "" or '' handled as None + if not name: + name = None +@@ -373,18 +373,18 @@ class CSSImportRule(cssrule.CSSRule): + self.styleSheet.title = name + + else: +- self._log.error(u'CSSImportRule: Not a valid name: %s' % name) ++ self._log.error('CSSImportRule: Not a valid name: %s' % name) + + name = property(lambda self: self._name, _setName, +- doc=u"An optional name for the imported sheet.") ++ doc="An optional name for the imported sheet.") + + styleSheet = property(lambda self: self._styleSheet, +- doc=u"(readonly) The style sheet referred to by this " +- u"rule.") ++ doc="(readonly) The style sheet referred to by this " ++ "rule.") + + type = property(lambda self: self.IMPORT_RULE, +- doc=u"The type of this rule, as defined by a CSSRule " +- u"type constant.") ++ doc="The type of this rule, as defined by a CSSRule " ++ "type constant.") + + def _getWellformed(self): + "Depending on if media is used at all." +diff --git a/src/cssutils/css/cssmediarule.py b/src/cssutils/css/cssmediarule.py +index e58af09..74187c3 100644 +--- a/src/cssutils/css/cssmediarule.py ++++ b/src/cssutils/css/cssmediarule.py +@@ -3,7 +3,7 @@ __all__ = ['CSSMediaRule'] + __docformat__ = 'restructuredtext' + __version__ = '$Id$' + +-import cssrule ++from . import cssrule + import cssutils + import xml.dom + +@@ -29,7 +29,7 @@ class CSSMediaRule(cssrule.CSSRuleRules): + """constructor""" + super(CSSMediaRule, self).__init__(parentRule=parentRule, + parentStyleSheet=parentStyleSheet) +- self._atkeyword = u'@media' ++ self._atkeyword = '@media' + + # 1. media + if mediaText: +@@ -41,12 +41,12 @@ class CSSMediaRule(cssrule.CSSRuleRules): + self._readonly = readonly + + def __repr__(self): +- return u"cssutils.css.%s(mediaText=%r)" % ( ++ return "cssutils.css.%s(mediaText=%r)" % ( + self.__class__.__name__, + self.media.mediaText) + + def __str__(self): +- return u"" % ( ++ return "" % ( + self.__class__.__name__, + self.media.mediaText, + id(self)) +@@ -90,7 +90,7 @@ class CSSMediaRule(cssrule.CSSRuleRules): + tokenizer = self._tokenize2(cssText) + attoken = self._nexttoken(tokenizer, None) + if self._type(attoken) != self._prods.MEDIA_SYM: +- self._log.error(u'CSSMediaRule: No CSSMediaRule found: %s' % ++ self._log.error('CSSMediaRule: No CSSMediaRule found: %s' % + self._valuestr(cssText), + error=xml.dom.InvalidModificationErr) + +@@ -106,7 +106,7 @@ class CSSMediaRule(cssrule.CSSRuleRules): + mediatokens, end = self._tokensupto2(tokenizer, + mediaqueryendonly=True, + separateEnd=True) +- if u'{' == self._tokenvalue(end)\ ++ if '{' == self._tokenvalue(end)\ + or self._prods.STRING == self._type(end): + self.media = cssutils.stylesheets.MediaList(parentRule=self) + # TODO: remove special case +@@ -130,13 +130,13 @@ class CSSMediaRule(cssrule.CSSRuleRules): + {}) + if not wellformed: + ok = False +- self._log.error(u'CSSMediaRule: Syntax Error: %s' % ++ self._log.error('CSSMediaRule: Syntax Error: %s' % + self._valuestr(cssText)) + + + # check for { +- if u'{' != self._tokenvalue(end): +- self._log.error(u'CSSMediaRule: No "{" found: %s' % ++ if '{' != self._tokenvalue(end): ++ self._log.error('CSSMediaRule: No "{" found: %s' % + self._valuestr(cssText)) + return + +@@ -150,14 +150,14 @@ class CSSMediaRule(cssrule.CSSRuleRules): + # TODO: Not complete, add EOF to rule and } to @media + cssrulestokens.append(braceOrEOF) + braceOrEOF = ('CHAR', '}', 0, 0) +- self._log.debug(u'CSSMediaRule: Incomplete, adding "}".', ++ self._log.debug('CSSMediaRule: Incomplete, adding "}".', + token=braceOrEOF, neverraise=True) + +- if u'}' != self._tokenvalue(braceOrEOF): +- self._log.error(u'CSSMediaRule: No "}" found.', ++ if '}' != self._tokenvalue(braceOrEOF): ++ self._log.error('CSSMediaRule: No "}" found.', + token=braceOrEOF) + elif nonetoken: +- self._log.error(u'CSSMediaRule: Trailing content found.', ++ self._log.error('CSSMediaRule: Trailing content found.', + token=nonetoken) + else: + # for closures: must be a mutable +@@ -187,9 +187,9 @@ class CSSMediaRule(cssrule.CSSRuleRules): + } + if atval in ('@charset ', '@font-face', '@import', + '@namespace', '@variables'): +- self._log.error(u'CSSMediaRule: This rule is not ' +- u'allowed in CSSMediaRule - ignored: ' +- u'%s.' % self._valuestr(tokens), ++ self._log.error('CSSMediaRule: This rule is not ' ++ 'allowed in CSSMediaRule - ignored: ' ++ '%s.' % self._valuestr(tokens), + token = token, + error=xml.dom.HierarchyRequestErr) + elif atval in factories: +@@ -238,21 +238,21 @@ class CSSMediaRule(cssrule.CSSRuleRules): + self._cssRules = oldCssRules + + cssText = property(_getCssText, _setCssText, +- doc=u"(DOM) The parsable textual representation of this " +- u"rule.") ++ doc="(DOM) The parsable textual representation of this " ++ "rule.") + + def _setName(self, name): +- if isinstance(name, basestring) or name is None: ++ if isinstance(name, str) or name is None: + # "" or '' + if not name: + name = None + + self._name = name + else: +- self._log.error(u'CSSImportRule: Not a valid name: %s' % name) ++ self._log.error('CSSImportRule: Not a valid name: %s' % name) + + name = property(lambda self: self._name, _setName, +- doc=u"An optional name for this media rule.") ++ doc="An optional name for this media rule.") + + def _setMedia(self, media): + """ +@@ -260,7 +260,7 @@ class CSSMediaRule(cssrule.CSSRuleRules): + a :class:`~cssutils.stylesheets.MediaList` or string + """ + self._checkReadonly() +- if isinstance(media, basestring): ++ if isinstance(media, str): + self._media = cssutils.stylesheets.MediaList(mediaText=media, + parentRule=self) + else: +@@ -279,8 +279,8 @@ class CSSMediaRule(cssrule.CSSRuleRules): + # self._media, 'media', None, None) + + media = property(lambda self: self._media, _setMedia, +- doc=u"(DOM) A list of media types for this rule " +- u"of type :class:`~cssutils.stylesheets.MediaList`.") ++ doc="(DOM) A list of media types for this rule " ++ "of type :class:`~cssutils.stylesheets.MediaList`.") + + + def insertRule(self, rule, index=None): +@@ -297,7 +297,7 @@ class CSSMediaRule(cssrule.CSSRuleRules): + isinstance(rule, cssutils.css.CSSImportRule) or \ + isinstance(rule, cssutils.css.CSSNamespaceRule) or \ + isinstance(rule, cssutils.css.MarginRule): +- self._log.error(u'%s: This type of rule is not allowed here: %s' ++ self._log.error('%s: This type of rule is not allowed here: %s' + % (self.__class__.__name__, rule.cssText), + error=xml.dom.HierarchyRequestErr) + return +@@ -305,7 +305,7 @@ class CSSMediaRule(cssrule.CSSRuleRules): + return self._finishInsertRule(rule, index) + + type = property(lambda self: self.MEDIA_RULE, +- doc=u"The type of this rule, as defined by a CSSRule " +- u"type constant.") ++ doc="The type of this rule, as defined by a CSSRule " ++ "type constant.") + + wellformed = property(lambda self: self.media.wellformed) +diff --git a/src/cssutils/css/cssnamespacerule.py b/src/cssutils/css/cssnamespacerule.py +index a2610fc..5813713 100644 +--- a/src/cssutils/css/cssnamespacerule.py ++++ b/src/cssutils/css/cssnamespacerule.py +@@ -4,7 +4,7 @@ __all__ = ['CSSNamespaceRule'] + __docformat__ = 'restructuredtext' + __version__ = '$Id$' + +-import cssrule ++from . import cssrule + import cssutils + import xml.dom + +@@ -62,8 +62,8 @@ class CSSNamespaceRule(cssrule.CSSRule): + """ + super(CSSNamespaceRule, self).__init__(parentRule=parentRule, + parentStyleSheet=parentStyleSheet) +- self._atkeyword = u'@namespace' +- self._prefix = u'' ++ self._atkeyword = '@namespace' ++ self._prefix = '' + self._namespaceURI = None + + if namespaceURI: +@@ -83,13 +83,13 @@ class CSSNamespaceRule(cssrule.CSSRule): + self._readonly = readonly + + def __repr__(self): +- return u"cssutils.css.%s(namespaceURI=%r, prefix=%r)" % ( ++ return "cssutils.css.%s(namespaceURI=%r, prefix=%r)" % ( + self.__class__.__name__, + self.namespaceURI, + self.prefix) + + def __str__(self): +- return u"" % ( ++ return "" % ( + self.__class__.__name__, + self.namespaceURI, + self.prefix, +@@ -119,13 +119,13 @@ class CSSNamespaceRule(cssrule.CSSRule): + tokenizer = self._tokenize2(cssText) + attoken = self._nexttoken(tokenizer, None) + if self._type(attoken) != self._prods.NAMESPACE_SYM: +- self._log.error(u'CSSNamespaceRule: No CSSNamespaceRule found: %s' % ++ self._log.error('CSSNamespaceRule: No CSSNamespaceRule found: %s' % + self._valuestr(cssText), + error=xml.dom.InvalidModificationErr) + else: + # for closures: must be a mutable + new = {'keyword': self._tokenvalue(attoken), +- 'prefix': u'', ++ 'prefix': '', + 'uri': None, + 'wellformed': True + } +@@ -139,7 +139,7 @@ class CSSNamespaceRule(cssrule.CSSRule): + else: + new['wellformed'] = False + self._log.error( +- u'CSSNamespaceRule: Unexpected ident.', token) ++ 'CSSNamespaceRule: Unexpected ident.', token) + return expected + + def _string(expected, seq, token, tokenizer=None): +@@ -152,7 +152,7 @@ class CSSNamespaceRule(cssrule.CSSRule): + else: + new['wellformed'] = False + self._log.error( +- u'CSSNamespaceRule: Unexpected string.', token) ++ 'CSSNamespaceRule: Unexpected string.', token) + return expected + + def _uri(expected, seq, token, tokenizer=None): +@@ -165,18 +165,18 @@ class CSSNamespaceRule(cssrule.CSSRule): + else: + new['wellformed'] = False + self._log.error( +- u'CSSNamespaceRule: Unexpected URI.', token) ++ 'CSSNamespaceRule: Unexpected URI.', token) + return expected + + def _char(expected, seq, token, tokenizer=None): + # final ; + val = self._tokenvalue(token) +- if ';' == expected and u';' == val: ++ if ';' == expected and ';' == val: + return 'EOF' + else: + new['wellformed'] = False + self._log.error( +- u'CSSNamespaceRule: Unexpected char.', token) ++ 'CSSNamespaceRule: Unexpected char.', token) + return expected + + # "NAMESPACE_SYM S* [namespace_prefix S*]? [STRING|URI] S* ';' S*" +@@ -195,12 +195,12 @@ class CSSNamespaceRule(cssrule.CSSRule): + # post conditions + if new['uri'] is None: + wellformed = False +- self._log.error(u'CSSNamespaceRule: No namespace URI found: %s' ++ self._log.error('CSSNamespaceRule: No namespace URI found: %s' + % self._valuestr(cssText)) + + if expected != 'EOF': + wellformed = False +- self._log.error(u'CSSNamespaceRule: No ";" found: %s' % ++ self._log.error('CSSNamespaceRule: No ";" found: %s' % + self._valuestr(cssText)) + + # set all +@@ -211,8 +211,8 @@ class CSSNamespaceRule(cssrule.CSSRule): + self._setSeq(newseq) + + cssText = property(fget=_getCssText, fset=_setCssText, +- doc=u"(DOM) The parsable textual representation of this " +- u"rule.") ++ doc="(DOM) The parsable textual representation of this " ++ "rule.") + + def _setNamespaceURI(self, namespaceURI): + """ +@@ -230,7 +230,7 @@ class CSSNamespaceRule(cssrule.CSSRule): + tempseq.append(namespaceURI, 'namespaceURI') + self._setSeq(tempseq) # makes seq readonly! + elif self._namespaceURI != namespaceURI: +- self._log.error(u'CSSNamespaceRule: namespaceURI is readonly.', ++ self._log.error('CSSNamespaceRule: namespaceURI is readonly.', + error=xml.dom.NoModificationAllowedErr) + + namespaceURI = property(lambda self: self._namespaceURI, _setNamespaceURI, +@@ -261,12 +261,12 @@ class CSSNamespaceRule(cssrule.CSSRule): + """ + self._checkReadonly() + if not prefix: +- prefix = u'' ++ prefix = '' + else: + tokenizer = self._tokenize2(prefix) + prefixtoken = self._nexttoken(tokenizer, None) + if not prefixtoken or self._type(prefixtoken) != self._prods.IDENT: +- self._log.error(u'CSSNamespaceRule: No valid prefix "%s".' % ++ self._log.error('CSSNamespaceRule: No valid prefix "%s".' % + self._valuestr(prefix), + error=xml.dom.SyntaxErr) + return +@@ -285,11 +285,11 @@ class CSSNamespaceRule(cssrule.CSSRule): + self._prefix = prefix + + prefix = property(lambda self: self._prefix, _setPrefix, +- doc=u"Prefix used for the defined namespace.") ++ doc="Prefix used for the defined namespace.") + + type = property(lambda self: self.NAMESPACE_RULE, +- doc=u"The type of this rule, as defined by a CSSRule " +- u"type constant.") ++ doc="The type of this rule, as defined by a CSSRule " ++ "type constant.") + + wellformed = property(lambda self: self.namespaceURI is not None) + +\ No newline at end of file +diff --git a/src/cssutils/css/csspagerule.py b/src/cssutils/css/csspagerule.py +index cc2f451..9910678 100644 +--- a/src/cssutils/css/csspagerule.py ++++ b/src/cssutils/css/csspagerule.py +@@ -4,9 +4,9 @@ __docformat__ = 'restructuredtext' + __version__ = '$Id$' + + from itertools import chain +-from cssstyledeclaration import CSSStyleDeclaration +-from marginrule import MarginRule +-import cssrule ++from .cssstyledeclaration import CSSStyleDeclaration ++from .marginrule import MarginRule ++from . import cssrule + import cssutils + import xml.dom + +@@ -64,7 +64,7 @@ class CSSPageRule(cssrule.CSSRuleRules): + """ + super(CSSPageRule, self).__init__(parentRule=parentRule, + parentStyleSheet=parentStyleSheet) +- self._atkeyword = u'@page' ++ self._atkeyword = '@page' + self._specificity = (0, 0, 0) + + tempseq = self._tempSeq() +@@ -86,14 +86,14 @@ class CSSPageRule(cssrule.CSSRuleRules): + self._readonly = readonly + + def __repr__(self): +- return u"cssutils.css.%s(selectorText=%r, style=%r)" % ( ++ return "cssutils.css.%s(selectorText=%r, style=%r)" % ( + self.__class__.__name__, + self.selectorText, + self.style.cssText) + + def __str__(self): +- return (u"") % ( ++ return ("") % ( + self.__class__.__name__, + self.selectorText, + self.specificity, +@@ -103,7 +103,7 @@ class CSSPageRule(cssrule.CSSRuleRules): + + def __contains__(self, margin): + """Check if margin is set in the rule.""" +- return margin in self.keys() ++ return margin in list(self.keys()) + + def keys(self): + "Return list of all set margins (MarginRule)." +@@ -152,24 +152,24 @@ class CSSPageRule(cssrule.CSSRuleRules): + # pseudo_page, :left, :right or :first + val = self._tokenvalue(token) + if not new['last-S'] and expected in ['page', ': or EOF']\ +- and u':' == val: ++ and ':' == val: + try: +- identtoken = tokenizer.next() ++ identtoken = next(tokenizer) + except StopIteration: + self._log.error( +- u'CSSPageRule selectorText: No IDENT found.', token) ++ 'CSSPageRule selectorText: No IDENT found.', token) + else: + ival, ityp = self._tokenvalue(identtoken),\ + self._type(identtoken) + if self._prods.IDENT != ityp: +- self._log.error(u'CSSPageRule selectorText: Expected ' +- u'IDENT but found: %r' % ival, token) ++ self._log.error('CSSPageRule selectorText: Expected ' ++ 'IDENT but found: %r' % ival, token) + else: +- if not ival in (u'first', u'left', u'right'): +- self._log.warn(u'CSSPageRule: Unknown @page ' +- u'selector: %r' +- % (u':'+ival,), neverraise=True) +- if ival == u'first': ++ if not ival in ('first', 'left', 'right'): ++ self._log.warn('CSSPageRule: Unknown @page ' ++ 'selector: %r' ++ % (':'+ival,), neverraise=True) ++ if ival == 'first': + new['first'] = 1 + else: + new['lr'] = 1 +@@ -178,7 +178,7 @@ class CSSPageRule(cssrule.CSSRuleRules): + return expected + else: + new['wellformed'] = False +- self._log.error(u'CSSPageRule selectorText: Unexpected CHAR: %r' ++ self._log.error('CSSPageRule selectorText: Unexpected CHAR: %r' + % val, token) + return expected + +@@ -193,8 +193,8 @@ class CSSPageRule(cssrule.CSSRuleRules): + "" + val = self._tokenvalue(token) + if 'page' == expected: +- if self._normalize(val) == u'auto': +- self._log.error(u'CSSPageRule selectorText: Invalid pagename.', ++ if self._normalize(val) == 'auto': ++ self._log.error('CSSPageRule selectorText: Invalid pagename.', + token) + else: + new['name'] = 1 +@@ -203,8 +203,8 @@ class CSSPageRule(cssrule.CSSRuleRules): + return ': or EOF' + else: + new['wellformed'] = False +- self._log.error(u'CSSPageRule selectorText: Unexpected IDENT: ' +- u'%r' % val, token) ++ self._log.error('CSSPageRule selectorText: Unexpected IDENT: ' ++ '%r' % val, token) + return expected + + def COMMENT(expected, seq, token, tokenizer=None): +@@ -225,7 +225,7 @@ class CSSPageRule(cssrule.CSSRuleRules): + # post conditions + if expected == 'ident': + self._log.error( +- u'CSSPageRule selectorText: No valid selector: %r' % ++ 'CSSPageRule selectorText: No valid selector: %r' % + self._valuestr(selectorText)) + + return wellformed, newseq, (new['name'], new['first'], new['lr']) +@@ -288,7 +288,7 @@ class CSSPageRule(cssrule.CSSRuleRules): + + tokenizer = self._tokenize2(cssText) + if self._type(self._nexttoken(tokenizer)) != self._prods.PAGE_SYM: +- self._log.error(u'CSSPageRule: No CSSPageRule found: %s' % ++ self._log.error('CSSPageRule: No CSSPageRule found: %s' % + self._valuestr(cssText), + error=xml.dom.InvalidModificationErr) + else: +@@ -302,14 +302,14 @@ class CSSPageRule(cssrule.CSSRuleRules): + blockendonly=True, + separateEnd=True) + nonetoken = self._nexttoken(tokenizer) +- if self._tokenvalue(startbrace) != u'{': ++ if self._tokenvalue(startbrace) != '{': + ok = False +- self._log.error(u'CSSPageRule: No start { of style declaration ' +- u'found: %r' % ++ self._log.error('CSSPageRule: No start { of style declaration ' ++ 'found: %r' % + self._valuestr(cssText), startbrace) + elif nonetoken: + ok = False +- self._log.error(u'CSSPageRule: Trailing content found.', ++ self._log.error('CSSPageRule: Trailing content found.', + token=nonetoken) + + selok, newselseq, specificity = self.__parseSelectorText(selectortokens) +@@ -318,10 +318,10 @@ class CSSPageRule(cssrule.CSSRuleRules): + val, type_ = self._tokenvalue(braceorEOFtoken),\ + self._type(braceorEOFtoken) + +- if val != u'}' and type_ != 'EOF': ++ if val != '}' and type_ != 'EOF': + ok = False + self._log.error( +- u'CSSPageRule: No "}" after style declaration found: %r' % ++ 'CSSPageRule: No "}" after style declaration found: %r' % + self._valuestr(cssText)) + else: + if 'EOF' == type_: +@@ -343,7 +343,7 @@ class CSSPageRule(cssrule.CSSRuleRules): + self.cssRules.append(r) + + cssText = property(_getCssText, _setCssText, +- doc=u"(DOM) The parsable textual representation of this rule.") ++ doc="(DOM) The parsable textual representation of this rule.") + + + def _getSelectorText(self): +@@ -377,8 +377,8 @@ class CSSPageRule(cssrule.CSSRuleRules): + self._specificity = specificity + + selectorText = property(_getSelectorText, _setSelectorText, +- doc=u"(DOM) The parsable textual representation of " +- u"the page selector for the rule.") ++ doc="(DOM) The parsable textual representation of " ++ "the page selector for the rule.") + + def _setStyle(self, style): + """ +@@ -386,15 +386,15 @@ class CSSPageRule(cssrule.CSSRuleRules): + a CSSStyleDeclaration or string + """ + self._checkReadonly() +- if isinstance(style, basestring): ++ if isinstance(style, str): + self._style = CSSStyleDeclaration(cssText=style, parentRule=self) + else: + style._parentRule = self + self._style = style + + style = property(lambda self: self._style, _setStyle, +- doc=u"(DOM) The declaration-block of this rule set, " +- u"a :class:`~cssutils.css.CSSStyleDeclaration`.") ++ doc="(DOM) The declaration-block of this rule set, " ++ "a :class:`~cssutils.css.CSSStyleDeclaration`.") + + + def insertRule(self, rule, index=None): +@@ -412,7 +412,7 @@ class CSSPageRule(cssrule.CSSRuleRules): + isinstance(rule, cssutils.css.CSSNamespaceRule) or \ + isinstance(rule, CSSPageRule) or \ + isinstance(rule, cssutils.css.CSSMediaRule): +- self._log.error(u'%s: This type of rule is not allowed here: %s' ++ self._log.error('%s: This type of rule is not allowed here: %s' + % (self.__class__.__name__, rule.cssText), + error=xml.dom.HierarchyRequestErr) + return +@@ -420,7 +420,7 @@ class CSSPageRule(cssrule.CSSRuleRules): + return self._finishInsertRule(rule, index) + + specificity = property(lambda self: self._specificity, +- doc=u"""Specificity of this page rule (READONLY). ++ doc="""Specificity of this page rule (READONLY). + Tuple of (f, g, h) where: + + - if the page selector has a named page, f=1; else f=0 +@@ -429,8 +429,8 @@ Tuple of (f, g, h) where: + """) + + type = property(lambda self: self.PAGE_RULE, +- doc=u"The type of this rule, as defined by a CSSRule " +- u"type constant.") ++ doc="The type of this rule, as defined by a CSSRule " ++ "type constant.") + + # constant but needed: +- wellformed = property(lambda self: True) +\ No newline at end of file ++ wellformed = property(lambda self: True) +diff --git a/src/cssutils/css/cssrule.py b/src/cssutils/css/cssrule.py +index 1d3ab6f..981f2b8 100644 +--- a/src/cssutils/css/cssrule.py ++++ b/src/cssutils/css/cssrule.py +@@ -46,17 +46,17 @@ class CSSRule(cssutils.util.Base2): + """:class:`cssutils.css.MarginRule` - experimental rule + not in the offical spec""" + +- _typestrings = {UNKNOWN_RULE: u'UNKNOWN_RULE', +- STYLE_RULE: u'STYLE_RULE', +- CHARSET_RULE: u'CHARSET_RULE', +- IMPORT_RULE: u'IMPORT_RULE', +- MEDIA_RULE: u'MEDIA_RULE', +- FONT_FACE_RULE: u'FONT_FACE_RULE', +- PAGE_RULE: u'PAGE_RULE', +- NAMESPACE_RULE: u'NAMESPACE_RULE', +- COMMENT: u'COMMENT', +- VARIABLES_RULE: u'VARIABLES_RULE', +- MARGIN_RULE: u'MARGIN_RULE' ++ _typestrings = {UNKNOWN_RULE: 'UNKNOWN_RULE', ++ STYLE_RULE: 'STYLE_RULE', ++ CHARSET_RULE: 'CHARSET_RULE', ++ IMPORT_RULE: 'IMPORT_RULE', ++ MEDIA_RULE: 'MEDIA_RULE', ++ FONT_FACE_RULE: 'FONT_FACE_RULE', ++ PAGE_RULE: 'PAGE_RULE', ++ NAMESPACE_RULE: 'NAMESPACE_RULE', ++ COMMENT: 'COMMENT', ++ VARIABLES_RULE: 'VARIABLES_RULE', ++ MARGIN_RULE: 'MARGIN_RULE' + } + + def __init__(self, parentRule=None, parentStyleSheet=None, readonly=False): +@@ -77,12 +77,12 @@ class CSSRule(cssutils.util.Base2): + self._atkeyword = atkeyword + self._keyword = keyword + else: +- self._log.error(u'%s: Invalid atkeyword for this rule: %r' % ++ self._log.error('%s: Invalid atkeyword for this rule: %r' % + (self.atkeyword, keyword), + error=xml.dom.InvalidModificationErr) + + atkeyword = property(lambda self: self._atkeyword, _setAtkeyword, +- doc=u"Normalized keyword of an @rule (e.g. ``@import``).") ++ doc="Normalized keyword of an @rule (e.g. ``@import``).") + + def _setCssText(self, cssText): + """ +@@ -103,19 +103,19 @@ class CSSRule(cssutils.util.Base2): + """ + self._checkReadonly() + +- cssText = property(lambda self: u'', _setCssText, +- doc=u"(DOM) The parsable textual representation of the " +- u"rule. This reflects the current state of the rule " +- u"and not its initial value.") ++ cssText = property(lambda self: '', _setCssText, ++ doc="(DOM) The parsable textual representation of the " ++ "rule. This reflects the current state of the rule " ++ "and not its initial value.") + + parent = property(lambda self: self._parent, +- doc=u"The Parent Node of this CSSRule or None.") ++ doc="The Parent Node of this CSSRule or None.") + + parentRule = property(lambda self: self._parentRule, +- doc=u"If this rule is contained inside another rule " +- u"(e.g. a style rule inside an @media block), this " +- u"is the containing rule. If this rule is not nested " +- u"inside any other rules, this returns None.") ++ doc="If this rule is contained inside another rule " ++ "(e.g. a style rule inside an @media block), this " ++ "is the containing rule. If this rule is not nested " ++ "inside any other rules, this returns None.") + + def _getParentStyleSheet(self): + # rules contained in other rules (@media) use that rules parent +@@ -125,17 +125,17 @@ class CSSRule(cssutils.util.Base2): + return self._parentStyleSheet + + parentStyleSheet = property(_getParentStyleSheet, +- doc=u"The style sheet that contains this rule.") ++ doc="The style sheet that contains this rule.") + + type = property(lambda self: self.UNKNOWN_RULE, +- doc=u"The type of this rule, as defined by a CSSRule " +- u"type constant.") ++ doc="The type of this rule, as defined by a CSSRule " ++ "type constant.") + + typeString = property(lambda self: CSSRule._typestrings[self.type], +- doc=u"Descriptive name of this rule's type.") ++ doc="Descriptive name of this rule's type.") + + wellformed = property(lambda self: False, +- doc=u"If the rule is wellformed.") ++ doc="If the rule is wellformed.") + + + +@@ -201,8 +201,8 @@ class CSSRuleRules(CSSRule): + index = i + break + else: +- raise xml.dom.IndexSizeErr(u"%s: Not a rule in " +- u"this rule'a cssRules list: %s" ++ raise xml.dom.IndexSizeErr("%s: Not a rule in " ++ "this rule'a cssRules list: %s" + % (self.__class__.__name__, index)) + + try: +@@ -211,8 +211,8 @@ class CSSRuleRules(CSSRule): + del self._cssRules[index] + + except IndexError: +- raise xml.dom.IndexSizeErr(u'%s: %s is not a valid index ' +- u'in the rulelist of length %i' ++ raise xml.dom.IndexSizeErr('%s: %s is not a valid index ' ++ 'in the rulelist of length %i' + % (self.__class__.__name__, + index, self._cssRules.length)) + +@@ -225,18 +225,18 @@ class CSSRuleRules(CSSRule): + index = len(self._cssRules) + + elif index < 0 or index > self._cssRules.length: +- raise xml.dom.IndexSizeErr(u'%s: Invalid index %s for ' +- u'CSSRuleList with a length of %s.' ++ raise xml.dom.IndexSizeErr('%s: Invalid index %s for ' ++ 'CSSRuleList with a length of %s.' + % (self.__class__.__name__, + index, self._cssRules.length)) + + # check and optionally parse rule +- if isinstance(rule, basestring): ++ if isinstance(rule, str): + tempsheet = cssutils.css.CSSStyleSheet() + tempsheet.cssText = rule + if len(tempsheet.cssRules) != 1 or (tempsheet.cssRules and + not isinstance(tempsheet.cssRules[0], cssutils.css.CSSRule)): +- self._log.error(u'%s: Invalid Rule: %s' % (self.__class__.__name__, ++ self._log.error('%s: Invalid Rule: %s' % (self.__class__.__name__, + rule)) + return False, False + rule = tempsheet.cssRules[0] +@@ -248,7 +248,7 @@ class CSSRuleRules(CSSRule): + return True, True + + elif not isinstance(rule, cssutils.css.CSSRule): +- self._log.error(u'%s: Not a CSSRule: %s' % (rule, ++ self._log.error('%s: Not a CSSRule: %s' % (rule, + self.__class__.__name__)) + return False, False + +diff --git a/src/cssutils/css/cssrulelist.py b/src/cssutils/css/cssrulelist.py +index f9daff4..c59788a 100644 +--- a/src/cssutils/css/cssrulelist.py ++++ b/src/cssutils/css/cssrulelist.py +@@ -43,7 +43,7 @@ class CSSRuleList(list): + return None + + length = property(lambda self: len(self), +- doc=u"(DOM) The number of CSSRules in the list.") ++ doc="(DOM) The number of CSSRules in the list.") + + def rulesOfType(self, type): + """Yield the rules which have the given `type` only, one of the +diff --git a/src/cssutils/css/cssstyledeclaration.py b/src/cssutils/css/cssstyledeclaration.py +index 4dfc365..117a011 100644 +--- a/src/cssutils/css/cssstyledeclaration.py ++++ b/src/cssutils/css/cssstyledeclaration.py +@@ -53,8 +53,8 @@ __all__ = ['CSSStyleDeclaration', 'Property'] + __docformat__ = 'restructuredtext' + __version__ = '$Id$' + +-from cssproperties import CSS2Properties +-from property import Property ++from .cssproperties import CSS2Properties ++from .property import Property + import cssutils + import xml.dom + +@@ -94,7 +94,7 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2): + + [Property: Value Priority?;]* [Property: Value Priority?]? + """ +- def __init__(self, cssText=u'', parentRule=None, readonly=False, ++ def __init__(self, cssText='', parentRule=None, readonly=False, + validating=None): + """ + :param cssText: +@@ -182,17 +182,17 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2): + if n in known: + super(CSSStyleDeclaration, self).__setattr__(n, v) + else: +- raise AttributeError(u'Unknown CSS Property, ' +- u'``CSSStyleDeclaration.setProperty("%s", ' +- u'...)`` MUST be used.' % n) ++ raise AttributeError('Unknown CSS Property, ' ++ '``CSSStyleDeclaration.setProperty("%s", ' ++ '...)`` MUST be used.' % n) + + def __repr__(self): +- return u"cssutils.css.%s(cssText=%r)" % ( ++ return "cssutils.css.%s(cssText=%r)" % ( + self.__class__.__name__, +- self.getCssText(separator=u' ')) ++ self.getCssText(separator=' ')) + + def __str__(self): +- return u"" % ( ++ return "" % ( + self.__class__.__name__, + self.length, + len(self.getProperties(all=True)), +@@ -293,15 +293,15 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2): + + tokens = self._tokensupto2(tokenizer, starttoken=token, + semicolon=True) +- if self._tokenvalue(tokens[-1]) == u';': ++ if self._tokenvalue(tokens[-1]) == ';': + tokens.pop() + property = Property(parent=self) + property.cssText = tokens + if property.wellformed: + seq.append(property, 'Property') + else: +- self._log.error(u'CSSStyleDeclaration: Syntax Error in ' +- u'Property: %s' % self._valuestr(tokens)) ++ self._log.error('CSSStyleDeclaration: Syntax Error in ' ++ 'Property: %s' % self._valuestr(tokens)) + # does not matter in this case + return expected + +@@ -310,16 +310,16 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2): + ignored = self._tokenvalue(token) + self._valuestr( + self._tokensupto2(tokenizer, + propertyvalueendonly=True)) +- self._log.error(u'CSSStyleDeclaration: Unexpected token, ignoring ' ++ self._log.error('CSSStyleDeclaration: Unexpected token, ignoring ' + 'upto %r.' % ignored,token) + # does not matter in this case + return expected + + def char(expected, seq, token, tokenizer=None): + # a standalone ; or error... +- if self._tokenvalue(token) == u';': +- self._log.info(u'CSSStyleDeclaration: Stripped standalone semicolon' +- u': %s' % self._valuestr([token]), neverraise=True) ++ if self._tokenvalue(token) == ';': ++ self._log.info('CSSStyleDeclaration: Stripped standalone semicolon' ++ ': %s' % self._valuestr([token]), neverraise=True) + return expected + else: + return unexpected(expected, seq, token, tokenizer) +@@ -339,9 +339,9 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2): + self._setSeq(newseq) + + cssText = property(_getCssText, _setCssText, +- doc=u"(DOM) A parsable textual representation of the " +- u"declaration block excluding the surrounding curly " +- u"braces.") ++ doc="(DOM) A parsable textual representation of the " ++ "declaration block excluding the surrounding curly " ++ "braces.") + + def getCssText(self, separator=None): + """ +@@ -460,8 +460,8 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2): + """ + nname = self._normalize(name) + if nname in self._SHORTHANDPROPERTIES: +- self._log.info(u'CSSValue for shorthand property "%s" should be ' +- u'None, this may be implemented later.' % ++ self._log.info('CSSValue for shorthand property "%s" should be ' ++ 'None, this may be implemented later.' % + nname, neverraise=True) + + p = self.getProperty(name, normalize) +@@ -489,7 +489,7 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2): + if p: + return p.value + else: +- return u'' ++ return '' + + def getPropertyPriority(self, name, normalize=True): + """ +@@ -510,7 +510,7 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2): + if p: + return p.priority + else: +- return u'' ++ return '' + + def removeProperty(self, name, normalize=True): + """ +@@ -560,7 +560,7 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2): + self._setSeq(newseq) + return r + +- def setProperty(self, name, value=None, priority=u'', ++ def setProperty(self, name, value=None, priority='', + normalize=True, replace=True): + """(DOM) Set a property value and priority within this declaration + block. +@@ -636,7 +636,7 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2): + self.seq._readonly = True + + else: +- self._log.warn(u'Invalid Property: %s: %s %s' ++ self._log.warn('Invalid Property: %s: %s %s' + % (name, value, priority)) + + def item(self, index): +@@ -665,15 +665,15 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2): + try: + return names[index] + except IndexError: +- return u'' ++ return '' + + length = property(lambda self: len(list(self.__nnames())), +- doc=u"(DOM) The number of distinct properties that have " +- u"been explicitly in this declaration block. The " +- u"range of valid indices is 0 to length-1 inclusive. " +- u"These are properties with a different ``name`` " +- u"only. :meth:`item` and :attr:`length` work on the " +- u"same set here.") ++ doc="(DOM) The number of distinct properties that have " ++ "been explicitly in this declaration block. The " ++ "range of valid indices is 0 to length-1 inclusive. " ++ "These are properties with a different ``name`` " ++ "only. :meth:`item` and :attr:`length` work on the " ++ "same set here.") + + def _getValidating(self): + try: +@@ -690,15 +690,15 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2): + self._validating = validating + + validating = property(_getValidating, _setValidating, +- doc=u"If ``True`` this declaration validates " +- u"contained properties. The parent StyleSheet " +- u"validation setting does *always* win though so " +- u"even if validating is True it may not validate " +- u"if the StyleSheet defines else!") ++ doc="If ``True`` this declaration validates " ++ "contained properties. The parent StyleSheet " ++ "validation setting does *always* win though so " ++ "even if validating is True it may not validate " ++ "if the StyleSheet defines else!") + + def _getValid(self): + """Check each contained property for validity.""" + return all(prop.valid for prop in self.getProperties()) + + valid = property(_getValid, +- doc=u'``True`` if each property is valid.') ++ doc='``True`` if each property is valid.') +diff --git a/src/cssutils/css/cssstylerule.py b/src/cssutils/css/cssstylerule.py +index 329650d..c7a129c 100644 +--- a/src/cssutils/css/cssstylerule.py ++++ b/src/cssutils/css/cssstylerule.py +@@ -3,9 +3,9 @@ __all__ = ['CSSStyleRule'] + __docformat__ = 'restructuredtext' + __version__ = '$Id$' + +-from cssstyledeclaration import CSSStyleDeclaration +-from selectorlist import SelectorList +-import cssrule ++from .cssstyledeclaration import CSSStyleDeclaration ++from .selectorlist import SelectorList ++from . import cssrule + import cssutils + import xml.dom + +@@ -50,12 +50,12 @@ class CSSStyleRule(cssrule.CSSRule): + st = (self.selectorText, self._namespaces) + else: + st = self.selectorText +- return u"cssutils.css.%s(selectorText=%r, style=%r)" % ( ++ return "cssutils.css.%s(selectorText=%r, style=%r)" % ( + self.__class__.__name__, st, self.style.cssText) + + def __str__(self): +- return u"" % (self.__class__.__name__, ++ return "" % (self.__class__.__name__, + self.selectorText, + self.style.cssText, + self._namespaces, +@@ -100,13 +100,13 @@ class CSSStyleRule(cssrule.CSSRule): + styletokens = self._tokensupto2(tokenizer, blockendonly=True) + trail = self._nexttoken(tokenizer) + if trail: +- self._log.error(u'CSSStyleRule: Trailing content: %s' % ++ self._log.error('CSSStyleRule: Trailing content: %s' % + self._valuestr(cssText), token=trail) + elif not selectortokens: +- self._log.error(u'CSSStyleRule: No selector found: %r' % ++ self._log.error('CSSStyleRule: No selector found: %r' % + self._valuestr(cssText)) +- elif self._tokenvalue(selectortokens[0]).startswith(u'@'): +- self._log.error(u'CSSStyleRule: No style rule: %r' % ++ elif self._tokenvalue(selectortokens[0]).startswith('@'): ++ self._log.error('CSSStyleRule: No style rule: %r' % + self._valuestr(cssText), + error=xml.dom.InvalidModificationErr) + else: +@@ -115,14 +115,14 @@ class CSSStyleRule(cssrule.CSSRule): + ok = True + + bracetoken = selectortokens.pop() +- if self._tokenvalue(bracetoken) != u'{': ++ if self._tokenvalue(bracetoken) != '{': + ok = False + self._log.error( +- u'CSSStyleRule: No start { of style declaration found: %r' % ++ 'CSSStyleRule: No start { of style declaration found: %r' % + self._valuestr(cssText), bracetoken) + elif not selectortokens: + ok = False +- self._log.error(u'CSSStyleRule: No selector found: %r.' % ++ self._log.error('CSSStyleRule: No selector found: %r.' % + self._valuestr(cssText), bracetoken) + # SET + newSelectorList.selectorText = (selectortokens, +@@ -131,16 +131,16 @@ class CSSStyleRule(cssrule.CSSRule): + if not styletokens: + ok = False + self._log.error( +- u'CSSStyleRule: No style declaration or "}" found: %r' % ++ 'CSSStyleRule: No style declaration or "}" found: %r' % + self._valuestr(cssText)) + else: + braceorEOFtoken = styletokens.pop() + val, typ = self._tokenvalue(braceorEOFtoken),\ + self._type(braceorEOFtoken) +- if val != u'}' and typ != 'EOF': ++ if val != '}' and typ != 'EOF': + ok = False +- self._log.error(u'CSSStyleRule: No "}" after style ' +- u'declaration found: %r' ++ self._log.error('CSSStyleRule: No "}" after style ' ++ 'declaration found: %r' + % self._valuestr(cssText)) + else: + if 'EOF' == typ: +@@ -154,8 +154,8 @@ class CSSStyleRule(cssrule.CSSRule): + self.style = newStyle + + cssText = property(_getCssText, _setCssText, +- doc=u"(DOM) The parsable textual representation of this " +- u"rule.") ++ doc="(DOM) The parsable textual representation of this " ++ "rule.") + + def __getNamespaces(self): + """Uses children namespaces if not attached to a sheet, else the sheet's +@@ -166,10 +166,10 @@ class CSSStyleRule(cssrule.CSSRule): + return self.selectorList._namespaces + + _namespaces = property(__getNamespaces, +- doc=u"If this Rule is attached to a CSSStyleSheet " +- u"the namespaces of that sheet are mirrored " +- u"here. While the Rule is not attached the " +- u"namespaces of selectorList are used.""") ++ doc="If this Rule is attached to a CSSStyleSheet " ++ "the namespaces of that sheet are mirrored " ++ "here. While the Rule is not attached the " ++ "namespaces of selectorList are used.""") + + def _setSelectorList(self, selectorList): + """ +@@ -182,7 +182,7 @@ class CSSStyleRule(cssrule.CSSRule): + + _selectorList = None + selectorList = property(lambda self: self._selectorList, _setSelectorList, +- doc=u"The SelectorList of this rule.") ++ doc="The SelectorList of this rule.") + + def _setSelectorText(self, selectorText): + """ +@@ -209,8 +209,8 @@ class CSSStyleRule(cssrule.CSSRule): + + selectorText = property(lambda self: self._selectorList.selectorText, + _setSelectorText, +- doc=u"(DOM) The textual representation of the " +- u"selector for the rule set.") ++ doc="(DOM) The textual representation of the " ++ "selector for the rule set.") + + def _setStyle(self, style): + """ +@@ -218,17 +218,17 @@ class CSSStyleRule(cssrule.CSSRule): + current style object. + """ + self._checkReadonly() +- if isinstance(style, basestring): ++ if isinstance(style, str): + self._style = CSSStyleDeclaration(cssText=style, parentRule=self) + else: + style._parentRule = self + self._style = style + + style = property(lambda self: self._style, _setStyle, +- doc=u"(DOM) The declaration-block of this rule set.") ++ doc="(DOM) The declaration-block of this rule set.") + + type = property(lambda self: self.STYLE_RULE, +- doc=u"The type of this rule, as defined by a CSSRule " ++ doc="The type of this rule, as defined by a CSSRule " + "type constant.") + + wellformed = property(lambda self: self.selectorList.wellformed) +@@ -238,4 +238,4 @@ class CSSStyleRule(cssrule.CSSRule): + return self.style.valid + + valid = property(_getValid, +- doc=u'``True`` when the style declaration is true.') ++ doc='``True`` when the style declaration is true.') +diff --git a/src/cssutils/css/cssstylesheet.py b/src/cssutils/css/cssstylesheet.py +index 2f74daf..d2204af 100644 +--- a/src/cssutils/css/cssstylesheet.py ++++ b/src/cssutils/css/cssstylesheet.py +@@ -13,8 +13,8 @@ __version__ = '$Id$' + + from cssutils.helper import Deprecated + from cssutils.util import _Namespaces, _SimpleNamespaces, _readUrl +-from cssrule import CSSRule +-from cssvariablesdeclaration import CSSVariablesDeclaration ++from .cssrule import CSSRule ++from .cssvariablesdeclaration import CSSVariablesDeclaration + import cssutils.stylesheets + import xml.dom + +@@ -32,7 +32,7 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + ``cssRules`` + All Rules in this style sheet, a :class:`~cssutils.css.CSSRuleList`. + """ +- def __init__(self, href=None, media=None, title=u'', disabled=None, ++ def __init__(self, href=None, media=None, title='', disabled=None, + ownerNode=None, parentStyleSheet=None, readonly=False, + ownerRule=None, + validating=True): +@@ -82,7 +82,7 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + def _cleanNamespaces(self): + "Remove all namespace rules with same namespaceURI but last." + rules = self.cssRules +- namespaceitems = self.namespaces.items() ++ namespaceitems = list(self.namespaces.items()) + i = 0 + while i < len(rules): + rule = rules[i] +@@ -116,8 +116,8 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + self._cssRules = cssRules + + cssRules = property(lambda self: self._cssRules, _setCssRules, +- u"All Rules in this style sheet, a " +- u":class:`~cssutils.css.CSSRuleList`.") ++ "All Rules in this style sheet, a " ++ ":class:`~cssutils.css.CSSRuleList`.") + + def _getCssText(self): + "Textual representation of the stylesheet (a byte string)." +@@ -160,8 +160,8 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + rule.cssText = self._tokensupto2(tokenizer, token) + + if expected > 0: +- self._log.error(u'CSSStylesheet: CSSCharsetRule only allowed ' +- u'at beginning of stylesheet.', ++ self._log.error('CSSStylesheet: CSSCharsetRule only allowed ' ++ 'at beginning of stylesheet.', + token, xml.dom.HierarchyRequestErr) + return expected + elif rule.wellformed: +@@ -175,8 +175,8 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + rule.cssText = self._tokensupto2(tokenizer, token) + + if expected > 1: +- self._log.error(u'CSSStylesheet: CSSImportRule not allowed ' +- u'here.', token, xml.dom.HierarchyRequestErr) ++ self._log.error('CSSStylesheet: CSSImportRule not allowed ' ++ 'here.', token, xml.dom.HierarchyRequestErr) + return expected + elif rule.wellformed: + self.insertRule(rule) +@@ -190,8 +190,8 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + parentStyleSheet=self) + + if expected > 2: +- self._log.error(u'CSSStylesheet: CSSNamespaceRule not allowed ' +- u'here.', token, xml.dom.HierarchyRequestErr) ++ self._log.error('CSSStylesheet: CSSNamespaceRule not allowed ' ++ 'here.', token, xml.dom.HierarchyRequestErr) + return expected + elif rule.wellformed: + if rule.prefix not in self.namespaces: +@@ -213,8 +213,8 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + rule.cssText = self._tokensupto2(tokenizer, token) + + if expected > 2: +- self._log.error(u'CSSStylesheet: CSSVariablesRule not allowed ' +- u'here.', token, xml.dom.HierarchyRequestErr) ++ self._log.error('CSSStylesheet: CSSVariablesRule not allowed ' ++ 'here.', token, xml.dom.HierarchyRequestErr) + return expected + elif rule.wellformed: + self.insertRule(rule) +@@ -249,12 +249,12 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + def unknownrule(expected, seq, token, tokenizer): + # parse and consume tokens in any case + if token[1] in cssutils.css.MarginRule.margins: +- self._log.error(u'CSSStylesheet: MarginRule out CSSPageRule.', ++ self._log.error('CSSStylesheet: MarginRule out CSSPageRule.', + token, neverraise=True) + rule = cssutils.css.MarginRule(parentStyleSheet=self) + rule.cssText = self._tokensupto2(tokenizer, token) + else: +- self._log.warn(u'CSSStylesheet: Unknown @rule found.', ++ self._log.warn('CSSStylesheet: Unknown @rule found.', + token, neverraise=True) + rule = cssutils.css.CSSUnknownRule(parentStyleSheet=self) + rule.cssText = self._tokensupto2(tokenizer, token) +@@ -364,7 +364,7 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + self.encoding = encoding + try: + del self.__newEncoding +- except AttributeError, e: ++ except AttributeError as e: + pass + + def _setFetcher(self, fetcher=None): +@@ -422,10 +422,10 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + self._variables.setVariable(var, vr.variables[var]) + + variables = property(lambda self: self._variables, +- doc=u"A :class:`cssutils.css.CSSVariablesDeclaration` " +- u"containing all available variables in this " +- u"CSSStyleSheet including the ones defined in " +- u"imported sheets.") ++ doc="A :class:`cssutils.css.CSSVariablesDeclaration` " ++ "containing all available variables in this " ++ "CSSStyleSheet including the ones defined in " ++ "imported sheets.") + + def add(self, rule): + """Add `rule` to style sheet at appropriate position. +@@ -462,7 +462,7 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + index = i + break + else: +- raise xml.dom.IndexSizeErr(u"CSSStyleSheet: Not a rule in" ++ raise xml.dom.IndexSizeErr("CSSStyleSheet: Not a rule in" + " this sheets'a cssRules list: %s" + % index) + +@@ -470,8 +470,8 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + rule = self._cssRules[index] + except IndexError: + raise xml.dom.IndexSizeErr( +- u'CSSStyleSheet: %s is not a valid index in the rulelist of ' +- u'length %i' % (index, self._cssRules.length)) ++ 'CSSStyleSheet: %s is not a valid index in the rulelist of ' ++ 'length %i' % (index, self._cssRules.length)) + else: + if rule.type == rule.NAMESPACE_RULE: + # check all namespacerules if used +@@ -481,8 +481,8 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + if rule.namespaceURI in useduris and\ + uris.count(rule.namespaceURI) == 1: + raise xml.dom.NoModificationAllowedErr( +- u'CSSStyleSheet: NamespaceURI defined in this rule is ' +- u'used, cannot remove.') ++ 'CSSStyleSheet: NamespaceURI defined in this rule is ' ++ 'used, cannot remove.') + return + + rule._parentStyleSheet = None # detach +@@ -529,11 +529,11 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + index = len(self._cssRules) + elif index < 0 or index > self._cssRules.length: + raise xml.dom.IndexSizeErr( +- u'CSSStyleSheet: Invalid index %s for CSSRuleList with a ' +- u'length of %s.' % (index, self._cssRules.length)) ++ 'CSSStyleSheet: Invalid index %s for CSSRuleList with a ' ++ 'length of %s.' % (index, self._cssRules.length)) + return + +- if isinstance(rule, basestring): ++ if isinstance(rule, str): + # init a temp sheet which has the same properties as self + tempsheet = CSSStyleSheet(href=self.href, + media=self.media, +@@ -545,7 +545,7 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + # prepend encoding if in this sheet to be able to use it in + # @import rules encoding resolution + # do not add if new rule startswith "@charset" (which is exact!) +- if not rule.startswith(u'@charset') and (self._cssRules and ++ if not rule.startswith('@charset') and (self._cssRules and + self._cssRules[0].type == self._cssRules[0].CHARSET_RULE): + # rule 0 is @charset! + newrulescount, newruleindex = 2, 1 +@@ -558,7 +558,7 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + + if len(tempsheet.cssRules) != newrulescount or (not isinstance( + tempsheet.cssRules[newruleindex], cssutils.css.CSSRule)): +- self._log.error(u'CSSStyleSheet: Not a CSSRule: %s' % rule) ++ self._log.error('CSSStyleSheet: Not a CSSRule: %s' % rule) + return + rule = tempsheet.cssRules[newruleindex] + rule._parentStyleSheet = None # done later? +@@ -574,7 +574,7 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + return index + + if not rule.wellformed: +- self._log.error(u'CSSStyleSheet: Invalid rules cannot be added.') ++ self._log.error('CSSStyleSheet: Invalid rules cannot be added.') + return + + # CHECK HIERARCHY +@@ -591,7 +591,7 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + elif index != 0 or (self._cssRules and + self._cssRules[0].type == rule.CHARSET_RULE): + self._log.error( +- u'CSSStylesheet: @charset only allowed once at the' ++ 'CSSStylesheet: @charset only allowed once at the' + ' beginning of a stylesheet.', + error=xml.dom.HierarchyRequestErr) + return +@@ -603,7 +603,7 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + if index == 0 and self._cssRules and\ + self._cssRules[0].type == rule.CHARSET_RULE: + self._log.error( +- u'CSSStylesheet: @charset must be the first rule.', ++ 'CSSStylesheet: @charset must be the first rule.', + error=xml.dom.HierarchyRequestErr) + return + else: +@@ -632,7 +632,7 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + if index == 0 and self._cssRules and\ + self._cssRules[0].type == rule.CHARSET_RULE: + self._log.error( +- u'CSSStylesheet: Found @charset at index 0.', ++ 'CSSStylesheet: Found @charset at index 0.', + error=xml.dom.HierarchyRequestErr) + return + # before @namespace @variables @page @font-face @media stylerule +@@ -644,7 +644,7 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + r.STYLE_RULE, + r.FONT_FACE_RULE): + self._log.error( +- u'CSSStylesheet: Cannot insert @import here,' ++ 'CSSStylesheet: Cannot insert @import here,' + ' found @namespace, @variables, @media, @page or' + ' CSSStyleRule before index %s.' % + index, +@@ -676,7 +676,7 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + for r in self._cssRules[index:]: + if r.type in (r.CHARSET_RULE, r.IMPORT_RULE): + self._log.error( +- u'CSSStylesheet: Cannot insert @namespace here,' ++ 'CSSStylesheet: Cannot insert @namespace here,' + ' found @charset or @import after index %s.' % + index, + error=xml.dom.HierarchyRequestErr) +@@ -689,7 +689,7 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + r.STYLE_RULE, + r.FONT_FACE_RULE): + self._log.error( +- u'CSSStylesheet: Cannot insert @namespace here,' ++ 'CSSStylesheet: Cannot insert @namespace here,' + ' found @variables, @media, @page or CSSStyleRule' + ' before index %s.' % + index, +@@ -731,7 +731,7 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + r.IMPORT_RULE, + r.NAMESPACE_RULE): + self._log.error( +- u'CSSStylesheet: Cannot insert @variables here,' ++ 'CSSStylesheet: Cannot insert @variables here,' + ' found @charset, @import or @namespace after' + ' index %s.' % + index, +@@ -744,7 +744,7 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + r.STYLE_RULE, + r.FONT_FACE_RULE): + self._log.error( +- u'CSSStylesheet: Cannot insert @variables here,' ++ 'CSSStylesheet: Cannot insert @variables here,' + ' found @media, @page or CSSStyleRule' + ' before index %s.' % + index, +@@ -766,8 +766,8 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + r.IMPORT_RULE, + r.NAMESPACE_RULE): + self._log.error( +- u'CSSStylesheet: Cannot insert rule here, found ' +- u'@charset, @import or @namespace before index %s.' ++ 'CSSStylesheet: Cannot insert rule here, found ' ++ '@charset, @import or @namespace before index %s.' + % index, error=xml.dom.HierarchyRequestErr) + return + self._cssRules.insert(index, rule) +@@ -782,8 +782,8 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + return index + + ownerRule = property(lambda self: self._ownerRule, +- doc=u'A ref to an @import rule if it is imported, ' +- u'else ``None``.') ++ doc='A ref to an @import rule if it is imported, ' ++ 'else ``None``.') + + def _getValid(self): + """Check if each contained rule is valid.""" +@@ -794,19 +794,19 @@ class CSSStyleSheet(cssutils.stylesheets.StyleSheet): + return True + + valid = property(_getValid, +- doc=u'``True`` if all contained rules are valid') ++ doc='``True`` if all contained rules are valid') + + +- @Deprecated(u'Use ``cssutils.setSerializer(serializer)`` instead.') ++ @Deprecated('Use ``cssutils.setSerializer(serializer)`` instead.') + def setSerializer(self, cssserializer): + """Set the cssutils global Serializer used for all output.""" + if isinstance(cssserializer, cssutils.CSSSerializer): + cssutils.ser = cssserializer + else: +- raise ValueError(u'Serializer must be an instance of ' +- u'cssutils.CSSSerializer.') ++ raise ValueError('Serializer must be an instance of ' ++ 'cssutils.CSSSerializer.') + +- @Deprecated(u'Set pref in ``cssutils.ser.prefs`` instead.') ++ @Deprecated('Set pref in ``cssutils.ser.prefs`` instead.') + def setSerializerPref(self, pref, value): + """Set a Preference of CSSSerializer used for output. + See :class:`cssutils.serialize.Preferences` for possible +diff --git a/src/cssutils/css/cssunknownrule.py b/src/cssutils/css/cssunknownrule.py +index c9e4361..a474cd5 100644 +--- a/src/cssutils/css/cssunknownrule.py ++++ b/src/cssutils/css/cssunknownrule.py +@@ -3,7 +3,7 @@ __all__ = ['CSSUnknownRule'] + __docformat__ = 'restructuredtext' + __version__ = '$Id$' + +-import cssrule ++from . import cssrule + import cssutils + import xml.dom + +@@ -16,7 +16,7 @@ class CSSUnknownRule(cssrule.CSSRule): + + @xxx until ';' or block {...} + """ +- def __init__(self, cssText=u'', parentRule=None, ++ def __init__(self, cssText='', parentRule=None, + parentStyleSheet=None, readonly=False): + """ + :param cssText: +@@ -31,12 +31,12 @@ class CSSUnknownRule(cssrule.CSSRule): + self._readonly = readonly + + def __repr__(self): +- return u"cssutils.css.%s(cssText=%r)" % ( ++ return "cssutils.css.%s(cssText=%r)" % ( + self.__class__.__name__, + self.cssText) + + def __str__(self): +- return u"" % ( ++ return "" % ( + self.__class__.__name__, + self.cssText, + id(self)) +@@ -64,7 +64,7 @@ class CSSUnknownRule(cssrule.CSSRule): + tokenizer = self._tokenize2(cssText) + attoken = self._nexttoken(tokenizer, None) + if not attoken or self._type(attoken) != self._prods.ATKEYWORD: +- self._log.error(u'CSSUnknownRule: No CSSUnknownRule found: %s' % ++ self._log.error('CSSUnknownRule: No CSSUnknownRule found: %s' % + self._valuestr(cssText), + error=xml.dom.InvalidModificationErr) + else: +@@ -76,10 +76,10 @@ class CSSUnknownRule(cssrule.CSSRule): + def CHAR(expected, seq, token, tokenizer=None): + type_, val, line, col = token + if expected != 'EOF': +- if val in u'{[(': ++ if val in '{[(': + new['nesting'].append(val) +- elif val in u'}])': +- opening = {u'}': u'{', u']': u'[', u')': u'('}[val] ++ elif val in '}])': ++ opening = {'}': '{', ']': '[', ')': '('}[val] + try: + if new['nesting'][-1] == opening: + new['nesting'].pop() +@@ -87,17 +87,17 @@ class CSSUnknownRule(cssrule.CSSRule): + raise IndexError() + except IndexError: + new['wellformed'] = False +- self._log.error(u'CSSUnknownRule: Wrong nesting of ' +- u'{, [ or (.', token=token) ++ self._log.error('CSSUnknownRule: Wrong nesting of ' ++ '{, [ or (.', token=token) + +- if val in u'};' and not new['nesting']: ++ if val in '};' and not new['nesting']: + expected = 'EOF' + + seq.append(val, type_, line=line, col=col) + return expected + else: + new['wellformed'] = False +- self._log.error(u'CSSUnknownRule: Expected end of rule.', ++ self._log.error('CSSUnknownRule: Expected end of rule.', + token=token) + return expected + +@@ -106,26 +106,26 @@ class CSSUnknownRule(cssrule.CSSRule): + type_, val, line, col = token + val = self._tokenvalue(token) + if expected != 'EOF': +- new['nesting'].append(u'(') ++ new['nesting'].append('(') + seq.append(val, type_, line=line, col=col) + return expected + else: + new['wellformed'] = False +- self._log.error(u'CSSUnknownRule: Expected end of rule.', ++ self._log.error('CSSUnknownRule: Expected end of rule.', + token=token) + return expected + + def EOF(expected, seq, token, tokenizer=None): + "close all blocks and return 'EOF'" + for x in reversed(new['nesting']): +- closing = {u'{': u'}', u'[': u']', u'(': u')'}[x] ++ closing = {'{': '}', '[': ']', '(': ')'}[x] + seq.append(closing, closing) + new['nesting'] = [] + return 'EOF' + + def INVALID(expected, seq, token, tokenizer=None): + # makes rule invalid +- self._log.error(u'CSSUnknownRule: Bad syntax.', ++ self._log.error('CSSUnknownRule: Bad syntax.', + token=token, error=xml.dom.SyntaxErr) + new['wellformed'] = False + return expected +@@ -138,7 +138,7 @@ class CSSUnknownRule(cssrule.CSSRule): + return expected + else: + new['wellformed'] = False +- self._log.error(u'CSSUnknownRule: Expected end of rule.', ++ self._log.error('CSSUnknownRule: Expected end of rule.', + token=token) + return expected + +@@ -150,7 +150,7 @@ class CSSUnknownRule(cssrule.CSSRule): + return expected + else: + new['wellformed'] = False +- self._log.error(u'CSSUnknownRule: Expected end of rule.', ++ self._log.error('CSSUnknownRule: Expected end of rule.', + token=token) + return expected + +@@ -161,7 +161,7 @@ class CSSUnknownRule(cssrule.CSSRule): + return expected + else: + new['wellformed'] = False +- self._log.error(u'CSSUnknownRule: Expected end of rule.', ++ self._log.error('CSSUnknownRule: Expected end of rule.', + token=token) + return expected + +@@ -186,11 +186,11 @@ class CSSUnknownRule(cssrule.CSSRule): + # post conditions + if expected != 'EOF': + wellformed = False +- self._log.error(u'CSSUnknownRule: No ending ";" or "}" found: ' +- u'%r' % self._valuestr(cssText)) ++ self._log.error('CSSUnknownRule: No ending ";" or "}" found: ' ++ '%r' % self._valuestr(cssText)) + elif new['nesting']: + wellformed = False +- self._log.error(u'CSSUnknownRule: Unclosed "{", "[" or "(": %r' ++ self._log.error('CSSUnknownRule: Unclosed "{", "[" or "(": %r' + % self._valuestr(cssText)) + + # set all +@@ -199,11 +199,10 @@ class CSSUnknownRule(cssrule.CSSRule): + self._setSeq(newseq) + + cssText = property(fget=_getCssText, fset=_setCssText, +- doc=u"(DOM) The parsable textual representation.") ++ doc="(DOM) The parsable textual representation.") + + type = property(lambda self: self.UNKNOWN_RULE, +- doc=u"The type of this rule, as defined by a CSSRule " +- u"type constant.") ++ doc="The type of this rule, as defined by a CSSRule " ++ "type constant.") + + wellformed = property(lambda self: bool(self.atkeyword)) +- +\ No newline at end of file +diff --git a/src/cssutils/css/cssvalue.py b/src/cssutils/css/cssvalue.py +index 2f64345..f819580 100644 +--- a/src/cssutils/css/cssvalue.py ++++ b/src/cssutils/css/cssvalue.py +@@ -54,21 +54,21 @@ class CSSValue(cssutils.util._NewBase): + self.parent = parent + if cssText is not None: # may be 0 + if isinstance(cssText, int): +- cssText = unicode(cssText) # if it is an integer ++ cssText = str(cssText) # if it is an integer + elif isinstance(cssText, float): +- cssText = u'%f' % cssText # if it is a floating point number ++ cssText = '%f' % cssText # if it is a floating point number + + self.cssText = cssText + + self._readonly = readonly + + def __repr__(self): +- return u"cssutils.css.%s(%r)" % (self.__class__.__name__, ++ return "cssutils.css.%s(%r)" % (self.__class__.__name__, + self.cssText) + + def __str__(self): +- return u"" % (self.__class__.__name__, ++ return "" % (self.__class__.__name__, + self.cssValueTypeString, + self.cssText, + id(self)) +@@ -119,7 +119,7 @@ class CSSValue(cssutils.util._NewBase): + self._checkReadonly() + + # used as operator is , / or S +- nextSor = u',/' ++ nextSor = ',/' + + term = Choice(Sequence(PreDef.unary(), + Choice(PreDef.number(nextSor=nextSor), +@@ -133,21 +133,21 @@ class CSSValue(cssutils.util._NewBase): + # special case IE only expression + Prod(name='expression', + match=lambda t, v: t == self._prods.FUNCTION and ( +- cssutils.helper.normalize(v) in (u'expression(', +- u'alpha(', +- u'blur(', +- u'chroma(', +- u'dropshadow(', +- u'fliph(', +- u'flipv(', +- u'glow(', +- u'gray(', +- u'invert(', +- u'mask(', +- u'shadow(', +- u'wave(', +- u'xray(') or +- v.startswith(u'progid:DXImageTransform.Microsoft.') ++ cssutils.helper.normalize(v) in ('expression(', ++ 'alpha(', ++ 'blur(', ++ 'chroma(', ++ 'dropshadow(', ++ 'fliph(', ++ 'flipv(', ++ 'glow(', ++ 'gray(', ++ 'invert(', ++ 'mask(', ++ 'shadow(', ++ 'wave(', ++ 'xray(') or ++ v.startswith('progid:DXImageTransform.Microsoft.') + ), + nextSor=nextSor, + toSeq=lambda t, tokens: (ExpressionValue._functionName, +@@ -216,7 +216,7 @@ class CSSValue(cssutils.util._NewBase): + minmax=lambda: (0, None))) + # parse + wellformed, seq, store, notused = ProdParser().parse(cssText, +- u'CSSValue', ++ 'CSSValue', + valueprods, + keepS=True) + if wellformed: +@@ -231,7 +231,7 @@ class CSSValue(cssutils.util._NewBase): + if item.type == self._prods.S: + pass + +- elif (item.value, item.type) == (u',', 'operator'): ++ elif (item.value, item.type) == (',', 'operator'): + # , separared counts as a single STRING for now + # URI or STRING value might be a single CHAR too! + newseq.appendItem(item) +@@ -241,11 +241,11 @@ class CSSValue(cssutils.util._NewBase): + if firstvalue[1] == self._prods.IDENT: + firstvalue = firstvalue[0], 'STRING' + +- elif item.value == u'/': ++ elif item.value == '/': + # / separated items count as one + newseq.appendItem(item) + +- elif item.value == u'-' or item.value == u'+': ++ elif item.value == '-' or item.value == '+': + # combine +- and following number or other + i += 1 + try: +@@ -274,7 +274,7 @@ class CSSValue(cssutils.util._NewBase): + + if not firstvalue: + self._log.error( +- u'CSSValue: Unknown syntax or no value: %r.' % ++ 'CSSValue: Unknown syntax or no value: %r.' % + self._valuestr(cssText)) + else: + # ok and set +@@ -287,8 +287,8 @@ class CSSValue(cssutils.util._NewBase): + + if count == 1: + # inherit, primitive or variable +- if isinstance(firstvalue[0], basestring) and\ +- u'inherit' == cssutils.helper.normalize(firstvalue[0]): ++ if isinstance(firstvalue[0], str) and\ ++ 'inherit' == cssutils.helper.normalize(firstvalue[0]): + self.__class__ = CSSValue + self._cssValueType = CSSValue.CSS_INHERIT + elif 'CSSVariable' == firstvalue[1]: +@@ -328,7 +328,7 @@ class CSSValue(cssutils.util._NewBase): + """ + if commalist: + newseq.replace(-1, +- CSSPrimitiveValue(cssText=u''.join( ++ CSSPrimitiveValue(cssText=''.join( + commalist)), + CSSPrimitiveValue, + newseq[-1].line, +@@ -370,11 +370,11 @@ class CSSValue(cssutils.util._NewBase): + + nexttocommalist = False + +- elif u',' == item.value: ++ elif ',' == item.value: + if not commalist: + # save last item to commalist + commalist.append(itemValue(self._seq[i - 1])) +- commalist.append(u',') ++ commalist.append(',') + nexttocommalist = True + + else: +@@ -518,7 +518,7 @@ class CSSPrimitiveValue(CSSValue): + readonly=readonly) + + def __str__(self): +- return u""\ ++ return ""\ + % (self.__class__.__name__, + self.primitiveTypeString, + self.cssText, +@@ -541,7 +541,7 @@ class CSSPrimitiveValue(CSSValue): + 'CSS_UNICODE_RANGE' + ] + +- _reNumDim = re.compile(ur'([+-]?\d*\.\d+|[+-]?\d+)(.*)$', re.I | re.U | re.X) ++ _reNumDim = re.compile(r'([+-]?\d*\.\d+|[+-]?\d+)(.*)$', re.I | re.U | re.X) + + def _unitDIMENSION(value): + """Check val for dimension name.""" +@@ -565,7 +565,7 @@ class CSSPrimitiveValue(CSSValue): + 'rgb(': 'CSS_RGBCOLOR', + 'rgba(': 'CSS_RGBACOLOR', + } +- return units.get(re.findall(ur'^(.*?\()', ++ return units.get(re.findall(r'^(.*?\()', + cssutils.helper.normalize(value.cssText), + re.U)[0], + 'CSS_UNKNOWN') +@@ -613,7 +613,7 @@ class CSSPrimitiveValue(CSSValue): + try: + return self._unitnames[type] + except (IndexError, TypeError): +- return u'%r (UNKNOWN TYPE)' % type ++ return '%r (UNKNOWN TYPE)' % type + + def _getNumDim(self, value=None): + "Split self._value in numerical and dimension part." +@@ -623,14 +623,14 @@ class CSSPrimitiveValue(CSSValue): + try: + val, dim = CSSPrimitiveValue._reNumDim.findall(value)[0] + except IndexError: +- val, dim = value, u'' ++ val, dim = value, '' + try: + val = float(val) + if val == int(val): + val = int(val) + except ValueError: + raise xml.dom.InvalidAccessErr( +- u'CSSPrimitiveValue: No float value %r' % self._value[0]) ++ 'CSSPrimitiveValue: No float value %r' % self._value[0]) + + return val, dim + +@@ -655,7 +655,7 @@ class CSSPrimitiveValue(CSSValue): + """ + if unitType is not None and unitType not in self._floattypes: + raise xml.dom.InvalidAccessErr( +- u'unitType Parameter is not a float type') ++ 'unitType Parameter is not a float type') + + val, dim = self._getNumDim() + +@@ -665,7 +665,7 @@ class CSSPrimitiveValue(CSSValue): + val = self._converter[self.primitiveType, unitType](val) + except KeyError: + raise xml.dom.InvalidAccessErr( +- u'CSSPrimitiveValue: Cannot coerce primitiveType %r to %r' ++ 'CSSPrimitiveValue: Cannot coerce primitiveType %r to %r' + % (self.primitiveTypeString, + self._getCSSPrimitiveTypeString(unitType))) + +@@ -699,13 +699,13 @@ class CSSPrimitiveValue(CSSValue): + self._checkReadonly() + if unitType not in self._floattypes: + raise xml.dom.InvalidAccessErr( +- u'CSSPrimitiveValue: unitType %r is not a float type' % ++ 'CSSPrimitiveValue: unitType %r is not a float type' % + self._getCSSPrimitiveTypeString(unitType)) + try: + val = float(floatValue) +- except ValueError, e: ++ except ValueError as e: + raise xml.dom.InvalidAccessErr( +- u'CSSPrimitiveValue: floatValue %r is not a float' % ++ 'CSSPrimitiveValue: floatValue %r is not a float' % + floatValue) + + oldval, dim = self._getNumDim() +@@ -715,7 +715,7 @@ class CSSPrimitiveValue(CSSValue): + val = self._converter[unitType, self.primitiveType](val) + except KeyError: + raise xml.dom.InvalidAccessErr( +- u'CSSPrimitiveValue: Cannot coerce primitiveType %r to %r' ++ 'CSSPrimitiveValue: Cannot coerce primitiveType %r to %r' + % (self.primitiveTypeString, + self._getCSSPrimitiveTypeString(unitType))) + +@@ -736,7 +736,7 @@ class CSSPrimitiveValue(CSSValue): + """ + if self.primitiveType not in self._stringtypes: + raise xml.dom.InvalidAccessErr( +- u'CSSPrimitiveValue %r is not a string type' ++ 'CSSPrimitiveValue %r is not a string type' + % self.primitiveTypeString) + + if CSSPrimitiveValue.CSS_ATTR == self.primitiveType: +@@ -774,17 +774,17 @@ class CSSPrimitiveValue(CSSValue): + # self not stringType + if self.primitiveType not in self._stringtypes: + raise xml.dom.InvalidAccessErr( +- u'CSSPrimitiveValue %r is not a string type' ++ 'CSSPrimitiveValue %r is not a string type' + % self.primitiveTypeString) + # given stringType is no StringType + if stringType not in self._stringtypes: + raise xml.dom.InvalidAccessErr( +- u'CSSPrimitiveValue: stringType %s is not a string type' ++ 'CSSPrimitiveValue: stringType %s is not a string type' + % self._getCSSPrimitiveTypeString(stringType)) + + if self._primitiveType != stringType: + raise xml.dom.InvalidAccessErr( +- u'CSSPrimitiveValue: Cannot coerce primitiveType %r to %r' ++ 'CSSPrimitiveValue: Cannot coerce primitiveType %r to %r' + % (self.primitiveTypeString, + self._getCSSPrimitiveTypeString(stringType))) + +@@ -793,7 +793,7 @@ class CSSPrimitiveValue(CSSValue): + elif CSSPrimitiveValue.CSS_URI == self._primitiveType: + self.cssText = cssutils.helper.uri(stringValue) + elif CSSPrimitiveValue.CSS_ATTR == self._primitiveType: +- self.cssText = u'attr(%s)' % stringValue ++ self.cssText = 'attr(%s)' % stringValue + else: + self.cssText = stringValue + self._primitiveType = stringType +@@ -807,7 +807,7 @@ class CSSPrimitiveValue(CSSValue): + **Not implemented.** + """ + if not self.CSS_COUNTER == self.primitiveType: +- raise xml.dom.InvalidAccessErr(u'Value is not a counter type') ++ raise xml.dom.InvalidAccessErr('Value is not a counter type') + # TODO: use Counter class + raise NotImplementedError() + +@@ -818,7 +818,7 @@ class CSSPrimitiveValue(CSSValue): + can be achieved using the RGBColor interface. + """ + if self.primitiveType not in self._rbgtypes: +- raise xml.dom.InvalidAccessErr(u'Value is not a RGBColor value') ++ raise xml.dom.InvalidAccessErr('Value is not a RGBColor value') + return RGBColor(self._value[0]) + + def getRectValue(self): +@@ -830,7 +830,7 @@ class CSSPrimitiveValue(CSSValue): + **Not implemented.** + """ + if self.primitiveType not in self._recttypes: +- raise xml.dom.InvalidAccessErr(u'value is not a Rect value') ++ raise xml.dom.InvalidAccessErr('value is not a Rect value') + # TODO: use Rect class + raise NotImplementedError() + +@@ -872,8 +872,8 @@ class CSSValueList(CSSValue): + yield item.value + + def __str__(self): +- return u"" % (self.__class__.__name__, ++ return "" % (self.__class__.__name__, + self.cssValueTypeString, + self.cssText, + self.length, +@@ -895,13 +895,13 @@ class CSSValueList(CSSValue): + return None + + length = property(lambda self: len(self.__items()), +- doc=u"(DOM attribute) The number of CSSValues in the " +- u"list.") ++ doc="(DOM attribute) The number of CSSValues in the " ++ "list.") + + + class CSSFunction(CSSPrimitiveValue): + """A CSS function value like rect() etc.""" +- _functionName = u'CSSFunction' ++ _functionName = 'CSSFunction' + primitiveType = CSSPrimitiveValue.CSS_UNKNOWN + + def __init__(self, cssText=None, parent=None, readonly=False): +@@ -976,7 +976,7 @@ class CSSFunction(CSSPrimitiveValue): + item = seq[i] + if item.type == self._prods.S: + pass +- elif item.value == u'+' or item.value == u'-': ++ elif item.value == '+' or item.value == '-': + i += 1 + next = seq[i] + newval = next.value +@@ -1007,7 +1007,7 @@ class CSSFunction(CSSPrimitiveValue): + class RGBColor(CSSFunction): + """A CSS color like RGB, RGBA or a simple value like `#000` or `red`.""" + +- _functionName = u'Function rgb()' ++ _functionName = 'Function rgb()' + + def __init__(self, cssText=None, parent=None, readonly=False): + """ +@@ -1033,11 +1033,11 @@ class RGBColor(CSSFunction): + self._readonly = readonly + + def __repr__(self): +- return u"cssutils.css.%s(%r)" % (self.__class__.__name__, ++ return "cssutils.css.%s(%r)" % (self.__class__.__name__, + self.cssText) + + def __str__(self): +- return u"" % ( ++ return "" % ( + self.__class__.__name__, + self.colorType, + self.cssText, +@@ -1074,7 +1074,7 @@ class RGBColor(CSSFunction): + ) + # store: colorType, parts + wellformed, seq, store, unusedtokens = ProdParser().parse(cssText, +- u'RGBColor', ++ 'RGBColor', + colorprods, + keepS=True, + store={'parts': []}) +@@ -1099,7 +1099,7 @@ class RGBColor(CSSFunction): + + class CalcValue(CSSFunction): + """Calc Function""" +- _functionName = u'Function calc()' ++ _functionName = 'Function calc()' + + def _productiondefinition(self): + """Return defintion used for parsing.""" +@@ -1120,7 +1120,7 @@ class CalcValue(CSSFunction): + tokens))) + ), + Prod(name='part', +- match=lambda t, v: v != u')', ++ match=lambda t, v: v != ')', + toSeq=lambda t, tokens: (t[0], t[1])), + ), + minmax=lambda: (0, None)), +@@ -1134,13 +1134,13 @@ class CalcValue(CSSFunction): + return super(CalcValue, self)._setCssText(cssText) + + cssText = property(_getCssText, _setCssText, +- doc=u"A string representation of the current value.") ++ doc="A string representation of the current value.") + + + class ExpressionValue(CSSFunction): + """Special IE only CSSFunction which may contain *anything*. + Used for expressions and ``alpha(opacity=100)`` currently.""" +- _functionName = u'Expression (IE only)' ++ _functionName = 'Expression (IE only)' + + def _productiondefinition(self): + """Return defintion used for parsing.""" +@@ -1161,7 +1161,7 @@ class ExpressionValue(CSSFunction): + tokens))) + ), + Prod(name='part', +- match=lambda t, v: v != u')', ++ match=lambda t, v: v != ')', + toSeq=lambda t, tokens: (t[0], t[1])), + ), + minmax=lambda: (0, None)), +@@ -1176,7 +1176,7 @@ class ExpressionValue(CSSFunction): + return super(ExpressionValue, self)._setCssText(cssText) + + cssText = property(_getCssText, _setCssText, +- doc=u"A string representation of the current value.") ++ doc="A string representation of the current value.") + + + class CSSVariable(CSSValue): +@@ -1196,10 +1196,10 @@ class CSSVariable(CSSValue): + readonly=readonly) + + def __repr__(self): +- return u"cssutils.css.%s(%r)" % (self.__class__.__name__, self.cssText) ++ return "cssutils.css.%s(%r)" % (self.__class__.__name__, self.cssText) + + def __str__(self): +- return u"" % ( ++ return "" % ( + self.__class__.__name__, + self.name, + self.value, +@@ -1219,7 +1219,7 @@ class CSSVariable(CSSValue): + # store: name of variable + store = {'ident': None} + wellformed, seq, store, unusedtokens = ProdParser().parse(cssText, +- u'CSSVariable', ++ 'CSSVariable', + funcProds, + keepS=True) + if wellformed: +@@ -1229,7 +1229,7 @@ class CSSVariable(CSSValue): + + cssText = property(lambda self: cssutils.ser.do_css_CSSVariable(self), + _setCssText, +- doc=u"A string representation of the current variable.") ++ doc="A string representation of the current variable.") + + cssValueType = CSSValue.CSS_VARIABLE + +diff --git a/src/cssutils/css/cssvariablesdeclaration.py b/src/cssutils/css/cssvariablesdeclaration.py +index 50b3b31..e2b0291 100644 +--- a/src/cssutils/css/cssvariablesdeclaration.py ++++ b/src/cssutils/css/cssvariablesdeclaration.py +@@ -7,7 +7,7 @@ __version__ = '$Id: cssstyledeclaration.py 1819 2009-08-01 20:52:43Z cthedot $' + + from cssutils.prodparser import * + from cssutils.helper import normalize +-from value import PropertyValue ++from .value import PropertyValue + import cssutils + import itertools + import xml.dom +@@ -16,7 +16,7 @@ class CSSVariablesDeclaration(cssutils.util._NewBase): + """The CSSVariablesDeclaration interface represents a single block of + variable declarations. + """ +- def __init__(self, cssText=u'', parentRule=None, readonly=False): ++ def __init__(self, cssText='', parentRule=None, readonly=False): + """ + :param cssText: + Shortcut, sets CSSVariablesDeclaration.cssText +@@ -49,11 +49,11 @@ class CSSVariablesDeclaration(cssutils.util._NewBase): + self._readonly = readonly + + def __repr__(self): +- return u"cssutils.css.%s(cssText=%r)" % (self.__class__.__name__, ++ return "cssutils.css.%s(cssText=%r)" % (self.__class__.__name__, + self.cssText) + + def __str__(self): +- return u"" % ( ++ return "" % ( + self.__class__.__name__, + self.length, + id(self)) +@@ -64,7 +64,7 @@ class CSSVariablesDeclaration(cssutils.util._NewBase): + :param variableName: + a string + """ +- return normalize(variableName) in self.keys() ++ return normalize(variableName) in list(self.keys()) + + def __getitem__(self, variableName): + """Retrieve the value of variable ``variableName`` from this +@@ -80,13 +80,13 @@ class CSSVariablesDeclaration(cssutils.util._NewBase): + + def __iter__(self): + """Iterator of names of set variables.""" +- for name in self.keys(): ++ for name in list(self.keys()): + yield name + + def keys(self): + """Analoguous to standard dict returns variable names which are set in + this declaration.""" +- return self._vars.keys() ++ return list(self._vars.keys()) + + def _getCssText(self): + """Return serialized property cssText.""" +@@ -127,10 +127,10 @@ class CSSVariablesDeclaration(cssutils.util._NewBase): + + vardeclaration = Sequence( + PreDef.ident(), +- PreDef.char(u':', u':', toSeq=False, optional=True), ++ PreDef.char(':', ':', toSeq=False, optional=True), + #PreDef.S(toSeq=False, optional=True), +- Prod(name=u'term', match=lambda t, v: True, +- toSeq=lambda t, tokens: (u'value', ++ Prod(name='term', match=lambda t, v: True, ++ toSeq=lambda t, tokens: ('value', + PropertyValue(itertools.chain([t], + tokens), + parent=self) +@@ -139,17 +139,17 @@ class CSSVariablesDeclaration(cssutils.util._NewBase): + ) + prods = Sequence(vardeclaration, + Sequence(PreDef.S(optional=True), +- PreDef.char(u';', u';', toSeq=False, optional=True), ++ PreDef.char(';', ';', toSeq=False, optional=True), + PreDef.S(optional=True), + vardeclaration, + minmax=lambda: (0, None)), + PreDef.S(optional=True), +- PreDef.char(u';', u';', toSeq=False, optional=True) ++ PreDef.char(';', ';', toSeq=False, optional=True) + ) + # parse + wellformed, seq, store, notused = \ + ProdParser().parse(cssText, +- u'CSSVariableDeclaration', ++ 'CSSVariableDeclaration', + prods, + emptyOk=True) + if wellformed: +@@ -159,9 +159,9 @@ class CSSVariablesDeclaration(cssutils.util._NewBase): + # seq contains only name: value pairs plus comments etc + nameitem = None + for item in seq: +- if u'IDENT' == item.type: ++ if 'IDENT' == item.type: + nameitem = item +- elif u'value' == item.type: ++ elif 'value' == item.type: + nname = normalize(nameitem.value) + if nname in newvars: + # replace var with same name +@@ -191,16 +191,16 @@ class CSSVariablesDeclaration(cssutils.util._NewBase): + self.wellformed = True + + cssText = property(_getCssText, _setCssText, +- doc=u"(DOM) A parsable textual representation of the declaration " +- u"block excluding the surrounding curly braces.") ++ doc="(DOM) A parsable textual representation of the declaration " ++ "block excluding the surrounding curly braces.") + + def _setParentRule(self, parentRule): + self._parentRule = parentRule + + parentRule = property(lambda self: self._parentRule, _setParentRule, +- doc=u"(DOM) The CSS rule that contains this" +- u" declaration block or None if this block" +- u" is not attached to a CSSRule.") ++ doc="(DOM) The CSS rule that contains this" ++ " declaration block or None if this block" ++ " is not attached to a CSSRule.") + + def getVariableValue(self, variableName): + """Used to retrieve the value of a variable if it has been explicitly +@@ -215,8 +215,8 @@ class CSSVariablesDeclaration(cssutils.util._NewBase): + """ + try: + return self._vars[normalize(variableName)].cssText +- except KeyError, e: +- return u'' ++ except KeyError as e: ++ return '' + + def removeVariable(self, variableName): + """Used to remove a variable if it has been explicitly set within this +@@ -236,8 +236,8 @@ class CSSVariablesDeclaration(cssutils.util._NewBase): + normalname = variableName + try: + r = self._vars[normalname] +- except KeyError, e: +- return u'' ++ except KeyError as e: ++ return '' + else: + self.seq._readonly = False + if normalname in self._vars: +@@ -270,10 +270,10 @@ class CSSVariablesDeclaration(cssutils.util._NewBase): + # check name + wellformed, seq, store, unused = \ + ProdParser().parse(normalize(variableName), +- u'variableName', ++ 'variableName', + Sequence(PreDef.ident())) + if not wellformed: +- self._log.error(u'Invalid variableName: %r: %r' ++ self._log.error('Invalid variableName: %r: %r' + % (variableName, value)) + else: + # check value +@@ -283,7 +283,7 @@ class CSSVariablesDeclaration(cssutils.util._NewBase): + v = PropertyValue(cssText=value, parent=self) + + if not v.wellformed: +- self._log.error(u'Invalid variable value: %r: %r' ++ self._log.error('Invalid variable value: %r: %r' + % (variableName, value)) + else: + # update seq +@@ -321,11 +321,11 @@ class CSSVariablesDeclaration(cssutils.util._NewBase): + string if no variable exists at this position. + """ + try: +- return self.keys()[index] ++ return list(self.keys())[index] + except IndexError: +- return u'' ++ return '' + + length = property(lambda self: len(self._vars), +- doc=u"The number of variables that have been explicitly set in this" +- u" variable declaration block. The range of valid indices is 0" +- u" to length-1 inclusive.") ++ doc="The number of variables that have been explicitly set in this" ++ " variable declaration block. The range of valid indices is 0" ++ " to length-1 inclusive.") +diff --git a/src/cssutils/css/cssvariablesrule.py b/src/cssutils/css/cssvariablesrule.py +index c7fbabf..5312dd7 100644 +--- a/src/cssutils/css/cssvariablesrule.py ++++ b/src/cssutils/css/cssvariablesrule.py +@@ -5,8 +5,8 @@ __all__ = ['CSSVariablesRule'] + __docformat__ = 'restructuredtext' + __version__ = '$Id: cssfontfacerule.py 1818 2009-07-30 21:39:00Z cthedot $' + +-from cssvariablesdeclaration import CSSVariablesDeclaration +-import cssrule ++from .cssvariablesdeclaration import CSSVariablesDeclaration ++from . import cssrule + import cssutils + import xml.dom + +@@ -48,7 +48,7 @@ class CSSVariablesRule(cssrule.CSSRule): + """ + super(CSSVariablesRule, self).__init__(parentRule=parentRule, + parentStyleSheet=parentStyleSheet) +- self._atkeyword = u'@variables' ++ self._atkeyword = '@variables' + + # dummy + self._media = cssutils.stylesheets.MediaList(mediaText, +@@ -62,14 +62,14 @@ class CSSVariablesRule(cssrule.CSSRule): + self._readonly = readonly + + def __repr__(self): +- return u"cssutils.css.%s(mediaText=%r, variables=%r)" % ( ++ return "cssutils.css.%s(mediaText=%r, variables=%r)" % ( + self.__class__.__name__, + self._media.mediaText, + self.variables.cssText) + + def __str__(self): +- return u"" % (self.__class__.__name__, ++ return "" % (self.__class__.__name__, + self._media.mediaText, + self.variables.cssText, + self.valid, +@@ -110,7 +110,7 @@ class CSSVariablesRule(cssrule.CSSRule): + tokenizer = self._tokenize2(cssText) + attoken = self._nexttoken(tokenizer, None) + if self._type(attoken) != self._prods.VARIABLES_SYM: +- self._log.error(u'CSSVariablesRule: No CSSVariablesRule found: %s' % ++ self._log.error('CSSVariablesRule: No CSSVariablesRule found: %s' % + self._valuestr(cssText), + error=xml.dom.InvalidModificationErr) + else: +@@ -120,10 +120,10 @@ class CSSVariablesRule(cssrule.CSSRule): + beforetokens, brace = self._tokensupto2(tokenizer, + blockstartonly=True, + separateEnd=True) +- if self._tokenvalue(brace) != u'{': ++ if self._tokenvalue(brace) != '{': + ok = False +- self._log.error(u'CSSVariablesRule: No start { of variable ' +- u'declaration found: %r' ++ self._log.error('CSSVariablesRule: No start { of variable ' ++ 'declaration found: %r' + % self._valuestr(cssText), brace) + + # parse stuff before { which should be comments and S only +@@ -141,16 +141,16 @@ class CSSVariablesRule(cssrule.CSSRule): + + val, type_ = self._tokenvalue(braceorEOFtoken), \ + self._type(braceorEOFtoken) +- if val != u'}' and type_ != 'EOF': ++ if val != '}' and type_ != 'EOF': + ok = False +- self._log.error(u'CSSVariablesRule: No "}" after variables ' +- u'declaration found: %r' ++ self._log.error('CSSVariablesRule: No "}" after variables ' ++ 'declaration found: %r' + % self._valuestr(cssText)) + + nonetoken = self._nexttoken(tokenizer) + if nonetoken: + ok = False +- self._log.error(u'CSSVariablesRule: Trailing content found.', ++ self._log.error('CSSVariablesRule: Trailing content found.', + token=nonetoken) + + if 'EOF' == type_: +@@ -165,11 +165,11 @@ class CSSVariablesRule(cssrule.CSSRule): + self.variables = newVariables + + cssText = property(_getCssText, _setCssText, +- doc=u"(DOM) The parsable textual representation of this " +- u"rule.") ++ doc="(DOM) The parsable textual representation of this " ++ "rule.") + +- media = property(doc=u"NOT IMPLEMENTED! As cssutils resolves variables "\ +- u"during serializing media information is lost.") ++ media = property(doc="NOT IMPLEMENTED! As cssutils resolves variables "\ ++ "during serializing media information is lost.") + + def _setVariables(self, variables): + """ +@@ -177,7 +177,7 @@ class CSSVariablesRule(cssrule.CSSRule): + a CSSVariablesDeclaration or string + """ + self._checkReadonly() +- if isinstance(variables, basestring): ++ if isinstance(variables, str): + self._variables = CSSVariablesDeclaration(cssText=variables, + parentRule=self) + else: +@@ -185,12 +185,12 @@ class CSSVariablesRule(cssrule.CSSRule): + self._variables = variables + + variables = property(lambda self: self._variables, _setVariables, +- doc=u"(DOM) The variables of this rule set, a " +- u":class:`cssutils.css.CSSVariablesDeclaration`.") ++ doc="(DOM) The variables of this rule set, a " ++ ":class:`cssutils.css.CSSVariablesDeclaration`.") + + type = property(lambda self: self.VARIABLES_RULE, +- doc=u"The type of this rule, as defined by a CSSRule " +- u"type constant.") ++ doc="The type of this rule, as defined by a CSSRule " ++ "type constant.") + + valid = property(lambda self: True, doc='NOT IMPLEMTED REALLY (TODO)') + +diff --git a/src/cssutils/css/marginrule.py b/src/cssutils/css/marginrule.py +index 0c789fa..f1301a3 100644 +--- a/src/cssutils/css/marginrule.py ++++ b/src/cssutils/css/marginrule.py +@@ -4,8 +4,8 @@ __docformat__ = 'restructuredtext' + __version__ = '$Id$' + + from cssutils.prodparser import * +-from cssstyledeclaration import CSSStyleDeclaration +-import cssrule ++from .cssstyledeclaration import CSSStyleDeclaration ++from . import cssrule + import cssutils + import xml.dom + +@@ -92,7 +92,7 @@ class MarginRule(cssrule.CSSRule): + n = self._normalize(margin) + + if n not in MarginRule.margins: +- self._log.error(u'Invalid margin @keyword for this %s rule: %r' % ++ self._log.error('Invalid margin @keyword for this %s rule: %r' % + (self.margin, margin), + error=xml.dom.InvalidModificationErr) + +@@ -101,20 +101,20 @@ class MarginRule(cssrule.CSSRule): + self._keyword = margin + + margin = property(lambda self: self._atkeyword, _setMargin, +- doc=u"Margin area of parent CSSPageRule. " +- u"`margin` and `atkeyword` are both normalized " +- u"@keyword of the @rule.") ++ doc="Margin area of parent CSSPageRule. " ++ "`margin` and `atkeyword` are both normalized " ++ "@keyword of the @rule.") + + atkeyword = margin + + def __repr__(self): +- return u"cssutils.css.%s(margin=%r, style=%r)" % (self.__class__.__name__, ++ return "cssutils.css.%s(margin=%r, style=%r)" % (self.__class__.__name__, + self.margin, + self.style.cssText) + + def __str__(self): +- return u"" % (self.__class__.__name__, ++ return "" % (self.__class__.__name__, + self.margin, + self.style.cssText, + id(self)) +@@ -143,7 +143,7 @@ class MarginRule(cssrule.CSSRule): + # TEMP: all style tokens are saved in store to fill styledeclaration + # TODO: resolve when all generators + styletokens = Prod(name='styletokens', +- match=lambda t, v: v != u'}', ++ match=lambda t, v: v != '}', + #toSeq=False, + toStore='styletokens', + storeToken=True +@@ -157,16 +157,16 @@ class MarginRule(cssrule.CSSRule): + # TODO? + #, exception=xml.dom.InvalidModificationErr + ), +- PreDef.char('OPEN', u'{'), ++ PreDef.char('OPEN', '{'), + Sequence(Choice(PreDef.unknownrule(toStore='@'), + styletokens), + minmax=lambda: (0, None) + ), +- PreDef.char('CLOSE', u'}', stopAndKeep=True) ++ PreDef.char('CLOSE', '}', stopAndKeep=True) + ) + # parse + ok, seq, store, unused = ProdParser().parse(cssText, +- u'MarginRule', ++ 'MarginRule', + prods) + + if ok: +@@ -177,7 +177,7 @@ class MarginRule(cssrule.CSSRule): + # may raise: + self.margin = store['margin'].value + else: +- self._log.error(u'No margin @keyword for this %s rule' % ++ self._log.error('No margin @keyword for this %s rule' % + self.margin, + error=xml.dom.InvalidModificationErr) + +@@ -190,7 +190,7 @@ class MarginRule(cssrule.CSSRule): + + + cssText = property(fget=_getCssText, fset=_setCssText, +- doc=u"(DOM) The parsable textual representation.") ++ doc="(DOM) The parsable textual representation.") + + def _setStyle(self, style): + """ +@@ -198,18 +198,18 @@ class MarginRule(cssrule.CSSRule): + current style object. + """ + self._checkReadonly() +- if isinstance(style, basestring): ++ if isinstance(style, str): + self._style = CSSStyleDeclaration(cssText=style, parentRule=self) + else: + style._parentRule = self + self._style = style + + style = property(lambda self: self._style, _setStyle, +- doc=u"(DOM) The declaration-block of this rule set.") ++ doc="(DOM) The declaration-block of this rule set.") + + type = property(lambda self: self.MARGIN_RULE, +- doc=u"The type of this rule, as defined by a CSSRule " +- u"type constant.") ++ doc="The type of this rule, as defined by a CSSRule " ++ "type constant.") + + wellformed = property(lambda self: bool(self.atkeyword)) + +\ No newline at end of file +diff --git a/src/cssutils/css/property.py b/src/cssutils/css/property.py +index fad240c..8490982 100644 +--- a/src/cssutils/css/property.py ++++ b/src/cssutils/css/property.py +@@ -4,7 +4,7 @@ __docformat__ = 'restructuredtext' + __version__ = '$Id$' + + from cssutils.helper import Deprecated +-from value import PropertyValue ++from .value import PropertyValue + import cssutils + import xml.dom + +@@ -43,7 +43,7 @@ class Property(cssutils.util.Base): + ; + + """ +- def __init__(self, name=None, value=None, priority=u'', ++ def __init__(self, name=None, value=None, priority='', + _mediaQuery=False, parent=None): + """ + :param name: +@@ -66,27 +66,27 @@ class Property(cssutils.util.Base): + self.parent = parent + + self.__nametoken = None +- self._name = u'' +- self._literalname = u'' ++ self._name = '' ++ self._literalname = '' + self.seqs[1] = PropertyValue(parent=self) + if name: + self.name = name + self.propertyValue = value + +- self._priority = u'' +- self._literalpriority = u'' ++ self._priority = '' ++ self._literalpriority = '' + if priority: + self.priority = priority + + def __repr__(self): +- return u"cssutils.css.%s(name=%r, value=%r, priority=%r)" % ( ++ return "cssutils.css.%s(name=%r, value=%r, priority=%r)" % ( + self.__class__.__name__, + self.literalname, + self.propertyValue.cssText, + self.priority) + + def __str__(self): +- return u"<%s.%s object name=%r value=%r priority=%r valid=%r at 0x%x>" \ ++ return "<%s.%s object name=%r value=%r priority=%r valid=%r at 0x%x>" \ + % (self.__class__.__module__, + self.__class__.__name__, + self.name, +@@ -136,22 +136,22 @@ class Property(cssutils.util.Base): + + # remove colon from nametokens + colontoken = nametokens.pop() +- if self._tokenvalue(colontoken) != u':': ++ if self._tokenvalue(colontoken) != ':': + wellformed = False +- self._log.error(u'Property: No ":" after name found: %s' % ++ self._log.error('Property: No ":" after name found: %s' % + self._valuestr(cssText), colontoken) + elif not nametokens: + wellformed = False +- self._log.error(u'Property: No property name found: %s' % ++ self._log.error('Property: No property name found: %s' % + self._valuestr(cssText), colontoken) + + if valuetokens: +- if self._tokenvalue(valuetokens[-1]) == u'!': ++ if self._tokenvalue(valuetokens[-1]) == '!': + # priority given, move "!" to prioritytokens + prioritytokens.insert(0, valuetokens.pop(-1)) + else: + wellformed = False +- self._log.error(u'Property: No property value found: %s' % ++ self._log.error('Property: No property value found: %s' % + self._valuestr(cssText), colontoken) + + if wellformed: +@@ -166,7 +166,7 @@ class Property(cssutils.util.Base): + self.validate() + + else: +- self._log.error(u'Property: No property name found: %s' % ++ self._log.error('Property: No property name found: %s' % + self._valuestr(cssText)) + + cssText = property(fget=_getCssText, fset=_setCssText, +@@ -191,7 +191,7 @@ class Property(cssutils.util.Base): + return 'EOF' + else: + new['wellformed'] = False +- self._log.error(u'Property: Unexpected ident.', token) ++ self._log.error('Property: Unexpected ident.', token) + return expected + + newseq = [] +@@ -211,7 +211,7 @@ class Property(cssutils.util.Base): + + if not new['literalname']: + wellformed = False +- self._log.error(u'Property: No name found: %s' % ++ self._log.error('Property: No name found: %s' % + self._valuestr(name), token=token) + + if wellformed: +@@ -223,7 +223,7 @@ class Property(cssutils.util.Base): + # validate + if self._isValidating() and self._name not in cssutils.profile.knownNames: + # self.valid = False +- self._log.warn(u'Property: Unknown Property name.', ++ self._log.warn('Property: Unknown Property name.', + token=token, neverraise=True) + else: + pass +@@ -261,7 +261,7 @@ class Property(cssutils.util.Base): + + propertyValue = property(lambda self: self.seqs[1], + _setPropertyValue, +- doc=u"(cssutils) PropertyValue object of property") ++ doc="(cssutils) PropertyValue object of property") + + + def _getValue(self): +@@ -269,7 +269,7 @@ class Property(cssutils.util.Base): + # value without comments + return self.propertyValue.value + else: +- return u'' ++ return '' + + def _setValue(self, value): + self._setPropertyValue(value) +@@ -300,30 +300,30 @@ class Property(cssutils.util.Base): + priority + """ + if self._mediaQuery: +- self._priority = u'' +- self._literalpriority = u'' ++ self._priority = '' ++ self._literalpriority = '' + if priority: +- self._log.error(u'Property: No priority in a MediaQuery - ' +- u'ignored.') ++ self._log.error('Property: No priority in a MediaQuery - ' ++ 'ignored.') + return + +- if isinstance(priority, basestring) and\ +- u'important' == self._normalize(priority): +- priority = u'!%s' % priority ++ if isinstance(priority, str) and\ ++ 'important' == self._normalize(priority): ++ priority = '!%s' % priority + + # for closures: must be a mutable +- new = {'literalpriority': u'', ++ new = {'literalpriority': '', + 'wellformed': True} + + def _char(expected, seq, token, tokenizer=None): + # "!" + val = self._tokenvalue(token) +- if u'!' == expected == val: ++ if '!' == expected == val: + seq.append(val) + return 'important' + else: + new['wellformed'] = False +- self._log.error(u'Property: Unexpected char.', token) ++ self._log.error('Property: Unexpected char.', token) + return expected + + def _ident(expected, seq, token, tokenizer=None): +@@ -335,7 +335,7 @@ class Property(cssutils.util.Base): + return 'EOF' + else: + new['wellformed'] = False +- self._log.error(u'Property: Unexpected ident.', token) ++ self._log.error('Property: Unexpected ident.', token) + return expected + + newseq = [] +@@ -349,7 +349,7 @@ class Property(cssutils.util.Base): + # post conditions + if priority and not new['literalpriority']: + wellformed = False +- self._log.info(u'Property: Invalid priority: %s' % ++ self._log.info('Property: Invalid priority: %s' % + self._valuestr(priority)) + + if wellformed: +@@ -358,8 +358,8 @@ class Property(cssutils.util.Base): + self._priority = self._normalize(self.literalpriority) + self.seqs[2] = newseq + # validate priority +- if self._priority not in (u'', u'important'): +- self._log.error(u'Property: No CSS priority value: %s' % ++ if self._priority not in ('', 'important'): ++ self._log.error('Property: No CSS priority value: %s' % + self._priority) + + priority = property(lambda self: self._priority, _setPriority, +@@ -463,46 +463,46 @@ class Property(cssutils.util.Base): + profiles) + + if not valid: +- self._log.error(u'Property: Invalid value for ' +- u'"%s" property: %s' +- % (u'/'.join(validprofiles), self.value), ++ self._log.error('Property: Invalid value for ' ++ '"%s" property: %s' ++ % ('/'.join(validprofiles), self.value), + token=self.__nametoken, + neverraise=True) + + # TODO: remove logic to profiles! + elif valid and not matching:#(profiles and profiles not in validprofiles): + if not profiles: +- notvalidprofiles = u'/'.join(cssutils.profile.defaultProfiles) ++ notvalidprofiles = '/'.join(cssutils.profile.defaultProfiles) + else: + notvalidprofiles = profiles +- self._log.warn(u'Property: Not valid for profile "%s" ' +- u'but valid "%s" value: %s ' +- % (notvalidprofiles, u'/'.join(validprofiles), ++ self._log.warn('Property: Not valid for profile "%s" ' ++ 'but valid "%s" value: %s ' ++ % (notvalidprofiles, '/'.join(validprofiles), + self.value), + token = self.__nametoken, + neverraise=True) + valid = False + + elif valid: +- self._log.debug(u'Property: Found valid "%s" value: %s' +- % (u'/'.join(validprofiles), self.value), ++ self._log.debug('Property: Found valid "%s" value: %s' ++ % ('/'.join(validprofiles), self.value), + token = self.__nametoken, + neverraise=True) + +- if self._priority not in (u'', u'important'): ++ if self._priority not in ('', 'important'): + valid = False + + return valid + +- valid = property(validate, doc=u"Check if value of this property is valid " +- u"in the properties context.") ++ valid = property(validate, doc="Check if value of this property is valid " ++ "in the properties context.") + + +- @Deprecated(u'Use ``property.propertyValue`` instead.') ++ @Deprecated('Use ``property.propertyValue`` instead.') + def _getCSSValue(self): + return self.propertyValue + +- @Deprecated(u'Use ``property.propertyValue`` instead.') ++ @Deprecated('Use ``property.propertyValue`` instead.') + def _setCSSValue(self, cssText): + self._setPropertyValue(cssText) + +diff --git a/src/cssutils/css/selector.py b/src/cssutils/css/selector.py +index 87840a0..2c858c7 100644 +--- a/src/cssutils/css/selector.py ++++ b/src/cssutils/css/selector.py +@@ -127,12 +127,12 @@ class Selector(cssutils.util.Base2): + st = (self.selectorText, self._getUsedNamespaces()) + else: + st = self.selectorText +- return u"cssutils.css.%s(selectorText=%r)" % (self.__class__.__name__, ++ return "cssutils.css.%s(selectorText=%r)" % (self.__class__.__name__, + st) + + def __str__(self): +- return u"" % (self.__class__.__name__, ++ return "" % (self.__class__.__name__, + self.selectorText, + self.specificity, + self._getUsedNamespaces(), +@@ -143,8 +143,8 @@ class Selector(cssutils.util.Base2): + uris = set() + for item in self.seq: + type_, val = item.type, item.value +- if type_.endswith(u'-selector') or type_ == u'universal' and \ +- isinstance(val, tuple) and val[0] not in (None, u'*'): ++ if type_.endswith('-selector') or type_ == 'universal' and \ ++ isinstance(val, tuple) and val[0] not in (None, '*'): + uris.add(val[0]) + return uris + +@@ -152,7 +152,7 @@ class Selector(cssutils.util.Base2): + "Return actually used namespaces only." + useduris = self._getUsedUris() + namespaces = _SimpleNamespaces(log=self._log) +- for p, uri in self._namespaces.items(): ++ for p, uri in list(self._namespaces.items()): + if uri in useduris: + namespaces[p] = uri + return namespaces +@@ -165,21 +165,21 @@ class Selector(cssutils.util.Base2): + return self.__namespaces + + _namespaces = property(__getNamespaces, +- doc=u"If this Selector is attached to a " +- u"CSSStyleSheet the namespaces of that sheet " +- u"are mirrored here. While the Selector (or " +- u"parent SelectorList or parentRule(s) of that " +- u"are not attached a own dict of {prefix: " +- u"namespaceURI} is used.") ++ doc="If this Selector is attached to a " ++ "CSSStyleSheet the namespaces of that sheet " ++ "are mirrored here. While the Selector (or " ++ "parent SelectorList or parentRule(s) of that " ++ "are not attached a own dict of {prefix: " ++ "namespaceURI} is used.") + + + element = property(lambda self: self._element, +- doc=u"Effective element target of this selector.") ++ doc="Effective element target of this selector.") + + parent = property(lambda self: self._parent, +- doc=u"(DOM) The SelectorList that contains this Selector " +- u"or None if this Selector is not attached to a " +- u"SelectorList.") ++ doc="(DOM) The SelectorList that contains this Selector " ++ "or None if this Selector is not attached to a " ++ "SelectorList.") + + def _getSelectorText(self): + """Return serialized format.""" +@@ -215,7 +215,7 @@ class Selector(cssutils.util.Base2): + pass + tokenizer = self._tokenize2(selectorText) + if not tokenizer: +- self._log.error(u'Selector: No selectorText given.') ++ self._log.error('Selector: No selectorText given.') + else: + # prepare tokenlist: + # "*" -> type "universal" +@@ -228,54 +228,54 @@ class Selector(cssutils.util.Base2): + tokens = [] + for t in tokenizer: + typ, val, lin, col = t +- if val == u':' and tokens and\ ++ if val == ':' and tokens and\ + self._tokenvalue(tokens[-1]) == ':': + # combine ":" and ":" +- tokens[-1] = (typ, u'::', lin, col) ++ tokens[-1] = (typ, '::', lin, col) + + elif typ == 'IDENT' and tokens\ +- and self._tokenvalue(tokens[-1]) == u'.': ++ and self._tokenvalue(tokens[-1]) == '.': + # class: combine to .IDENT +- tokens[-1] = ('class', u'.'+val, lin, col) ++ tokens[-1] = ('class', '.'+val, lin, col) + elif typ == 'IDENT' and tokens and \ +- self._tokenvalue(tokens[-1]).startswith(u':') and\ +- not self._tokenvalue(tokens[-1]).endswith(u'('): ++ self._tokenvalue(tokens[-1]).startswith(':') and\ ++ not self._tokenvalue(tokens[-1]).endswith('('): + # pseudo-X: combine to :IDENT or ::IDENT but not ":a(" + "b" +- if self._tokenvalue(tokens[-1]).startswith(u'::'): ++ if self._tokenvalue(tokens[-1]).startswith('::'): + t = 'pseudo-element' + else: + t = 'pseudo-class' + tokens[-1] = (t, self._tokenvalue(tokens[-1])+val, lin, col) + +- elif typ == 'FUNCTION' and val == u'not(' and tokens and \ +- u':' == self._tokenvalue(tokens[-1]): +- tokens[-1] = ('negation', u':' + val, lin, tokens[-1][3]) ++ elif typ == 'FUNCTION' and val == 'not(' and tokens and \ ++ ':' == self._tokenvalue(tokens[-1]): ++ tokens[-1] = ('negation', ':' + val, lin, tokens[-1][3]) + elif typ == 'FUNCTION' and tokens\ +- and self._tokenvalue(tokens[-1]).startswith(u':'): ++ and self._tokenvalue(tokens[-1]).startswith(':'): + # pseudo-X: combine to :FUNCTION( or ::FUNCTION( +- if self._tokenvalue(tokens[-1]).startswith(u'::'): ++ if self._tokenvalue(tokens[-1]).startswith('::'): + t = 'pseudo-element' + else: + t = 'pseudo-class' + tokens[-1] = (t, self._tokenvalue(tokens[-1])+val, lin, col) + +- elif val == u'*' and tokens and\ ++ elif val == '*' and tokens and\ + self._type(tokens[-1]) == 'namespace_prefix' and\ +- self._tokenvalue(tokens[-1]).endswith(u'|'): ++ self._tokenvalue(tokens[-1]).endswith('|'): + # combine prefix|* + tokens[-1] = ('universal', self._tokenvalue(tokens[-1])+val, + lin, col) +- elif val == u'*': ++ elif val == '*': + # universal: "*" + tokens.append(('universal', val, lin, col)) + +- elif val == u'|' and tokens and\ ++ elif val == '|' and tokens and\ + self._type(tokens[-1]) in (self._prods.IDENT, 'universal')\ +- and self._tokenvalue(tokens[-1]).find(u'|') == -1: ++ and self._tokenvalue(tokens[-1]).find('|') == -1: + # namespace_prefix: "IDENT|" or "*|" + tokens[-1] = ('namespace_prefix', +- self._tokenvalue(tokens[-1])+u'|', lin, col) +- elif val == u'|': ++ self._tokenvalue(tokens[-1])+'|', lin, col) ++ elif val == '|': + # namespace_prefix: "|" + tokens.append(('namespace_prefix', val, lin, col)) + +@@ -292,7 +292,7 @@ class Selector(cssutils.util.Base2): + 'wellformed': True + } + # used for equality checks and setting of a space combinator +- S = u' ' ++ S = ' ' + + def append(seq, val, typ=None, token=None): + """ +@@ -331,16 +331,16 @@ class Selector(cssutils.util.Base2): + if (typ.endswith('-selector') or typ == 'universal') and not ( + 'attribute-selector' == typ and not prefix): + # att **IS NOT** in default ns +- if prefix == u'*': ++ if prefix == '*': + # *|name: in ANY_NS + namespaceURI = cssutils._ANYNS + elif prefix is None: + # e or *: default namespace with prefix u'' + # or local-name() +- namespaceURI = namespaces.get(u'', None) +- elif prefix == u'': ++ namespaceURI = namespaces.get('', None) ++ elif prefix == '': + # |name or |*: in no (or the empty) namespace +- namespaceURI = u'' ++ namespaceURI = '' + else: + # explicit namespace prefix + # does not raise KeyError, see _SimpleNamespaces +@@ -348,8 +348,8 @@ class Selector(cssutils.util.Base2): + + if namespaceURI is None: + new['wellformed'] = False +- self._log.error(u'Selector: No namespaceURI found ' +- u'for prefix %r' % prefix, ++ self._log.error('Selector: No namespaceURI found ' ++ 'for prefix %r' % prefix, + token=token, + error=xml.dom.NamespaceErr) + return +@@ -403,7 +403,7 @@ class Selector(cssutils.util.Base2): + # S + context = new['context'][-1] + if context.startswith('pseudo-'): +- if seq and seq[-1].value not in u'+-': ++ if seq and seq[-1].value not in '+-': + # e.g. x:func(a + b) + append(seq, S, 'S', token=token) + return expected +@@ -430,7 +430,7 @@ class Selector(cssutils.util.Base2): + else: + new['wellformed'] = False + self._log.error( +- u'Selector: Unexpected universal.', token=token) ++ 'Selector: Unexpected universal.', token=token) + return expected + + def _namespace_prefix(expected, seq, token, tokenizer=None): +@@ -449,7 +449,7 @@ class Selector(cssutils.util.Base2): + else: + new['wellformed'] = False + self._log.error( +- u'Selector: Unexpected namespace prefix.', token=token) ++ 'Selector: Unexpected namespace prefix.', token=token) + return expected + + def _pseudo(expected, seq, token, tokenizer=None): +@@ -474,7 +474,7 @@ class Selector(cssutils.util.Base2): + typ = 'pseudo-element' + append(seq, val, typ, token=token) + +- if val.endswith(u'('): ++ if val.endswith('('): + # function + # "pseudo-" "class" or "element" + new['context'].append(typ) +@@ -490,7 +490,7 @@ class Selector(cssutils.util.Base2): + else: + new['wellformed'] = False + self._log.error( +- u'Selector: Unexpected start of pseudo.', token=token) ++ 'Selector: Unexpected start of pseudo.', token=token) + return expected + + def _expression(expected, seq, token, tokenizer=None): +@@ -503,7 +503,7 @@ class Selector(cssutils.util.Base2): + else: + new['wellformed'] = False + self._log.error( +- u'Selector: Unexpected %s.' % typ, token=token) ++ 'Selector: Unexpected %s.' % typ, token=token) + return expected + + def _attcombinator(expected, seq, token, tokenizer=None): +@@ -519,7 +519,7 @@ class Selector(cssutils.util.Base2): + else: + new['wellformed'] = False + self._log.error( +- u'Selector: Unexpected %s.' % typ, token=token) ++ 'Selector: Unexpected %s.' % typ, token=token) + return expected + + def _string(expected, seq, token, tokenizer=None): +@@ -542,7 +542,7 @@ class Selector(cssutils.util.Base2): + else: + new['wellformed'] = False + self._log.error( +- u'Selector: Unexpected STRING.', token=token) ++ 'Selector: Unexpected STRING.', token=token) + return expected + + def _ident(expected, seq, token, tokenizer=None): +@@ -580,7 +580,7 @@ class Selector(cssutils.util.Base2): + + else: + new['wellformed'] = False +- self._log.error(u'Selector: Unexpected IDENT.', token=token) ++ self._log.error('Selector: Unexpected IDENT.', token=token) + return expected + + def _class(expected, seq, token, tokenizer=None): +@@ -597,7 +597,7 @@ class Selector(cssutils.util.Base2): + + else: + new['wellformed'] = False +- self._log.error(u'Selector: Unexpected class.', token=token) ++ self._log.error('Selector: Unexpected class.', token=token) + return expected + + def _hash(expected, seq, token, tokenizer=None): +@@ -614,7 +614,7 @@ class Selector(cssutils.util.Base2): + + else: + new['wellformed'] = False +- self._log.error(u'Selector: Unexpected HASH.', token=token) ++ self._log.error('Selector: Unexpected HASH.', token=token) + return expected + + def _char(expected, seq, token, tokenizer=None): +@@ -623,7 +623,7 @@ class Selector(cssutils.util.Base2): + val = self._tokenvalue(token) + + # context: attrib +- if u']' == val and 'attrib' == context and ']' in expected: ++ if ']' == val and 'attrib' == context and ']' in expected: + # end of attrib + append(seq, val, 'attribute-end', token=token) + context = new['context'].pop() # attrib is done +@@ -633,14 +633,14 @@ class Selector(cssutils.util.Base2): + else: + return simple_selector_sequence2 + combinator + +- elif u'=' == val and 'attrib' == context\ ++ elif '=' == val and 'attrib' == context\ + and 'combinator' in expected: + # combinator in attrib + append(seq, val, 'equals', token=token) + return attvalue + + # context: negation +- elif u')' == val and 'negation' == context and u')' in expected: ++ elif ')' == val and 'negation' == context and ')' in expected: + # not(negation_arg)" + append(seq, val, 'negation-end', token=token) + new['context'].pop() # negation is done +@@ -648,17 +648,17 @@ class Selector(cssutils.util.Base2): + return simple_selector_sequence + combinator + + # context: pseudo (at least one expression) +- elif val in u'+-' and context.startswith('pseudo-'): ++ elif val in '+-' and context.startswith('pseudo-'): + # :func(+ -)" + _names = {'+': 'plus', '-': 'minus'} +- if val == u'+' and seq and seq[-1].value == S: ++ if val == '+' and seq and seq[-1].value == S: + seq.replace(-1, val, _names[val]) + else: + append(seq, val, _names[val], + token=token) + return expression + +- elif u')' == val and context.startswith('pseudo-') and\ ++ elif ')' == val and context.startswith('pseudo-') and\ + expression == expected: + # :func(expression)" + append(seq, val, 'function-end', token=token) +@@ -669,13 +669,13 @@ class Selector(cssutils.util.Base2): + return simple_selector_sequence + combinator + + # context: ROOT +- elif u'[' == val and 'attrib' in expected: ++ elif '[' == val and 'attrib' in expected: + # start of [attrib] + append(seq, val, 'attribute-start', token=token) + new['context'].append('attrib') + return attname + +- elif val in u'+>~' and 'combinator' in expected: ++ elif val in '+>~' and 'combinator' in expected: + # no other combinator except S may be following + _names = { + '>': 'child', +@@ -687,11 +687,11 @@ class Selector(cssutils.util.Base2): + append(seq, val, _names[val], token=token) + return simple_selector_sequence + +- elif u',' == val: ++ elif ',' == val: + # not a selectorlist + new['wellformed'] = False + self._log.error( +- u'Selector: Single selector only.', ++ 'Selector: Single selector only.', + error=xml.dom.InvalidModificationErr, + token=token) + return expected +@@ -699,7 +699,7 @@ class Selector(cssutils.util.Base2): + else: + new['wellformed'] = False + self._log.error( +- u'Selector: Unexpected CHAR.', token=token) ++ 'Selector: Unexpected CHAR.', token=token) + return expected + + def _negation(expected, seq, token, tokenizer=None): +@@ -713,14 +713,14 @@ class Selector(cssutils.util.Base2): + else: + new['wellformed'] = False + self._log.error( +- u'Selector: Unexpected negation.', token=token) ++ 'Selector: Unexpected negation.', token=token) + return expected + + def _atkeyword(expected, seq, token, tokenizer=None): + "invalidates selector" + new['wellformed'] = False + self._log.error( +- u'Selector: Unexpected ATKEYWORD.', token=token) ++ 'Selector: Unexpected ATKEYWORD.', token=token) + return expected + + +@@ -758,21 +758,21 @@ class Selector(cssutils.util.Base2): + # post condition + if len(new['context']) > 1 or not newseq: + wellformed = False +- self._log.error(u'Selector: Invalid or incomplete selector: %s' ++ self._log.error('Selector: Invalid or incomplete selector: %s' + % self._valuestr(selectorText)) + + if expected == 'element_name': + wellformed = False +- self._log.error(u'Selector: No element name found: %s' ++ self._log.error('Selector: No element name found: %s' + % self._valuestr(selectorText)) + + if expected == simple_selector_sequence and newseq: + wellformed = False +- self._log.error(u'Selector: Cannot end with combinator: %s' ++ self._log.error('Selector: Cannot end with combinator: %s' + % self._valuestr(selectorText)) + + if newseq and hasattr(newseq[-1].value, 'strip') \ +- and newseq[-1].value.strip() == u'': ++ and newseq[-1].value.strip() == '': + del newseq[-1] + + # set +@@ -785,8 +785,8 @@ class Selector(cssutils.util.Base2): + self.__namespaces = self._getUsedNamespaces() + + selectorText = property(_getSelectorText, _setSelectorText, +- doc=u"(DOM) The parsable textual representation of " +- u"the selector.") ++ doc="(DOM) The parsable textual representation of " ++ "the selector.") + + specificity = property(lambda self: self._specificity, + doc="""Specificity of this selector (READONLY). +diff --git a/src/cssutils/css/selectorlist.py b/src/cssutils/css/selectorlist.py +index 2072cd5..184ca92 100644 +--- a/src/cssutils/css/selectorlist.py ++++ b/src/cssutils/css/selectorlist.py +@@ -19,7 +19,7 @@ __all__ = ['SelectorList'] + __docformat__ = 'restructuredtext' + __version__ = '$Id$' + +-from selector import Selector ++from .selector import Selector + import cssutils + import xml.dom + +@@ -49,12 +49,12 @@ class SelectorList(cssutils.util.Base, cssutils.util.ListSeq): + st = (self.selectorText, self._namespaces) + else: + st = self.selectorText +- return u"cssutils.css.%s(selectorText=%r)" % (self.__class__.__name__, ++ return "cssutils.css.%s(selectorText=%r)" % (self.__class__.__name__, + st) + + def __str__(self): +- return u"" % (self.__class__.__name__, ++ return "" % (self.__class__.__name__, + self.selectorText, + self._namespaces, + id(self)) +@@ -200,35 +200,35 @@ class SelectorList(cssutils.util.Base, cssutils.util.ListSeq): + newseq.append(selector) + else: + wellformed = False +- self._log.error(u'SelectorList: Invalid Selector: %s' % ++ self._log.error('SelectorList: Invalid Selector: %s' % + self._valuestr(selectortokens)) + else: + break + + # post condition +- if u',' == expected: ++ if ',' == expected: + wellformed = False +- self._log.error(u'SelectorList: Cannot end with ",": %r' % ++ self._log.error('SelectorList: Cannot end with ",": %r' % + self._valuestr(selectorText)) + elif expected: + wellformed = False +- self._log.error(u'SelectorList: Unknown Syntax: %r' % ++ self._log.error('SelectorList: Unknown Syntax: %r' % + self._valuestr(selectorText)) + if wellformed: + self.seq = newseq + + selectorText = property(_getSelectorText, _setSelectorText, +- doc=u"(cssutils) The textual representation of the " +- u"selector for a rule set.") ++ doc="(cssutils) The textual representation of the " ++ "selector for a rule set.") + + length = property(lambda self: len(self), +- doc=u"The number of :class:`~cssutils.css.Selector` " +- u"objects in the list.") ++ doc="The number of :class:`~cssutils.css.Selector` " ++ "objects in the list.") + + parentRule = property(lambda self: self._parentRule, +- doc=u"(DOM) The CSS rule that contains this " +- u"SelectorList or ``None`` if this SelectorList " +- u"is not attached to a CSSRule.") ++ doc="(DOM) The CSS rule that contains this " ++ "SelectorList or ``None`` if this SelectorList " ++ "is not attached to a CSSRule.") + + wellformed = property(lambda self: bool(len(self.seq))) + +diff --git a/src/cssutils/css/value.py b/src/cssutils/css/value.py +index 22d91ba..34c9a12 100644 +--- a/src/cssutils/css/value.py ++++ b/src/cssutils/css/value.py +@@ -23,7 +23,7 @@ import colorsys + import math + import re + import xml.dom +-import urlparse ++import urllib.parse + + class PropertyValue(cssutils.util._NewBase): + """ +@@ -53,7 +53,7 @@ class PropertyValue(cssutils.util._NewBase): + + if cssText is not None: # may be 0 + if isinstance(cssText, (int, float)): +- cssText = unicode(cssText) # if it is a number ++ cssText = str(cssText) # if it is a number + self.cssText = cssText + + self._readonly = readonly +@@ -73,12 +73,12 @@ class PropertyValue(cssutils.util._NewBase): + yield item + + def __repr__(self): +- return u"cssutils.css.%s(%r)" % (self.__class__.__name__, ++ return "cssutils.css.%s(%r)" % (self.__class__.__name__, + self.cssText) + + def __str__(self): +- return u"" % (self.__class__.__name__, ++ return "" % (self.__class__.__name__, + self.length, self.cssText, id(self)) + + def __items(self, seq=None): +@@ -89,7 +89,7 @@ class PropertyValue(cssutils.util._NewBase): + + def _setCssText(self, cssText): + if isinstance(cssText, (int, float)): +- cssText = unicode(cssText) # if it is a number ++ cssText = str(cssText) # if it is a number + """ + Format:: + +@@ -135,7 +135,7 @@ class PropertyValue(cssutils.util._NewBase): + self._checkReadonly() + + # used as operator is , / or S +- nextSor = u',/' ++ nextSor = ',/' + term = Choice(_ColorProd(self, nextSor), + _DimensionProd(self, nextSor), + _URIProd(self, nextSor), +@@ -169,7 +169,7 @@ class PropertyValue(cssutils.util._NewBase): + minmax=lambda: (0, None))) + # parse + ok, seq, store, unused = ProdParser().parse(cssText, +- u'PropertyValue', ++ 'PropertyValue', + prods) + # must be at least one value! + ok = ok and len(list(self.__items(seq))) > 0 +@@ -183,7 +183,7 @@ class PropertyValue(cssutils.util._NewBase): + if ok: + self._setSeq(seq) + else: +- self._log.error(u'PropertyValue: Unknown syntax or no value: %s' % ++ self._log.error('PropertyValue: Unknown syntax or no value: %s' % + self._valuestr(cssText)) + + cssText = property(lambda self: cssutils.ser.do_css_PropertyValue(self), +@@ -204,12 +204,12 @@ class PropertyValue(cssutils.util._NewBase): + return self[index] + + length = property(lambda self: len(self), +- doc=u"Number of values set.") ++ doc="Number of values set.") + + value = property(lambda self: cssutils.ser.do_css_PropertyValue(self, + valuesOnly=True), +- doc=u"A string representation of the current value " +- u"without any comments used for validation.") ++ doc="A string representation of the current value " ++ "without any comments used for validation.") + + + class Value(cssutils.util._NewBase): +@@ -219,24 +219,24 @@ class Value(cssutils.util._NewBase): + as Value objects. Other values like e.g. FUNCTIONs are represented by + subclasses with an extended API. + """ +- IDENT = u'IDENT' +- STRING = u'STRING' +- UNICODE_RANGE = u'UNICODE-RANGE' +- URI = u'URI' ++ IDENT = 'IDENT' ++ STRING = 'STRING' ++ UNICODE_RANGE = 'UNICODE-RANGE' ++ URI = 'URI' + +- DIMENSION = u'DIMENSION' +- NUMBER = u'NUMBER' +- PERCENTAGE = u'PERCENTAGE' ++ DIMENSION = 'DIMENSION' ++ NUMBER = 'NUMBER' ++ PERCENTAGE = 'PERCENTAGE' + +- COLOR_VALUE = u'COLOR_VALUE' +- HASH = u'HASH' ++ COLOR_VALUE = 'COLOR_VALUE' ++ HASH = 'HASH' + +- FUNCTION = u'FUNCTION' +- CALC = u'CALC' +- VARIABLE = u'VARIABLE' ++ FUNCTION = 'FUNCTION' ++ CALC = 'CALC' ++ VARIABLE = 'VARIABLE' + + _type = None +- _value = u'' ++ _value = '' + + def __init__(self, cssText=None, parent=None, readonly=False): + super(Value, self).__init__() +@@ -248,11 +248,11 @@ class Value(cssutils.util._NewBase): + self.cssText = cssText + + def __repr__(self): +- return u"cssutils.css.%s(%r)" % (self.__class__.__name__, ++ return "cssutils.css.%s(%r)" % (self.__class__.__name__, + self.cssText) + + def __str__(self): +- return u""\ ++ return ""\ + % (self.__class__.__name__, + self.type, self.value, self.cssText, + id(self)) +@@ -265,7 +265,7 @@ class Value(cssutils.util._NewBase): + PreDef.string(stop=True), + PreDef.unicode_range(stop=True), + ) +- ok, seq, store, unused = ProdParser().parse(cssText, u'Value', prods) ++ ok, seq, store, unused = ProdParser().parse(cssText, 'Value', prods) + self.wellformed = ok + if ok: + # only 1 value anyway! +@@ -276,20 +276,20 @@ class Value(cssutils.util._NewBase): + + cssText = property(lambda self: cssutils.ser.do_css_Value(self), + _setCssText, +- doc=u'String value of this value.') ++ doc='String value of this value.') + + type = property(lambda self: self._type, #_setType, +- doc=u"Type of this value, for now the production type " +- u"like e.g. `DIMENSION` or `STRING`. All types are " +- u"defined as constants in :class:`~cssutils.css.Value`.") ++ doc="Type of this value, for now the production type " ++ "like e.g. `DIMENSION` or `STRING`. All types are " ++ "defined as constants in :class:`~cssutils.css.Value`.") + + def _setValue(self, value): + # TODO: check! + self._value = value + + value = property(lambda self: self._value, _setValue, +- doc=u"Actual value if possible: An int or float or else " +- u" a string") ++ doc="Actual value if possible: An int or float or else " ++ " a string") + + + class ColorValue(Value): +@@ -298,7 +298,7 @@ class ColorValue(Value): + + TODO: Color Keywords + """ +- from colors import COLORS ++ from .colors import COLORS + + type = Value.COLOR_VALUE + # hexcolor, FUNCTION? +@@ -309,8 +309,8 @@ class ColorValue(Value): + _alpha = 0 + + def __str__(self): +- return u""\ ++ return ""\ + % (self.__class__.__name__, + self.type, self.value, + self.colorType, self.red, self.green, self.blue, self.alpha, +@@ -335,7 +335,7 @@ class ColorValue(Value): + ) + noalp = Sequence(Prod(name='FUNCTION', + match=lambda t, v: t == types.FUNCTION and +- v in (u'rgb(', u'hsl('), ++ v in ('rgb(', 'hsl('), + toSeq=lambda t, tokens: (t[0], normalize(t[1]))), + component, + Sequence(PreDef.comma(optional=True), +@@ -346,7 +346,7 @@ class ColorValue(Value): + ) + witha = Sequence(Prod(name='FUNCTION', + match=lambda t, v: t == types.FUNCTION and +- v in (u'rgba(', u'hsla('), ++ v in ('rgba(', 'hsla('), + toSeq=lambda t, tokens: (t[0], + normalize(t[1])) + ), +@@ -359,7 +359,7 @@ class ColorValue(Value): + ) + namedcolor = Prod(name='Named Color', + match=lambda t, v: t == 'IDENT' and ( +- normalize(v) in self.COLORS.keys() ++ normalize(v) in list(self.COLORS.keys()) + ), + stop=True) + +@@ -374,9 +374,9 @@ class ColorValue(Value): + self.wellformed = ok + if ok: + t, v = seq[0].type, seq[0].value +- if u'IDENT' == t: ++ if 'IDENT' == t: + rgba = self.COLORS[normalize(v)] +- if u'HASH' == t: ++ if 'HASH' == t: + if len(v) == 4: + # HASH #rgb + rgba = (int(2*v[1], 16), +@@ -390,24 +390,24 @@ class ColorValue(Value): + int(v[5:7], 16), + 1.0) + +- elif u'FUNCTION' == t: +- functiontype, raw, check = None, [], u'' ++ elif 'FUNCTION' == t: ++ functiontype, raw, check = None, [], '' + HSL = False + + for item in seq: + try: + type_ = item.value.type +- except AttributeError, e: ++ except AttributeError as e: + # type of function, e.g. rgb( + if item.type == 'FUNCTION': + functiontype = item.value +- HSL = functiontype in (u'hsl(', u'hsla(') ++ HSL = functiontype in ('hsl(', 'hsla(') + continue + + # save components + if type_ == Value.NUMBER: + raw.append(item.value.value) +- check += u'N' ++ check += 'N' + elif type_ == Value.PERCENTAGE: + if HSL: + # save as percentage fraction +@@ -415,7 +415,7 @@ class ColorValue(Value): + else: + # save as real value of percentage of 255 + raw.append(int(255 * item.value.value / 100)) +- check += u'P' ++ check += 'P' + + if HSL: + # convert to rgb +@@ -439,14 +439,14 @@ class ColorValue(Value): + rgba.append(1.0) + + # validate +- checks = {u'rgb(': ('NNN', 'PPP'), +- u'rgba(': ('NNNN', 'PPPN'), +- u'hsl(': ('NPP',), +- u'hsla(': ('NPPN',) ++ checks = {'rgb(': ('NNN', 'PPP'), ++ 'rgba(': ('NNNN', 'PPPN'), ++ 'hsl(': ('NPP',), ++ 'hsla(': ('NPPN',) + } + if check not in checks[functiontype]: +- self._log.error(u'ColorValue has invalid %s) parameters: ' +- u'%s (N=Number, P=Percentage)' % ++ self._log.error('ColorValue has invalid %s) parameters: ' ++ '%s (N=Number, P=Percentage)' % + (functiontype, check)) + + self._colorType = t +@@ -455,34 +455,34 @@ class ColorValue(Value): + + cssText = property(lambda self: cssutils.ser.do_css_ColorValue(self), + _setCssText, +- doc=u"String value of this value.") ++ doc="String value of this value.") + + value = property(lambda self: cssutils.ser.do_css_CSSFunction(self, True), +- doc=u'Same as cssText but without comments.') ++ doc='Same as cssText but without comments.') + + type = property(lambda self: Value.COLOR_VALUE, +- doc=u"Type is fixed to Value.COLOR_VALUE.") ++ doc="Type is fixed to Value.COLOR_VALUE.") + + def _getName(self): +- for n, v in self.COLORS.items(): ++ for n, v in list(self.COLORS.items()): + if v == (self.red, self.green, self.blue, self.alpha): + return n + + colorType = property(lambda self: self._colorType, +- doc=u"IDENT (red), HASH (#f00) or FUNCTION (rgb(255, 0, 0).") ++ doc="IDENT (red), HASH (#f00) or FUNCTION (rgb(255, 0, 0).") + + name = property(_getName, +- doc=u'Name of the color if known (in ColorValue.COLORS) ' +- u'else None') ++ doc='Name of the color if known (in ColorValue.COLORS) ' ++ 'else None') + + red = property(lambda self: self._red, +- doc=u'red part as integer between 0 and 255') ++ doc='red part as integer between 0 and 255') + green = property(lambda self: self._green, +- doc=u'green part as integer between 0 and 255') ++ doc='green part as integer between 0 and 255') + blue = property(lambda self: self._blue, +- doc=u'blue part as integer between 0 and 255') ++ doc='blue part as integer between 0 and 255') + alpha = property(lambda self: self._alpha, +- doc=u'alpha part as float between 0.0 and 1.0') ++ doc='alpha part as float between 0.0 and 1.0') + + class DimensionValue(Value): + """ +@@ -490,12 +490,12 @@ class DimensionValue(Value): + + Covers DIMENSION, PERCENTAGE or NUMBER values. + """ +- __reUnNumDim = re.compile(ur'^([+-]?)(\d*\.\d+|\d+)(.*)$', re.I | re.U | re.X) ++ __reUnNumDim = re.compile(r'^([+-]?)(\d*\.\d+|\d+)(.*)$', re.I | re.U | re.X) + _dimension = None + _sign = None + + def __str__(self): +- return u""\ ++ return ""\ + % (self.__class__.__name__, + self.type, self.value, self.dimension, self.cssText, + id(self)) +@@ -510,7 +510,7 @@ class DimensionValue(Value): + ) + ) + ok, seq, store, unused = ProdParser().parse(cssText, +- u'DimensionValue', ++ 'DimensionValue', + prods) + self.wellformed = ok + if ok: +@@ -518,7 +518,7 @@ class DimensionValue(Value): + + sign, v, d = self.__reUnNumDim.findall( + normalize(item.value))[0] +- if u'.' in v: ++ if '.' in v: + val = float(sign + v) + else: + val = int(sign + v) +@@ -536,11 +536,11 @@ class DimensionValue(Value): + + cssText = property(lambda self: cssutils.ser.do_css_Value(self), + _setCssText, +- doc=u"String value of this value including dimension.") ++ doc="String value of this value including dimension.") + + dimension = property(lambda self: self._dimension, #_setValue, +- doc=u"Dimension if a DIMENSION or PERCENTAGE value, " +- u"else None") ++ doc="Dimension if a DIMENSION or PERCENTAGE value, " ++ "else None") + class URIValue(Value): + """ + An URI value like ``url(example.png)``. +@@ -549,7 +549,7 @@ class URIValue(Value): + _uri = Value._value + + def __str__(self): +- return u""\ ++ return ""\ + % (self.__class__.__name__, + self.type, self.value, self.uri, self.cssText, + id(self)) +@@ -559,7 +559,7 @@ class URIValue(Value): + + prods = Sequence(PreDef.uri(stop=True)) + +- ok, seq, store, unused = ProdParser().parse(cssText, u'URIValue', prods) ++ ok, seq, store, unused = ProdParser().parse(cssText, 'URIValue', prods) + self.wellformed = ok + if ok: + # only 1 value only anyway +@@ -570,14 +570,14 @@ class URIValue(Value): + + cssText = property(lambda self: cssutils.ser.do_css_Value(self), + _setCssText, +- doc=u'String value of this value.') ++ doc='String value of this value.') + + def _setUri(self, uri): + # TODO: check? + self._value = uri + + uri = property(lambda self: self._value, _setUri, +- doc=u"Actual URL without delimiters or the empty string") ++ doc="Actual URL without delimiters or the empty string") + + def absoluteUri(self): + """Actual URL, made absolute if possible, else same as `uri`.""" +@@ -586,10 +586,10 @@ class URIValue(Value): + try: + # TODO: better way? + styleSheet = self.parent.parent.parent.parentRule.parentStyleSheet +- except AttributeError, e: ++ except AttributeError as e: + return self.uri + else: +- return urlparse.urljoin(styleSheet.href, self.uri) ++ return urllib.parse.urljoin(styleSheet.href, self.uri) + + absoluteUri = property(absoluteUri, doc=absoluteUri.__doc__) + +@@ -636,13 +636,13 @@ class CSSFunction(Value): + + cssText = property(lambda self: cssutils.ser.do_css_CSSFunction(self), + _setCssText, +- doc=u"String value of this value.") ++ doc="String value of this value.") + + value = property(lambda self: cssutils.ser.do_css_CSSFunction(self, True), +- doc=u'Same as cssText but without comments.') ++ doc='Same as cssText but without comments.') + + type = property(lambda self: Value.FUNCTION, +- doc=u"Type is fixed to Value.FUNCTION.") ++ doc="Type is fixed to Value.FUNCTION.") + + class MSValue(CSSFunction): + """An IE specific Microsoft only function value which is much looser +@@ -678,7 +678,7 @@ class MSValue(CSSFunction): + func, + #_CSSFunctionProd(self), + Prod(name='MSValuePart', +- match=lambda t, v: v != u')', ++ match=lambda t, v: v != ')', + toSeq=lambda t, tokens: (t[0], t[1]) + ) + ), +@@ -693,7 +693,7 @@ class MSValue(CSSFunction): + + cssText = property(lambda self: cssutils.ser.do_css_MSValue(self), + _setCssText, +- doc=u"String value of this value.") ++ doc="String value of this value.") + + + class CSSCalc(CSSFunction): +@@ -705,7 +705,7 @@ class CSSCalc(CSSFunction): + _functionName = 'CSSCalc' + + def __str__(self): +- return u"" % ( ++ return "" % ( + self.__class__.__name__, id(self)) + + def _setCssText(self, cssText): +@@ -714,7 +714,7 @@ class CSSCalc(CSSFunction): + types = self._prods # rename! + + _operator = Choice(Prod(name='Operator */', +- match=lambda t, v: v in u'*/', ++ match=lambda t, v: v in '*/', + toSeq=lambda t, tokens: (t[0], t[1]) + ), + Sequence( +@@ -722,14 +722,14 @@ class CSSCalc(CSSFunction): + Choice( + Sequence( + Prod(name='Operator */', +- match=lambda t, v: v in u'*/', ++ match=lambda t, v: v in '*/', + toSeq=lambda t, tokens: (t[0], t[1]) + ), + PreDef.S(optional=True) + ), + Sequence( + Prod(name='Operator +-', +- match=lambda t, v: v in u'+-', ++ match=lambda t, v: v in '+-', + toSeq=lambda t, tokens: (t[0], t[1]) + ), + PreDef.S() +@@ -744,7 +744,7 @@ class CSSCalc(CSSFunction): + + prods = Sequence(Prod(name='CALC', + match=lambda t, v: t == types.FUNCTION and +- normalize(v) == u'calc(' ++ normalize(v) == 'calc(' + ), + PreDef.S(optional=True), + _operant(), +@@ -757,7 +757,7 @@ class CSSCalc(CSSFunction): + + # store: name of variable + ok, seq, store, unused = ProdParser().parse(cssText, +- u'CSSCalc', ++ 'CSSCalc', + prods, + checkS=True) + self.wellformed = ok +@@ -766,10 +766,10 @@ class CSSCalc(CSSFunction): + + + cssText = property(lambda self: cssutils.ser.do_css_CSSCalc(self), +- _setCssText, doc=u"String representation of calc function.") ++ _setCssText, doc="String representation of calc function.") + + type = property(lambda self: Value.CALC, +- doc=u"Type is fixed to Value.CALC.") ++ doc="Type is fixed to Value.CALC.") + + + +@@ -785,7 +785,7 @@ class CSSVariable(CSSFunction): + _fallback = None + + def __str__(self): +- return u"" % ( ++ return "" % ( + self.__class__.__name__, self.name, self.value, id(self)) + + def _setCssText(self, cssText): +@@ -794,7 +794,7 @@ class CSSVariable(CSSFunction): + types = self._prods # rename! + prods = Sequence(Prod(name='var', + match=lambda t, v: t == types.FUNCTION and +- normalize(v) == u'var(' ++ normalize(v) == 'var(' + ), + PreDef.ident(toStore='ident'), + Sequence(PreDef.comma(), +@@ -813,7 +813,7 @@ class CSSVariable(CSSFunction): + # store: name of variable + store = {'ident': None, 'fallback': None} + ok, seq, store, unused = ProdParser().parse(cssText, +- u'CSSVariable', ++ 'CSSVariable', + prods) + self.wellformed = ok + +@@ -827,19 +827,19 @@ class CSSVariable(CSSFunction): + self._setSeq(seq) + + cssText = property(lambda self: cssutils.ser.do_css_CSSVariable(self), +- _setCssText, doc=u"String representation of variable.") ++ _setCssText, doc="String representation of variable.") + + # TODO: writable? check if var (value) available? + name = property(lambda self: self._name, +- doc=u"The name identifier of this variable referring to " +- u"a value in a " +- u":class:`cssutils.css.CSSVariablesDeclaration`.") ++ doc="The name identifier of this variable referring to " ++ "a value in a " ++ ":class:`cssutils.css.CSSVariablesDeclaration`.") + + fallback = property(lambda self: self._fallback, +- doc=u"The fallback Value of this variable") ++ doc="The fallback Value of this variable") + + type = property(lambda self: Value.VARIABLE, +- doc=u"Type is fixed to Value.VARIABLE.") ++ doc="Type is fixed to Value.VARIABLE.") + + def _getValue(self): + "Find contained sheet and @variables there" +@@ -861,7 +861,7 @@ class CSSVariable(CSSFunction): + return None + + value = property(_getValue, +- doc=u'The resolved actual value or None.') ++ doc='The resolved actual value or None.') + + + +@@ -879,12 +879,12 @@ def _ValueProd(parent, nextSor=False, toStore=None): + + def _DimensionProd(parent, nextSor=False, toStore=None): + return Prod(name='Dimension', +- match=lambda t, v: t in (u'DIMENSION', +- u'NUMBER', +- u'PERCENTAGE'), ++ match=lambda t, v: t in ('DIMENSION', ++ 'NUMBER', ++ 'PERCENTAGE'), + nextSor = nextSor, + toStore=toStore, +- toSeq=lambda t, tokens: (u'DIMENSION', DimensionValue( ++ toSeq=lambda t, tokens: ('DIMENSION', DimensionValue( + pushtoken(t, + tokens), + parent=parent) +@@ -912,13 +912,13 @@ def _ColorProd(parent, nextSor=False, toStore=None): + reHexcolor.match(v) + ) or + (t == 'FUNCTION' and +- normalize(v) in (u'rgb(', +- u'rgba(', +- u'hsl(', +- u'hsla(') ++ normalize(v) in ('rgb(', ++ 'rgba(', ++ 'hsl(', ++ 'hsla(') + ) or + (t == 'IDENT' and +- normalize(v) in ColorValue.COLORS.keys() ++ normalize(v) in list(ColorValue.COLORS.keys()) + ), + nextSor = nextSor, + toStore=toStore, +@@ -942,7 +942,7 @@ def _CSSFunctionProd(parent, nextSor=False, toStore=None): + def _CalcValueProd(parent, nextSor=False, toStore=None): + return Prod(name=CSSCalc._functionName, + match=lambda t, v: t == PreDef.types.FUNCTION and +- normalize(v) == u'calc(', ++ normalize(v) == 'calc(', + toStore=toStore, + toSeq=lambda t, tokens: (CSSCalc._functionName, + CSSCalc( +@@ -964,21 +964,21 @@ def _CSSVariableProd(parent, nextSor=False, toStore=None): + def _MSValueProd(parent, nextSor=False): + return Prod(name=MSValue._functionName, + match=lambda t, v: (#t == self._prods.FUNCTION and ( +- normalize(v) in (u'expression(', +- u'alpha(', +- u'blur(', +- u'chroma(', +- u'dropshadow(', +- u'fliph(', +- u'flipv(', +- u'glow(', +- u'gray(', +- u'invert(', +- u'mask(', +- u'shadow(', +- u'wave(', +- u'xray(') or +- v.startswith(u'progid:DXImageTransform.Microsoft.') ++ normalize(v) in ('expression(', ++ 'alpha(', ++ 'blur(', ++ 'chroma(', ++ 'dropshadow(', ++ 'fliph(', ++ 'flipv(', ++ 'glow(', ++ 'gray(', ++ 'invert(', ++ 'mask(', ++ 'shadow(', ++ 'wave(', ++ 'xray(') or ++ v.startswith('progid:DXImageTransform.Microsoft.') + ), + nextSor=nextSor, + toSeq=lambda t, tokens: (MSValue._functionName, +diff --git a/src/cssutils/cssproductions.py b/src/cssutils/cssproductions.py +index 84ba954..4fa4ed3 100644 +--- a/src/cssutils/cssproductions.py ++++ b/src/cssutils/cssproductions.py +@@ -107,19 +107,19 @@ class CSSProductions(object): + EOF = True + # removed from productions as they simply are ATKEYWORD until + # tokenizing +- CHARSET_SYM = u'CHARSET_SYM' +- FONT_FACE_SYM = u'FONT_FACE_SYM' +- MEDIA_SYM = u'MEDIA_SYM' +- IMPORT_SYM = u'IMPORT_SYM' +- NAMESPACE_SYM = u'NAMESPACE_SYM' +- PAGE_SYM = u'PAGE_SYM' +- VARIABLES_SYM = u'VARIABLES_SYM' ++ CHARSET_SYM = 'CHARSET_SYM' ++ FONT_FACE_SYM = 'FONT_FACE_SYM' ++ MEDIA_SYM = 'MEDIA_SYM' ++ IMPORT_SYM = 'IMPORT_SYM' ++ NAMESPACE_SYM = 'NAMESPACE_SYM' ++ PAGE_SYM = 'PAGE_SYM' ++ VARIABLES_SYM = 'VARIABLES_SYM' + + for i, t in enumerate(PRODUCTIONS): + setattr(CSSProductions, t[0].replace('-', '_'), t[0]) + + + # may be enabled by settings.set +-_DXImageTransform = (u'FUNCTION', +- ur'progid\:DXImageTransform\.Microsoft\..+\(' ++_DXImageTransform = ('FUNCTION', ++ r'progid\:DXImageTransform\.Microsoft\..+\(' + ) +diff --git a/src/cssutils/errorhandler.py b/src/cssutils/errorhandler.py +index 916adff..dc4b1e3 100644 +--- a/src/cssutils/errorhandler.py ++++ b/src/cssutils/errorhandler.py +@@ -19,7 +19,7 @@ __docformat__ = 'restructuredtext' + __version__ = '$Id$' + + import logging +-import urllib2 ++import urllib.request, urllib.error, urllib.parse + import xml.dom + + class _ErrorHandler(object): +@@ -70,7 +70,7 @@ class _ErrorHandler(object): + raise AttributeError( + '(errorhandler) No Attribute %r found' % name) + +- def __handle(self, msg=u'', token=None, error=xml.dom.SyntaxErr, ++ def __handle(self, msg='', token=None, error=xml.dom.SyntaxErr, + neverraise=False, args=None): + """ + handles all calls +@@ -86,11 +86,11 @@ class _ErrorHandler(object): + value, line, col = token[1], token[2], token[3] + else: + value, line, col = token.value, token.line, token.col +- msg = u'%s [%s:%s: %s]' % ( ++ msg = '%s [%s:%s: %s]' % ( + msg, line, col, value) + + if error and self.raiseExceptions and not neverraise: +- if isinstance(error, urllib2.HTTPError) or isinstance(error, urllib2.URLError): ++ if isinstance(error, urllib.error.HTTPError) or isinstance(error, urllib.error.URLError): + raise + elif issubclass(error, xml.dom.DOMException): + error.line = line +diff --git a/src/cssutils/helper.py b/src/cssutils/helper.py +index 7eeb7a2..320074b 100644 +--- a/src/cssutils/helper.py ++++ b/src/cssutils/helper.py +@@ -6,7 +6,7 @@ __version__ = '$Id: errorhandler.py 1234 2008-05-22 20:26:12Z cthedot $' + import os + import re + import sys +-import urllib ++import urllib.request, urllib.parse, urllib.error + + class Deprecated(object): + """This is a decorator which can be used to mark functions +@@ -33,7 +33,7 @@ class Deprecated(object): + return newFunc + + # simple escapes, all non unicodes +-_simpleescapes = re.compile(ur'(\\[^0-9a-fA-F])').sub ++_simpleescapes = re.compile(r'(\\[^0-9a-fA-F])').sub + def normalize(x): + """ + normalizes x, namely: +@@ -53,7 +53,7 @@ def normalize(x): + + def path2url(path): + """Return file URL of `path`""" +- return u'file:' + urllib.pathname2url(os.path.abspath(path)) ++ return 'file:' + urllib.request.pathname2url(os.path.abspath(path)) + + def pushtoken(token, tokens): + """Return new generator starting with token followed by all tokens in +@@ -70,15 +70,15 @@ def string(value): + ``a \'string`` => ``'a \'string'`` + """ + # \n = 0xa, \r = 0xd, \f = 0xc +- value = value.replace(u'\n', u'\\a ').replace( +- u'\r', u'\\d ').replace( +- u'\f', u'\\c ').replace( +- u'"', u'\\"') ++ value = value.replace('\n', '\\a ').replace( ++ '\r', '\\d ').replace( ++ '\f', '\\c ').replace( ++ '"', '\\"') + +- if value.endswith(u'\\'): +- value = value[:-1] + u'\\\\' ++ if value.endswith('\\'): ++ value = value[:-1] + '\\\\' + +- return u'"%s"' % value ++ return '"%s"' % value + + def stringvalue(string): + """ +@@ -87,9 +87,9 @@ def stringvalue(string): + + ``'a \'string'`` => ``a 'string`` + """ +- return string.replace(u'\\'+string[0], string[0])[1:-1] ++ return string.replace('\\'+string[0], string[0])[1:-1] + +-_match_forbidden_in_uri = re.compile(ur'''.*?[\(\)\s\;,'"]''', re.U).match ++_match_forbidden_in_uri = re.compile(r'''.*?[\(\)\s\;,'"]''', re.U).match + def uri(value): + """ + Serialize value by adding ``url()`` and with quotes if needed e.g.:: +@@ -98,7 +98,7 @@ def uri(value): + """ + if _match_forbidden_in_uri(value): + value = string(value) +- return u'url(%s)' % value ++ return 'url(%s)' % value + + def urivalue(uri): + """ +diff --git a/src/cssutils/parse.py b/src/cssutils/parse.py +index 4b25e4e..1483690 100644 +--- a/src/cssutils/parse.py ++++ b/src/cssutils/parse.py +@@ -4,13 +4,13 @@ __all__ = ['CSSParser'] + __docformat__ = 'restructuredtext' + __version__ = '$Id$' + +-from helper import path2url ++from .helper import path2url + import codecs + import cssutils + import os + import sys +-import tokenize2 +-import urllib ++from . import tokenize2 ++import urllib.request, urllib.parse, urllib.error + + from cssutils import css + +diff --git a/src/cssutils/prodparser.py b/src/cssutils/prodparser.py +index 140fb81..877ce76 100644 +--- a/src/cssutils/prodparser.py ++++ b/src/cssutils/prodparser.py +@@ -18,7 +18,7 @@ __all__ = ['ProdParser', 'Sequence', 'Choice', 'Prod', 'PreDef'] + __docformat__ = 'restructuredtext' + __version__ = '$Id: parse.py 1418 2008-08-09 19:27:50Z cthedot $' + +-from helper import pushtoken ++from .helper import pushtoken + import cssutils + import itertools + import re +@@ -62,7 +62,7 @@ class Choice(object): + + try: + self.optional = options['optional'] +- except KeyError, e: ++ except KeyError as e: + for p in self._prods: + if p.optional: + self.optional = True +@@ -107,17 +107,17 @@ class Choice(object): + else: + if not optional: + # None matched but also None is optional +- raise NoMatch(u'No match for %s in %s' % (token, self)) ++ raise NoMatch('No match for %s in %s' % (token, self)) + #raise ParseError(u'No match in %s for %s' % (self, token)) + elif token: +- raise Exhausted(u'Extra token') ++ raise Exhausted('Extra token') + + def __repr__(self): + return "" % ( + self.__class__.__name__, self.__str__(), self.optional, id(self)) + + def __str__(self): +- return u'Choice(%s)' % u', '.join([str(x) for x in self._prods]) ++ return 'Choice(%s)' % ', '.join([str(x) for x in self._prods]) + + + class Sequence(object): +@@ -144,7 +144,7 @@ class Sequence(object): + self._max = sys.maxsize + except AttributeError: + # py<2.6 +- self._max = sys.maxint ++ self._max = sys.maxsize + + self._prodcount = len(self._prods) + self.reset() +@@ -212,26 +212,26 @@ class Sequence(object): + continue + + elif round < self._min or self._roundstarted: #or (round == 0 and self._min == 0): +- raise Missing(u'Missing token for production %s' % p) ++ raise Missing('Missing token for production %s' % p) + + elif not token: + if self._roundstarted: +- raise Missing(u'Missing token for production %s' % p) ++ raise Missing('Missing token for production %s' % p) + else: + raise Done() + + else: +- raise NoMatch(u'No match for %s in %s' % (token, self)) ++ raise NoMatch('No match for %s in %s' % (token, self)) + + if token: +- raise Exhausted(u'Extra token') ++ raise Exhausted('Extra token') + + def __repr__(self): + return "" % ( + self.__class__.__name__, self.__str__(), self.optional, id(self)) + + def __str__(self): +- return u'Sequence(%s)' % u', '.join([str(x) for x in self._prods]) ++ return 'Sequence(%s)' % ', '.join([str(x) for x in self._prods]) + + + +@@ -356,7 +356,7 @@ class ProdParser(object): + """Build a generator which is the only thing that is parsed! + old classes may use lists etc + """ +- if isinstance(text, basestring): ++ if isinstance(text, str): + # DEFAULT, to tokenize strip space + return tokenizer.tokenize(text.strip()) + +@@ -387,7 +387,7 @@ class ProdParser(object): + for token in tokens: + if token[0] == self.types.S: + try: +- next_ = tokens.next() ++ next_ = next(tokens) + except StopIteration: + yield token + else: +@@ -450,7 +450,7 @@ class ProdParser(object): + tokens = self._texttotokens(text) + + if not tokens: +- self._log.error(u'No content to parse.') ++ self._log.error('No content to parse.') + return False, [], None, None + + seq = cssutils.util.Seq(readonly=False) +@@ -473,9 +473,9 @@ class ProdParser(object): + try: + #print debug, "SAVED", savedTokens + token = savedTokens.pop() +- except IndexError, e: ++ except IndexError as e: + try: +- token = tokens.next() ++ token = next(tokens) + except StopIteration: + break + +@@ -503,7 +503,7 @@ class ProdParser(object): + elif type_ == self.types.INVALID: + # invalidate parse + wellformed = False +- self._log.error(u'Invalid token: %r' % (token,)) ++ self._log.error('Invalid token: %r' % (token,)) + break + + elif type_ == 'EOF': +@@ -519,7 +519,7 @@ class ProdParser(object): + # find next matching production + try: + prod = prods[-1].nextProd(token) +- except (Exhausted, NoMatch), e: ++ except (Exhausted, NoMatch) as e: + # try next + prod = None + +@@ -536,7 +536,7 @@ class ProdParser(object): + else: + raise NoMatch('No match') + +- except NoMatch, e: ++ except NoMatch as e: + if stopIfNoMoreMatch: # and token: + #print "\t1stopIfNoMoreMatch", e, token, prod, 'PUSHING' + #tokenizer.push(token) +@@ -546,10 +546,10 @@ class ProdParser(object): + + else: + wellformed = False +- self._log.error(u'%s: %s: %r' % (name, e, token)) ++ self._log.error('%s: %s: %r' % (name, e, token)) + break + +- except ParseError, e: ++ except ParseError as e: + # needed??? + if stopIfNoMoreMatch: # and token: + #print "\t2stopIfNoMoreMatch", e, token, prod +@@ -559,7 +559,7 @@ class ProdParser(object): + + else: + wellformed = False +- self._log.error(u'%s: %s: %r' % (name, e, token)) ++ self._log.error('%s: %s: %r' % (name, e, token)) + break + + else: +@@ -615,21 +615,21 @@ class ProdParser(object): + # all productions exhausted? + try: + prod = prods[-1].nextProd(token=None) +- except Done, e: ++ except Done as e: + # ok + prod = None + +- except Missing, e: ++ except Missing as e: + prod = None + # last was a S operator which may End a Sequence, then ok + if hasattr(lastprod, 'mayEnd') and not lastprod.mayEnd: + wellformed = False +- self._log.error(u'%s: %s' % (name, e)) ++ self._log.error('%s: %s' % (name, e)) + +- except ParseError, e: ++ except ParseError as e: + prod = None + wellformed = False +- self._log.error(u'%s: %s' % (name, e)) ++ self._log.error('%s: %s' % (name, e)) + + else: + if prods[-1].optional: +@@ -640,7 +640,7 @@ class ProdParser(object): + + if prod and not prod.optional: + wellformed = False +- self._log.error(u'%s: Missing token for production %r' ++ self._log.error('%s: Missing token for production %r' + % (name, str(prod))) + break + elif len(prods) > 1: +@@ -650,7 +650,7 @@ class ProdParser(object): + break + + if not emptyOk and not len(seq): +- self._log.error(u'No content to parse.') ++ self._log.error('No content to parse.') + return False, [], None, None + + # trim S from end +@@ -667,13 +667,13 @@ class PreDef(object): + + @staticmethod + def calc(toSeq=None, nextSor=False): +- return Prod(name=u'calcfunction', +- match=lambda t, v: u'calc(' == cssutils.helper.normalize(v), ++ return Prod(name='calcfunction', ++ match=lambda t, v: 'calc(' == cssutils.helper.normalize(v), + toSeq=toSeq, + nextSor=nextSor) + + @staticmethod +- def char(name='char', char=u',', toSeq=None, ++ def char(name='char', char=',', toSeq=None, + stop=False, stopAndKeep=False, mayEnd=False, + stopIfNoMoreMatch=False, + optional=False, # WAS: optional=True, +@@ -687,11 +687,11 @@ class PreDef(object): + + @staticmethod + def comma(optional=False, toSeq=None): +- return PreDef.char(u'comma', u',', optional=optional, toSeq=toSeq) ++ return PreDef.char('comma', ',', optional=optional, toSeq=toSeq) + + @staticmethod + def comment(parent=None): +- return Prod(name=u'comment', ++ return Prod(name='comment', + match=lambda t, v: t == 'COMMENT', + toSeq=lambda t, tokens: (t[0], cssutils.css.CSSComment([1], + parentRule=parent)), +@@ -701,7 +701,7 @@ class PreDef(object): + + @staticmethod + def dimension(nextSor=False, stop=False): +- return Prod(name=u'dimension', ++ return Prod(name='dimension', + match=lambda t, v: t == PreDef.types.DIMENSION, + toSeq=lambda t, tokens: (t[0], cssutils.helper.normalize(t[1])), + stop=stop, +@@ -709,7 +709,7 @@ class PreDef(object): + + @staticmethod + def function(toSeq=None, nextSor=False, toStore=None): +- return Prod(name=u'function', ++ return Prod(name='function', + match=lambda t, v: t == PreDef.types.FUNCTION, + toStore=toStore, + toSeq=toSeq, +@@ -718,7 +718,7 @@ class PreDef(object): + @staticmethod + def funcEnd(stop=False, mayEnd=False): + ")" +- return PreDef.char(u'end FUNC ")"', u')', stop=stop, mayEnd=mayEnd) ++ return PreDef.char('end FUNC ")"', ')', stop=stop, mayEnd=mayEnd) + + @staticmethod + def hexcolor(stop=False, nextSor=False): +@@ -733,7 +733,7 @@ class PreDef(object): + + @staticmethod + def ident(stop=False, toStore=None, nextSor=False): +- return Prod(name=u'ident', ++ return Prod(name='ident', + match=lambda t, v: t == PreDef.types.IDENT, + stop=stop, + toStore=toStore, +@@ -741,7 +741,7 @@ class PreDef(object): + + @staticmethod + def number(stop=False, toSeq=None, nextSor=False): +- return Prod(name=u'number', ++ return Prod(name='number', + match=lambda t, v: t == PreDef.types.NUMBER, + stop=stop, + toSeq=toSeq, +@@ -749,7 +749,7 @@ class PreDef(object): + + @staticmethod + def percentage(stop=False, toSeq=None, nextSor=False): +- return Prod(name=u'percentage', ++ return Prod(name='percentage', + match=lambda t, v: t == PreDef.types.PERCENTAGE, + stop=stop, + toSeq=toSeq, +@@ -758,14 +758,14 @@ class PreDef(object): + @staticmethod + def string(stop=False, nextSor=False): + "string delimiters are removed by default" +- return Prod(name=u'string', ++ return Prod(name='string', + match=lambda t, v: t == PreDef.types.STRING, + toSeq=lambda t, tokens: (t[0], cssutils.helper.stringvalue(t[1])), + stop=stop, + nextSor=nextSor) + + @staticmethod +- def S(name=u'whitespace', toSeq=None, optional=False): ++ def S(name='whitespace', toSeq=None, optional=False): + return Prod(name=name, + match=lambda t, v: t == PreDef.types.S, + toSeq=toSeq, +@@ -775,7 +775,7 @@ class PreDef(object): + @staticmethod + def unary(stop=False, toSeq=None, nextSor=False): + "+ or -" +- return Prod(name=u'unary +-', match=lambda t, v: v in (u'+', u'-'), ++ return Prod(name='unary +-', match=lambda t, v: v in ('+', '-'), + optional=True, + stop=stop, + toSeq=toSeq, +@@ -784,7 +784,7 @@ class PreDef(object): + @staticmethod + def uri(stop=False, nextSor=False): + "'url(' and ')' are removed and URI is stripped" +- return Prod(name=u'URI', ++ return Prod(name='URI', + match=lambda t, v: t == PreDef.types.URI, + toSeq=lambda t, tokens: (t[0], cssutils.helper.urivalue(t[1])), + stop=stop, +@@ -802,8 +802,8 @@ class PreDef(object): + + @staticmethod + def variable(toSeq=None, stop=False, nextSor=False, toStore=None): +- return Prod(name=u'variable', +- match=lambda t, v: u'var(' == cssutils.helper.normalize(v), ++ return Prod(name='variable', ++ match=lambda t, v: 'var(' == cssutils.helper.normalize(v), + toSeq=toSeq, + toStore=toStore, + stop=stop, +@@ -811,7 +811,7 @@ class PreDef(object): + + # used for MarginRule for now: + @staticmethod +- def unknownrule(name=u'@', toStore=None): ++ def unknownrule(name='@', toStore=None): + """@rule dummy (matches ATKEYWORD to remove unknown rule tokens from + stream:: + +@@ -824,12 +824,12 @@ class PreDef(object): + saved = [] + for t in tokens: + saved.append(t) +- if (t[1] == u'}' or t[1] == u';'): ++ if (t[1] == '}' or t[1] == ';'): + return cssutils.css.CSSUnknownRule(saved) + + return Prod(name=name, +- match=lambda t, v: t == u'ATKEYWORD', +- toSeq=lambda t, tokens: (u'CSSUnknownRule', ++ match=lambda t, v: t == 'ATKEYWORD', ++ toSeq=lambda t, tokens: ('CSSUnknownRule', + rule(pushtoken(t, tokens)) + ), + toStore=toStore +diff --git a/src/cssutils/profiles.py b/src/cssutils/profiles.py +index 71a9a30..873bf87 100644 +--- a/src/cssutils/profiles.py ++++ b/src/cssutils/profiles.py +@@ -45,15 +45,15 @@ class Profiles(object): + If you want to redefine any of these macros do this in your custom + macros. + """ +- CSS_LEVEL_2 = u'CSS Level 2.1' +- CSS3_BACKGROUNDS_AND_BORDERS = u'CSS Backgrounds and Borders Module Level 3' +- CSS3_BASIC_USER_INTERFACE = u'CSS3 Basic User Interface Module' +- CSS3_BOX = CSS_BOX_LEVEL_3 = u'CSS Box Module Level 3' +- CSS3_COLOR = CSS_COLOR_LEVEL_3 = u'CSS Color Module Level 3' +- CSS3_FONTS = u'CSS Fonts Module Level 3' +- CSS3_FONT_FACE = u'CSS Fonts Module Level 3 @font-face properties' +- CSS3_PAGED_MEDIA = u'CSS3 Paged Media Module' +- CSS3_TEXT = u'CSS Text Level 3' ++ CSS_LEVEL_2 = 'CSS Level 2.1' ++ CSS3_BACKGROUNDS_AND_BORDERS = 'CSS Backgrounds and Borders Module Level 3' ++ CSS3_BASIC_USER_INTERFACE = 'CSS3 Basic User Interface Module' ++ CSS3_BOX = CSS_BOX_LEVEL_3 = 'CSS Box Module Level 3' ++ CSS3_COLOR = CSS_COLOR_LEVEL_3 = 'CSS Color Module Level 3' ++ CSS3_FONTS = 'CSS Fonts Module Level 3' ++ CSS3_FONT_FACE = 'CSS Fonts Module Level 3 @font-face properties' ++ CSS3_PAGED_MEDIA = 'CSS3 Paged Media Module' ++ CSS3_TEXT = 'CSS Text Level 3' + + _TOKEN_MACROS = { + 'ident': r'[-]?{nmstart}{nmchar}*', +@@ -155,7 +155,7 @@ class Profiles(object): + def macro_value(m): + return '(?:%s)' % macros[m.groupdict()['macro']] + +- for key, value in dictionary.items(): ++ for key, value in list(dictionary.items()): + if not hasattr(value, '__call__'): + while re.search(r'{[a-z][a-z0-9-]*}', value): + value = re.sub(r'{(?P[a-z][a-z0-9-]*)}', +@@ -166,7 +166,7 @@ class Profiles(object): + + def _compile_regexes(self, dictionary): + """Compile all regular expressions into callable objects""" +- for key, value in dictionary.items(): ++ for key, value in list(dictionary.items()): + if not hasattr(value, '__call__'): + # Compiling them now will slow down the cssutils import time, + # even if cssutils is not needed. We lazily compile them the +@@ -179,8 +179,8 @@ class Profiles(object): + + def __update_knownNames(self): + self._knownNames = [] +- for properties in self._profilesProperties.values(): +- self._knownNames.extend(properties.keys()) ++ for properties in list(self._profilesProperties.values()): ++ self._knownNames.extend(list(properties.keys())) + + def _getDefaultProfiles(self): + "If not explicitly set same as Profiles.profiles but in reverse order." +@@ -191,20 +191,20 @@ class Profiles(object): + + def _setDefaultProfiles(self, profiles): + "profiles may be a single or a list of profile names" +- if isinstance(profiles, basestring): ++ if isinstance(profiles, str): + self._defaultProfiles = (profiles,) + else: + self._defaultProfiles = profiles + + defaultProfiles = property(_getDefaultProfiles, + _setDefaultProfiles, +- doc=u"Names of profiles to use for validation." +- u"To use e.g. the CSS2 profile set " +- u"``cssutils.profile.defaultProfiles = " +- u"cssutils.profile.CSS_LEVEL_2``") ++ doc="Names of profiles to use for validation." ++ "To use e.g. the CSS2 profile set " ++ "``cssutils.profile.defaultProfiles = " ++ "cssutils.profile.CSS_LEVEL_2``") + + profiles = property(lambda self: self._profileNames, +- doc=u'Names of all profiles in order as defined.') ++ doc='Names of all profiles in order as defined.') + + knownNames = property(lambda self: self._knownNames, + doc="All known property names of all profiles.") +@@ -278,7 +278,7 @@ class Profiles(object): + """ + if macros: + # check if known macros would change and if yes reset properties +- if len(set(macros.keys()).intersection(self._usedMacros.keys())): ++ if len(set(macros.keys()).intersection(list(self._usedMacros.keys()))): + self._resetProperties(newMacros=macros) + + else: +@@ -289,7 +289,7 @@ class Profiles(object): + # might have been set by addProfiles before + try: + macros = self._rawProfiles[profile]['macros'] +- except KeyError, e: ++ except KeyError as e: + macros = {} + + # save name and raw props/macros if macros change to completely reset +@@ -333,7 +333,7 @@ class Profiles(object): + del self._rawProfiles[profile] + del self._profileNames[self._profileNames.index(profile)] + except KeyError: +- raise NoSuchProfileException(u'No profile %r.' % profile) ++ raise NoSuchProfileException('No profile %r.' % profile) + + else: + if reset: +@@ -351,13 +351,13 @@ class Profiles(object): + """ + if not profiles: + profiles = self.profiles +- elif isinstance(profiles, basestring): ++ elif isinstance(profiles, str): + profiles = (profiles, ) + try: + for profile in sorted(profiles): + for name in sorted(self._profilesProperties[profile].keys()): + yield name +- except KeyError, e: ++ except KeyError as e: + raise NoSuchProfileException(e) + + def validate(self, name, value): +@@ -377,7 +377,7 @@ class Profiles(object): + try: + # custom validation errors are caught + r = bool(self._profilesProperties[profile][name](value)) +- except Exception, e: ++ except Exception as e: + # TODO: more specific exception? + # Validate should not be fatal though! + self._log.error(e, error=Exception) +@@ -414,7 +414,7 @@ class Profiles(object): + else: + if not profiles: + profiles = self.defaultProfiles +- elif isinstance(profiles, basestring): ++ elif isinstance(profiles, str): + profiles = (profiles, ) + for profilename in reversed(profiles): + # check given profiles +@@ -423,7 +423,7 @@ class Profiles(object): + try: + if validate(value): + return True, True, [profilename] +- except Exception, e: ++ except Exception as e: + self._log.error(e, error=Exception) + + for profilename in (p for p in self._profileNames +@@ -434,13 +434,13 @@ class Profiles(object): + try: + if validate(value): + return True, False, [profilename] +- except Exception, e: ++ except Exception as e: + self._log.error(e, error=Exception) + + names = [] +- for profilename, properties in self._profilesProperties.items(): ++ for profilename, properties in list(self._profilesProperties.items()): + # return profile to which name belongs +- if name in properties.keys(): ++ if name in list(properties.keys()): + names.append(profilename) + names.sort() + return False, False, names +diff --git a/src/cssutils/sac.py b/src/cssutils/sac.py +index 4e4fe09..9880d73 100644 +--- a/src/cssutils/sac.py ++++ b/src/cssutils/sac.py +@@ -4,12 +4,12 @@ __all__ = ['CSSParser'] + __docformat__ = 'restructuredtext' + __version__ = '$Id: parse.py 1754 2009-05-30 14:50:13Z cthedot $' + +-import helper ++from . import helper + import codecs +-import errorhandler ++from . import errorhandler + import os +-import tokenize2 +-import urllib ++from . import tokenize2 ++import urllib.request, urllib.parse, urllib.error + import sys + + +@@ -115,12 +115,12 @@ class EchoHandler(DocumentHandler): + super(EchoHandler, self).__init__() + self._out = [] + +- out = property(lambda self: u''.join(self._out)) ++ out = property(lambda self: ''.join(self._out)) + + def startDocument(self, encoding): + super(EchoHandler, self).startDocument(encoding) +- if u'utf-8' != encoding: +- self._out.append(u'@charset "%s";\n' % encoding) ++ if 'utf-8' != encoding: ++ self._out.append('@charset "%s";\n' % encoding) + + # def comment(self, text, line=None, col=None): + # self._out.append(u'/*%s*/' % text) +@@ -129,30 +129,30 @@ class EchoHandler(DocumentHandler): + "Receive notification of a import statement in the style sheet." + # defaultNamespaceURI??? + super(EchoHandler, self).importStyle(uri, media, name, line, col) +- self._out.append(u'@import %s%s%s;\n' % (helper.string(uri), +- u'%s ' % media if media else u'', +- u'%s ' % name if name else u'') ++ self._out.append('@import %s%s%s;\n' % (helper.string(uri), ++ '%s ' % media if media else '', ++ '%s ' % name if name else '') + ) + + + def namespaceDeclaration(self, prefix, uri, line=None, col=None): + super(EchoHandler, self).namespaceDeclaration(prefix, uri, line, col) +- self._out.append(u'@namespace %s%s;\n' % (u'%s ' % prefix if prefix else u'', ++ self._out.append('@namespace %s%s;\n' % ('%s ' % prefix if prefix else '', + helper.string(uri))) + + def startSelector(self, selectors=None, line=None, col=None): + super(EchoHandler, self).startSelector(selectors, line, col) + if selectors: +- self._out.append(u', '.join(selectors)) +- self._out.append(u' {\n') ++ self._out.append(', '.join(selectors)) ++ self._out.append(' {\n') + + def endSelector(self, selectors=None, line=None, col=None): +- self._out.append(u' }') ++ self._out.append(' }') + + def property(self, name, value, important=False, line=None, col=None): + super(EchoHandler, self).property(name, value, line, col) +- self._out.append(u' %s: %s%s;\n' % (name, value, +- u' !important' if important else u'')) ++ self._out.append(' %s: %s%s;\n' % (name, value, ++ ' !important' if important else '')) + + + class Parser(object): +@@ -219,24 +219,24 @@ class Parser(object): + return False + + # START PARSING +- t = tokens.next() ++ t = next(tokens) + type_, val, line, col = t + + encoding = 'utf-8' + if 'CHARSET_SYM' == type_: + # @charset "encoding"; + # S +- encodingtoken = tokens.next() +- semicolontoken = tokens.next() ++ encodingtoken = next(tokens) ++ semicolontoken = next(tokens) + if 'STRING' == type_: + encoding = helper.stringvalue(val) + # ; + if 'STRING' == encodingtoken[0] and semicolontoken: + encoding = helper.stringvalue(encodingtoken[1]) + else: +- self._errorHandler.fatal(u'Invalid @charset') ++ self._errorHandler.fatal('Invalid @charset') + +- t = tokens.next() ++ t = next(tokens) + type_, val, line, col = t + + self._handler.startDocument(encoding) +@@ -253,44 +253,44 @@ class Parser(object): + while True: + # read till end ; + # TODO: or {} +- t = tokens.next() ++ t = next(tokens) + type_, val, line, col = t + atRule.append(val) +- if u';' == val and not braces: ++ if ';' == val and not braces: + break +- elif u'{' == val: ++ elif '{' == val: + braces += 1 +- elif u'}' == val: ++ elif '}' == val: + braces -= 1 + if braces == 0: + break + +- self._handler.ignorableAtRule(u''.join(atRule), *start) ++ self._handler.ignorableAtRule(''.join(atRule), *start) + + elif 'IMPORT_SYM' == type_: + # import URI or STRING media? name? + uri, media, name = None, None, None + while True: +- t = tokens.next() ++ t = next(tokens) + type_, val, line, col = t + if 'STRING' == type_: + uri = helper.stringvalue(val) + elif 'URI' == type_: + uri = helper.urivalue(val) +- elif u';' == val: ++ elif ';' == val: + break + + if uri: + self._handler.importStyle(uri, media, name) + else: +- self._errorHandler.error(u'Invalid @import' +- u' declaration at %r' ++ self._errorHandler.error('Invalid @import' ++ ' declaration at %r' + % (start,)) + + elif 'NAMESPACE_SYM' == type_: + prefix, uri = None, None + while True: +- t = tokens.next() ++ t = next(tokens) + type_, val, line, col = t + if 'IDENT' == type_: + prefix = val +@@ -298,13 +298,13 @@ class Parser(object): + uri = helper.stringvalue(val) + elif 'URI' == type_: + uri = helper.urivalue(val) +- elif u';' == val: ++ elif ';' == val: + break + if uri: + self._handler.namespaceDeclaration(prefix, uri, *start) + else: +- self._errorHandler.error(u'Invalid @namespace' +- u' declaration at %r' ++ self._errorHandler.error('Invalid @namespace' ++ ' declaration at %r' + % (start,)) + + else: +@@ -314,20 +314,20 @@ class Parser(object): + while True: + # selectors[, selector]* { + if 'S' == type_: +- selector.append(u' ') ++ selector.append(' ') + elif simple(t): + pass +- elif u',' == val: +- selectors.append(u''.join(selector).strip()) ++ elif ',' == val: ++ selectors.append(''.join(selector).strip()) + selector = [] +- elif u'{' == val: +- selectors.append(u''.join(selector).strip()) ++ elif '{' == val: ++ selectors.append(''.join(selector).strip()) + self._handler.startSelector(selectors, *start) + break + else: + selector.append(val) + +- t = tokens.next() ++ t = next(tokens) + type_, val, line, col = t + + end = None +@@ -337,7 +337,7 @@ class Parser(object): + + while True: + # name: +- t = tokens.next() ++ t = next(tokens) + type_, val, line, col = t + if 'S' == type_: + pass +@@ -348,15 +348,15 @@ class Parser(object): + self._errorHandler.error('more than one property name', t) + else: + name = val +- elif u':' == val: ++ elif ':' == val: + if not name: + self._errorHandler.error('no property name', t) + break +- elif u';' == val: ++ elif ';' == val: + self._errorHandler.error('premature end of property', t) + end = val + break +- elif u'}' == val: ++ elif '}' == val: + if name: + self._errorHandler.error('premature end of property', t) + end = val +@@ -364,16 +364,16 @@ class Parser(object): + else: + self._errorHandler.error('unexpected property name token %r' % val, t) + +- while not u';' == end and not u'}' == end: ++ while not ';' == end and not '}' == end: + # value !;} +- t = tokens.next() ++ t = next(tokens) + type_, val, line, col = t + + if 'S' == type_: +- value.append(u' ') ++ value.append(' ') + elif simple(t): + pass +- elif u'!' == val or u';' == val or u'}' == val: ++ elif '!' == val or ';' == val or '}' == val: + value = ''.join(value).strip() + if not value: + self._errorHandler.error('premature end of property (no value)', t) +@@ -382,16 +382,16 @@ class Parser(object): + else: + value.append(val) + +- while u'!' == end: ++ while '!' == end: + # !important +- t = tokens.next() ++ t = next(tokens) + type_, val, line, col = t + + if simple(t): + pass +- elif u'IDENT' == type_ and not important: ++ elif 'IDENT' == type_ and not important: + important = True +- elif u';' == val or u'}' == val: ++ elif ';' == val or '}' == val: + end = val + break + else: +@@ -400,7 +400,7 @@ class Parser(object): + if name and value: + self._handler.property(name, value, important) + +- if u'}' == end: ++ if '}' == end: + self._handler.endSelector(selectors, line=line, col=col) + break + else: +@@ -410,7 +410,7 @@ class Parser(object): + else: + self._handler.endSelector(selectors, line=line, col=col) + +- t = tokens.next() ++ t = next(tokens) + type_, val, line, col = t + + except StopIteration: +@@ -425,4 +425,3 @@ class Parser(object): + def setErrorHandler(self, handler): + "TODO" + self._errorHandler = handler +- +\ No newline at end of file +diff --git a/src/cssutils/script.py b/src/cssutils/script.py +index 31fcae0..d1af89f 100644 +--- a/src/cssutils/script.py ++++ b/src/cssutils/script.py +@@ -4,15 +4,15 @@ __all__ = ['CSSCapture', 'csscombine'] + __docformat__ = 'restructuredtext' + __version__ = '$Id: parse.py 1323 2008-07-06 18:13:57Z cthedot $' + +-import HTMLParser ++import html.parser + import codecs + import cssutils + import errno + import logging + import os + import sys +-import urllib2 +-import urlparse ++import urllib.request, urllib.error, urllib.parse ++import urllib.parse + + try: + import cssutils.encutils as encutils +@@ -26,31 +26,31 @@ except ImportError: + LINK = 0 # + STYLE = 1 # + +-class CSSCaptureHTMLParser(HTMLParser.HTMLParser): ++class CSSCaptureHTMLParser(html.parser.HTMLParser): + """CSSCapture helper: Parse given data for link and style elements""" +- curtag = u'' ++ curtag = '' + sheets = [] # (type, [atts, cssText]) + + def _loweratts(self, atts): + return dict([(a.lower(), v.lower()) for a, v in atts]) + + def handle_starttag(self, tag, atts): +- if tag == u'link': ++ if tag == 'link': + atts = self._loweratts(atts) +- if u'text/css' == atts.get(u'type', u''): ++ if 'text/css' == atts.get('type', ''): + self.sheets.append((LINK, atts)) +- elif tag == u'style': ++ elif tag == 'style': + # also get content of style + atts = self._loweratts(atts) +- if u'text/css' == atts.get(u'type', u''): +- self.sheets.append((STYLE, [atts, u''])) ++ if 'text/css' == atts.get('type', ''): ++ self.sheets.append((STYLE, [atts, ''])) + self.curtag = tag + else: + # close as only intersting