From d024d546ae13207eaf6735f461b295280fbd75ed Mon Sep 17 00:00:00 2001 From: Berker Peksag Date: Sun, 19 Nov 2017 09:50:14 +0300 Subject: [PATCH 1/6] bpo-1102: View.Fetch() now returns None when it's exhausted --- .../next/Windows/2017-11-19-09-46-27.bpo-1102.NY-g1F.rst | 4 ++++ PC/_msi.c | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Windows/2017-11-19-09-46-27.bpo-1102.NY-g1F.rst diff --git a/Misc/NEWS.d/next/Windows/2017-11-19-09-46-27.bpo-1102.NY-g1F.rst b/Misc/NEWS.d/next/Windows/2017-11-19-09-46-27.bpo-1102.NY-g1F.rst new file mode 100644 index 00000000000000..6a6618e9692558 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2017-11-19-09-46-27.bpo-1102.NY-g1F.rst @@ -0,0 +1,4 @@ +Return ``None`` when ``View.Fetch()`` returns ``ERROR_NO_MORE_ITEMS`` +instead of raising ``MSIError``. + +Initial patch by Anthony Tuininga. diff --git a/PC/_msi.c b/PC/_msi.c index df6c881b4ec44f..a6a12e2010738b 100644 --- a/PC/_msi.c +++ b/PC/_msi.c @@ -723,8 +723,12 @@ view_fetch(msiobj *view, PyObject*args) int status; MSIHANDLE result; - if ((status = MsiViewFetch(view->h, &result)) != ERROR_SUCCESS) + status = MsiViewFetch(view->h, &result); + if (status == ERROR_NO_MORE_ITEMS) { + Py_RETURN_NONE; + } else if (status != ERROR_SUCCESS) { return msierror(status); + } return record_new(result); } From 1718e0250a97543ec52da0df2037e64dcadd7e91 Mon Sep 17 00:00:00 2001 From: Berker Peksag Date: Tue, 21 Nov 2017 10:27:06 +0300 Subject: [PATCH 2/6] Add test case --- Lib/test/test_msilib.py | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_msilib.py b/Lib/test/test_msilib.py index f656f7234e2d33..67e99ef1921487 100644 --- a/Lib/test/test_msilib.py +++ b/Lib/test/test_msilib.py @@ -1,8 +1,44 @@ """ Test suite for the code in msilib """ +import pathlib import unittest -from test.support import import_module +from test.support import TESTFN, import_module, unlink msilib = import_module('msilib') + +def initialize_db(): + path = pathlib.Path(TESTFN) / 'test.msi' + db = msilib.init_database( + path, msilib.schema, 'Python Tests', 'product_code', '1.0', 'PSF', + ) + return db, path + + +class MsiTestCase(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.db, cls.db_path = initialize_db() + + @classmethod + def tearDownClass(cls): + unlink(cls.db_path) + + def test_view_fetch(self): + properties = [] + view = self.db.OpenView('SELECT Value FROM Property') + view.Execute(None) + while True: + cur_record = view.Fetch() + if cur_record is None: + break + properties.append(cur_record.GetString(0)) + self.assertEqual( + properties, + ['ProductName', 'ProductCode', 'ProductVersion', + 'Manufacturer', 'ProductLanguage'] + ) + + class Test_make_id(unittest.TestCase): #http://msdn.microsoft.com/en-us/library/aa369212(v=vs.85).aspx """The Identifier data type is a text string. Identifiers may contain the From f94bd0455e1c8cf5fd4ae7eccba0176e8a9c1e5d Mon Sep 17 00:00:00 2001 From: Berker Peksag Date: Tue, 21 Nov 2017 10:37:41 +0300 Subject: [PATCH 3/6] Fix import --- Lib/test/test_msilib.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_msilib.py b/Lib/test/test_msilib.py index 67e99ef1921487..0cea585ee7bd82 100644 --- a/Lib/test/test_msilib.py +++ b/Lib/test/test_msilib.py @@ -3,6 +3,7 @@ import unittest from test.support import TESTFN, import_module, unlink msilib = import_module('msilib') +import msilib.schema def initialize_db(): From a6c244367017f268d717c25791d5a2a08790afdd Mon Sep 17 00:00:00 2001 From: Berker Peksag Date: Tue, 21 Nov 2017 10:49:45 +0300 Subject: [PATCH 4/6] Fix path call --- Lib/test/test_msilib.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_msilib.py b/Lib/test/test_msilib.py index 0cea585ee7bd82..c4742cf354a076 100644 --- a/Lib/test/test_msilib.py +++ b/Lib/test/test_msilib.py @@ -9,7 +9,12 @@ def initialize_db(): path = pathlib.Path(TESTFN) / 'test.msi' db = msilib.init_database( - path, msilib.schema, 'Python Tests', 'product_code', '1.0', 'PSF', + str(path), # TODO: OpenDatabase() doesn't accept PathLike objects. + msilib.schema, + 'Python Tests', + 'product_code', + '1.0', + 'PSF', ) return db, path From 17dac80b0981d9b2e7e183c286102ae43ea56c8b Mon Sep 17 00:00:00 2001 From: Berker Peksag Date: Tue, 21 Nov 2017 12:36:30 +0300 Subject: [PATCH 5/6] Fix test --- Lib/test/test_msilib.py | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/Lib/test/test_msilib.py b/Lib/test/test_msilib.py index c4742cf354a076..715bf4d0382d09 100644 --- a/Lib/test/test_msilib.py +++ b/Lib/test/test_msilib.py @@ -1,15 +1,14 @@ """ Test suite for the code in msilib """ -import pathlib import unittest from test.support import TESTFN, import_module, unlink msilib = import_module('msilib') import msilib.schema -def initialize_db(): - path = pathlib.Path(TESTFN) / 'test.msi' +def init_database(): + path = TESTFN + '.msi' db = msilib.init_database( - str(path), # TODO: OpenDatabase() doesn't accept PathLike objects. + path, msilib.schema, 'Python Tests', 'product_code', @@ -19,30 +18,27 @@ def initialize_db(): return db, path -class MsiTestCase(unittest.TestCase): +class MsiDatabaseTestCase(unittest.TestCase): - @classmethod - def setUpClass(cls): - cls.db, cls.db_path = initialize_db() - - @classmethod - def tearDownClass(cls): - unlink(cls.db_path) - - def test_view_fetch(self): + def test_view_fetch_returns_none(self): + db, db_path = init_database() properties = [] - view = self.db.OpenView('SELECT Value FROM Property') + view = db.OpenView('SELECT Property, Value FROM Property') view.Execute(None) while True: - cur_record = view.Fetch() - if cur_record is None: + record = view.Fetch() + if record is None: break - properties.append(cur_record.GetString(0)) + properties.append(record.GetString(1)) self.assertEqual( properties, - ['ProductName', 'ProductCode', 'ProductVersion', - 'Manufacturer', 'ProductLanguage'] + [ + 'ProductName', 'ProductCode', 'ProductVersion', + 'Manufacturer', 'ProductLanguage', + ] ) + view.Close() + self.addCleanup(unlink, db_path) class Test_make_id(unittest.TestCase): From 375835cd6de8eb848959451ac769d6acbc3e46ad Mon Sep 17 00:00:00 2001 From: Berker Peksag Date: Thu, 23 Nov 2017 12:54:08 +0300 Subject: [PATCH 6/6] Close database too --- Lib/test/test_msilib.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_msilib.py b/Lib/test/test_msilib.py index 715bf4d0382d09..65ff3869c33cbe 100644 --- a/Lib/test/test_msilib.py +++ b/Lib/test/test_msilib.py @@ -30,6 +30,8 @@ def test_view_fetch_returns_none(self): if record is None: break properties.append(record.GetString(1)) + view.Close() + db.Close() self.assertEqual( properties, [ @@ -37,7 +39,6 @@ def test_view_fetch_returns_none(self): 'Manufacturer', 'ProductLanguage', ] ) - view.Close() self.addCleanup(unlink, db_path)