Contact: fumanchu@aminus.org

Log in as guest/dejavu to create tickets

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

Changeset 18

Show
Ignore:
Timestamp:
10/17/04 07:20:12
Author:
fumanchu
Message:

Doc updates + new TemporaryUnitError?

Files:

Legend:

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

    r17 r18  
    754754    pass 
    755755 
     756class TemporaryUnitError(DejavuError): 
     757    """Exception raised when a temporary Unit was sought but not found.""" 
     758    pass 
     759 
    756760 
    757761########################################################################### 
  • trunk/analysis.py

    r17 r18  
    3030 
    3131def _force_function(attr): 
     32    """If attr is callable, return it, else wrap it in a function.""" 
    3233    if callable(attr): 
    3334        return attr 
     
    7576    Example: 
    7677        >>> f = ["a", "b", "cc", "addd", "a4", "6"] 
    77         >>> group = [lambda x: x.isalpha()] 
     78        >>> group = lambda x: x.isalpha() 
    7879        >>> pivot = lambda x: x.startswith("a") 
    79         >>> ctab = analysis.CrossTab(f, groups, pivot) 
     80        >>> ctab = analysis.CrossTab(f, [group], pivot) 
    8081        >>> data, columns = ctab.results() 
    8182        >>> data 
  • trunk/doc/index.html

    r17 r18  
    6262        </ul> 
    6363    </li> 
    64     <li>Analysis Tools</li> 
     64    <li>Analysis Tools 
     65        <ul> 
     66        <li>Sorting Units</li> 
     67        <li>Cross-tabulation</li> 
     68        </ul> 
     69    </li> 
    6570    <li>The Arena Object 
    6671        <ul> 
  • trunk/doc/modeling.html

    r17 r18  
    736736 
    737737<p>Each Rule has an <tt>Operation</tt> property (a string, one of the above), 
    738 a <tt>SetID</tt>, and an <tt>Operand</tt>.</p> 
     738a <tt>SetID</tt>, and an <tt>Operand</tt>. Here's an example ruleset:</p> 
     739<table> 
     740<tr><th>Operation</th><th>SetID</th><th>Operand</th></tr> 
     741<tr><td>CREATE</td><td>1</td><td>Invoice</td></tr> 
     742<tr><td>FILTER</td><td>1</td><td>(Expression)</td></tr> 
     743<tr><td>CREATE</td><td>2</td><td>Inventory</td></tr> 
     744<tr><td>FILTER</td><td>2</td><td>(Expression)</td></tr> 
     745<tr><td>TRANSFORM</td><td>2</td><td>Invoice</td></tr> 
     746<tr><td>DIFFERENCE</td><td>1</td><td>2</td></tr> 
     747<tr><td>RETURN</td><td>1</td><td></td></tr> 
     748</table> 
     749 
     750<p>As you can see, every Rule operates on a <i>Set</i> of Units. The first 
     751rule is always to CREATE a set, declaring it to contain a certain Type 
     752of Units. In most cases, you will then FILTER that set. If you simply 
     753created a set and then returned it, it would contain all Units of the 
     754declared Type. When you filter a set, howevr, you remove Units from 
     755the whole which do not match the filter's Expression.</p> 
     756 
     757<p>In the example above, we CREATE a second Set so that we can eventually 
     758obtain the DIFFERENCE between Set 1 and Set 2. The second Set contains 
     759Units of a different Type than the first. Once we filter Set 2, we then 
     760TRANSFORM it; for each Inventory Unit, we look up associated Invoice 
     761Units. Then, we find the difference between the two Invoice sets and 
     762RETURN it.</p> 
     763 
     764<p>Rules are executed in order according to their <tt>Sequence</tt> 
     765attribute (lowest first). When you use the <tt>Engine.add_rule</tt> method, 
     766the next <tt>Sequence</tt> value is retrieved for you. Notice that each 
     767Rule belongs to one and only one Engine; they are not shared between 
     768Engines. Each Rule has its own <tt>EngineID</tt> attribute.</p> 
    739769 
    740770<h4>Engine Functions</h4> 
    741 <p></p> 
     771<p>The FUNCTION rule deserves special mention. The Operand of a FUNCTION 
     772rule is a string, a key in the <tt>Arena.engine_functions</tt> dictionary. 
     773When the rule is executed, that key is used to look up the function, which 
     774is then called, passing <tt>(sandbox, set)</tt>. The function should 
     775mutate the set directly. Use FUNCTION rules to mutate sets in ways which 
     776are more complex than those provided by FILTER and TRANSFORM. For example, 
     777you might provide a function which removes all but the first Unit in the 
     778Set (according to some ordering algorithm).</p> 
    742779 
    743780 
    744781<h3>Analysis Tools</h3> 
    745 <p></p> 
    746  
     782<p>Dejavu includes various tools to help you manipulate groups of Units.</p> 
     783 
     784<h4>Sorting Units</h4> 
     785<p>When you recall Units, you receive a generator, and must iterate over 
     786the values in some way. Often, this is accomplished with a list 
     787comprehension: 
     788<pre>f = logic.Expression(lambda x: 'Aa' in x.Name) 
     789people = [x for x in sandbox.recall(Person, f)] 
     790</pre> 
     791However, the <tt>recall</tt> method doesn't do any sorting; you must sort 
     792your list in your Python code. Dejavu provides a <tt>sort(attrs, 
     793descending=False)</tt> function to assist you. It returns a function, which 
     794you can then use in Python's sort function. Continuing our example: 
     795<pre>sorted_people = people.sort(dejavu.sort('Size', 'Name'))</pre> 
     796The most important issue (and the reason we don't just use 2.4's attrgetter), 
     797is that any Unit property must allow values of None, which tends to raise 
     798errors when compared to values of other types. The function which 
     799<tt>sort</tt> creates for you treats None as "less than" any other value.</p> 
     800 
     801<h4>Cross-tabulation</h4> 
     802<p>Cross-tabs (also called <i>aggregate tables</i> or <i>pivot tables</i>) 
     803display aggregate information about objects by category. For example, 
     804rather than show a list of Safari records, one row per trip, you might 
     805wish to show a table where each row represents a Destination, and each 
     806column shows the count of Safaris to that Destination for each distinct 
     807Year. In this example, we say that the Safaris are "grouped by" their 
     808Destination values, and that we "pivot" on the Year values.</p> 
     809 
     810<p>Dejavu helps you form such a table via the <tt>CrossTab</tt> class. 
     811You need to specify the group(s) you wish to use, and the pivot attribute. 
     812Finally, you must specify the aggregate function. Here's a code example: 
     813<pre> 
     814>>> data = ["a", "b", "cc", "bddd", "a4", "b6"] 
     815>>> group = lambda x: x.isalpha() 
     816>>> pivot = lambda x: x[0] 
     817>>> ctab = analysis.CrossTab(data, [group], pivot, dejavu.COUNT) 
     818>>> data, columns = ctab.results() 
     819>>> data 
     820{(True,): {"a": 1, "b": 2, "c": 1}, 
     821 (False,): {"a": 1, "b": 1}} 
     822>>> columns 
     823["a", "b", "c"]</pre> 
     824You may notice that we're not using Units in our example; the 
     825<tt>CrossTab</tt> class is designed to work with any objects. Here's one 
     826way to lay out that data:</p> 
     827<table> 
     828<tr><th>Is Alpha</th><th>a</th><th>b</th><th>c</th></tr> 
     829<tr><td>Y</td><td>1</td><td>2</td><td>1</td></tr> 
     830<tr><td>N</td><td>1</td><td>1</td><td>0</td></tr> 
     831</table> 
     832 
     833<p>The <tt>results</tt> method returns two values. First, the table 
     834itself in the form of a dictionary; each key is a tuple of group values, 
     835and the corresponding value is a sub-dictionary. Each sub-dict has keys 
     836which are the pivot attribute, and values which equal the aggregates. 
     837I know, that was confusing; look at the example. The second value to 
     838be returned is a list of the pivot column values; you'll notice they're 
     839sorted.</p> 
     840 
     841<p>The groups and pivot arguments may be either strings or functions. 
     842If strings, they must be the names of attributes of the source objects. 
     843The final aggfunc argument defaults to COUNT, but may also be SUM. 
     844More aggfuncs may arrive in the future.</p> 
    747845 
    748846<h3>The Arena Object</h3> 
  • trunk/engines.py

    r17 r18  
    180180     
    181181    def expr(self): 
     182        """expr() -> If a FILTER rule, return the Expression, else None.""" 
    182183        if self.Operation == 'FILTER': 
    183184            op = self.Operand