Hello community, here is the log from the commit of package python-dbf for openSUSE:Factory checked in at 2019-07-26 17:33:54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-dbf (Old) and /work/SRC/openSUSE:Factory/.python-dbf.new.4126 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "python-dbf" Fri Jul 26 17:33:54 2019 rev:4 rq:718786 version:0.98.2 Changes: -------- --- /work/SRC/openSUSE:Factory/python-dbf/python-dbf.changes 2019-03-26 22:31:39.249716909 +0100 +++ /work/SRC/openSUSE:Factory/.python-dbf.new.4126/python-dbf.changes 2019-07-26 17:33:56.368096394 +0200 @@ -1,0 +2,7 @@ +Fri Jul 26 07:45:21 UTC 2019 - pgajdos@suse.com + +- version update to 0.98.2 + * allow dbf files without .dbf ending + * allow any case for accessing field names + +------------------------------------------------------------------- Old: ---- dbf-0.98.0.tar.gz New: ---- dbf-0.98.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-dbf.spec ++++++ --- /var/tmp/diff_new_pack.X4QfDb/_old 2019-07-26 17:33:56.832096211 +0200 +++ /var/tmp/diff_new_pack.X4QfDb/_new 2019-07-26 17:33:56.832096211 +0200 @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-dbf -Version: 0.98.0 +Version: 0.98.2 Release: 0 Summary: Pure python package for reading/writing dBase, FoxPro, and Visual FoxPro .dbf License: BSD-3-Clause ++++++ dbf-0.98.0.tar.gz -> dbf-0.98.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dbf-0.98.0/PKG-INFO new/dbf-0.98.2/PKG-INFO --- old/dbf-0.98.0/PKG-INFO 2019-03-16 01:39:55.000000000 +0100 +++ new/dbf-0.98.2/PKG-INFO 2019-07-11 20:34:24.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: dbf -Version: 0.98.0 +Version: 0.98.2 Summary: Pure python package for reading/writing dBase, FoxPro, and Visual FoxPro .dbf files (including memos) Home-page: https://pypi.python.org/pypi/dbf Author: Ethan Furman diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dbf-0.98.0/dbf/README.md new/dbf-0.98.2/dbf/README.md --- old/dbf-0.98.0/dbf/README.md 2019-03-16 01:38:25.000000000 +0100 +++ new/dbf-0.98.2/dbf/README.md 2019-07-11 20:32:48.000000000 +0200 @@ -101,12 +101,12 @@ table.append(datum) for record in table: - print record - print '--------' - print record[0:3] - print record['name':'qualified'] - print [record.name, record.age, record.birth] - print '--------' + print(record) + print('--------') + print(record[0:3]) + print(record['name':'qualified']) + print([record.name, record.age, record.birth]) + print('--------') custom = table.new( filename='test_on_disk', @@ -118,11 +118,11 @@ custom.append(record) for record in custom: dbf.write(record, name=record.name.upper()) - print record - print '--------' - print record[0:3] - print record['name':'qualified'] - print [record.name, record.age, record.birth] - print '--------' + print(record) + print('--------') + print(record[0:3]) + print(record['name':'qualified']) + print([record.name, record.age, record.birth]) + print('--------') table.close() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dbf-0.98.0/dbf/WHATSNEW new/dbf-0.98.2/dbf/WHATSNEW --- old/dbf-0.98.0/dbf/WHATSNEW 2019-03-16 01:38:25.000000000 +0100 +++ new/dbf-0.98.2/dbf/WHATSNEW 2019-07-11 20:32:48.000000000 +0200 @@ -1,6 +1,13 @@ What's New ========== +0.98.001 +-------- + +allow dbf files without .dbf ending +allow any case for accessing field names + + 0.98.000 -------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dbf-0.98.0/dbf/__init__.py new/dbf-0.98.2/dbf/__init__.py --- old/dbf-0.98.0/dbf/__init__.py 2019-03-16 01:38:25.000000000 +0100 +++ new/dbf-0.98.2/dbf/__init__.py 2019-07-11 20:32:48.000000000 +0200 @@ -74,7 +74,7 @@ long = int xrange = range -version = 0, 98, 0 +version = 0, 98, 2 NoneType = type(None) @@ -2919,6 +2919,7 @@ def __getattr__(self, name): if name[0:2] == '__' and name[-2:] == '__': raise AttributeError('Method %s is not implemented.' % name) + name = name.lower() if not name in self._meta.fields: raise FieldMissingError(name) if name in self._memos: @@ -3365,6 +3366,7 @@ def __getattr__(self, name): if name[0:2] == '__' and name[-2:] == '__': raise AttributeError('Method %s is not implemented.' % name) + name = name.lower() if not name in self._meta.fields: raise FieldMissingError(name) if name in self._memos: @@ -5059,7 +5061,7 @@ specs = specs.strip(sep).split(sep) else: specs = list(specs) - specs = [s.strip() for s in specs] + specs = [s.strip().lower() for s in specs] return specs def _nav_check(self): @@ -5233,13 +5235,22 @@ meta.header.data else: base, ext = os.path.splitext(filename) - if ext.lower() != '.dbf': - meta.filename = filename + '.dbf' - searchname = filename + '.[Db][Bb][Ff]' + search_name = None + if ext == '.': + # use filename without the '.' + search_name = base + matches = glob(search_name) + elif ext.lower() == '.dbf': + # use filename as-is + matches = glob(filename) else: - meta.filename = filename - searchname = filename - matches = glob(searchname) + meta.filename = filename + '.dbf' + search_name = filename + '.[Db][Bb][Ff]' + matches = glob(search_name) + if not matches: + meta.filename = filename + search_name = filename + matches = glob(search_name) if len(matches) == 1: meta.filename = matches[0] elif matches: @@ -5348,9 +5359,6 @@ raise DbfError("Unknown table type: %s" % dbf_type) return object.__new__(table) else: - base, ext = os.path.splitext(filename) - if ext.lower() != '.dbf': - filename = filename + '.dbf' possibles = guess_table_type(filename) if len(possibles) == 1: return object.__new__(possibles[0][2]) @@ -5837,6 +5845,7 @@ """ returns (field type, size, dec, class) of field """ + field = field.lower() if field in self.field_names: field = self._meta[field] return FieldInfo(field[TYPE], field[LENGTH], field[DECIMALS], field[CLASS]) @@ -5890,6 +5899,7 @@ """ returns True if field allows Nulls """ + field = field.lower() if field not in self.field_names: raise FieldMissingError(field) return bool(self._meta[field][FLAGS] & NULLABLE) @@ -5988,6 +5998,8 @@ """ renames an existing field """ + oldname = oldname.lower() + newname = newname.lower() meta = self._meta if meta.status != READ_WRITE: raise DbfError('%s not in read/write mode, unable to change field names' % meta.filename) @@ -5997,7 +6009,6 @@ raise FieldMissingError("field --%s-- does not exist -- cannot rename it." % oldname) if newname[0] == '_' or newname[0].isdigit() or not newname.replace('_', '').isalnum(): raise FieldSpecError("field names cannot start with _ or digits, and can only contain the _, letters, and digits") - newname = newname.lower() if newname in self._meta.fields: raise DbfError("field --%s-- already exists" % newname) if len(newname) > 10: @@ -8595,17 +8606,31 @@ """ returns text representation of a table's dbf version """ + actual_filename = None + search_name = None base, ext = os.path.splitext(filename) - if ext == '': - filename = base + '.[Dd][Bb][Ff]' + if ext == '.': + # use filename without the '.' + search_name = base + matches = glob(search_name) + elif ext.lower() == '.dbf': + # use filename as-is + search_name = filename + matches = glob(search_name) + else: + search_name = base + '.[Dd][Bb][Ff]' matches = glob(filename) - if matches: - filename = matches[0] - else: - filename = base + '.dbf' - if not os.path.exists(filename): - raise DbfError('File %s not found' % filename) - fd = open(filename, 'rb') + if not matches: + # back to original name + search_name = filename + matches = glob(search_name) + if len(matches) == 1: + actual_filename = matches[0] + elif matches: + raise DbfError("please specify exactly which of %r you want" % (matches, )) + else: + raise DbfError('File %r not found' % search_name) + fd = open(actual_filename, 'rb') version = ord(fd.read(1)) fd.close() fd = None @@ -8754,6 +8779,7 @@ record_fields = field_names(record) for key in field_names(data): value = data[key] + key = key.lower() if not key in record_fields: if drop: continue diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dbf-0.98.0/dbf/test.py new/dbf-0.98.2/dbf/test.py --- old/dbf-0.98.0/dbf/test.py 2019-03-16 01:38:25.000000000 +0100 +++ new/dbf-0.98.2/dbf/test.py 2019-07-11 20:32:48.000000000 +0200 @@ -3656,6 +3656,20 @@ )) self.assertNotEqual(old_data, dbf.scatter(record)) + def test_field_capitalization(self): + "ensure mixed- and upper-case field names work" + table = dbf.Table('mixed', 'NAME C(30); Age N(5,2)', on_disk=False) + self.assertEqual(['name', 'age'], field_names(table)) + table.open(dbf.READ_WRITE) + table.append({'Name':'Ethan', 'AGE': 99}) + rec = table[0] + self.assertEqual(rec.NaMe.strip(), 'Ethan') + table.rename_field('NaMe', 'My_NAME') + self.assertEqual(rec.My_NaMe.strip(), 'Ethan') + self.assertEqual(['my_name', 'age'], field_names(table)) + table.append({'MY_Name':'Allen', 'AGE': 7}) + rec = table[1] + self.assertEqual(rec.my_NaMe.strip(), 'Allen') class TestDbfRecordTemplates(TestCase): "Testing records" @@ -5169,6 +5183,50 @@ self.assertRaises((IOError, OSError), table.open, READ_WRITE) +class TestDBC(TestCase): + "test DBC handling" + + +class TestMisc(TestCase): + "miscellaneous tests" + + def setUp(self): + self.table = Table( + os.path.join(tempdir, 'dbf_table.'), + 'name C(25); paid L; qty N(11,5); orderdate D; desc M', + dbf_type='db3', + ) + self.table_dbf = Table( + os.path.join(tempdir, 'dbf_table.dbf'), + 'name C(25); paid L; qty N(11,5); orderdate D; desc M', + dbf_type='db3', + ) + self.table_implicit = Table( + os.path.join(tempdir, 'dbf_table'), + 'name C(25); paid L; qty N(11,5); orderdate D; desc M', + dbf_type='db3', + ) + self.table_wierd = Table( + os.path.join(tempdir, 'dbf_table.blah'), + 'name C(25); paid L; qty N(11,5); orderdate D; desc M', + dbf_type='db3', + ) + self.table.close() + self.table_dbf.close() + self.table_implicit.close() + self.table_wierd.close() + + def test_table_type_with_dbf(self): + dbf.table_type(self.table.filename) + dbf.table_type(self.table_dbf.filename) + dbf.table_type(self.table_implicit.filename) + dbf.table_type(self.table_wierd.filename) + dbf.Table(self.table.filename) + dbf.Table(self.table_dbf.filename) + dbf.Table(self.table_implicit.filename) + dbf.Table(self.table_wierd.filename) + + class TestWhatever(TestCase): "move tests here to run one at a time while debugging" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dbf-0.98.0/dbf.egg-info/PKG-INFO new/dbf-0.98.2/dbf.egg-info/PKG-INFO --- old/dbf-0.98.0/dbf.egg-info/PKG-INFO 2019-03-16 01:39:55.000000000 +0100 +++ new/dbf-0.98.2/dbf.egg-info/PKG-INFO 2019-07-11 20:34:24.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: dbf -Version: 0.98.0 +Version: 0.98.2 Summary: Pure python package for reading/writing dBase, FoxPro, and Visual FoxPro .dbf files (including memos) Home-page: https://pypi.python.org/pypi/dbf Author: Ethan Furman diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dbf-0.98.0/setup.py new/dbf-0.98.2/setup.py --- old/dbf-0.98.0/setup.py 2019-03-16 01:38:25.000000000 +0100 +++ new/dbf-0.98.2/setup.py 2019-07-11 20:32:48.000000000 +0200 @@ -21,7 +21,7 @@ data = dict( name='dbf', - version='0.98.0', + version='0.98.2', license='BSD License', description='Pure python package for reading/writing dBase, FoxPro, and Visual FoxPro .dbf files (including memos)', long_description=long_desc,