Changeset 19
- Timestamp:
- 10/19/04 06:15:52
- Files:
-
- trunk/containers.py (modified) (3 diffs)
- trunk/doc/dejavu.css (modified) (1 diff)
- trunk/doc/index.html (modified) (1 diff)
- trunk/doc/modeling.html (modified) (1 diff)
- trunk/doc/storage.html (modified) (3 diffs)
- trunk/storage/storeado.py (modified) (2 diffs)
- trunk/test_containers.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/containers.py
r18 r19 9 9 and map. 10 10 11 Find herein the containers: Balloon, Graph, Index, and Prism.11 Find herein the containers: warehouse, Graph, Index, and Prism. 12 12 13 13 This work, including the source code, documentation … … 27 27 import new 28 28 29 class Balloon(object): 30 """Iterate from a base sequence, stretching or shrinking it as needed. 31 32 Once the current sequence is exhausted, the factory function is called 33 to produce a new valid object upon each subsequent call to next(). 29 def warehouse(stock, factory=None): 30 """warehouse(stock, factory=None) -> iavailable, iremainder. 31 32 Iterate over stock, extending as needed. Once the 'stock' sequence is 33 exhausted, the factory function is called to produce a new valid object 34 upon each subsequent call to next(). 34 35 35 36 If factory is None, the class of the first item in the sequence is used … … 38 39 wrap the class in a function which can supply those. 39 40 40 The most common use for the Balloon classis to reuse a set of existing41 The most common use for warehouse is to reuse a set of existing 41 42 objects, often because object creation and/or destruction is expensive. 42 43 43 44 Example: 44 45 45 b = Balloon(seq, cls) 46 for item in newseq: 47 b.next().thing = item 48 b.shrink() 46 available, remainder = warehouse(seq) 47 for line in order: 48 line.use(available.next()) 49 for item in remainder: 50 item.close() 49 51 """ 50 def __init__(self, sequence, factory=None, dump=None):51 try:52 seqlen = len(sequence)53 except TypeError:54 raise TypeError("Sequence must support len() and slicing.")55 self.sequence = sequence52 if not hasattr(stock, 'next'): 53 stock = iter(stock) 54 55 def pull(): 56 for item in stock: 57 yield item 56 58 57 59 if factory is None: 58 if seqlen == 0: 59 raise ValueError(u"Empty sequence and no factory supplied.") 60 factory = sequence[0].__class__ 61 self.factory = factory 62 self.dump = dump 63 self._cursor = 0 64 65 def __iter__(self): 66 return self 67 68 def next(self): 69 try: 70 item = self.sequence[self._cursor] 71 except IndexError: 72 item = self.factory() 73 self.sequence.append(item) 74 self._cursor += 1 75 return item 76 77 def shrink(self): 78 if self._cursor < len(self.sequence): 79 for i in range(len(self.sequence) - 1, self._cursor - 1, -1): 80 if self.dump: 81 self.dump(self.sequence[i]) 82 del self.sequence[i] 60 try: 61 local_factory = item.__class__ 62 except NameError: 63 raise ValueError("Empty sequence and no factory supplied.") 64 else: 65 local_factory = factory 66 67 while True: 68 yield local_factory() 69 70 return pull(), stock 83 71 84 72 trunk/doc/dejavu.css
r18 r19 5 5 } 6 6 7 body { 8 /* IE shoves the body element off the right-hand side, forcing scrollbars. 9 Set body to 97% to avoid this. */ 10 width: 97%; 11 } 7 body { padding: 0.75em; } 12 8 13 9 h1 { trunk/doc/index.html
r18 r19 78 78 </li> 79 79 <li><a href='storage.html'>Deployers: Configuring Storage</a> 80 <ul> 81 <li>Storage Managers 82 <ul> 83 <li>Database Storage Managers 84 <ul> 85 <li>Microsoft Access (Jet)</li> 86 <li>Microsoft SQL Server</li> 87 <li>ODBC</li> 88 </ul> 89 </li> 90 <li>Middleware 91 <ul> 92 <li>Caching Proxy</li> 93 <li>Burned Proxy</li> 94 </ul> 95 </li> 96 </ul> 97 </li> 98 </ul> 80 99 </li> 81 100 <li><a href='framework.html'>Framework Development</a> trunk/doc/modeling.html
r18 r19 284 284 the trick. Notice that flushing calls <tt>repress()</tt> for each Unit in 285 285 the Sandbox, and any <tt>on_repress()</tt> triggers will be executed.</p> 286 287 <p>Some Units may have their <tt>temporary</tt> flag set. When you use 288 a <tt>CachingProxy</tt> as a Storage Manager, temporary Units will be 289 destroyed rather than persisted. This happens independently of forgetting 290 and sandbox flushing.</p> 291 286 292 287 293 <h4>Aggregate Functions</h4> trunk/doc/storage.html
r18 r19 5 5 <head> 6 6 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 7 <title>Dejavu: Reference</title>7 <title>Dejavu: Configuring Storage</title> 8 8 <link href='dejavu.css' rel='stylesheet' type='text/css' /> 9 9 </head> … … 11 11 <body> 12 12 13 <h2>Reference</h2> 14 15 <h3>Units</h3> 16 <p></p> 17 18 <h3>Sandboxes</h3> 19 <p></p> 20 21 <h4>Expressions and Querying</h4> 22 <p></p> 23 24 <h3>The Arena Object</h3> 25 <p>The topmost class in Dejavu is the <tt>Arena</tt> class. When building 26 a Dejavu application, you must first create an instance of this class, 27 and must find a way to persist this object across client connections. 28 This can be achieved in multiple ways; web applications, for example, 29 will typically create a single process to serve all requests. Desktop 30 applications will probably create a single Arena object for each 31 running instance of the program.</p> 32 33 <h4>Startup and Shutdown</h4> 34 <p></p> 35 36 <h4>Unit Class roster</h4> 37 <p></p> 13 <h2>Deployers: Configuring Storage</h2> 38 14 39 15 <h3>Storage Managers</h3> 40 16 41 <p>Storage Managers insulate the domain model from the specifics of databases, 42 query languages, and cache mechanisms.</p> 17 <p>Storage Managers insulate an application developer from the specifics of 18 databases, query languages, and cache mechanisms. As the <i>deployer</i> of 19 a Dejavu application, you get to be in control of these. But don't worry; 20 in the vast majority of cases, you will set up a single database with just 21 two lines in a configuration file. Often, the application developer will 22 have already prepared default config files which you can simply "plug and 23 play". But if you <i>need</i> more control over your data storage, you 24 have it, without becoming a programmer.</p> 43 25 44 <p>Some Storage Managers can be chained together to provide layered 45 functionality. For example, a CachingProxy class might be used to 46 give deployers the ability to cache objects across client requests, 47 independent of the underlying database-specific Storage Manager.</p> 26 <p>When you deploy an app built with Dejavu, you must specify Storage 27 Managers to use for persisting application objects. This is usually 28 done through an ini-style configuration file. Here's a short example: 29 <pre>[Junct] 30 Class: dejavu.storage.storeado.StorageManagerADO_MSAccess 31 Connect: "DSN=Junct;Driver=Microsoft Access Driver (*.mdb);Dbq=D:\data\junct.mdb;" 32 </pre> 33 The first line of our example ("[Junct]") names the Storage Manager; 34 each section in your conf file defines a different SM. You can use whatever 35 name you like here; in this example, we used the name of the application. 36 The second line tells Dejavu the <i>class</i> of SM we'd like to use. 37 For most applications, you'll decide which class to use based on the 38 database you want to use. Our example declares that we want to persist our 39 application data in an "MS Access" (i.e., Jet) database.</p> 48 40 49 <p>Configuration entries for Storage Managers:</p> 41 <p>The third line in our example is a standard ODBC-style Connect string. 42 The _MSAccess class requires this entry; other SM's may not. There are very 43 few configuration entries which apply to all Storage Managers. Here are 44 the common ones which do:</p> 50 45 51 46 <table> … … 73 68 <td>Optional. Declares which Unit classes to manage with this SM.</td> 74 69 </tr> 75 <tr>76 <td>Lifetime</td>77 <td><tt>"10 minutes"</tt></td>78 <td>Optional for caching SM's. The recurrence string which declares how79 often to sweep Units out of the in-memory cache.</td>80 </tr>81 <tr>82 <td>Next Store</td>83 <td><tt>"Main"</tt></td>84 <td>Required for proxy SM's. The next Storage Manager in the chain.</td>85 </tr>86 70 </table> 87 71 88 <h4>Unit Engines</h4> 89 <p></p> 72 <p>The "Units" entry is what you will use to separate application objects 73 into separate stores (if you need to). The objects in an application which 74 need to be stored are called "Units", and each Unit is of a certain Unit 75 class. If you specify a "Units" entry, then only Units of those classes 76 will be managed by that Storage Manager. If you do <i>not</i> specify such 77 an entry, then <b>all</b> Units will be handled by that Storage Manager. 78 This means that only <i>one</i> SM should be missing this entry.</p> 90 79 91 <h4>Analysis Tools</h4> 92 <p></p> 80 81 <h4>Database Storage Managers</h4> 82 83 <h5>Microsoft Access (Jet)</h5> 84 <p>This class was developed against ADO 2.7.</p> 85 <ul> 86 <li><b>Class:</b> <tt>dejavu.storage.storeado.StorageManagerADO_MSAccess</tt></li> 87 <li><b>Connect:</b> A valid ADO connect string. There are plenty of 88 online references for how to form these; for example, at 89 <a href='http://support.microsoft.com/?kbid=193332'>Microsoft</a>.</li> 90 <li><b>Threaded:</b> Optional. If set to any value, a new connection 91 is established for each thread. Otherwise, a single connection 92 is used for all threads.</li> 93 <li><b>Prefix:</b> If specified, all tables in the database will 94 have names starting with this prefix. If not provided, it 95 defaults to "djv". This helps if you need to mix Dejavu tables 96 with tables from another application.</li> 97 <li><b>CursorType:</b> Optional. Passed to Recordset.Open(). See 98 <a href='http://msdn.microsoft.com/library/en-us/ado270/htm/mdmthrstopen.asp'>Microsoft</a> 99 again.</li> 100 <li><b>LockType:</b> Optional. Passed to Recordset.Open(). See 101 <a href='http://msdn.microsoft.com/library/en-us/ado270/htm/mdmthrstopen.asp'>Microsoft</a> 102 again.</li> 103 </ul> 104 105 <h5>Microsoft SQL Server</h5> 106 <p>This class was developed against ADO 2.7.</p> 107 <ul> 108 <li><b>Class:</b> <tt>dejavu.storage.storeado.StorageManagerADO_SQLServer</tt></li> 109 <li><b>Connect:</b> A valid ADO connect string. There are plenty of 110 online references for how to form these; for example, at 111 <a href='http://support.microsoft.com/?kbid=193332'>Microsoft</a>.</li> 112 <li><b>Threaded:</b> Optional. If set to any value, a new connection 113 is established for each thread. Otherwise, a single connection 114 is used for all threads.</li> 115 <li><b>Prefix:</b> If specified, all tables in the database will 116 have names starting with this prefix. If not provided, it 117 defaults to "djv". This helps if you need to mix Dejavu tables 118 with tables from another application.</li> 119 <li><b>CursorType:</b> Optional. Passed to Recordset.Open(). See 120 <a href='http://msdn.microsoft.com/library/en-us/ado270/htm/mdmthrstopen.asp'>Microsoft</a> 121 again.</li> 122 <li><b>LockType:</b> Optional. Passed to Recordset.Open(). See 123 <a href='http://msdn.microsoft.com/library/en-us/ado270/htm/mdmthrstopen.asp'>Microsoft</a> 124 again.</li> 125 </ul> 126 127 <h5>ODBC</h5> 128 <p>This class doesn't currently work. It needs some updating.</p> 129 <ul> 130 <li><b>Class:</b> <tt>dejavu.storage.storeodbc.StorageManagerODBC</tt></li> 131 <li><b>Connect:</b> A valid ADO connect string. There are plenty of 132 online references for how to form these; for example, at 133 <a href='http://support.microsoft.com/?kbid=193332'>Microsoft</a>.</li> 134 <li><b>Prefix:</b> If specified, all tables in the database will 135 have names starting with this prefix. If not provided, it 136 defaults to "djv". This helps if you need to mix Dejavu tables 137 with tables from another application.</li> 138 </ul> 139 140 141 <h4>Middleware</h4> 142 143 <p>Some Storage Managers act as "middleware", and can be chained together 144 to provide layered functionality. Consider, for example, the 145 <tt>CachingProxy</tt> class; it requires another Storage Manager 146 "behind it", which it proxies. It can be used to cache objects between 147 client connections independently from the underlying, database-specific 148 Storage Manager. The beauty of this design is that the decision to 149 use a CachingProxy is completely up to the deployer, <i>not</i> the 150 application developer. The deployer can test response times, separate 151 stores, and address other integration concerns on their own systems.</p> 152 153 <h5>Caching Proxy</h5> 154 <p>Use this class to persist Units between client connections. It needs 155 another Storage Manager to proxy.</p> 156 <ul> 157 <li><b>Class:</b> <tt>dejavu.storage.CachingProxy</tt></li> 158 <li><b>Next Store:</b> Required. The next Storage Manager in the 159 chain.</li> 160 <li><b>Lifetime:</b> Optional. The recurrence string which declares 161 how often to sweep Units out of the in-memory cache.</li> 162 </ul> 163 164 <h5>Burned Proxy</h5> 165 <p>Use this class to persist Units between client connections. It needs 166 another Storage Manager to proxy. Unlike the Caching Proxy above, this 167 Storage Manager recalls all Units at once upon the first request, and won't 168 recall them again from storage. They are "burned" into memory for the 169 lifetime of the application.</p> 170 <ul> 171 <li><b>Class:</b> <tt>dejavu.storage.BurnedProxy</tt></li> 172 <li><b>Next Store:</b> Required. The next Storage Manager in the 173 chain.</li> 174 <li><b>Lifetime:</b> Optional. The recurrence string which declares 175 how often to sweep Units out of the in-memory cache. In general, 176 you should not set this value for BurnedProxy stores.</li> 177 </ul> 178 93 179 94 180 </body> trunk/storage/storeado.py
r18 r19 635 635 636 636 decompiler = ADOSQLDecompiler 637 monopoly = False638 637 threaded = False 639 638 … … 654 653 self.cursorType = int(allOptions.get(u'CursorType', adOpenDynamic)) 655 654 self.lockType = int(allOptions.get(u'LockType', adLockOptimistic)) 656 if allOptions.get(u'Monopoly', ''):657 self.monopoly = True658 655 659 656 self.reserve_lock = threading.Lock() trunk/test_containers.py
r18 r19 1 1 import unittest 2 2 import operator 3 import containers 4 5 6 class ChainTests(unittest.TestCase): 7 8 def test_Chain(self): 9 cd = containers.Chain({'Antony': 'Cleopatra', 10 'Napoleon': 'Josephine', 11 'Mystico': 'Janet', 12 }) 13 self.assertEqual(cd, {'Antony': ['Cleopatra'], 14 'Napoleon': ['Josephine'], 15 'Mystico': ['Janet'], 16 }) 17 # And, paradoxically... 18 self.assertEqual(cd['Napoleon'], 'Josephine') 19 20 # Try adding a value. 21 cd['Antony'] = 'Octavia' 22 self.assertEqual(cd['Antony'], 'Octavia') 23 self.assertEqual(cd.chain('Antony'), ['Octavia', 'Cleopatra']) 24 25 # Test .update() 26 cd = containers.Chain() 27 cd.update({'Antony': 'Cleopatra', 28 'Napoleon': 'Josephine', 29 'Mystico': 'Janet', 30 }) 31 self.assertEqual(cd, {'Antony': ['Cleopatra'], 32 'Napoleon': ['Josephine'], 33 'Mystico': ['Janet'], 34 }) 35 36 # Test .get(key, default) 37 self.assertEqual(cd.get('Mystico', 'Carol'), 'Janet') 38 39 # Test has_key 40 self.assertEqual(cd.has_key('Napoleon'), True) 41 self.assertEqual(cd.has_key('Trotsky'), False) 42 43 # Test .clear() 44 cd.clear() 45 self.assertEqual(cd, {}) 3 from dejavu import containers 4 5 6 class WarehouseTests(unittest.TestCase): 7 8 def test_builtin_types(self): 9 # ints 10 avail, rem = containers.warehouse([1,2,3]) 11 self.assertEqual([avail.next() for x in xrange(5)], [1,2,3,0,0]) 12 13 avail, rem = containers.warehouse([1,2,3]) 14 self.assertEqual([avail.next() for x in xrange(2)], [1,2]) 15 self.assertEqual([x for x in rem], [3]) 16 17 # strings 18 avail, rem = containers.warehouse(['fish', 'bananas', 'old pyjamas']) 19 self.assertEqual([avail.next() for x in xrange(5)], ['fish', 'bananas', 'old pyjamas', '', '']) 20 21 avail, rem = containers.warehouse(['fish', 'bananas', 'old pyjamas']) 22 self.assertEqual([avail.next() for x in xrange(2)], ['fish', 'bananas']) 23 self.assertEqual([x for x in rem], ['old pyjamas']) 24 25 # Empty seq 26 avail, rem = containers.warehouse([]) 27 self.assertRaises(ValueError, avail.next) 28 29 def test_custom_classes(self): 30 class Thing: 31 def __init__(self, value=None): 32 self.value = value 33 34 things = Thing(1), Thing(2), Thing(3), Thing(4) 35 avail, rem = containers.warehouse(things) 36 self.assertEqual([avail.next().value for x in xrange(5)], 37 [1, 2, 3, 4, None]) 38 39 avail, rem = containers.warehouse(things) 40 self.assertEqual([avail.next().value for x in xrange(2)], [1, 2]) 41 self.assertEqual([x for x in rem], [things[2], things[3]]) 42 43 # Empty seq 44 avail, rem = containers.warehouse([], Thing) 45 self.assertEqual([avail.next().value for x in xrange(2)], [None, None]) 46 self.assertEqual([x for x in rem], []) 46 47 47 48
