fixed import_from_csv_field and new tests, thanks Jonathan
This commit is contained in:
@@ -1 +1 @@
|
|||||||
Version 2.00.0 (2012-07-31 15:06:22) dev
|
Version 2.00.0 (2012-07-31 19:24:21) dev
|
||||||
|
|||||||
+19
-22
@@ -7566,24 +7566,24 @@ class Table(dict):
|
|||||||
id_map=None,
|
id_map=None,
|
||||||
null='<NULL>',
|
null='<NULL>',
|
||||||
unique='uuid',
|
unique='uuid',
|
||||||
id_offset={}, # id_offset only used when id_map is None
|
id_offset=None, # id_offset used only when id_map is None
|
||||||
*args, **kwargs
|
*args, **kwargs
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
import records from csv file. Column headers must have same names as
|
Import records from csv file.
|
||||||
table fields. field 'id' is ignored. If column names read 'table.file'
|
Column headers must have same names as table fields.
|
||||||
the 'table.' prefix is ignored.
|
Field 'id' is ignored.
|
||||||
'unique' argument is a field which must be unique
|
If column names read 'table.file' the 'table.' prefix is ignored.
|
||||||
(typically a uuid field)
|
'unique' argument is a field which must be unique
|
||||||
'restore' argument is default False.
|
(typically a uuid field)
|
||||||
If set True will remove old values
|
'restore' argument is default False;
|
||||||
in table first.
|
if set True will remove old values in table first.
|
||||||
'id_map' If set to None will not map id.
|
'id_map' ff set to None will not map ids.
|
||||||
The import will keep the id numbers in the restored table.
|
The import will keep the id numbers in the restored table.
|
||||||
This assumes that there is an field of type id that
|
This assumes that there is an field of type id that
|
||||||
is integer and in incrementing order.
|
is integer and in incrementing order.
|
||||||
Will keep the id numbers in restored table.
|
Will keep the id numbers in restored table.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
delimiter = kwargs.get('delimiter', ',')
|
delimiter = kwargs.get('delimiter', ',')
|
||||||
quotechar = kwargs.get('quotechar', '"')
|
quotechar = kwargs.get('quotechar', '"')
|
||||||
@@ -7643,12 +7643,13 @@ class Table(dict):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
first = True
|
first = True
|
||||||
|
unique_idx = None
|
||||||
for line in reader:
|
for line in reader:
|
||||||
if not line:
|
if not line:
|
||||||
break
|
break
|
||||||
if not colnames:
|
if not colnames:
|
||||||
colnames = [x.split('.',1)[-1] for x in line][:len(line)]
|
colnames = [x.split('.',1)[-1] for x in line][:len(line)]
|
||||||
cols, cid = [], []
|
cols, cid = [], None
|
||||||
for i,colname in enumerate(colnames):
|
for i,colname in enumerate(colnames):
|
||||||
if is_id(colname):
|
if is_id(colname):
|
||||||
cid = i
|
cid = i
|
||||||
@@ -7659,10 +7660,10 @@ class Table(dict):
|
|||||||
else:
|
else:
|
||||||
items = [fix(self[colnames[i]], line[i], id_map, id_offset) \
|
items = [fix(self[colnames[i]], line[i], id_map, id_offset) \
|
||||||
for i in cols if colnames[i] in self.fields]
|
for i in cols if colnames[i] in self.fields]
|
||||||
if not id_map and cid:
|
|
||||||
|
if not id_map and cid is not None and id_offset is not None and not unique_idx:
|
||||||
csv_id = int(line[cid])
|
csv_id = int(line[cid])
|
||||||
curr_id = self.insert(**dict(items))
|
curr_id = self.insert(**dict(items))
|
||||||
del_id = curr_id
|
|
||||||
if first:
|
if first:
|
||||||
first = False
|
first = False
|
||||||
# First curr_id is bigger than csv_id,
|
# First curr_id is bigger than csv_id,
|
||||||
@@ -7672,17 +7673,13 @@ class Table(dict):
|
|||||||
id_offset[self._tablename] = curr_id-csv_id
|
id_offset[self._tablename] = curr_id-csv_id
|
||||||
else:
|
else:
|
||||||
id_offset[self._tablename] = 0
|
id_offset[self._tablename] = 0
|
||||||
# create new id until we get the same as old_id
|
# create new id until we get the same as old_id+offset
|
||||||
while curr_id<csv_id+id_offset[self._tablename]:
|
while curr_id<csv_id+id_offset[self._tablename]:
|
||||||
|
self._db(self._db[self][colnames[cid]] == curr_id).delete()
|
||||||
curr_id = self.insert(**dict(items))
|
curr_id = self.insert(**dict(items))
|
||||||
# remove ids that are not used
|
|
||||||
while del_id<csv_id:
|
|
||||||
query = self._db[self][colnames[cid]] == del_id
|
|
||||||
self._db(query).delete()
|
|
||||||
del_id += 1
|
|
||||||
# Validation. Check for duplicate of 'unique' &,
|
# Validation. Check for duplicate of 'unique' &,
|
||||||
# if present, update instead of insert.
|
# if present, update instead of insert.
|
||||||
elif not unique or unique not in colnames:
|
elif not unique_idx:
|
||||||
new_id = self.insert(**dict(items))
|
new_id = self.insert(**dict(items))
|
||||||
else:
|
else:
|
||||||
unique_value = line[unique_idx]
|
unique_value = line[unique_idx]
|
||||||
@@ -7693,7 +7690,7 @@ class Table(dict):
|
|||||||
new_id = record[self._id.name]
|
new_id = record[self._id.name]
|
||||||
else:
|
else:
|
||||||
new_id = self.insert(**dict(items))
|
new_id = self.insert(**dict(items))
|
||||||
if id_map and cid != []:
|
if id_map and cid is not None:
|
||||||
id_map_self[int(line[cid])] = new_id
|
id_map_self[int(line[cid])] = new_id
|
||||||
|
|
||||||
def with_alias(self, alias):
|
def with_alias(self, alias):
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ else:
|
|||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
import datetime
|
import datetime
|
||||||
|
import cStringIO
|
||||||
from dal import DAL, Field, Table, SQLALL
|
from dal import DAL, Field, Table, SQLALL
|
||||||
|
|
||||||
ALLOWED_DATATYPES = [
|
ALLOWED_DATATYPES = [
|
||||||
@@ -483,6 +484,52 @@ class TestVirtualFields(unittest.TestCase):
|
|||||||
db.t.drop()
|
db.t.drop()
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
|
class TestImportExportFields(unittest.TestCase):
|
||||||
|
|
||||||
|
def testRun(self):
|
||||||
|
db = DAL('sqlite:memory:')
|
||||||
|
db.define_table('person', Field('name'))
|
||||||
|
db.define_table('pet',Field('friend',db.person),Field('name'))
|
||||||
|
for n in range(2):
|
||||||
|
db(db.pet).delete()
|
||||||
|
db(db.person).delete()
|
||||||
|
for k in range(10):
|
||||||
|
id = db.person.insert(name=str(k))
|
||||||
|
db.pet.insert(friend=id,name=str(k))
|
||||||
|
db.commit()
|
||||||
|
stream = cStringIO.StringIO()
|
||||||
|
db.export_to_csv_file(stream)
|
||||||
|
db(db.pet).delete()
|
||||||
|
db(db.person).delete()
|
||||||
|
stream = cStringIO.StringIO(stream.getvalue())
|
||||||
|
db.import_from_csv_file(stream)
|
||||||
|
assert db(db.person.id==db.pet.friend)(db.person.name==db.pet.name).count()==10
|
||||||
|
db.pet.drop()
|
||||||
|
db.person.drop()
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
class TestImportExportUuidFields(unittest.TestCase):
|
||||||
|
|
||||||
|
def testRun(self):
|
||||||
|
db = DAL('sqlite:memory:')
|
||||||
|
db.define_table('person', Field('name'),Field('uuid'))
|
||||||
|
db.define_table('pet',Field('friend',db.person),Field('name'))
|
||||||
|
for n in range(2):
|
||||||
|
db(db.pet).delete()
|
||||||
|
db(db.person).delete()
|
||||||
|
for k in range(10):
|
||||||
|
id = db.person.insert(name=str(k),uuid=str(k))
|
||||||
|
db.pet.insert(friend=id,name=str(k))
|
||||||
|
db.commit()
|
||||||
|
stream = cStringIO.StringIO()
|
||||||
|
db.export_to_csv_file(stream)
|
||||||
|
stream = cStringIO.StringIO(stream.getvalue())
|
||||||
|
db.import_from_csv_file(stream)
|
||||||
|
assert db(db.person).count()==10
|
||||||
|
assert db(db.person.id==db.pet.friend)(db.person.name==db.pet.name).count()==20
|
||||||
|
db.pet.drop()
|
||||||
|
db.person.drop()
|
||||||
|
db.commit()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user