Changeset 6
- Timestamp:
- 02/12/07 22:34:25
- Files:
-
- trunk/geniusql/__init__.py (modified) (15 diffs)
- trunk/geniusql/providers/ado.py (modified) (4 diffs)
- trunk/geniusql/providers/firebird.py (modified) (5 diffs)
- trunk/geniusql/providers/mysql.py (modified) (4 diffs)
- trunk/geniusql/providers/psycopg.py (modified) (2 diffs)
- trunk/geniusql/providers/pypgsql.py (modified) (2 diffs)
- trunk/geniusql/providers/sqlite.py (modified) (3 diffs)
- trunk/geniusql/select.py (modified) (2 diffs)
- trunk/geniusql/test/zoo_fixture.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/geniusql/__init__.py
r5 r6 129 129 name: the SQL name for this table (unquoted). 130 130 qname: the SQL name for this table (quoted). 131 pytype: the Python type (the actual type object, not its name). 131 132 dbtype: the database type name (as used in a CREATE TABLE statement). 132 default: default value for this column for new rows.133 default: default Python value for this column for new rows. 133 134 hints: a dict of implementation hints, such as precision, scale, or bytes. 134 135 key: True if this column is part of the table's primary key. … … 143 144 """ 144 145 145 def __init__(self, dbtype, default=None, hints=None, key=False,146 def __init__(self, pytype, dbtype, default=None, hints=None, key=False, 146 147 name=None, qname=None): 148 self.pytype = pytype 147 149 self.dbtype = dbtype 148 150 self.name = name … … 164 166 165 167 def __repr__(self): 166 return ("%s.%s(%r, %r, d btype=%r, default=%r, hints=%r, key=%r)" %168 return ("%s.%s(%r, %r, default=%r, hints=%r, key=%r, name=%r, qname=%r)" % 167 169 (self.__module__, self.__class__.__name__, 168 self.name, self.qname, self.dbtype, 169 self.default, self.hints, self.key) 170 self.pytype, self.dbtype, 171 self.default, self.hints, self.key, 172 self.name, self.qname) 170 173 ) 171 174 172 175 def __copy__(self): 173 newcol = self.__class__(self.name, self.qname, self.dbtype, 174 self.default, self.hints.copy(), self.key) 176 newcol = self.__class__(self.pytype, self.dbtype, 177 self.default, self.hints, self.key, 178 self.name, self.qname) 175 179 newcol.autoincrement = self.autoincrement 176 180 newcol.initial = self.initial … … 245 249 def _add_column(self, column): 246 250 """Internal function to add the column to the database.""" 247 coldef = self.db.col _def(column)251 coldef = self.db.columnclause(column) 248 252 self.db.execute("ALTER TABLE %s ADD COLUMN %s;" % (self.qname, coldef)) 249 253 … … 337 341 self.indices[columnkey] = i 338 342 return i 343 344 def select_all(self, restriction=None): 345 """Yield data dicts matching the given restriction.""" 346 attrs = self.keys() 347 data = self.db.select(self, attrs, restriction) 348 for row in data: 349 row = dict(zip(attrs, row)) 350 if restriction and data.imperfect: 351 # Run a dummy object through our restriction before yielding. 352 if not restriction(ImperfectDummy(**row)): 353 continue 354 yield row 355 356 def select_one(self, restriction=None): 357 """Return a single data dict matching the given restriction (or None).""" 358 try: 359 return self.select_all(restriction).next() 360 except StopIteration: 361 return None 362 363 364 class ImperfectDummy(object): 365 """A dummy object for resolving imperfect queries.""" 366 def __init__(self, **kwargs): 367 for k, v in kwargs.iteritems(): 368 setattr(self, k, v) 339 369 340 370 … … 362 392 363 393 selectwriter = SelectWriter 364 def select(self, *args, **kwargs):365 return self.selectwriter(self, *args, **kwargs)366 367 394 tableclass = Table 368 395 … … 536 563 # Container # 537 564 538 def col _def(self, column):565 def columnclause(self, column): 539 566 """Return a clause for the given column for CREATE or ALTER TABLE. 540 567 … … 581 608 self.create_sequence(table, column) 582 609 583 fields.append(self.col _def(column))610 fields.append(self.columnclause(column)) 584 611 if column.key: 585 612 pk.append(column.qname) … … 671 698 return self.sql_name(columnkey) 672 699 673 def column(self, pytype=unicode, d efault=None, hints=None,700 def column(self, pytype=unicode, dbtype=None, default=None, hints=None, 674 701 key=False, autoincrement=False): 675 702 """Return a Column object from the given arguments.""" 676 col = Column(None, default, hints) 677 col.dbtype = self.typeadapter.coerce(col, pytype) 703 col = Column(pytype, dbtype, default, hints) 704 col.key = key 705 col.autoincrement = autoincrement 706 707 if dbtype is None: 708 col.dbtype = self.typeadapter.coerce(col, pytype) 678 709 pytype2 = self.python_type(col.dbtype) 679 710 col.imperfect_type = not self.isrelatedtype(pytype, pytype2) 680 col.key = key 681 col.autoincrement = autoincrement 711 682 712 return col 683 713 … … 720 750 721 751 def execute(self, query, conn=None): 722 """ execute(query, conn=None) -> result set."""752 """Return a native response for the given query.""" 723 753 if conn is None: 724 754 conn = self.connection() … … 739 769 res = self.execute(query, conn) 740 770 return res.row_list, res.col_defs 771 772 def select(self, relation, attributes, restriction=None, distinct=False): 773 """Yield matching data, coerced to Python types (where known).""" 774 sel = self.selectwriter(self, relation, attributes, restriction) 775 data, _ = self.fetch(sel.sql(distinct), self.get_transaction()) 776 return ResultSet(data, sel.columns, sel.imperfect) 741 777 742 778 def create_database(self): … … 919 955 """Insert a row and return {idcolkey: newid}.""" 920 956 t = self[tablekey] 957 coerce_out = self.adaptertosql.coerce 958 coerce_in = self.adapterfromdb.coerce 921 959 922 960 fields = [] … … 929 967 continue 930 968 if key in inputs: 931 val = self.adaptertosql.coerce(inputs[key], col.dbtype)969 val = coerce_out(inputs[key], col.dbtype) 932 970 fields.append(col.qname) 933 971 values.append(val) … … 938 976 values = ", ".join(values) 939 977 self.execute('INSERT INTO %s (%s) VALUES (%s);' % 940 (t.qname, fields, values), transconn)978 (t.qname, fields, values), transconn) 941 979 942 980 if idkeys: 943 return self._grab_new_ids(t, idkeys, transconn) 981 newids = self._grab_new_ids(t, idkeys, transconn) 982 for key in newids.keys(): 983 col = t[key] 984 newids[key] = coerce_in(newids[key], col.dbtype, col.pytype) 985 return newids 944 986 else: 945 987 return {} 946 988 947 989 def _grab_new_ids(self, table, idkeys): 990 # Override this to fetch and return new autoincrement values. 948 991 raise NotImplementedError 949 992 … … 968 1011 self.execute(sql, self.get_transaction()) 969 1012 1013 1014 class ResultSet: 1015 1016 def __init__(self, data, columns, imperfect): 1017 self.data = data 1018 self.columns = columns 1019 self.imperfect = imperfect 1020 self.cursor = 0 1021 1022 def __iter__(self): 1023 return self 1024 1025 def next(self): 1026 try: 1027 row = self.data[self.cursor] 1028 self.cursor += 1 1029 except IndexError: 1030 raise StopIteration 1031 1032 coerced_row = [] 1033 for i, (table, col, qname) in enumerate(self.columns): 1034 val = row[i] 1035 if table and col: 1036 val = table.db.adapterfromdb.coerce(val, col.dbtype, col.pytype) 1037 coerced_row.append(val) 1038 return coerced_row 1039 trunk/geniusql/providers/ado.py
r5 r6 363 363 def _add_column(self, column): 364 364 """Internal function to add the column to the database.""" 365 coldef = self.db.col _def(column)365 coldef = self.db.columnclause(column) 366 366 # SQL Server doesn't use the "COLUMN" keyword with "ADD" 367 367 self.db.execute("ALTER TABLE %s ADD %s;" % (self.qname, coldef)) … … 473 473 474 474 name = str(row[3]) 475 c = geniusql.Column(name, self.quote(name), dbtype, default, 476 key=(name in pknames)) 475 c = geniusql.Column(self.python_type(dbtype), dbtype, 476 default, hints={}, key=(name in pknames), 477 name=name, qname=self.quote(name)) 477 478 478 479 # This only works for SQL Server. The MSAccessDatabase will … … 893 894 self.unlock() 894 895 895 def col _def(self, column):896 def columnclause(self, column): 896 897 """Return a clause for the given column for CREATE or ALTER TABLE. 897 898 … … 1111 1112 return ADODatabase.python_type(self, dbtype) 1112 1113 1113 def col _def(self, column):1114 def columnclause(self, column): 1114 1115 """Return a clause for the given column for CREATE or ALTER TABLE. 1115 1116 trunk/geniusql/providers/firebird.py
r5 r6 241 241 def _add_column(self, column): 242 242 """Internal function to add the column to the database.""" 243 coldef = self.db.col _def(column)243 coldef = self.db.columnclause(column) 244 244 # FB doesn't recognize the keyword "COLUMN" in "ADD". 245 245 self.db.execute("ALTER TABLE %s ADD %s;" % (self.qname, coldef)) … … 362 362 default = float(default) 363 363 364 # Column(name, qname, dbtype, default=None, hints=None, key=False) 365 col = geniusql.Column(name, self.quote(name), dbtype, default, hints, key) 364 # Column(pytype, dbtype, default=None, hints=None, key=False, name, qname) 365 col = geniusql.Column(self.python_type(dbtype), dbtype, default, 366 hints, key, name, self.quote(name)) 366 367 cols.append(col) 367 368 return cols … … 416 417 "to a Python type." % dbtype) 417 418 418 def col _def(self, column):419 def columnclause(self, column): 419 420 """Return a clause for the given column for CREATE or ALTER TABLE. 420 421 … … 660 661 """Insert a row and return {idcolkey: newid}.""" 661 662 t = self[tablekey] 663 coerce_out = self.adaptertosql.coerce 664 coerce_in = self.adapterfromdb.coerce 662 665 663 666 newids = {} … … 669 672 data, _ = self.fetch("SELECT GEN_ID(%s, 1) FROM RDB$DATABASE;" 670 673 % col.sequence_name) 671 val, = data[0]672 newids[key] = val674 newid = coerce_in(data[0][0], col.dbtype, col.pytype) 675 newids[key] = newid 673 676 674 val = self.adaptertosql.coerce(val, col.dbtype)677 val = coerce_out(newid, col.dbtype) 675 678 fields.append(col.qname) 676 679 values.append(val) 677 680 elif key in inputs: 678 val = self.adaptertosql.coerce(inputs[key], col.dbtype)681 val = coerce_out(inputs[key], col.dbtype) 679 682 fields.append(col.qname) 680 683 values.append(val) trunk/geniusql/providers/mysql.py
r5 r6 215 215 return "MySQL Version: %s" % self._version 216 216 217 def col _def(self, column):217 def columnclause(self, column): 218 218 """Return a clause for the given column for CREATE or ALTER TABLE. 219 219 … … 246 246 pk = [] 247 247 for colkey, col in table.iteritems(): 248 fields.append(self.col _def(col))248 fields.append(self.columnclause(col)) 249 249 250 250 if col.autoincrement: … … 324 324 cols = [] 325 325 for row in data: 326 c = geniusql.Column(row[0], self.quote(row[0]), None, None) 327 326 hints = {} 328 327 dbtype = row[1].upper() 329 328 parenpos = dbtype.find("(") … … 333 332 if baretype in ("DECIMAL", "NUMERIC"): 334 333 args = [x.strip() for x in args.split(",")] 335 c.hints['precision'], c.hints['scale'] = args334 hints['precision'], hints['scale'] = args 336 335 else: 337 c.hints['bytes'] = args336 hints['bytes'] = args 338 337 elif dbtype == "FLOAT": 339 c.hints['precision'] = 24338 hints['precision'] = 24 340 339 elif dbtype.startswith("DOUBLE"): 341 c.hints['precision'] = 53340 hints['precision'] = 53 342 341 elif dbtype in ("TINYBLOB", "TINYTEXT"): 343 c.hints['bytes'] = (2 ** 8) - 1342 hints['bytes'] = (2 ** 8) - 1 344 343 elif dbtype in ("BLOB", "TEXT"): 345 c.hints['bytes'] = (2 ** 16) - 1344 hints['bytes'] = (2 ** 16) - 1 346 345 elif dbtype in ("MEDIUMBLOB", "MEDIUMTEXT"): 347 c.hints['bytes'] = (2 ** 24) - 1346 hints['bytes'] = (2 ** 24) - 1 348 347 elif dbtype in ("LONGBLOB", "LONGTEXT"): 349 c.hints['bytes'] = (2 ** 32) - 1 350 351 c.key = (row[3] == "PRI") 348 hints['bytes'] = (2 ** 32) - 1 349 350 key = (row[3] == "PRI") 351 pytype = self.python_type(dbtype) 352 353 col = geniusql.Column(pytype, dbtype, None, hints, key, 354 row[0], self.quote(row[0])) 352 355 353 356 if row[4]: 354 c.default = self.python_type(dbtype)(row[4]) 355 357 col.default = pytype(row[4]) 356 358 if "auto_increment" in row[5].lower(): 357 c.autoincrement = True 358 359 c.dbtype = dbtype 360 361 cols.append(c) 359 col.autoincrement = True 360 361 cols.append(col) 362 362 return cols 363 363 trunk/geniusql/providers/psycopg.py
r5 r6 216 216 else: 217 217 dbtype = None 218 c = geniusql.Column(row[0], self.quote(row[0]), dbtype, 219 key=row[2] in indices) 218 c = geniusql.Column(self.python_type(dbtype), dbtype, 219 None, {}, row[2] in indices, 220 row[0], self.quote(row[0])) 220 221 221 222 if dbtype in ('FLOAT4', 'FLOAT8'): … … 315 316 "to a Python type." % dbtype) 316 317 317 def col _def(self, column):318 def columnclause(self, column): 318 319 """Return a clause for the given column for CREATE or ALTER TABLE. 319 320 trunk/geniusql/providers/pypgsql.py
r5 r6 203 203 else: 204 204 dbtype = None 205 c = geniusql.Column(row[0], self.quote(row[0]), dbtype, 206 key=row[2] in indices) 205 c = geniusql.Column(self.python_type(dbtype), dbtype, 206 None, {}, row[2] in indices, 207 row[0], self.quote(row[0])) 207 208 208 209 if dbtype in ('FLOAT4', 'FLOAT8'): … … 302 303 "to a Python type." % dbtype) 303 304 304 def col _def(self, column):305 def columnclause(self, column): 305 306 """Return a clause for the given column for CREATE or ALTER TABLE. 306 307 trunk/geniusql/providers/sqlite.py
r5 r6 527 527 cols = [] 528 528 for row in data: 529 c = geniusql.Column(row[1], self.quote(row[1]), row[2].upper(), 530 default=row[4], key=bool(row[5])) 529 dbtype = row[2].upper() 530 c = geniusql.Column(self.python_type(dbtype), dbtype, 531 row[4], {}, bool(row[5]), 532 row[1], self.quote(row[1])) 531 533 532 534 # "A single row can hold up to 2 ** 30 bytes of data … … 621 623 return {idkeys[0]: new_id} 622 624 623 def col _def(self, column):625 def columnclause(self, column): 624 626 """Return a clause for the given column for CREATE or ALTER TABLE. 625 627 … … 652 654 autoincr_col = None 653 655 for col in table.itervalues(): 654 fields.append(self.col _def(col))656 fields.append(self.columnclause(col)) 655 657 656 658 if col.autoincrement: trunk/geniusql/select.py
r5 r6 510 510 self.whereclause, self.imperfect = self.where() 511 511 512 self.columns = [] 512 513 if self.attributes is None: 513 514 # Return all columns 514 self.colnames = []515 515 for t in self.tables: 516 self.col names.extend(self.columns(t, None))516 self.columns.extend(self._get_columns(t, None)) 517 517 else: 518 518 if isinstance(relation, Join): 519 self.colnames = []520 519 for t, attrs in zip(self.tables, self.attributes): 521 self.colnames.extend(self.columns(t, attrs)) 522 else: 523 self.colnames = [relation[a].qname for a in self.attributes] 524 525 def columns(self, tablewrapper, attrs=None): 526 """Return a list of quoted table.col names: ['"tbl"."col"', ...].""" 520 self.columns.extend(self._get_columns(t, attrs)) 521 else: 522 for a in self.attributes: 523 col = relation[a] 524 self.columns.append((relation, col, col.qname)) 525 526 def _get_columns(self, tablewrapper, attrs=None): 527 """Return a list of (column, full quoted name) pairs.""" 527 528 tablename = tablewrapper.alias or tablewrapper.qname 529 table = tablewrapper.table 528 530 if attrs is None: 529 531 # Place the identifier (primary key) properties first 530 532 # in case others depend upon them. 531 cols = [(col.key, col.qname) for col 532 in tablewrapper.table.itervalues()] 533 cols = [(col.key, col) for col in table.itervalues()] 533 534 cols.sort() 534 cols = [qname for iskey, qname in cols] 535 else: 536 table = tablewrapper.table 537 cols = [table[a].qname for a in attrs] 538 return ['%s.%s' % (tablename, qname) for qname in cols] 535 return [(table, col, '%s.%s' % (tablename, col.qname)) 536 for iskey, col in cols] 537 else: 538 cols = [] 539 for a in attrs: 540 col = table[a] 541 cols.append((table, col, '%s.%s' % (tablename, col.qname))) 542 return cols 539 543 540 544 def sql(self, distinct=False): … … 545 549 d = '' 546 550 547 cols = ', '.join( self.colnames)551 cols = ', '.join([qname for t, c, qname in self.columns]) 548 552 549 553 w = self.whereclause trunk/geniusql/test/zoo_fixture.py
r5 r6 257 257 def test_3_Properties(self): 258 258 # Zoos 259 sel = db.select(db['Zoo'], ('Founded', 'Opens', 'Admission'), 260 logic.Expression(lambda z: z.Name == 'Wild Animal Park')) 261 data, _ = db.fetch(sel.sql(), db.get_transaction()) 262 self.assertEqual(data[0][0], datetime.date(2000, 1, 1)) 263 self.assertEqual(data[0][1], datetime.time(8, 15, 59)) 264 # This should have been updated when leopard.LastEscape was set. 265 ## self.assertEqual(WAP.LastEscape, 266 ## datetime.datetime(2004, 12, 21, 8, 15, 0, 999907)) 267 self.assertEqual(data[0][2], 4.95) 268 ## 269 ## SDZ = box.unit(Zoo, Founded=datetime.date(1835, 9, 13)) 270 ## self.assertNotEqual(SDZ, None) 271 ## self.assertEqual(SDZ.Founded, datetime.date(1835, 9, 13)) 272 ## self.assertEqual(SDZ.Opens, datetime.time(9, 0, 0)) 273 ## self.assertEqual(SDZ.LastEscape, None) 274 ## self.assertEqual(float(SDZ.Admission), 0) 275 ## 276 ## # Try a magic Sandbox recaller method 277 ## Biodome = box.Zoo(Name = u'Montr\xe9al Biod\xf4me') 278 ## self.assertNotEqual(Biodome, None) 279 ## self.assertEqual(Biodome.Name, u'Montr\xe9al Biod\xf4me') 280 ## self.assertEqual(Biodome.Founded, datetime.date(1992, 6, 19)) 281 ## self.assertEqual(Biodome.Opens, datetime.time(9, 0, 0)) 282 ## self.assertEqual(Biodome.LastEscape, None) 283 ## self.assertEqual(float(Biodome.Admission), 11.75) 284 ## 285 ## if typerefs.fixedpoint: 286 ## seaworld = box.unit(Zoo, Admission = typerefs.fixedpoint.FixedPoint(60)) 287 ## else: 288 ## seaworld = box.unit(Zoo, Admission = float(60)) 289 ## self.assertNotEqual(seaworld, None) 290 ## self.assertEqual(seaworld.Name, u'Sea_World') 291 ## 292 ## # Animals 293 ## leopard = box.unit(Animal, Species='Leopard') 294 ## self.assertEqual(leopard.Species, 'Leopard') 295 ## self.assertEqual(leopard.Legs, 4) 296 ## self.assertEqual(leopard.Lifespan, 73.5) 297 ## self.assertEqual(leopard.ZooID, WAP.ID) 298 ## self.assertEqual(leopard.PreviousZoos, None) 299 ## ## self.assertEqual(leopard.LastEscape, 300 ## ## datetime.datetime(2004, 12, 21, 8, 15, 0, 999907)) 301 ## 302 ## ostrich = box.unit(Animal, Species='Ostrich') 303 ## self.assertEqual(ostrich.Species, 'Ostrich') 304 ## self.assertEqual(ostrich.Legs, 2) 305 ## self.assertEqual(ostrich.ZooID, None) 306 ## self.assertEqual(ostrich.PreviousZoos, []) 307 ## self.assertEqual(ostrich.LastEscape, None) 308 ## 309 ## millipede = box.unit(Animal, Legs=1000000) 310 ## self.assertEqual(millipede.Species, 'Millipede') 311 ## self.assertEqual(millipede.Legs, 1000000) 312 ## self.assertEqual(millipede.ZooID, SDZ.ID) 313 ## self.assertEqual(millipede.PreviousZoos, [WAP.Name]) 314 ## self.assertEqual(millipede.LastEscape, None) 315 ## 316 ## # Test that strings in a list get decoded correctly. 317 ## # See http://projects.amor.org/dejavu/ticket/50 318 ## tiger = box.unit(Animal, Species='Tiger') 319 ## self.assertEqual(tiger.PreviousZoos, ["animal\\universe"]) 320 ## 321 ## # Test our 8000-byte limit. 322 ## # len(pickle.dumps(["f" * (8000 - 14)]) == 8000 323 ## slug = box.unit(Animal, Species='Slug') 324 ## self.assertEqual(len(slug.PreviousZoos[0]), 8000 - 14) 325 ## 326 ## # Exhibits 327 ## exes = box.recall(Exhibit) 328 ## self.assertEqual(len(exes), 2) 329 ## if exes[0].Name == 'The Penguin Encounter': 330 ## pe = exes[0] 331 ## tr = exes[1] 332 ## else: 333 ## pe = exes[1] 334 ## tr = exes[0] 335 ## self.assertEqual(pe.ZooID, seaworld.ID) 336 ## self.assertEqual(len(pe.Animals), 2) 337 ## self.assertEqual(float(pe.Acreage), 3.1) 338 ## self.assertEqual(pe.PettingAllowed, True) 339 ## self.assertEqual(pe.Creators, (u'Richard F\xfcrst', u'Sonja Martin')) 340 ## 341 ## self.assertEqual(tr.ZooID, SDZ.ID) 342 ## self.assertEqual(len(tr.Animals), 1) 343 ## self.assertEqual(float(tr.Acreage), 4) 344 ## self.assertEqual(tr.PettingAllowed, False) 345 ## 346 ## finally: 347 ## box.flush_all() 348 ## 259 data = db.select(db['Zoo'], ('Founded', 'Opens', 'Admission'), 260 logic.Expression(lambda z: z.Name == 'Wild Animal Park')) 261 wap = data.next() 262 self.assertEqual(wap[0], datetime.date(2000, 1, 1)) 263 self.assertEqual(wap[1], datetime.time(8, 15, 59)) 264 if typerefs.fixedpoint: 265 self.assertEqual(wap[2], typerefs.fixedpoint.FixedPoint("4.95")) 266 else: 267 self.assertEqual(wap[2], 4.95) 268 269 SDZ = db['Zoo'].select_one(lambda z: z.Founded == datetime.date(1835, 9, 13)) 270 self.assertEqual(SDZ['Founded'], datetime.date(1835, 9, 13)) 271 self.assertEqual(SDZ['Opens'], datetime.time(9, 0, 0)) 272 self.assertEqual(SDZ['LastEscape'], None) 273 self.assertEqual(float(SDZ['Admission']), 0) 274 275 Biodome = db['Zoo'].select_one(lambda z: z.Name == u'Montr\xe9al Biod\xf4me') 276 self.assertEqual(Biodome['Name'], u'Montr\xe9al Biod\xf4me') 277 self.assertEqual(Biodome['Founded'], datetime.date(1992, 6, 19)) 278 self.assertEqual(Biodome['Opens'], datetime.time(9, 0, 0)) 279 self.assertEqual(Biodome['LastEscape'], None) 280 self.assertEqual(float(Biodome['Admission']), 11.75) 281 282 if typerefs.fixedpoint: 283 seaworld = db['Zoo'].select_one(lambda z: z.Admission == 284 typerefs.fixedpoint.FixedPoint(60)) 285 else: 286 seaworld = db['Zoo'].select_one(lambda z: z.Admission == float(60)) 287 self.assertEqual(seaworld['Name'], u'Sea_World') 288 ## 289 ## # Animals 290 ## leopard = box.unit(Animal, Species='Leopard') 291 ## self.assertEqual(leopard.Species, 'Leopard') 292 ## self.assertEqual(leopard.Legs, 4) 293 ## self.assertEqual(leopard.Lifespan, 73.5) 294 ## self.assertEqual(leopard.ZooID, WAP.ID) 295 ## self.assertEqual(leopard.PreviousZoos, None) 296 #### self.assertEqual(leopard.LastEscape, 297 #### datetime.datetime(2004, 12, 21, 8, 15, 0, 999907)) 298 ## 299 ## ostrich = box.unit(Animal, Species='Ostrich') 300 ## self.assertEqual(ostrich.Species, 'Ostrich') 301 ## self.assertEqual(ostrich.Legs, 2) 302 ## self.assertEqual(ostrich.ZooID, None) 303 ## self.assertEqual(ostrich.PreviousZoos, []) 304 ## self.assertEqual(ostrich.LastEscape, None) 305 ## 306 ## millipede = box.unit(Animal, Legs=1000000) 307 ## self.assertEqual(millipede.Species, 'Millipede') 308 ## self.assertEqual(millipede.Legs, 1000000) 309 ## self.assertEqual(millipede.ZooID, SDZ.ID) 310 ## self.assertEqual(millipede.PreviousZoos, [WAP.Name]) 311 ## self.assertEqual(millipede.LastEscape, None) 312 ## 313 ## # Test that strings in a list get decoded correctly. 314 ## # See http://projects.amor.org/dejavu/ticket/50 315 ## tiger = box.unit(Animal, Species='Tiger') 316 ## self.assertEqual(tiger.PreviousZoos, ["animal\\universe"]) 317 ## 318 ## # Test our 8000-byte limit. 319 ## # len(pickle.dumps(["f" * (8000 - 14)]) == 8000 320 ## slug = box.unit(Animal, Species='Slug') 321 ## self.assertEqual(len(slug.PreviousZoos[0]), 8000 - 14) 322 ## 323 ## # Exhibits 324 ## exes = box.recall(Exhibit) 325 ## self.assertEqual(len(exes), 2) 326 ## if exes[0].Name == 'The Penguin Encounter': 327 ## pe = exes[0] 328 ## tr = exes[1] 329 ## else: 330 ## pe = exes[1] 331 ## tr = exes[0] 332 ## self.assertEqual(pe.ZooID, seaworld.ID) 333 ## self.assertEqual(len(pe.Animals), 2) 334 ## self.assertEqual(float(pe.Acreage), 3.1) 335 ## self.assertEqual(pe.PettingAllowed, True) 336 ## self.assertEqual(pe.Creators, (u'Richard F\xfcrst', u'Sonja Martin')) 337 ## 338 ## self.assertEqual(tr.ZooID, SDZ.ID) 339 ## self.assertEqual(len(tr.Animals), 1) 340 ## self.assertEqual(float(tr.Acreage), 4) 341 ## self.assertEqual(tr.PettingAllowed, False) 342 ## 349 343 ## def test_4_Expressions(self): 350 344 ## box = arena.new_sandbox()
