diff options
author | John Carter <john@therefromhere.org> | 2019-01-19 14:11:28 +1300 |
---|---|---|
committer | John Carter <john@therefromhere.org> | 2019-01-19 14:11:28 +1300 |
commit | cdaf2c628a0b2bca5f808f13eb2fd150c508ca6b (patch) | |
tree | dbcc58797b6feb15bea7966ac36fefa7dc3f7a90 | |
parent | 9f3193da7408cec9ac9c612e047d1c48ba9e542c (diff) | |
download | webtest-cdaf2c628a0b2bca5f808f13eb2fd150c508ca6b.tar.gz |
Converted lint check_* functions to raise AssertionError instead of assert
So they still check when PYTHONOPTIMIZE>=1
-rw-r--r-- | tests/test_lint.py | 6 | ||||
-rw-r--r-- | webtest/lint.py | 226 |
2 files changed, 149 insertions, 83 deletions
diff --git a/tests/test_lint.py b/tests/test_lint.py index e0b7f31..1472edf 100644 --- a/tests/test_lint.py +++ b/tests/test_lint.py @@ -43,7 +43,6 @@ def application(environ, start_response): return resp(environ, start_response) -@unittest.skipIf(sys.flags.optimize > 0, "skip assert tests if optimize is enabled") class TestLatin1Assertion(unittest.TestCase): def test_valid_type(self): @@ -66,9 +65,9 @@ class TestToString(unittest.TestCase): self.assertEqual(to_string(b'foo'), 'foo') -@unittest.skipIf(sys.flags.optimize > 0, "skip assert tests if optimize is enabled") class TestMiddleware(unittest.TestCase): + @unittest.skipIf(sys.flags.optimize > 0, "skip assert tests if optimize is enabled") def test_lint_too_few_args(self): linter = middleware(application) with self.assertRaisesRegexp(AssertionError, "Two arguments required"): @@ -76,6 +75,7 @@ class TestMiddleware(unittest.TestCase): with self.assertRaisesRegexp(AssertionError, "Two arguments required"): linter({}) + @unittest.skipIf(sys.flags.optimize > 0, "skip assert tests if optimize is enabled") def test_lint_no_keyword_args(self): linter = middleware(application) with self.assertRaisesRegexp(AssertionError, "No keyword arguments " @@ -144,7 +144,6 @@ class TestMiddleware2(unittest.TestCase): # don't know what to assert here... a bit cheating, just covers code -@unittest.skipIf(sys.flags.optimize > 0, "skip assert tests if optimize is enabled") class TestCheckContentType(unittest.TestCase): def test_no_content(self): status = "204 No Content" @@ -162,7 +161,6 @@ class TestCheckContentType(unittest.TestCase): self.assertRaises(AssertionError, check_content_type, status, headers) -@unittest.skipIf(sys.flags.optimize > 0, "skip assert tests if optimize is enabled") class TestCheckHeaders(unittest.TestCase): @unittest.skipIf(PY3, 'unicode is str in Python3') diff --git a/webtest/lint.py b/webtest/lint.py index a477f40..f4c2b25 100644 --- a/webtest/lint.py +++ b/webtest/lint.py @@ -199,8 +199,10 @@ def middleware(application, global_conf=None): environ['wsgi.errors'] = ErrorWrapper(environ['wsgi.errors']) iterator = application(environ, start_response_wrapper) - assert isinstance(iterator, Iterable), ( - "The application must return an iterator, if only an empty list") + if not isinstance(iterator, Iterable): + raise AssertionError( + "The application must return an iterator, if only an empty list" + ) check_iterator(iterator) @@ -316,21 +318,25 @@ class IteratorWrapper(object): def check_environ(environ): - assert type(environ) is dict, ( - "Environment is not of the right type: %r (environment: %r)" - % (type(environ), environ)) + if type(environ) is not dict: + raise AssertionError( + "Environment is not of the right type: %r (environment: %r)" + % (type(environ), environ) + ) for key in ['REQUEST_METHOD', 'SERVER_NAME', 'SERVER_PORT', 'wsgi.version', 'wsgi.input', 'wsgi.errors', 'wsgi.multithread', 'wsgi.multiprocess', 'wsgi.run_once']: - assert key in environ, ( - "Environment missing required key: %r" % key) + if key not in environ: + raise AssertionError("Environment missing required key: %r" % key) for key in ['HTTP_CONTENT_TYPE', 'HTTP_CONTENT_LENGTH']: - assert key not in environ, ( - "Environment should not have the key: %s " - "(use %s instead)" % (key, key[5:])) + if key in environ: + raise AssertionError( + "Environment should not have the key: %s " + "(use %s instead)" % (key, key[5:]) + ) if 'QUERY_STRING' not in environ: warnings.warn( @@ -343,14 +349,21 @@ def check_environ(environ): if '.' in key: # Extension, we don't care about its type continue - assert type(environ[key]) in METADATA_TYPE, ( - "Environmental variable %s is not a string: %r (value: %r)" - % (key, type(environ[key]), environ[key])) + if type(environ[key]) not in METADATA_TYPE: + raise AssertionError( + "Environmental variable %s is not a string: %r (value: %r)" + % (key, type(environ[key]), environ[key]) + ) + + if type(environ['wsgi.version']) is not tuple: + raise AssertionError( + "wsgi.version should be a tuple (%r)" % environ['wsgi.version'] + ) - assert type(environ['wsgi.version']) is tuple, ( - "wsgi.version should be a tuple (%r)" % environ['wsgi.version']) - assert environ['wsgi.url_scheme'] in ('http', 'https'), ( - "wsgi.url_scheme unknown: %r" % environ['wsgi.url_scheme']) + if environ['wsgi.url_scheme'] not in ('http', 'https'): + raise AssertionError( + "wsgi.url_scheme unknown: %r" % environ['wsgi.url_scheme'] + ) check_input(environ['wsgi.input']) check_errors(environ['wsgi.errors']) @@ -361,62 +374,89 @@ def check_environ(environ): "Unknown REQUEST_METHOD: %r" % environ['REQUEST_METHOD'], WSGIWarning) - assert (not environ.get('SCRIPT_NAME') - or environ['SCRIPT_NAME'].startswith(SLASH)), ( - "SCRIPT_NAME doesn't start with /: %r" % environ['SCRIPT_NAME']) - assert (not environ.get('PATH_INFO') - or environ['PATH_INFO'].startswith(SLASH)), ( - "PATH_INFO doesn't start with /: %r" % environ['PATH_INFO']) + if environ.get('SCRIPT_NAME') and not environ['SCRIPT_NAME'].startswith(SLASH): + raise AssertionError( + "SCRIPT_NAME doesn't start with /: %r" % environ['SCRIPT_NAME'] + ) + + if environ.get('PATH_INFO') and not environ['PATH_INFO'].startswith(SLASH): + raise AssertionError( + "PATH_INFO doesn't start with /: %r" % environ['PATH_INFO'] + ) + if environ.get('CONTENT_LENGTH'): - assert int(environ['CONTENT_LENGTH']) >= 0, ( - "Invalid CONTENT_LENGTH: %r" % environ['CONTENT_LENGTH']) + if int(environ['CONTENT_LENGTH']) < 0: + raise AssertionError( + "Invalid CONTENT_LENGTH: %r" % environ['CONTENT_LENGTH'] + ) if not environ.get('SCRIPT_NAME'): - assert 'PATH_INFO' in environ, ( - "One of SCRIPT_NAME or PATH_INFO are required (PATH_INFO " - "should at least be '/' if SCRIPT_NAME is empty)") - assert environ.get('SCRIPT_NAME') != SLASH, ( - "SCRIPT_NAME cannot be '/'; it should instead be '', and " - "PATH_INFO should be '/'") + if 'PATH_INFO' not in environ: + raise AssertionError( + "One of SCRIPT_NAME or PATH_INFO are required (PATH_INFO " + "should at least be '/' if SCRIPT_NAME is empty)" + ) + + if environ.get('SCRIPT_NAME') == SLASH: + raise AssertionError( + "SCRIPT_NAME cannot be '/'; it should instead be '', and " + "PATH_INFO should be '/'" + ) def check_input(wsgi_input): for attr in ['read', 'readline', 'readlines', '__iter__']: - assert hasattr(wsgi_input, attr), ( - "wsgi.input (%r) doesn't have the attribute %s" - % (wsgi_input, attr)) + if not hasattr(wsgi_input, attr): + raise AssertionError( + "wsgi.input (%r) doesn't have the attribute %s" + % (wsgi_input, attr) + ) def check_errors(wsgi_errors): for attr in ['flush', 'write', 'writelines']: - assert hasattr(wsgi_errors, attr), ( - "wsgi.errors (%r) doesn't have the attribute %s" - % (wsgi_errors, attr)) + if not hasattr(wsgi_errors, attr): + raise AssertionError( + "wsgi.errors (%r) doesn't have the attribute %s" + % (wsgi_errors, attr) + ) def check_status(status): - assert type(status) in METADATA_TYPE, ( - "Status must be a %s (not %r)" % (METADATA_TYPE, status)) + if type(status) not in METADATA_TYPE: + raise AssertionError("Status must be a %s (not %r)" % (METADATA_TYPE, status)) + status = to_string(status) - assert len(status) > 5, ( - "The status string (%r) should be a three-digit " - "integer followed by a single space and a status explanation" - ) % status - assert status[:3].isdigit(), ( - "The status string (%r) should start with" - "three digits") % status + + if len(status) <= 5: + raise AssertionError( + "The status string (%r) should be a three-digit " + "integer followed by a single space and a status explanation" % status + ) + + if not status[:3].isdigit(): + raise AssertionError( + "The status string (%r) should start with three digits" % status + ) status_int = int(status[:3]) - assert status_int >= 100, ( - "The status code must be greater or equal than " - "100 (got %d)") % status_int - assert status[3] == ' ', ( - "The status string (%r) should start with three" - "digits and a space (4th characters is not a space here)") % status + + if status_int < 100: + raise AssertionError( + "The status code must be greater or equal than 100 (got %d)" % status_int + ) + + if status[3] != ' ': + raise AssertionError( + "The status string (%r) should start with three" + "digits and a space (4th characters is not a space here)" % status + ) def _assert_latin1_str(string, message): - assert type(string) is str, message + if type(string) is not str: + raise AssertionError(message) + if type(string) is text_type: try: string.encode('latin1') @@ -426,13 +466,18 @@ def _assert_latin1_str(string, message): def check_headers(headers): - assert type(headers) is list, ( - "Headers (%r) must be of type list: %r" - % (headers, type(headers))) + if type(headers) is not list: + raise AssertionError( + "Headers (%r) must be of type list: %r" % (headers, type(headers)) + ) + for item in headers: - assert type(item) is tuple, ( - "Individual headers (%r) must be of type tuple: %r" - % (item, type(item))) + if type(item) is not tuple: + raise AssertionError( + "Individual headers (%r) must be of type tuple: %r" + % (item, type(item)) + ) + assert len(item) == 2 name, value = item _assert_latin1_str( @@ -441,24 +486,37 @@ def check_headers(headers): "(not Py2 unicode or Py3 bytes type). " "%r is not a valid latin1 string" % (name,) ) - assert name.lower() != 'status', ( - "The Status header cannot be used; it conflicts with CGI " - "script, and HTTP status is not given through headers " - "(value: %r)." % value) - assert '\n' not in name and ':' not in name, ( - "Header names may not contain ':' or '\\n': %r" % name) - assert header_re.search(name), "Bad header name: %r" % name - assert not name.endswith('-') and not name.endswith('_'), ( - "Names may not end in '-' or '_': %r" % name) + + if name.lower() == 'status': + raise AssertionError( + "The Status header cannot be used; it conflicts with CGI " + "script, and HTTP status is not given through headers " + "(value: %r)." % value + ) + + if '\n' in name or ':' in name: + raise AssertionError( + "Header names may not contain ':' or '\\n': %r" % name + ) + + if not header_re.search(name): + raise AssertionError("Bad header name: %r" % name) + + if name.endswith('-') or name.endswith('_'): + raise AssertionError("Names may not end in '-' or '_': %r" % name) + _assert_latin1_str( value, "Header values must be latin1 string " "(not Py2 unicode or Py3 bytes type)." "%r is not a valid latin1 string" % (value,) ) - assert not bad_header_value_re.search(value), ( - "Bad header value: %r (bad char: %r)" - % (str_value, bad_header_value_re.search(value).group(0))) + + if bad_header_value_re.search(value): + raise AssertionError( + "Bad header value: %r (bad char: %r)" + % (str_value, bad_header_value_re.search(value).group(0)) + ) def check_content_type(status, headers): @@ -482,15 +540,22 @@ def check_content_type(status, headers): WSGIWarning) return else: - assert 0, (("Content-Type header found in a %s response, " - "which must not return content.") % code) + raise AssertionError( + "Content-Type header found in a %s response, " + "which must not return content." % code + ) + if code not in NO_MESSAGE_BODY and length is not None and length > 0: - assert 0, "No Content-Type header found in headers (%s)" % headers + raise AssertionError( + "No Content-Type header found in headers (%s)" % headers + ) def check_exc_info(exc_info): - assert exc_info is None or type(exc_info) is tuple, ( - "exc_info (%r) is not a tuple: %r" % (exc_info, type(exc_info))) + if exc_info is not None and type(exc_info) is not tuple: + raise AssertionError( + "exc_info (%r) is not a tuple: %r" % (exc_info, type(exc_info)) + ) # More exc_info checks? @@ -499,8 +564,11 @@ def check_iterator(iterator): # Technically a bytes (str for py2.x) is legal, which is why it's a # really bad idea, because it may cause the response to be returned # character-by-character - assert not isinstance(iterator, valid_type), ( - "You should not return a bytes as your application iterator, " - "instead return a single-item list containing that string.") + + if isinstance(iterator, valid_type): + raise AssertionError( + "You should not return a bytes as your application iterator, " + "instead return a single-item list containing that string." + ) __all__ = ['middleware'] |