Contact: fumanchu@aminus.org

Log in as guest/dejavu to create tickets

I think I've seen this ORM somewhere before...

Changeset 19

Show
Ignore:
Timestamp:
10/19/04 06:15:52
Author:
fumanchu
Message:

1. Changed containers.Balloon class to .warehouse function.
2. Doc updates.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/containers.py

    r18 r19  
    99and map. 
    1010 
    11 Find herein the containers: Balloon, Graph, Index, and Prism. 
     11Find herein the containers: warehouse, Graph, Index, and Prism. 
    1212 
    1313This work, including the source code, documentation 
     
    2727import new 
    2828 
    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(). 
     29def 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(). 
    3435     
    3536    If factory is None, the class of the first item in the sequence is used 
     
    3839    wrap the class in a function which can supply those. 
    3940     
    40     The most common use for the Balloon class is to reuse a set of existing 
     41    The most common use for warehouse is to reuse a set of existing 
    4142    objects, often because object creation and/or destruction is expensive. 
    4243     
    4344    Example: 
    4445     
    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() 
    4951    """ 
    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 = sequence 
     52    if not hasattr(stock, 'next'): 
     53        stock = iter(stock) 
     54     
     55    def pull()
     56        for item in stock: 
     57            yield item 
    5658         
    5759        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 
    8371 
    8472 
  • trunk/doc/dejavu.css

    r18 r19  
    55} 
    66 
    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 
     7body { padding: 0.75em; } 
    128 
    139h1 { 
  • trunk/doc/index.html

    r18 r19  
    7878</li> 
    7979<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> 
    8099</li> 
    81100<li><a href='framework.html'>Framework Development</a> 
  • trunk/doc/modeling.html

    r18 r19  
    284284the trick. Notice that flushing calls <tt>repress()</tt> for each Unit in 
    285285the 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 
     288a <tt>CachingProxy</tt> as a Storage Manager, temporary Units will be 
     289destroyed rather than persisted. This happens independently of forgetting 
     290and sandbox flushing.</p> 
     291 
    286292 
    287293<h4>Aggregate Functions</h4> 
  • trunk/doc/storage.html

    r18 r19  
    55<head> 
    66    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
    7     <title>Dejavu: Reference</title> 
     7    <title>Dejavu: Configuring Storage</title> 
    88    <link href='dejavu.css' rel='stylesheet' type='text/css' /> 
    99</head> 
     
    1111<body> 
    1212 
    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> 
    3814 
    3915<h3>Storage Managers</h3> 
    4016 
    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 
     18databases, query languages, and cache mechanisms. As the <i>deployer</i> of 
     19a Dejavu application, you get to be in control of these. But don't worry; 
     20in the vast majority of cases, you will set up a single database with just 
     21two lines in a configuration file. Often, the application developer will 
     22have already prepared default config files which you can simply "plug and 
     23play". But if you <i>need</i> more control over your data storage, you 
     24have it, without becoming a programmer.</p> 
    4325 
    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 
     27Managers to use for persisting application objects. This is usually 
     28done through an ini-style configuration file. Here's a short example: 
     29<pre>[Junct] 
     30Class: dejavu.storage.storeado.StorageManagerADO_MSAccess 
     31Connect: "DSN=Junct;Driver=Microsoft Access Driver (*.mdb);Dbq=D:\data\junct.mdb;" 
     32</pre> 
     33The first line of our example ("[Junct]") names the Storage Manager; 
     34each section in your conf file defines a different SM. You can use whatever 
     35name you like here; in this example, we used the name of the application. 
     36The second line tells Dejavu the <i>class</i> of SM we'd like to use. 
     37For most applications, you'll decide which class to use based on the 
     38database you want to use. Our example declares that we want to persist our 
     39application data in an "MS Access" (i.e., Jet) database.</p> 
    4840 
    49 <p>Configuration entries for Storage Managers:</p> 
     41<p>The third line in our example is a standard ODBC-style Connect string. 
     42The _MSAccess class requires this entry; other SM's may not. There are very 
     43few configuration entries which apply to all Storage Managers. Here are 
     44the common ones which do:</p> 
    5045 
    5146<table> 
     
    7368    <td>Optional. Declares which Unit classes to manage with this SM.</td> 
    7469</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 how 
    79         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> 
    8670</table> 
    8771 
    88 <h4>Unit Engines</h4> 
    89 <p></p> 
     72<p>The "Units" entry is what you will use to separate application objects 
     73into separate stores (if you need to). The objects in an application which 
     74need to be stored are called "Units", and each Unit is of a certain Unit 
     75class. If you specify a "Units" entry, then only Units of those classes 
     76will be managed by that Storage Manager. If you do <i>not</i> specify such 
     77an entry, then <b>all</b> Units will be handled by that Storage Manager. 
     78This means that only <i>one</i> SM should be missing this entry.</p> 
    9079 
    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 
     144to 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 
     147client connections independently from the underlying, database-specific 
     148Storage Manager. The beauty of this design is that the decision to 
     149use a CachingProxy is completely up to the deployer, <i>not</i> the 
     150application developer. The deployer can test response times, separate 
     151stores, 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 
     155another 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 
     166another Storage Manager to proxy. Unlike the Caching Proxy above, this 
     167Storage Manager recalls all Units at once upon the first request, and won't 
     168recall them again from storage. They are "burned" into memory for the 
     169lifetime 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 
    93179 
    94180</body> 
  • trunk/storage/storeado.py

    r18 r19  
    635635     
    636636    decompiler = ADOSQLDecompiler 
    637     monopoly = False 
    638637    threaded = False 
    639638     
     
    654653        self.cursorType = int(allOptions.get(u'CursorType', adOpenDynamic)) 
    655654        self.lockType = int(allOptions.get(u'LockType', adLockOptimistic)) 
    656         if allOptions.get(u'Monopoly', ''): 
    657             self.monopoly = True 
    658655         
    659656        self.reserve_lock = threading.Lock() 
  • trunk/test_containers.py

    r18 r19  
    11import unittest 
    22import 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, {}) 
     3from dejavu import containers 
     4 
     5 
     6class 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], []) 
    4647 
    4748