From 9fcc98bd3e5bde3a26326f3156845093f84b8832 Mon Sep 17 00:00:00 2001 From: Chris Dent Date: Tue, 23 Oct 2018 17:01:47 +0100 Subject: Fix up testing after switch to pytest pytest exposes many warnings, some but not all of which are cleaned up here. The main switch is to use html.escape instead of cgi.escape. This inspired the addition of 'future' to requirements. The remaining warnings are related to pytest deprecations or over-eager test discovery. It is perhaps ironic that the switch to pytest is to avoid nose being mostly dead, and now we are using features in pytest that pytest wants to make dead. These are left for later cleanups, which means that running the tests is noisy. --- paste/evalexception/middleware.py | 6 +- paste/exceptions/formatter.py | 6 +- paste/url.py | 10 +-- paste/urlmap.py | 10 +-- paste/util/quoting.py | 12 ++-- paste/util/template.py | 4 +- setup.py | 2 +- tests/template.txt | 136 ++++++++++++++++++++++++++++++++++++++ tests/test_doctests.py | 2 +- tests/test_template.txt | 136 -------------------------------------- tox.ini | 2 +- 11 files changed, 163 insertions(+), 163 deletions(-) create mode 100644 tests/template.txt delete mode 100644 tests/test_template.txt diff --git a/paste/evalexception/middleware.py b/paste/evalexception/middleware.py index da7876d..f41a4f5 100644 --- a/paste/evalexception/middleware.py +++ b/paste/evalexception/middleware.py @@ -29,7 +29,7 @@ from __future__ import print_function import sys import os -import cgi +import html import traceback import six from six.moves import cStringIO as StringIO @@ -54,7 +54,7 @@ def html_quote(v): """ if v is None: return '' - return cgi.escape(str(v), 1) + return html.escape(str(v), 1) def preserve_whitespace(v, quote=True): """ @@ -527,7 +527,7 @@ def format_eval_html(exc_data, base_path, counter):
- """ % (short_er, full_traceback_html, cgi.escape(text_er)) + """ % (short_er, full_traceback_html, html.escape(text_er)) def make_repost_button(environ): url = request.construct_url(environ) diff --git a/paste/exceptions/formatter.py b/paste/exceptions/formatter.py index 09309de..3be07ef 100644 --- a/paste/exceptions/formatter.py +++ b/paste/exceptions/formatter.py @@ -7,13 +7,13 @@ Formatters for the exception data that comes from ExceptionCollector. # @@: TODO: # Use this: http://www.zope.org/Members/tino/VisualTraceback/VisualTracebackNews -import cgi +import html import six import re from paste.util import PySourceColor def html_quote(s): - return cgi.escape(str(s), True) + return html.escape(str(s), True) class AbstractFormatter(object): @@ -463,7 +463,7 @@ def format_html(exc_data, include_hidden_frames=False, **ops):
- """ % (short_er, long_er, cgi.escape(text_er)) + """ % (short_er, long_er, html.escape(text_er)) def format_text(exc_data, **ops): return TextFormatter(**ops).format_collected_data(exc_data) diff --git a/paste/url.py b/paste/url.py index fb08d6d..653c657 100644 --- a/paste/url.py +++ b/paste/url.py @@ -5,7 +5,7 @@ This module implements a class for handling URLs. """ from six.moves.urllib.parse import parse_qsl, quote, unquote, urlencode -import cgi +import html from paste import request import six @@ -17,7 +17,7 @@ __all__ = ["URL", "Image"] def html_quote(v): if v is None: return '' - return cgi.escape(str(v), 1) + return html.escape(str(v), 1) def url_quote(v): if v is None: @@ -274,7 +274,7 @@ class URL(URLResource): >>> u['//foo'].param(content='view').html 'view' >>> u.param(confirm='Really?', content='goto').html - 'goto' + 'goto' >>> u(title='See "it"', content='goto').html 'goto' >>> u('another', var='fuggetaboutit', content='goto').html @@ -373,7 +373,7 @@ class Button(URLResource): >>> u = u / 'delete' >>> b = u.button['confirm=Sure?'](id=5, content='del') >>> str(b) - '' + '' """ default_params = {'tag': 'button'} @@ -417,7 +417,7 @@ class JSPopup(URLResource): >>> u = u / 'view' >>> j = u.js_popup(content='view') >>> j.html - 'view' + 'view' """ default_params = {'tag': 'a', 'target': '_blank'} diff --git a/paste/urlmap.py b/paste/urlmap.py index f721f2d..4ba19c1 100644 --- a/paste/urlmap.py +++ b/paste/urlmap.py @@ -6,7 +6,7 @@ Map URL prefixes to WSGI applications. See ``URLMap`` import re import os -import cgi +import html try: # Python 3 from collections import MutableMapping as DictMixin @@ -114,12 +114,12 @@ class URLMap(DictMixin): ',\n '.join(map(repr, matches))) else: extra = '' - extra += '\nSCRIPT_NAME: %r' % cgi.escape(environ.get('SCRIPT_NAME')) - extra += '\nPATH_INFO: %r' % cgi.escape(environ.get('PATH_INFO')) - extra += '\nHTTP_HOST: %r' % cgi.escape(environ.get('HTTP_HOST')) + extra += '\nSCRIPT_NAME: %r' % html.escape(environ.get('SCRIPT_NAME')) + extra += '\nPATH_INFO: %r' % html.escape(environ.get('PATH_INFO')) + extra += '\nHTTP_HOST: %r' % html.escape(environ.get('HTTP_HOST')) app = httpexceptions.HTTPNotFound( environ['PATH_INFO'], - comment=cgi.escape(extra)).wsgi_application + comment=html.escape(extra)).wsgi_application return app(environ, start_response) def normalize_url(self, url, trim=True): diff --git a/paste/util/quoting.py b/paste/util/quoting.py index df0d9da..c1f635f 100644 --- a/paste/util/quoting.py +++ b/paste/util/quoting.py @@ -1,7 +1,7 @@ # (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org) # Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php -import cgi +import html import six import re from six.moves import html_entities @@ -22,17 +22,17 @@ def html_quote(v, encoding=None): if v is None: return '' elif isinstance(v, six.binary_type): - return cgi.escape(v, 1) + return html.escape(v, 1) elif isinstance(v, six.text_type): if six.PY3: - return cgi.escape(v, 1) + return html.escape(v, 1) else: - return cgi.escape(v.encode(encoding), 1) + return html.escape(v.encode(encoding), 1) else: if six.PY3: - return cgi.escape(six.text_type(v), 1) + return html.escape(six.text_type(v), 1) else: - return cgi.escape(six.text_type(v).encode(encoding), 1) + return html.escape(six.text_type(v).encode(encoding), 1) _unquote_re = re.compile(r'&([a-zA-Z]+);') def _entity_subber(match, name2c=html_entities.name2codepoint): diff --git a/paste/util/template.py b/paste/util/template.py index 5a63664..c1f22f3 100644 --- a/paste/util/template.py +++ b/paste/util/template.py @@ -33,7 +33,7 @@ If there are syntax errors ``TemplateError`` will be raised. import re import six import sys -import cgi +from html import escape from six.moves.urllib.parse import quote from paste.util.looper import looper @@ -322,7 +322,7 @@ def html_quote(value): value = unicode(value) else: value = str(value) - value = cgi.escape(value, 1) + value = escape(value, 1) if six.PY2 and isinstance(value, unicode): value = value.encode('ascii', 'xmlcharrefreplace') return value diff --git a/setup.py b/setup.py index 786e72f..d023e23 100644 --- a/setup.py +++ b/setup.py @@ -59,7 +59,7 @@ setup(name="Paste", namespace_packages=['paste'], zip_safe=False, test_suite='nose.collector', - install_requires=['six>=1.4.0'], + install_requires=['six>=1.4.0', 'future'], tests_require=['nose>=0.11'], extras_require={ 'subprocess': [], diff --git a/tests/template.txt b/tests/template.txt new file mode 100644 index 0000000..1313d34 --- /dev/null +++ b/tests/template.txt @@ -0,0 +1,136 @@ +The templating language is fairly simple, just {{stuff}}. For +example:: + + >>> from paste.util.template import Template, sub + >>> sub('Hi {{name}}', name='Ian') + 'Hi Ian' + >>> Template('Hi {{repr(name)}}').substitute(name='Ian') + "Hi 'Ian'" + >>> Template('Hi {{name+1}}').substitute(name='Ian') # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + TypeError: cannot concatenate 'str' and 'int' objects at line 1 column 6 + +It also has Django-style piping:: + + >>> sub('Hi {{name|repr}}', name='Ian') + "Hi 'Ian'" + +Note that None shows up as an empty string:: + + >>> sub('Hi {{name}}', name=None) + 'Hi ' + +And if/elif/else:: + + >>> t = Template('{{if x}}{{y}}{{else}}{{z}}{{endif}}') + >>> t.substitute(x=1, y=2, z=3) + '2' + >>> t.substitute(x=0, y=2, z=3) + '3' + >>> t = Template('{{if x > 0}}positive{{elif x < 0}}negative{{else}}zero{{endif}}') + >>> t.substitute(x=1), t.substitute(x=-10), t.substitute(x=0) + ('positive', 'negative', 'zero') + +Plus a for loop:: + + >>> t = Template('{{for i in x}}i={{i}}\n{{endfor}}') + >>> t.substitute(x=range(3)) + 'i=0\ni=1\ni=2\n' + >>> t = Template('{{for a, b in sorted(z.items()):}}{{a}}={{b}},{{endfor}}') + >>> t.substitute(z={1: 2, 3: 4}) + '1=2,3=4,' + >>> t = Template('{{for i in x}}{{if not i}}{{break}}' + ... '{{endif}}{{i}} {{endfor}}') + >>> t.substitute(x=[1, 2, 0, 3, 4]) + '1 2 ' + >>> t = Template('{{for i in x}}{{if not i}}{{continue}}' + ... '{{endif}}{{i}} {{endfor}}') + >>> t.substitute(x=[1, 2, 0, 3, 0, 4]) + '1 2 3 4 ' + +Also Python blocks:: + + >>> sub('{{py:\nx=1\n}}{{x}}') + '1' + +And some syntax errors:: + + >>> t = Template('{{if x}}', name='foo.html') + Traceback (most recent call last): + ... + TemplateError: No {{endif}} at line 1 column 3 in foo.html + >>> t = Template('{{for x}}', name='foo2.html') + Traceback (most recent call last): + ... + TemplateError: Bad for (no "in") in 'x' at line 1 column 3 in foo2.html + +There's also an HTMLTemplate that uses HTMLisms:: + + >>> from paste.util.template import HTMLTemplate, sub_html, html + >>> sub_html('hi {{name}}', name='') + 'hi <foo>' + +But if you don't want quoting to happen you can do:: + + >>> sub_html('hi {{name}}', name=html('')) + 'hi ' + >>> sub_html('hi {{name|html}}', name='') + 'hi ' + +Also a couple handy functions;: + + >>> t = HTMLTemplate('') + >>> t.substitute(id=1, class_='foo') + '' + >>> t.substitute(id='with space', class_=None) + '' + +There's a handyish looper thing you can also use in your templates (or +in Python, but it's more useful in templates generally):: + + >>> from paste.util.looper import looper + >>> seq = ['apple', 'asparagus', 'Banana', 'orange'] + >>> for loop, item in looper(seq): + ... if item == 'apple': + ... assert loop.first + ... elif item == 'orange': + ... assert loop.last + ... if loop.first_group(lambda i: i[0].upper()): + ... print('%s:' % item[0].upper()) + ... print("%s %s" % (loop.number, item)) + A: + 1 apple + 2 asparagus + B: + 3 Banana + O: + 4 orange + +It will also strip out empty lines, when there is a line that only +contains a directive/statement (if/for, etc):: + + >>> sub('{{if 1}}\n{{x}}\n{{endif}}\n', x=0) + '0\n' + >>> sub('{{if 1}}x={{x}}\n{{endif}}\n', x=1) + 'x=1\n' + >>> sub('{{if 1}}\nx={{x}}\n{{endif}}\n', x=1) + 'x=1\n' + +Lastly, there is a special directive that will create a default value +for a variable, if no value is given:: + + >>> sub('{{default x=1}}{{x}}', x=2) + '2' + >>> sub('{{default x=1}}{{x}}') + '1' + >>> # The normal case: + >>> sub('{{x}}') # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + NameError: name 'x' is not defined at line 1 column 3 + +And comments work:: + + >>> sub('Test=x{{#whatever}}') + 'Test=x' diff --git a/tests/test_doctests.py b/tests/test_doctests.py index d59d666..efea589 100644 --- a/tests/test_doctests.py +++ b/tests/test_doctests.py @@ -4,7 +4,7 @@ from paste.util.import_string import simple_import import os filenames = [ - 'tests/test_template.txt', + 'tests/template.txt', ] modules = [ diff --git a/tests/test_template.txt b/tests/test_template.txt deleted file mode 100644 index 1313d34..0000000 --- a/tests/test_template.txt +++ /dev/null @@ -1,136 +0,0 @@ -The templating language is fairly simple, just {{stuff}}. For -example:: - - >>> from paste.util.template import Template, sub - >>> sub('Hi {{name}}', name='Ian') - 'Hi Ian' - >>> Template('Hi {{repr(name)}}').substitute(name='Ian') - "Hi 'Ian'" - >>> Template('Hi {{name+1}}').substitute(name='Ian') # doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - ... - TypeError: cannot concatenate 'str' and 'int' objects at line 1 column 6 - -It also has Django-style piping:: - - >>> sub('Hi {{name|repr}}', name='Ian') - "Hi 'Ian'" - -Note that None shows up as an empty string:: - - >>> sub('Hi {{name}}', name=None) - 'Hi ' - -And if/elif/else:: - - >>> t = Template('{{if x}}{{y}}{{else}}{{z}}{{endif}}') - >>> t.substitute(x=1, y=2, z=3) - '2' - >>> t.substitute(x=0, y=2, z=3) - '3' - >>> t = Template('{{if x > 0}}positive{{elif x < 0}}negative{{else}}zero{{endif}}') - >>> t.substitute(x=1), t.substitute(x=-10), t.substitute(x=0) - ('positive', 'negative', 'zero') - -Plus a for loop:: - - >>> t = Template('{{for i in x}}i={{i}}\n{{endfor}}') - >>> t.substitute(x=range(3)) - 'i=0\ni=1\ni=2\n' - >>> t = Template('{{for a, b in sorted(z.items()):}}{{a}}={{b}},{{endfor}}') - >>> t.substitute(z={1: 2, 3: 4}) - '1=2,3=4,' - >>> t = Template('{{for i in x}}{{if not i}}{{break}}' - ... '{{endif}}{{i}} {{endfor}}') - >>> t.substitute(x=[1, 2, 0, 3, 4]) - '1 2 ' - >>> t = Template('{{for i in x}}{{if not i}}{{continue}}' - ... '{{endif}}{{i}} {{endfor}}') - >>> t.substitute(x=[1, 2, 0, 3, 0, 4]) - '1 2 3 4 ' - -Also Python blocks:: - - >>> sub('{{py:\nx=1\n}}{{x}}') - '1' - -And some syntax errors:: - - >>> t = Template('{{if x}}', name='foo.html') - Traceback (most recent call last): - ... - TemplateError: No {{endif}} at line 1 column 3 in foo.html - >>> t = Template('{{for x}}', name='foo2.html') - Traceback (most recent call last): - ... - TemplateError: Bad for (no "in") in 'x' at line 1 column 3 in foo2.html - -There's also an HTMLTemplate that uses HTMLisms:: - - >>> from paste.util.template import HTMLTemplate, sub_html, html - >>> sub_html('hi {{name}}', name='') - 'hi <foo>' - -But if you don't want quoting to happen you can do:: - - >>> sub_html('hi {{name}}', name=html('')) - 'hi ' - >>> sub_html('hi {{name|html}}', name='') - 'hi ' - -Also a couple handy functions;: - - >>> t = HTMLTemplate('') - >>> t.substitute(id=1, class_='foo') - '' - >>> t.substitute(id='with space', class_=None) - '' - -There's a handyish looper thing you can also use in your templates (or -in Python, but it's more useful in templates generally):: - - >>> from paste.util.looper import looper - >>> seq = ['apple', 'asparagus', 'Banana', 'orange'] - >>> for loop, item in looper(seq): - ... if item == 'apple': - ... assert loop.first - ... elif item == 'orange': - ... assert loop.last - ... if loop.first_group(lambda i: i[0].upper()): - ... print('%s:' % item[0].upper()) - ... print("%s %s" % (loop.number, item)) - A: - 1 apple - 2 asparagus - B: - 3 Banana - O: - 4 orange - -It will also strip out empty lines, when there is a line that only -contains a directive/statement (if/for, etc):: - - >>> sub('{{if 1}}\n{{x}}\n{{endif}}\n', x=0) - '0\n' - >>> sub('{{if 1}}x={{x}}\n{{endif}}\n', x=1) - 'x=1\n' - >>> sub('{{if 1}}\nx={{x}}\n{{endif}}\n', x=1) - 'x=1\n' - -Lastly, there is a special directive that will create a default value -for a variable, if no value is given:: - - >>> sub('{{default x=1}}{{x}}', x=2) - '2' - >>> sub('{{default x=1}}{{x}}') - '1' - >>> # The normal case: - >>> sub('{{x}}') # doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - ... - NameError: name 'x' is not defined at line 1 column 3 - -And comments work:: - - >>> sub('Test=x{{#whatever}}') - 'Test=x' diff --git a/tox.ini b/tox.ini index c154d05..8ac2e18 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py26, py27, py34, py35, py36, py37, pypy +envlist = py27, py35, py36, py37, pypy [testenv] deps = -- cgit v1.2.1