/timm's /charming /python /tricks
Download
demo.py.
Read more on How to be Charming (in Python).
001: import sys 002: sys.dont_write_bytecode = True 003: from copyleft import * 004: 005: """ 006: This file address three problems: 007: 008: - The demo problem: how to show off your cool code. 009: - The test suite problem: how to check if past 010: code still runs. 011: - The command-line problem: how to call code from 012: command-line. 013: 014: #################################################### 015: Quick and dirty method. We do better below. 016: """ 017: 018: def go(f): 019: "Annotate functions to run at load time." 020: print "\n# ---|", f.__name__,"|-----------------" 021: if f.__doc__: 022: print "#", f.__doc__ 023: f() 024: return f 025: 026: #@go #<-- uncomment this line and load this file 027: def someFunctionWithLongName(): 028: "example of using @go." 029: print "All done with a few keystrokes" 030: quit() 031: 032: """################################################# 033: PROBLEM: How to show off you cool code to other 034: people, remembering all those tricks that make the 035: code do cool things. 036: 037: SOLUTION: Do all those cool things in a function. 038: 039: CONVENTIONS : 040: 1. Annotate those functions with @demo 041: 2. Demo functions end in "d". 042: 3. If there are many 043: demos, make a seperate file, also ending in "d". 044: So demos for lib.py would be found in libd.py. 045: 3. For functions that random numbers, there is no 046: call to "resetSeed" unless that the argument to 047: that call can be set by a demo function. 048: """ 049: 050: def demo0(f=None): return demo(f,0) 051: def demo1(f=None): return demo(f,1) 052: def demo2(f=None): return demo(f,2) 053: def demo3(f=None): return demo(f,3) 054: def demo4(f=None): return demo(f,4) 055: def demo5(f=None): return demo(f,5) 056: def demo6(f=None): return demo(f,6) 057: def demo7(f=None): return demo(f,7) 058: 059: def demo(f=None,lvl=0,d={}): 060: """ 061: A decorator for a demo suite. E.g. 062: 063: @demo1 064: def demoed() : 065: "Doco about this demo" 066: print "I am a demo" 067: 068: will add demoed to a list of known demos. 069: Then, we can call all demos using "demo()". 070: Note that demos can be defined at one of 071: eight levels demo0...demo7 and higher 072: level demos are run after lower-ones. 073: """ 074: if f: 075: if not lvl in d: d[lvl] = [] 076: d[lvl] += [f] 077: return f 078: for lvl in sorted(d.keys()): 079: for f in d[lvl]: 080: print '\n--|','('+str(lvl)+')',\ 081: f.func_name,'|','-'*40,'\n',f.__doc__,'\n' 082: f() 083: 084: """################################################# 085: PROBLEM: How to build a regression suite so that 086: tomorrow you can test that the code still does what 087: it did yesterday? 088: 089: SOLUTION: Write lots of functions that return 090: (want,got) pairs, count how many times want == got 091: and want != got. 092: 093: CONVENTIONS: 094: 1. Annotate those functions with @test 095: 2. Test functions end in "d". 096: 3. If lots of tests, store them in a seperate demos 097: files (name ending in "d"). 098: """ 099: 100: def test(f=None,tests=[]): 101: """ 102: A decorator for test suites. Each test function 103: returns a list of n pairs `[(got1,want1),(got2,want2),...]` 104: and this scores n more "passes" if `got==want`. E.g. 105: 106: @test 107: def tested(): 108: thing = 22 109: return [(22,thing), 110: (False, type thing = float)] 111: 112: will add "tested" to a list of known tests. Then, 113: we can call all tests and get a print out of 114: number of passes and fails using "test() 115: """ 116: if f: tests.append(f); return f 117: ok=no=0 118: for t in tests: 119: print "#",t.func_name + ': ',t.__doc__ 120: for n,(want,got) in enumerate(t()): 121: if want == got: 122: ok += 1; print "CORRECT:",t.func_name,'question', n+1 123: else: 124: no += 1; print "WRONG :",t.func_name,'question',n+1 125: if tests: 126: print '\n# Final score = %s/%s = %s%% CORRECT' \ 127: % (ok,(ok+no),round(100*ok/(ok+no))) 128: 129: """################################################# 130: PROBLEM: How to call all these code/test functions 131: from the command line (handling arguments, compiling 132: number strings, etc). 133: 134: SOLUTION: See below. 135: 136: CONVENTIONS: The function called in this way has 137: default values to its arguments, which can be 138: over-ridden from the command line. 139: """ 140: 141: def cmd(com='demo()'): 142: """ 143: If the call to python file.py includes additional; 144: arguments then parse them into a function call. 145: If not, call some default command. For example, 146: if this line is added to end of file: 147: 148: if __name__ == '__main__' : 149: eval(cmd('copyleft()')) 150: 151: Then if the call this file as follows: 152: 153: python demo,py 154: 155: then some default copyright notice will be shown. 156: But it we do it again using 157: 158: python demo.py copyleft hilary 2016 1000 159: 160: then we see a customized copyright notice where 161: the defaults for the copyleft function have been 162: replaced with name=hilary, year=2016, rate=1000. 163: """ 164: if len(sys.argv) < 2: 165: return com 166: else: 167: def stringp(x): 168: return isinstance(x,basestring) 169: def atom(x): 170: try: return float(x) 171: except ValueError: return x 172: def wrapper(x): 173: return "'" + x + "'" if stringp(x) else str(x) 174: words = map(wrapper,map(atom,sys.argv[2:])) 175: return sys.argv[1] + '(' + ','.join(words) + ')' 176: 177: if __name__ == '__main__' : 178: eval(cmd('copyleft()')) 179:
This file is part of Timm's charming Python tricks.
© 2014, Tim Menzies:
tim.menzies@gmail.com,
http://menzies.us.
Timm's charming Python tricks are free software: you can redistribute it and/or modify it under the terms of the GNU Lesser Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
Timm's charming Python tricks are distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU Lesser Public License along with Foobar. If not, see http://www.gnu.org/licenses.