diff options
author | Daniele Varrazzo <daniele.varrazzo@gmail.com> | 2018-10-30 00:23:56 +0000 |
---|---|---|
committer | Daniele Varrazzo <daniele.varrazzo@gmail.com> | 2018-10-30 00:23:56 +0000 |
commit | 2f24a2e22ddf83f6448f2ecb48bfffcc40a94899 (patch) | |
tree | ebef12dbef456fd632c991d140a76d2819bc3011 | |
parent | 60935b9b3d1a32da5ce0702f1bdb71eb148c2b34 (diff) | |
download | psycopg2-decorators-fun.tar.gz |
Use class decorators to decorate all testsdecorators-fun
Test decorators changed so that they can be applied either to a method
or to a class. Of course their double nature is implemented by a
decorator.
-rwxr-xr-x | tests/test_connection.py | 6 | ||||
-rwxr-xr-x | tests/test_copy.py | 7 | ||||
-rwxr-xr-x | tests/test_fast_executemany.py | 5 | ||||
-rwxr-xr-x | tests/test_ipaddress.py | 5 | ||||
-rwxr-xr-x | tests/test_lobject.py | 45 | ||||
-rwxr-xr-x | tests/test_psycopg2_dbapi20.py | 5 | ||||
-rwxr-xr-x | tests/test_types_basic.py | 29 | ||||
-rwxr-xr-x | tests/test_types_extras.py | 24 | ||||
-rw-r--r-- | tests/testutils.py | 42 |
9 files changed, 81 insertions, 87 deletions
diff --git a/tests/test_connection.py b/tests/test_connection.py index ffc9887..fa93ba5 100755 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -35,7 +35,7 @@ import psycopg2.errorcodes from psycopg2 import extensions as ext from .testutils import ( - unittest, decorate_all_tests, skip_if_no_superuser, skip_before_postgres, + unittest, skip_if_no_superuser, skip_before_postgres, skip_after_postgres, skip_before_libpq, skip_after_libpq, ConnectingTestCase, skip_if_tpc_disabled, skip_if_windows, slow) @@ -812,6 +812,7 @@ class IsolationLevelsTestCase(ConnectingTestCase): self.conn.isolation_level +@skip_if_tpc_disabled class ConnectionTwoPhaseTests(ConnectingTestCase): def setUp(self): ConnectingTestCase.setUp(self) @@ -1183,9 +1184,6 @@ class ConnectionTwoPhaseTests(ConnectingTestCase): self.assertEqual(None, xid.bqual) -decorate_all_tests(ConnectionTwoPhaseTests, skip_if_tpc_disabled) - - class TransactionControlTests(ConnectingTestCase): def test_closed(self): self.conn.close() diff --git a/tests/test_copy.py b/tests/test_copy.py index 1eb1090..11ab492 100755 --- a/tests/test_copy.py +++ b/tests/test_copy.py @@ -25,8 +25,7 @@ import sys import string import unittest -from .testutils import (ConnectingTestCase, decorate_all_tests, - skip_before_postgres, slow, StringIO) +from .testutils import (ConnectingTestCase, skip_before_postgres, slow, StringIO) from itertools import cycle from subprocess import Popen, PIPE @@ -63,6 +62,7 @@ class MinimalWrite(_base): return self.f.write(data) +@skip_copy_if_green class CopyTests(ConnectingTestCase): def setUp(self): @@ -378,9 +378,6 @@ conn.close() curs.copy_to, BrokenWrite(), "tcopy") -decorate_all_tests(CopyTests, skip_copy_if_green) - - def test_suite(): return unittest.TestLoader().loadTestsFromName(__name__) diff --git a/tests/test_fast_executemany.py b/tests/test_fast_executemany.py index 94e5c3e..f1e88b2 100755 --- a/tests/test_fast_executemany.py +++ b/tests/test_fast_executemany.py @@ -134,6 +134,7 @@ class TestExecuteBatch(FastExecuteTestMixin, testutils.ConnectingTestCase): self.assertEqual(cur.fetchone(), (3, snowman)) +@testutils.skip_before_postgres(8, 2) class TestExecuteValues(FastExecuteTestMixin, testutils.ConnectingTestCase): def test_empty(self): cur = self.conn.cursor() @@ -251,10 +252,6 @@ class TestExecuteValues(FastExecuteTestMixin, testutils.ConnectingTestCase): self.assertEqual(cur.fetchall(), [(1, 'hi')]) -testutils.decorate_all_tests(TestExecuteValues, - testutils.skip_before_postgres(8, 2)) - - def test_suite(): return unittest.TestLoader().loadTestsFromName(__name__) diff --git a/tests/test_ipaddress.py b/tests/test_ipaddress.py index 0db2724..28f1836 100755 --- a/tests/test_ipaddress.py +++ b/tests/test_ipaddress.py @@ -26,6 +26,7 @@ import psycopg2 import psycopg2.extras +@testutils.decorate_all_tests def skip_if_no_ipaddress(f): @wraps(f) def skip_if_no_ipaddress_(self): @@ -40,6 +41,7 @@ def skip_if_no_ipaddress(f): return skip_if_no_ipaddress_ +@skip_if_no_ipaddress class NetworkingTestCase(testutils.ConnectingTestCase): def test_inet_cast(self): import ipaddress as ip @@ -126,9 +128,6 @@ class NetworkingTestCase(testutils.ConnectingTestCase): self.assertEquals(cur.fetchone()[0], '::ffff:102:300/128') -testutils.decorate_all_tests(NetworkingTestCase, skip_if_no_ipaddress) - - def test_suite(): return unittest.TestLoader().loadTestsFromName(__name__) diff --git a/tests/test_lobject.py b/tests/test_lobject.py index e32673c..291a734 100755 --- a/tests/test_lobject.py +++ b/tests/test_lobject.py @@ -31,19 +31,11 @@ import psycopg2 import psycopg2.extensions import unittest from .testutils import (decorate_all_tests, skip_if_tpc_disabled, - ConnectingTestCase, skip_if_green, slow) + skip_before_postgres, ConnectingTestCase, skip_if_green, slow) -def skip_if_no_lo(f): - @wraps(f) - def skip_if_no_lo_(self): - if self.conn.info.server_version < 80100: - return self.skipTest("large objects only supported from PG 8.1") - else: - return f(self) - - return skip_if_no_lo_ - +skip_if_no_lo = skip_before_postgres(8, 1, + "large objects only supported from PG 8.1") skip_lo_if_green = skip_if_green("libpq doesn't support LO in async mode") @@ -73,6 +65,8 @@ class LargeObjectTestCase(ConnectingTestCase): ConnectingTestCase.tearDown(self) +@skip_if_no_lo +@skip_lo_if_green class LargeObjectTests(LargeObjectTestCase): def test_create(self): lo = self.conn.lobject() @@ -399,9 +393,7 @@ class LargeObjectTests(LargeObjectTestCase): self.assert_(isinstance(lo, lobject_subclass)) -decorate_all_tests(LargeObjectTests, skip_if_no_lo, skip_lo_if_green) - - +@decorate_all_tests def skip_if_no_truncate(f): @wraps(f) def skip_if_no_truncate_(self): @@ -419,6 +411,9 @@ def skip_if_no_truncate(f): return skip_if_no_truncate_ +@skip_if_no_lo +@skip_lo_if_green +@skip_if_no_truncate class LargeObjectTruncateTests(LargeObjectTestCase): def test_truncate(self): lo = self.conn.lobject() @@ -456,10 +451,6 @@ class LargeObjectTruncateTests(LargeObjectTestCase): self.assertRaises(psycopg2.ProgrammingError, lo.truncate) -decorate_all_tests(LargeObjectTruncateTests, - skip_if_no_lo, skip_lo_if_green, skip_if_no_truncate) - - def _has_lo64(conn): """Return (bool, msg) about the lo64 support""" if conn.info.server_version < 90300: @@ -472,6 +463,7 @@ def _has_lo64(conn): return True, "this server and build support the lo64 API" +@decorate_all_tests def skip_if_no_lo64(f): @wraps(f) def skip_if_no_lo64_(self): @@ -484,6 +476,10 @@ def skip_if_no_lo64(f): return skip_if_no_lo64_ +@skip_if_no_lo +@skip_lo_if_green +@skip_if_no_truncate +@skip_if_no_lo64 class LargeObject64Tests(LargeObjectTestCase): def test_seek_tell_truncate_greater_than_2gb(self): lo = self.conn.lobject() @@ -495,10 +491,7 @@ class LargeObject64Tests(LargeObjectTestCase): self.assertEqual(lo.tell(), length) -decorate_all_tests(LargeObject64Tests, - skip_if_no_lo, skip_lo_if_green, skip_if_no_truncate, skip_if_no_lo64) - - +@decorate_all_tests def skip_if_lo64(f): @wraps(f) def skip_if_lo64_(self): @@ -511,6 +504,10 @@ def skip_if_lo64(f): return skip_if_lo64_ +@skip_if_no_lo +@skip_lo_if_green +@skip_if_no_truncate +@skip_if_lo64 class LargeObjectNot64Tests(LargeObjectTestCase): def test_seek_larger_than_2gb(self): lo = self.conn.lobject() @@ -527,10 +524,6 @@ class LargeObjectNot64Tests(LargeObjectTestCase): lo.truncate, length) -decorate_all_tests(LargeObjectNot64Tests, - skip_if_no_lo, skip_lo_if_green, skip_if_no_truncate, skip_if_lo64) - - def test_suite(): return unittest.TestLoader().loadTestsFromName(__name__) diff --git a/tests/test_psycopg2_dbapi20.py b/tests/test_psycopg2_dbapi20.py index 5bcb9e3..183c40f 100755 --- a/tests/test_psycopg2_dbapi20.py +++ b/tests/test_psycopg2_dbapi20.py @@ -26,7 +26,6 @@ from . import dbapi20 from . import dbapi20_tpc from .testutils import skip_if_tpc_disabled import unittest -from .testutils import decorate_all_tests import psycopg2 from .testconfig import dsn @@ -70,6 +69,7 @@ class Psycopg2Tests(dbapi20.DatabaseAPI20Test): pass +@skip_if_tpc_disabled class Psycopg2TPCTests(dbapi20_tpc.TwoPhaseCommitTests, unittest.TestCase): driver = psycopg2 @@ -77,9 +77,6 @@ class Psycopg2TPCTests(dbapi20_tpc.TwoPhaseCommitTests, unittest.TestCase): return psycopg2.connect(dsn=dsn) -decorate_all_tests(Psycopg2TPCTests, skip_if_tpc_disabled) - - def test_suite(): return unittest.TestLoader().loadTestsFromName(__name__) diff --git a/tests/test_types_basic.py b/tests/test_types_basic.py index 774f7ad..63f74b0 100755 --- a/tests/test_types_basic.py +++ b/tests/test_types_basic.py @@ -456,6 +456,20 @@ class AdaptSubclassTest(unittest.TestCase): self.assertEqual(ext.adapt(foo((1, 2, 3))).getquoted(), 'bar') +@decorate_all_tests +def skip_if_cant_cast(f): + @wraps(f) + def skip_if_cant_cast_(self, *args, **kwargs): + if self._cast is None: + return self.skipTest("can't test bytea parser: %s - %s" + % (self._exc.__class__.__name__, self._exc)) + + return f(self, *args, **kwargs) + + return skip_if_cant_cast_ + + +@skip_if_cant_cast class ByteaParserTest(unittest.TestCase): """Unit test for our bytea format parser.""" def setUp(self): @@ -543,21 +557,6 @@ class ByteaParserTest(unittest.TestCase): self.assertEqual(rv, tgt) -def skip_if_cant_cast(f): - @wraps(f) - def skip_if_cant_cast_(self, *args, **kwargs): - if self._cast is None: - return self.skipTest("can't test bytea parser: %s - %s" - % (self._exc.__class__.__name__, self._exc)) - - return f(self, *args, **kwargs) - - return skip_if_cant_cast_ - - -decorate_all_tests(ByteaParserTest, skip_if_cant_cast) - - def test_suite(): return unittest.TestLoader().loadTestsFromName(__name__) diff --git a/tests/test_types_extras.py b/tests/test_types_extras.py index 1aa2ecf..81b74df 100755 --- a/tests/test_types_extras.py +++ b/tests/test_types_extras.py @@ -24,8 +24,7 @@ from pickle import dumps, loads import unittest from .testutils import (skip_if_no_uuid, skip_before_postgres, - ConnectingTestCase, decorate_all_tests, py3_raises_typeerror, slow, - skip_from_python) + ConnectingTestCase, py3_raises_typeerror, slow, skip_from_python) import psycopg2 import psycopg2.extras @@ -1049,6 +1048,7 @@ def skip_if_no_jsonb_type(f): return skip_before_postgres(9, 4)(f) +@skip_if_no_jsonb_type class JsonbTestCase(ConnectingTestCase): @staticmethod def myloads(s): @@ -1139,9 +1139,6 @@ class JsonbTestCase(ConnectingTestCase): self.assertEqual(curs.fetchone()[0], None) -decorate_all_tests(JsonbTestCase, skip_if_no_jsonb_type) - - class RangeTestCase(unittest.TestCase): def test_noparam(self): from psycopg2.extras import Range @@ -1435,19 +1432,7 @@ class RangeTestCase(unittest.TestCase): self.assertEqual(result, expected) -def skip_if_no_range(f): - @wraps(f) - def skip_if_no_range_(self): - if self.conn.info.server_version < 90200: - return self.skipTest( - "server version %s doesn't support range types" - % self.conn.info.server_version) - - return f(self) - - return skip_if_no_range_ - - +@skip_before_postgres(9, 2, "range not supported before postgres 9.2") class RangeCasterTestCase(ConnectingTestCase): builtin_ranges = ('int4range', 'int8range', 'numrange', @@ -1766,9 +1751,6 @@ class RangeCasterTestCase(ConnectingTestCase): del ext.adapters[r.range, ext.ISQLQuote] -decorate_all_tests(RangeCasterTestCase, skip_if_no_range) - - def test_suite(): return unittest.TestLoader().loadTestsFromName(__name__) diff --git a/tests/testutils.py b/tests/testutils.py index 7fd11f9..bc1a8ab 100644 --- a/tests/testutils.py +++ b/tests/testutils.py @@ -25,6 +25,7 @@ import re import os import sys +import types import select import platform import unittest @@ -174,16 +175,31 @@ class ConnectingTestCase(unittest.TestCase): raise Exception("Unexpected result from poll: %r", state) -def decorate_all_tests(cls, *decorators): +def decorate_all_tests(obj, *decorators): """ - Apply all the *decorators* to all the tests defined in the TestCase *cls*. + Apply all the *decorators* to all the tests defined in the TestCase *obj*. + + The decorator can also be applied to a decorator: if *obj* is a function, + return a new decorator which can be applied either to a method or to a + class, in which case it will decorate all the tests. """ - for n in dir(cls): + if isinstance(obj, types.FunctionType): + def decorator(func_or_cls): + if isinstance(func_or_cls, types.FunctionType): + return obj(func_or_cls) + else: + decorate_all_tests(func_or_cls, obj) + return func_or_cls + + return decorator + + for n in dir(obj): if n.startswith('test'): for d in decorators: - setattr(cls, n, d(getattr(cls, n))) + setattr(obj, n, d(getattr(obj, n))) +@decorate_all_tests def skip_if_no_uuid(f): """Decorator to skip a test if uuid is not supported by Py/PG.""" @wraps(f) @@ -203,6 +219,7 @@ def skip_if_no_uuid(f): return skip_if_no_uuid_ +@decorate_all_tests def skip_if_tpc_disabled(f): """Skip a test if the server has tpc support disabled.""" @wraps(f) @@ -230,13 +247,19 @@ def skip_if_tpc_disabled(f): def skip_before_postgres(*ver): """Skip a test on PostgreSQL before a certain version.""" + reason = None + if isinstance(ver[-1], str): + ver, reason = ver[:-1], ver[-1] + ver = ver + (0,) * (3 - len(ver)) + @decorate_all_tests def skip_before_postgres_(f): @wraps(f) def skip_before_postgres__(self): if self.conn.info.server_version < int("%d%02d%02d" % ver): - return self.skipTest("skipped because PostgreSQL %s" + return self.skipTest( + reason or "skipped because PostgreSQL %s" % self.conn.info.server_version) else: return f(self) @@ -249,6 +272,7 @@ def skip_after_postgres(*ver): """Skip a test on PostgreSQL after (including) a certain version.""" ver = ver + (0,) * (3 - len(ver)) + @decorate_all_tests def skip_after_postgres_(f): @wraps(f) def skip_after_postgres__(self): @@ -274,6 +298,7 @@ def skip_before_libpq(*ver): """Skip a test if libpq we're linked to is older than a certain version.""" ver = ver + (0,) * (3 - len(ver)) + @decorate_all_tests def skip_before_libpq_(f): @wraps(f) def skip_before_libpq__(self): @@ -291,6 +316,7 @@ def skip_after_libpq(*ver): """Skip a test if libpq we're linked to is newer than a certain version.""" ver = ver + (0,) * (3 - len(ver)) + @decorate_all_tests def skip_after_libpq_(f): @wraps(f) def skip_after_libpq__(self): @@ -306,6 +332,7 @@ def skip_after_libpq(*ver): def skip_before_python(*ver): """Skip a test on Python before a certain version.""" + @decorate_all_tests def skip_before_python_(f): @wraps(f) def skip_before_python__(self): @@ -321,6 +348,7 @@ def skip_before_python(*ver): def skip_from_python(*ver): """Skip a test on Python after (including) a certain version.""" + @decorate_all_tests def skip_from_python_(f): @wraps(f) def skip_from_python__(self): @@ -334,6 +362,7 @@ def skip_from_python(*ver): return skip_from_python_ +@decorate_all_tests def skip_if_no_superuser(f): """Skip a test if the database user running the test is not a superuser""" @wraps(f) @@ -352,6 +381,7 @@ def skip_if_no_superuser(f): def skip_if_green(reason): + @decorate_all_tests def skip_if_green_(f): @wraps(f) def skip_if_green__(self): @@ -368,6 +398,7 @@ def skip_if_green(reason): skip_copy_if_green = skip_if_green("copy in async mode currently not supported") +@decorate_all_tests def skip_if_no_getrefcount(f): @wraps(f) def skip_if_no_getrefcount_(self): @@ -378,6 +409,7 @@ def skip_if_no_getrefcount(f): return skip_if_no_getrefcount_ +@decorate_all_tests def skip_if_windows(f): """Skip a test if run on windows""" @wraps(f) |