diff --git a/postgresql-python3.5-tests.patch b/postgresql-python3.5-tests.patch new file mode 100644 index 0000000..5b50b5a --- /dev/null +++ b/postgresql-python3.5-tests.patch @@ -0,0 +1,610 @@ +From 8e76ccde28901f96678f21a2487af3b6a433ee35 Mon Sep 17 00:00:00 2001 +From: Peter Eisentraut +Date: Wed, 3 Jun 2015 19:52:08 -0400 +Subject: [PATCH] PL/Python: Make tests pass with Python 3.5 + +The error message wording for AttributeError has changed in Python 3.5. +For the plpython_error test, add a new expected file. In the +plpython_subtransaction test, we didn't really care what the exception +is, only that it is something coming from Python. So use a generic +exception instead, which has a message that doesn't vary across +versions. +--- + src/pl/plpython/expected/README | 1 + + src/pl/plpython/expected/plpython_error_5.out | 428 +++++++++++++++++++++ + .../plpython/expected/plpython_subtransaction.out | 12 +- + .../expected/plpython_subtransaction_0.out | 8 +- + .../expected/plpython_subtransaction_5.out | 8 +- + src/pl/plpython/sql/plpython_subtransaction.sql | 4 +- + 6 files changed, 445 insertions(+), 16 deletions(-) + create mode 100644 src/pl/plpython/expected/plpython_error_5.out + +diff --git a/src/pl/plpython/expected/README b/src/pl/plpython/expected/README +index 5bf9366..b890563 100644 +--- a/src/pl/plpython/expected/README ++++ b/src/pl/plpython/expected/README +@@ -1,6 +1,7 @@ + Guide to alternative expected files: + + plpython_error_0.out Python 2.4 and older ++plpython_error_5.out Python 3.5 and newer + + plpython_unicode.out server encoding != SQL_ASCII + plpython_unicode_3.out server encoding == SQL_ASCII +diff --git a/src/pl/plpython/expected/plpython_error_5.out b/src/pl/plpython/expected/plpython_error_5.out +new file mode 100644 +index 0000000..fcd944c +--- /dev/null ++++ b/src/pl/plpython/expected/plpython_error_5.out +@@ -0,0 +1,428 @@ ++-- test error handling, i forgot to restore Warn_restart in ++-- the trigger handler once. the errors and subsequent core dump were ++-- interesting. ++/* Flat out Python syntax error ++ */ ++CREATE FUNCTION python_syntax_error() RETURNS text ++ AS ++'.syntaxerror' ++ LANGUAGE plpython3u; ++ERROR: could not compile PL/Python function "python_syntax_error" ++DETAIL: SyntaxError: invalid syntax (, line 2) ++/* With check_function_bodies = false the function should get defined ++ * and the error reported when called ++ */ ++SET check_function_bodies = false; ++CREATE FUNCTION python_syntax_error() RETURNS text ++ AS ++'.syntaxerror' ++ LANGUAGE plpython3u; ++SELECT python_syntax_error(); ++ERROR: could not compile PL/Python function "python_syntax_error" ++DETAIL: SyntaxError: invalid syntax (, line 2) ++/* Run the function twice to check if the hashtable entry gets cleaned up */ ++SELECT python_syntax_error(); ++ERROR: could not compile PL/Python function "python_syntax_error" ++DETAIL: SyntaxError: invalid syntax (, line 2) ++RESET check_function_bodies; ++/* Flat out syntax error ++ */ ++CREATE FUNCTION sql_syntax_error() RETURNS text ++ AS ++'plpy.execute("syntax error")' ++ LANGUAGE plpython3u; ++SELECT sql_syntax_error(); ++ERROR: spiexceptions.SyntaxError: syntax error at or near "syntax" ++LINE 1: syntax error ++ ^ ++QUERY: syntax error ++CONTEXT: Traceback (most recent call last): ++ PL/Python function "sql_syntax_error", line 1, in ++ plpy.execute("syntax error") ++PL/Python function "sql_syntax_error" ++/* check the handling of uncaught python exceptions ++ */ ++CREATE FUNCTION exception_index_invalid(text) RETURNS text ++ AS ++'return args[1]' ++ LANGUAGE plpython3u; ++SELECT exception_index_invalid('test'); ++ERROR: IndexError: list index out of range ++CONTEXT: Traceback (most recent call last): ++ PL/Python function "exception_index_invalid", line 1, in ++ return args[1] ++PL/Python function "exception_index_invalid" ++/* check handling of nested exceptions ++ */ ++CREATE FUNCTION exception_index_invalid_nested() RETURNS text ++ AS ++'rv = plpy.execute("SELECT test5(''foo'')") ++return rv[0]' ++ LANGUAGE plpython3u; ++SELECT exception_index_invalid_nested(); ++ERROR: spiexceptions.UndefinedFunction: function test5(unknown) does not exist ++LINE 1: SELECT test5('foo') ++ ^ ++HINT: No function matches the given name and argument types. You might need to add explicit type casts. ++QUERY: SELECT test5('foo') ++CONTEXT: Traceback (most recent call last): ++ PL/Python function "exception_index_invalid_nested", line 1, in ++ rv = plpy.execute("SELECT test5('foo')") ++PL/Python function "exception_index_invalid_nested" ++/* a typo ++ */ ++CREATE FUNCTION invalid_type_uncaught(a text) RETURNS text ++ AS ++'if "plan" not in SD: ++ q = "SELECT fname FROM users WHERE lname = $1" ++ SD["plan"] = plpy.prepare(q, [ "test" ]) ++rv = plpy.execute(SD["plan"], [ a ]) ++if len(rv): ++ return rv[0]["fname"] ++return None ++' ++ LANGUAGE plpython3u; ++SELECT invalid_type_uncaught('rick'); ++ERROR: spiexceptions.UndefinedObject: type "test" does not exist ++CONTEXT: Traceback (most recent call last): ++ PL/Python function "invalid_type_uncaught", line 3, in ++ SD["plan"] = plpy.prepare(q, [ "test" ]) ++PL/Python function "invalid_type_uncaught" ++/* for what it's worth catch the exception generated by ++ * the typo, and return None ++ */ ++CREATE FUNCTION invalid_type_caught(a text) RETURNS text ++ AS ++'if "plan" not in SD: ++ q = "SELECT fname FROM users WHERE lname = $1" ++ try: ++ SD["plan"] = plpy.prepare(q, [ "test" ]) ++ except plpy.SPIError as ex: ++ plpy.notice(str(ex)) ++ return None ++rv = plpy.execute(SD["plan"], [ a ]) ++if len(rv): ++ return rv[0]["fname"] ++return None ++' ++ LANGUAGE plpython3u; ++SELECT invalid_type_caught('rick'); ++NOTICE: type "test" does not exist ++CONTEXT: PL/Python function "invalid_type_caught" ++ invalid_type_caught ++--------------------- ++ ++(1 row) ++ ++/* for what it's worth catch the exception generated by ++ * the typo, and reraise it as a plain error ++ */ ++CREATE FUNCTION invalid_type_reraised(a text) RETURNS text ++ AS ++'if "plan" not in SD: ++ q = "SELECT fname FROM users WHERE lname = $1" ++ try: ++ SD["plan"] = plpy.prepare(q, [ "test" ]) ++ except plpy.SPIError as ex: ++ plpy.error(str(ex)) ++rv = plpy.execute(SD["plan"], [ a ]) ++if len(rv): ++ return rv[0]["fname"] ++return None ++' ++ LANGUAGE plpython3u; ++SELECT invalid_type_reraised('rick'); ++ERROR: plpy.Error: type "test" does not exist ++CONTEXT: Traceback (most recent call last): ++ PL/Python function "invalid_type_reraised", line 6, in ++ plpy.error(str(ex)) ++PL/Python function "invalid_type_reraised" ++/* no typo no messing about ++ */ ++CREATE FUNCTION valid_type(a text) RETURNS text ++ AS ++'if "plan" not in SD: ++ SD["plan"] = plpy.prepare("SELECT fname FROM users WHERE lname = $1", [ "text" ]) ++rv = plpy.execute(SD["plan"], [ a ]) ++if len(rv): ++ return rv[0]["fname"] ++return None ++' ++ LANGUAGE plpython3u; ++SELECT valid_type('rick'); ++ valid_type ++------------ ++ ++(1 row) ++ ++/* error in nested functions to get a traceback ++*/ ++CREATE FUNCTION nested_error() RETURNS text ++ AS ++'def fun1(): ++ plpy.error("boom") ++ ++def fun2(): ++ fun1() ++ ++def fun3(): ++ fun2() ++ ++fun3() ++return "not reached" ++' ++ LANGUAGE plpython3u; ++SELECT nested_error(); ++ERROR: plpy.Error: boom ++CONTEXT: Traceback (most recent call last): ++ PL/Python function "nested_error", line 10, in ++ fun3() ++ PL/Python function "nested_error", line 8, in fun3 ++ fun2() ++ PL/Python function "nested_error", line 5, in fun2 ++ fun1() ++ PL/Python function "nested_error", line 2, in fun1 ++ plpy.error("boom") ++PL/Python function "nested_error" ++/* raising plpy.Error is just like calling plpy.error ++*/ ++CREATE FUNCTION nested_error_raise() RETURNS text ++ AS ++'def fun1(): ++ raise plpy.Error("boom") ++ ++def fun2(): ++ fun1() ++ ++def fun3(): ++ fun2() ++ ++fun3() ++return "not reached" ++' ++ LANGUAGE plpython3u; ++SELECT nested_error_raise(); ++ERROR: plpy.Error: boom ++CONTEXT: Traceback (most recent call last): ++ PL/Python function "nested_error_raise", line 10, in ++ fun3() ++ PL/Python function "nested_error_raise", line 8, in fun3 ++ fun2() ++ PL/Python function "nested_error_raise", line 5, in fun2 ++ fun1() ++ PL/Python function "nested_error_raise", line 2, in fun1 ++ raise plpy.Error("boom") ++PL/Python function "nested_error_raise" ++/* using plpy.warning should not produce a traceback ++*/ ++CREATE FUNCTION nested_warning() RETURNS text ++ AS ++'def fun1(): ++ plpy.warning("boom") ++ ++def fun2(): ++ fun1() ++ ++def fun3(): ++ fun2() ++ ++fun3() ++return "you''ve been warned" ++' ++ LANGUAGE plpython3u; ++SELECT nested_warning(); ++WARNING: boom ++CONTEXT: PL/Python function "nested_warning" ++ nested_warning ++-------------------- ++ you've been warned ++(1 row) ++ ++/* AttributeError at toplevel used to give segfaults with the traceback ++*/ ++CREATE FUNCTION toplevel_attribute_error() RETURNS void AS ++$$ ++plpy.nonexistent ++$$ LANGUAGE plpython3u; ++SELECT toplevel_attribute_error(); ++ERROR: AttributeError: module 'plpy' has no attribute 'nonexistent' ++CONTEXT: Traceback (most recent call last): ++ PL/Python function "toplevel_attribute_error", line 2, in ++ plpy.nonexistent ++PL/Python function "toplevel_attribute_error" ++/* Calling PL/Python functions from SQL and vice versa should not lose context. ++ */ ++CREATE OR REPLACE FUNCTION python_traceback() RETURNS void AS $$ ++def first(): ++ second() ++ ++def second(): ++ third() ++ ++def third(): ++ plpy.execute("select sql_error()") ++ ++first() ++$$ LANGUAGE plpython3u; ++CREATE OR REPLACE FUNCTION sql_error() RETURNS void AS $$ ++begin ++ select 1/0; ++end ++$$ LANGUAGE plpgsql; ++CREATE OR REPLACE FUNCTION python_from_sql_error() RETURNS void AS $$ ++begin ++ select python_traceback(); ++end ++$$ LANGUAGE plpgsql; ++CREATE OR REPLACE FUNCTION sql_from_python_error() RETURNS void AS $$ ++plpy.execute("select sql_error()") ++$$ LANGUAGE plpython3u; ++SELECT python_traceback(); ++ERROR: spiexceptions.DivisionByZero: division by zero ++CONTEXT: Traceback (most recent call last): ++ PL/Python function "python_traceback", line 11, in ++ first() ++ PL/Python function "python_traceback", line 3, in first ++ second() ++ PL/Python function "python_traceback", line 6, in second ++ third() ++ PL/Python function "python_traceback", line 9, in third ++ plpy.execute("select sql_error()") ++PL/Python function "python_traceback" ++SELECT sql_error(); ++ERROR: division by zero ++CONTEXT: SQL statement "select 1/0" ++PL/pgSQL function sql_error() line 3 at SQL statement ++SELECT python_from_sql_error(); ++ERROR: spiexceptions.DivisionByZero: division by zero ++CONTEXT: Traceback (most recent call last): ++ PL/Python function "python_traceback", line 11, in ++ first() ++ PL/Python function "python_traceback", line 3, in first ++ second() ++ PL/Python function "python_traceback", line 6, in second ++ third() ++ PL/Python function "python_traceback", line 9, in third ++ plpy.execute("select sql_error()") ++PL/Python function "python_traceback" ++SQL statement "select python_traceback()" ++PL/pgSQL function python_from_sql_error() line 3 at SQL statement ++SELECT sql_from_python_error(); ++ERROR: spiexceptions.DivisionByZero: division by zero ++CONTEXT: Traceback (most recent call last): ++ PL/Python function "sql_from_python_error", line 2, in ++ plpy.execute("select sql_error()") ++PL/Python function "sql_from_python_error" ++/* check catching specific types of exceptions ++ */ ++CREATE TABLE specific ( ++ i integer PRIMARY KEY ++); ++CREATE FUNCTION specific_exception(i integer) RETURNS void AS ++$$ ++from plpy import spiexceptions ++try: ++ plpy.execute("insert into specific values (%s)" % (i or "NULL")); ++except spiexceptions.NotNullViolation as e: ++ plpy.notice("Violated the NOT NULL constraint, sqlstate %s" % e.sqlstate) ++except spiexceptions.UniqueViolation as e: ++ plpy.notice("Violated the UNIQUE constraint, sqlstate %s" % e.sqlstate) ++$$ LANGUAGE plpython3u; ++SELECT specific_exception(2); ++ specific_exception ++-------------------- ++ ++(1 row) ++ ++SELECT specific_exception(NULL); ++NOTICE: Violated the NOT NULL constraint, sqlstate 23502 ++CONTEXT: PL/Python function "specific_exception" ++ specific_exception ++-------------------- ++ ++(1 row) ++ ++SELECT specific_exception(2); ++NOTICE: Violated the UNIQUE constraint, sqlstate 23505 ++CONTEXT: PL/Python function "specific_exception" ++ specific_exception ++-------------------- ++ ++(1 row) ++ ++/* SPI errors in PL/Python functions should preserve the SQLSTATE value ++ */ ++CREATE FUNCTION python_unique_violation() RETURNS void AS $$ ++plpy.execute("insert into specific values (1)") ++plpy.execute("insert into specific values (1)") ++$$ LANGUAGE plpython3u; ++CREATE FUNCTION catch_python_unique_violation() RETURNS text AS $$ ++begin ++ begin ++ perform python_unique_violation(); ++ exception when unique_violation then ++ return 'ok'; ++ end; ++ return 'not reached'; ++end; ++$$ language plpgsql; ++SELECT catch_python_unique_violation(); ++ catch_python_unique_violation ++------------------------------- ++ ok ++(1 row) ++ ++/* manually starting subtransactions - a bad idea ++ */ ++CREATE FUNCTION manual_subxact() RETURNS void AS $$ ++plpy.execute("savepoint save") ++plpy.execute("create table foo(x integer)") ++plpy.execute("rollback to save") ++$$ LANGUAGE plpython3u; ++SELECT manual_subxact(); ++ERROR: plpy.SPIError: SPI_execute failed: SPI_ERROR_TRANSACTION ++CONTEXT: Traceback (most recent call last): ++ PL/Python function "manual_subxact", line 2, in ++ plpy.execute("savepoint save") ++PL/Python function "manual_subxact" ++/* same for prepared plans ++ */ ++CREATE FUNCTION manual_subxact_prepared() RETURNS void AS $$ ++save = plpy.prepare("savepoint save") ++rollback = plpy.prepare("rollback to save") ++plpy.execute(save) ++plpy.execute("create table foo(x integer)") ++plpy.execute(rollback) ++$$ LANGUAGE plpython3u; ++SELECT manual_subxact_prepared(); ++ERROR: plpy.SPIError: SPI_execute_plan failed: SPI_ERROR_TRANSACTION ++CONTEXT: Traceback (most recent call last): ++ PL/Python function "manual_subxact_prepared", line 4, in ++ plpy.execute(save) ++PL/Python function "manual_subxact_prepared" ++/* raising plpy.spiexception.* from python code should preserve sqlstate ++ */ ++CREATE FUNCTION plpy_raise_spiexception() RETURNS void AS $$ ++raise plpy.spiexceptions.DivisionByZero() ++$$ LANGUAGE plpython3u; ++DO $$ ++BEGIN ++ SELECT plpy_raise_spiexception(); ++EXCEPTION WHEN division_by_zero THEN ++ -- NOOP ++END ++$$ LANGUAGE plpgsql; ++/* setting a custom sqlstate should be handled ++ */ ++CREATE FUNCTION plpy_raise_spiexception_override() RETURNS void AS $$ ++exc = plpy.spiexceptions.DivisionByZero() ++exc.sqlstate = 'SILLY' ++raise exc ++$$ LANGUAGE plpython3u; ++DO $$ ++BEGIN ++ SELECT plpy_raise_spiexception_override(); ++EXCEPTION WHEN SQLSTATE 'SILLY' THEN ++ -- NOOP ++END ++$$ LANGUAGE plpgsql; +diff --git a/src/pl/plpython/expected/plpython_subtransaction.out b/src/pl/plpython/expected/plpython_subtransaction.out +index ced4682..c7bf6cc 100644 +--- a/src/pl/plpython/expected/plpython_subtransaction.out ++++ b/src/pl/plpython/expected/plpython_subtransaction.out +@@ -19,7 +19,7 @@ try: + if what_error == "SPI": + plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')") + elif what_error == "Python": +- plpy.attribute_error ++ raise Exception("Python exception") + except: + exc = False + subxact.__exit__(*sys.exc_info()) +@@ -58,10 +58,10 @@ SELECT * FROM subtransaction_tbl; + + TRUNCATE subtransaction_tbl; + SELECT subtransaction_test('Python'); +-ERROR: AttributeError: 'module' object has no attribute 'attribute_error' ++ERROR: Exception: Python exception + CONTEXT: Traceback (most recent call last): + PL/Python function "subtransaction_test", line 13, in +- plpy.attribute_error ++ raise Exception("Python exception") + PL/Python function "subtransaction_test" + SELECT * FROM subtransaction_tbl; + i +@@ -78,7 +78,7 @@ with plpy.subtransaction(): + if what_error == "SPI": + plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')") + elif what_error == "Python": +- plpy.attribute_error ++ raise Exception("Python exception") + $$ LANGUAGE plpythonu; + SELECT subtransaction_ctx_test(); + subtransaction_ctx_test +@@ -110,10 +110,10 @@ SELECT * FROM subtransaction_tbl; + + TRUNCATE subtransaction_tbl; + SELECT subtransaction_ctx_test('Python'); +-ERROR: AttributeError: 'module' object has no attribute 'attribute_error' ++ERROR: Exception: Python exception + CONTEXT: Traceback (most recent call last): + PL/Python function "subtransaction_ctx_test", line 8, in +- plpy.attribute_error ++ raise Exception("Python exception") + PL/Python function "subtransaction_ctx_test" + SELECT * FROM subtransaction_tbl; + i +diff --git a/src/pl/plpython/expected/plpython_subtransaction_0.out b/src/pl/plpython/expected/plpython_subtransaction_0.out +index 6f4be55..73bd724 100644 +--- a/src/pl/plpython/expected/plpython_subtransaction_0.out ++++ b/src/pl/plpython/expected/plpython_subtransaction_0.out +@@ -19,7 +19,7 @@ try: + if what_error == "SPI": + plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')") + elif what_error == "Python": +- plpy.attribute_error ++ raise Exception("Python exception") + except: + exc = False + subxact.__exit__(*sys.exc_info()) +@@ -58,10 +58,10 @@ SELECT * FROM subtransaction_tbl; + + TRUNCATE subtransaction_tbl; + SELECT subtransaction_test('Python'); +-ERROR: AttributeError: 'module' object has no attribute 'attribute_error' ++ERROR: Exception: Python exception + CONTEXT: Traceback (most recent call last): + PL/Python function "subtransaction_test", line 13, in +- plpy.attribute_error ++ raise Exception("Python exception") + PL/Python function "subtransaction_test" + SELECT * FROM subtransaction_tbl; + i +@@ -78,7 +78,7 @@ with plpy.subtransaction(): + if what_error == "SPI": + plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')") + elif what_error == "Python": +- plpy.attribute_error ++ raise Exception("Python exception") + $$ LANGUAGE plpythonu; + ERROR: could not compile PL/Python function "subtransaction_ctx_test" + DETAIL: SyntaxError: invalid syntax (line 3) +diff --git a/src/pl/plpython/expected/plpython_subtransaction_5.out b/src/pl/plpython/expected/plpython_subtransaction_5.out +index 4ca1835..d177620 100644 +--- a/src/pl/plpython/expected/plpython_subtransaction_5.out ++++ b/src/pl/plpython/expected/plpython_subtransaction_5.out +@@ -19,7 +19,7 @@ try: + if what_error == "SPI": + plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')") + elif what_error == "Python": +- plpy.attribute_error ++ raise Exception("Python exception") + except: + exc = False + subxact.__exit__(*sys.exc_info()) +@@ -58,10 +58,10 @@ SELECT * FROM subtransaction_tbl; + + TRUNCATE subtransaction_tbl; + SELECT subtransaction_test('Python'); +-ERROR: AttributeError: 'module' object has no attribute 'attribute_error' ++ERROR: Exception: Python exception + CONTEXT: Traceback (most recent call last): + PL/Python function "subtransaction_test", line 13, in +- plpy.attribute_error ++ raise Exception("Python exception") + PL/Python function "subtransaction_test" + SELECT * FROM subtransaction_tbl; + i +@@ -78,7 +78,7 @@ with plpy.subtransaction(): + if what_error == "SPI": + plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')") + elif what_error == "Python": +- plpy.attribute_error ++ raise Exception("Python exception") + $$ LANGUAGE plpythonu; + ERROR: could not compile PL/Python function "subtransaction_ctx_test" + DETAIL: SyntaxError: invalid syntax (, line 3) +diff --git a/src/pl/plpython/sql/plpython_subtransaction.sql b/src/pl/plpython/sql/plpython_subtransaction.sql +index 9ad6377..3c188e3 100644 +--- a/src/pl/plpython/sql/plpython_subtransaction.sql ++++ b/src/pl/plpython/sql/plpython_subtransaction.sql +@@ -23,7 +23,7 @@ try: + if what_error == "SPI": + plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')") + elif what_error == "Python": +- plpy.attribute_error ++ raise Exception("Python exception") + except: + exc = False + subxact.__exit__(*sys.exc_info()) +@@ -53,7 +53,7 @@ with plpy.subtransaction(): + if what_error == "SPI": + plpy.execute("INSERT INTO subtransaction_tbl VALUES ('oops')") + elif what_error == "Python": +- plpy.attribute_error ++ raise Exception("Python exception") + $$ LANGUAGE plpythonu; + + SELECT subtransaction_ctx_test(); +-- +2.5.0 + diff --git a/postgresql.spec b/postgresql.spec index 870994b..440281b 100644 --- a/postgresql.spec +++ b/postgresql.spec @@ -117,6 +117,7 @@ Patch4: postgresql-config-comment.patch Patch5: postgresql-var-run-socket.patch Patch6: postgresql-man.patch Patch7: postgresql-perl-5.22-test-fail.patch +Patch8: postgresql-python3.5-tests.patch BuildRequires: perl(ExtUtils::MakeMaker) glibc-devel bison flex gawk help2man BuildRequires: perl(ExtUtils::Embed), perl-devel @@ -357,6 +358,7 @@ benchmarks. %patch5 -p1 %patch6 -p1 %patch7 -p1 +%patch8 -p1 # We used to run autoconf here, but there's no longer any real need to, # since Postgres ships with a reasonably modern configure script. @@ -1184,6 +1186,9 @@ fi %endif %changelog +* Thu Nov 12 2015 Pavel Raiskup - 9.4.5-3 +- fix testsuite failure with new Python 3.5 (rhbz#1280404) + * Tue Nov 10 2015 Fedora Release Engineering - 9.4.5-3 - Rebuilt for https://fedoraproject.org/wiki/Changes/python3.5