/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.