allow a dict as uri, issue 1316, thanks Alan
This commit is contained in:
@@ -1 +1 @@
|
|||||||
Version 2.4.1-alpha.2+timestamp.2013.02.13.09.30.42
|
Version 2.4.1-alpha.2+timestamp.2013.02.13.09.35.21
|
||||||
|
|||||||
+71
-19
@@ -7005,6 +7005,13 @@ class DAL(object):
|
|||||||
db = DAL('sqlite://test.db')
|
db = DAL('sqlite://test.db')
|
||||||
db.define_table('tablename', Field('fieldname1'),
|
db.define_table('tablename', Field('fieldname1'),
|
||||||
Field('fieldname2'))
|
Field('fieldname2'))
|
||||||
|
|
||||||
|
(experimental)
|
||||||
|
you can pass a dict object as uri with the uri string
|
||||||
|
and table/field definitions. For an example of valid data check
|
||||||
|
the output of:
|
||||||
|
|
||||||
|
>>> db.as_dict(flat=True, sanitize=False)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __new__(cls, uri='sqlite://dummy.db', *args, **kwargs):
|
def __new__(cls, uri='sqlite://dummy.db', *args, **kwargs):
|
||||||
@@ -7109,7 +7116,7 @@ class DAL(object):
|
|||||||
db._adapter.commit_prepared(keys[i])
|
db._adapter.commit_prepared(keys[i])
|
||||||
return
|
return
|
||||||
|
|
||||||
def __init__(self, uri='sqlite://dummy.db',
|
def __init__(self, uri=None,
|
||||||
pool_size=0, folder=None,
|
pool_size=0, folder=None,
|
||||||
db_codec='UTF-8', check_reserved=None,
|
db_codec='UTF-8', check_reserved=None,
|
||||||
migrate=True, fake_migrate=False,
|
migrate=True, fake_migrate=False,
|
||||||
@@ -7145,16 +7152,26 @@ class DAL(object):
|
|||||||
:attempts (defaults to 5). Number of times to attempt connecting
|
:attempts (defaults to 5). Number of times to attempt connecting
|
||||||
"""
|
"""
|
||||||
|
|
||||||
dbdict = None
|
DEFAULT_URI = 'sqlite://dummy.db'
|
||||||
|
items = None
|
||||||
|
if isinstance(uri, dict):
|
||||||
|
if "items" in uri:
|
||||||
|
items = uri.pop("items")
|
||||||
|
try:
|
||||||
|
newuri = uri.pop("uri")
|
||||||
|
except KeyError:
|
||||||
|
newuri = DEFAULT_URI
|
||||||
|
locals().update(uri)
|
||||||
|
uri = newuri
|
||||||
|
elif not uri:
|
||||||
|
uri = DEFAULT_URI
|
||||||
|
|
||||||
if uri == '<zombie>' and db_uid is not None: return
|
if uri == '<zombie>' and db_uid is not None: return
|
||||||
elif isinstance(uri, dict):
|
|
||||||
dbdict = uri
|
|
||||||
uri = dbdict["uri"]
|
|
||||||
codec = dbdict["codec"] or codec
|
|
||||||
if not decode_credentials:
|
if not decode_credentials:
|
||||||
credential_decoder = lambda cred: cred
|
credential_decoder = lambda cred: cred
|
||||||
else:
|
else:
|
||||||
credential_decoder = lambda cred: urllib.unquote(cred)
|
credential_decoder = lambda cred: urllib.unquote(cred)
|
||||||
|
self._folder = folder
|
||||||
if folder:
|
if folder:
|
||||||
self.set_folder(folder)
|
self.set_folder(folder)
|
||||||
self._uri = uri
|
self._uri = uri
|
||||||
@@ -7172,6 +7189,13 @@ class DAL(object):
|
|||||||
self._LAZY_TABLES = {}
|
self._LAZY_TABLES = {}
|
||||||
self._lazy_tables = lazy_tables
|
self._lazy_tables = lazy_tables
|
||||||
self._tables = SQLCallableList()
|
self._tables = SQLCallableList()
|
||||||
|
self._driver_args = driver_args
|
||||||
|
self._adapter_args = adapter_args
|
||||||
|
self._check_reserved = check_reserved
|
||||||
|
self._decode_credentials = decode_credentials
|
||||||
|
self._attempts = attempts
|
||||||
|
self._do_connect = do_connect
|
||||||
|
|
||||||
if not str(attempts).isdigit() or attempts < 0:
|
if not str(attempts).isdigit() or attempts < 0:
|
||||||
attempts = 5
|
attempts = 5
|
||||||
if uri:
|
if uri:
|
||||||
@@ -7232,9 +7256,9 @@ class DAL(object):
|
|||||||
self._fake_migrate = fake_migrate
|
self._fake_migrate = fake_migrate
|
||||||
self._migrate_enabled = migrate_enabled
|
self._migrate_enabled = migrate_enabled
|
||||||
self._fake_migrate_all = fake_migrate_all
|
self._fake_migrate_all = fake_migrate_all
|
||||||
if auto_import or dbdict:
|
if auto_import or items:
|
||||||
self.import_table_definitions(adapter.folder,
|
self.import_table_definitions(adapter.folder,
|
||||||
items=dbdict["items"])
|
items=items)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def tables(self):
|
def tables(self):
|
||||||
@@ -7247,10 +7271,16 @@ class DAL(object):
|
|||||||
for tablename, table in items.iteritems():
|
for tablename, table in items.iteritems():
|
||||||
# TODO: read all field/table options
|
# TODO: read all field/table options
|
||||||
fields = []
|
fields = []
|
||||||
for fieldname, field in table["items"].iteritems():
|
# remove unsupported/illegal Table arguments
|
||||||
type = field["type"]
|
[table.pop(name) for name in ("name", "fields") if
|
||||||
fields.append(Field(fieldname, type))
|
name in table]
|
||||||
self.define_table(tablename, *fields)
|
if "items" in table:
|
||||||
|
for fieldname, field in table.pop("items").iteritems():
|
||||||
|
# remove unsupported/illegal Field arguments
|
||||||
|
[field.pop(key) for key in ("requires", "name",
|
||||||
|
"compute", "colname") if key in field]
|
||||||
|
fields.append(Field(str(fieldname), **field))
|
||||||
|
self.define_table(str(tablename), *fields, **table)
|
||||||
else:
|
else:
|
||||||
for filename in glob.glob(pattern):
|
for filename in glob.glob(pattern):
|
||||||
tfile = self._adapter.file_open(filename, 'r')
|
tfile = self._adapter.file_open(filename, 'r')
|
||||||
@@ -7611,12 +7641,20 @@ def index():
|
|||||||
return table
|
return table
|
||||||
|
|
||||||
def as_dict(self, flat=False, sanitize=True):
|
def as_dict(self, flat=False, sanitize=True):
|
||||||
dbname = codec = uid = uri = None
|
dbname = db_uid = uri = None
|
||||||
if not sanitize:
|
if not sanitize:
|
||||||
uri, dbname, codec, uid = (self._uri, self._dbname,
|
uri, dbname, db_uid = (self._uri, self._dbname, self._db_uid)
|
||||||
self._db_codec, self._db_uid)
|
|
||||||
db_as_dict = dict(items={}, tables=[], uri=uri, dbname=dbname,
|
db_as_dict = dict(items={}, tables=[], uri=uri, dbname=dbname,
|
||||||
codec=codec, uid=uid)
|
db_uid=db_uid,
|
||||||
|
**dict([(k, getattr(self, "_" + k)) for
|
||||||
|
k in 'pool_size','folder','db_codec',
|
||||||
|
'check_reserved','migrate','fake_migrate',
|
||||||
|
'migrate_enabled','fake_migrate_all',
|
||||||
|
'decode_credentials','driver_args',
|
||||||
|
'adapter_args', 'attempts',
|
||||||
|
'bigint_id','debug','lazy_tables',
|
||||||
|
'do_connect']))
|
||||||
|
|
||||||
for table in self:
|
for table in self:
|
||||||
tablename = str(table)
|
tablename = str(table)
|
||||||
db_as_dict["tables"].append(tablename)
|
db_as_dict["tables"].append(tablename)
|
||||||
@@ -8533,7 +8571,12 @@ class Table(object):
|
|||||||
|
|
||||||
def as_dict(self, flat=False, sanitize=True):
|
def as_dict(self, flat=False, sanitize=True):
|
||||||
tablename = str(self)
|
tablename = str(self)
|
||||||
table_as_dict = dict(name=tablename, items={}, fields=[])
|
table_as_dict = dict(name=tablename, items={}, fields=[],
|
||||||
|
sequence_name=self._sequence_name,
|
||||||
|
trigger_name=self._trigger_name,
|
||||||
|
common_filter=self._common_filter, format=self._format,
|
||||||
|
singular=self._singular, plural=self._plural)
|
||||||
|
|
||||||
for field in self:
|
for field in self:
|
||||||
if (field.readable or field.writable) or (not sanitize):
|
if (field.readable or field.writable) or (not sanitize):
|
||||||
table_as_dict["fields"].append(field.name)
|
table_as_dict["fields"].append(field.name)
|
||||||
@@ -9213,8 +9256,17 @@ class Field(Expression):
|
|||||||
return Expression(self.db, self.db._adapter.COUNT, self, distinct, 'integer')
|
return Expression(self.db, self.db._adapter.COUNT, self, distinct, 'integer')
|
||||||
|
|
||||||
def as_dict(self, flat=False, sanitize=True):
|
def as_dict(self, flat=False, sanitize=True):
|
||||||
attrs = ("readable", "writable", "label", "default", "name",
|
|
||||||
"type", "represent", "compute")
|
attrs = ('type', 'length', 'default', 'required',
|
||||||
|
'ondelete', 'notnull', 'unique', 'uploadfield',
|
||||||
|
'widget', 'label', 'comment', 'writable', 'readable',
|
||||||
|
'update', 'authorize', 'autodelete', 'represent',
|
||||||
|
'uploadfolder', 'uploadseparate', 'uploadfs',
|
||||||
|
'compute', 'custom_store', 'custom_retrieve',
|
||||||
|
'custom_retrieve_file_properties', 'custom_delete',
|
||||||
|
'filter_in', 'filter_out', 'custom_qualifier',
|
||||||
|
'map_none', 'name')
|
||||||
|
|
||||||
SERIALIZABLE_TYPES = (int, long, basestring, dict, list,
|
SERIALIZABLE_TYPES = (int, long, basestring, dict, list,
|
||||||
float, tuple, bool, type(None))
|
float, tuple, bool, type(None))
|
||||||
def flatten(obj):
|
def flatten(obj):
|
||||||
|
|||||||
@@ -597,6 +597,96 @@ class TestImportExportUuidFields(unittest.TestCase):
|
|||||||
db.person.drop()
|
db.person.drop()
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
|
|
||||||
|
class TestDALDictImportExport(unittest.TestCase):
|
||||||
|
|
||||||
|
def testRun(self):
|
||||||
|
db = DAL('sqlite:memory:')
|
||||||
|
db.define_table('person', Field('name', default="Michael"),Field('uuid'))
|
||||||
|
db.define_table('pet',Field('friend',db.person),Field('name'))
|
||||||
|
dbdict = db.as_dict(flat=True, sanitize=False)
|
||||||
|
assert isinstance(dbdict, dict)
|
||||||
|
uri = dbdict["uri"]
|
||||||
|
assert isinstance(uri, basestring) and uri
|
||||||
|
assert len(dbdict["items"]) == 2
|
||||||
|
assert len(dbdict["items"]["person"]["items"]) == 3
|
||||||
|
assert dbdict["items"]["person"]["items"]["name"]["type"] == db.person.name.type
|
||||||
|
assert dbdict["items"]["person"]["items"]["name"]["default"] == db.person.name.default
|
||||||
|
assert dbdict
|
||||||
|
|
||||||
|
db2 = DAL(dbdict)
|
||||||
|
assert len(db.tables) == len(db2.tables)
|
||||||
|
assert hasattr(db2, "pet") and isinstance(db2.pet, Table)
|
||||||
|
assert hasattr(db2.pet, "friend") and isinstance(db2.pet.friend, Field)
|
||||||
|
|
||||||
|
have_serializers = True
|
||||||
|
|
||||||
|
try:
|
||||||
|
import serializers
|
||||||
|
dbjson = db.as_json(sanitize=False)
|
||||||
|
assert isinstance(dbjson, basestring) and len(dbjson) > 0
|
||||||
|
db3 = DAL(serializers.loads_json(dbjson))
|
||||||
|
assert hasattr(db3, "person") and hasattr(db3.person, "uuid") and\
|
||||||
|
db3.person.uuid.type == db.person.uuid.type
|
||||||
|
db3.pet.drop()
|
||||||
|
db3.person.drop()
|
||||||
|
db3.commit()
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
mpfc = "Monty Python's Flying Circus"
|
||||||
|
dbdict4 = {"uri": 'sqlite:memory:',
|
||||||
|
"items":{"staff":{"items": {"name":
|
||||||
|
{"default":"Michael"},
|
||||||
|
"food":
|
||||||
|
{"default":"Spam"}}},
|
||||||
|
"show":{"items": {"name":
|
||||||
|
{"default":mpfc},
|
||||||
|
"rating":
|
||||||
|
{"type":"double"}}}}}
|
||||||
|
db4 = DAL(dbdict4)
|
||||||
|
assert "staff" in db4.tables
|
||||||
|
assert "name" in db4.staff
|
||||||
|
assert db4.show.rating.type == "double"
|
||||||
|
assert db4.show.insert() is not None
|
||||||
|
assert db4(db4.show).select().first().id == 1
|
||||||
|
assert db4(db4.show).select().first().name == mpfc
|
||||||
|
|
||||||
|
dbdict5 = {"uri": 'sqlite:memory:'}
|
||||||
|
db5 = DAL(dbdict5)
|
||||||
|
assert db5.tables in ([], None)
|
||||||
|
|
||||||
|
dbdict6 = {"items":{"staff":{},
|
||||||
|
"show":{"items": {"name": {},
|
||||||
|
"rating":
|
||||||
|
{"type":"double"}}}}}
|
||||||
|
db6 = DAL(dbdict6)
|
||||||
|
assert len(db6["staff"].fields) == 1
|
||||||
|
assert "name" in db6["show"].fields
|
||||||
|
|
||||||
|
# the following would fail (see issue 1332)
|
||||||
|
# assert db6.staff.insert() is not None
|
||||||
|
# assert db6(db6.staff).select().first().id == 1
|
||||||
|
|
||||||
|
dbdict7 = {}
|
||||||
|
db7 = DAL(dbdict7)
|
||||||
|
db7.tables() in (None, [])
|
||||||
|
assert not str(db7) in ("", None)
|
||||||
|
|
||||||
|
db6.staff.drop()
|
||||||
|
db6.show.drop()
|
||||||
|
db6.commit()
|
||||||
|
db4.staff.drop()
|
||||||
|
db4.show.drop()
|
||||||
|
db4.commit()
|
||||||
|
db2.pet.drop()
|
||||||
|
db2.person.drop()
|
||||||
|
db2.commit()
|
||||||
|
db.pet.drop()
|
||||||
|
db.person.drop()
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
tearDownModule()
|
tearDownModule()
|
||||||
|
|||||||
Reference in New Issue
Block a user