Changeset 71
- Timestamp:
- 12/22/06 22:03:41 (2 years ago)
- Files:
-
- sandbox/annotater/annotater.py (modified) (1 diff)
- sandbox/annotater/annotater_test.py (modified) (1 diff)
- sandbox/annotater/model.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
sandbox/annotater/annotater.py
Revision 68 Revision 71 1 """ 1 """ 2 Annotation of a web resource. 2 Annotation of a web resource. 3 3 4 @copyright: (c) 2006 Open Knowledge Foundation 4 @copyright: (c) 2006 Open Knowledge Foundation 5 @author: Rufus Pollock (Open Knowledge Foundation) 5 @author: Rufus Pollock (Open Knowledge Foundation) 6 @license: MIT License <http://www.opensource.org/licenses/mit-license.php> 6 @license: MIT License <http://www.opensource.org/licenses/mit-license.php> 7 """ 7 """ 8 import os 8 import os 9 9 10 import wsgiref.simple_server 10 import wsgiref.simple_server 11 import paste.request 11 import paste.request 12 # import genshi.template 12 # import genshi.template 13 # import genshi.output 13 # import genshi.output 14 14 15 from routes import * 15 from routes import * 16 16 17 # annotater stuff 17 import model 18 import model 18 19 19 # absolute url to annotation service 20 # absolute url to annotation service 20 service_path = '/annotate' 21 # this should go 21 22 service_path = '/annotation' 22 23 23 map = Mapper() 24 map = Mapper() 24 map.connect('annotate', controller='annotate', action='index', 25 map.connect('annotation/delete/:id', controller='annotation', action='delete', 25 conditions={'method': ['GET']}) 26 conditions=dict(method=['GET'])) 26 map.connect('annotate/create', controller='annotate', action='create', 27 map.connect('annotation/edit/:id', controller='annotation', action='edit', 27 conditions={'method': ['GET']}) 28 conditions=dict(method=['GET'])) 28 map.connect('annotate', controller='annotate', action='new', id=None, 29 29 conditions={'method': ['POST']}) 30 map.resource('annotation') 30 map.connect('annotate/:id', controller='annotate', action='edit', 31 31 conditions={'method': ['GET']}) 32 # map.resource assumes PUT for update but marginalias uses POST 32 map.connect('annotate/:id', controller='annotate', action='delete', 33 # the exacting mappings for REST seems a hotly contested matter see e.g. 33 conditions={'method': ['DELETE']}) 34 # http://www.megginson.com/blogs/quoderat/archives/2005/04/03/post-in-rest-create-update-or-action/ 34 35 # must have this *after* map.resource as otherwise overrides the create action 36 map.connect('annotation/:id', controller='annotation', action='update', 37 conditions=dict(method=['POST'])) 38 39 # misc config 35 marginalia_path = os.path.abspath('./marginalia') 40 marginalia_path = os.path.abspath('./marginalia') 36 html_doc_path = os.path.join(marginalia_path, 'index.html') 41 html_doc_path = os.path.join(marginalia_path, 'index.html') 37 42 38 43 39 import logging 44 import logging 40 def setup_logging(): 45 def setup_logging(): 41 level = logging.DEBUG 46 level = logging.DEBUG 42 logger = logging.getLogger('annotater') 47 logger = logging.getLogger('annotater') 43 logger.setLevel(level) 48 logger.setLevel(level) 44 log_file_path = 'debug.log' 49 log_file_path = 'debug.log' 45 fh = logging.FileHandler(log_file_path, 'w') 50 fh = logging.FileHandler(log_file_path, 'w') 46 fh.setLevel(level) 51 fh.setLevel(level) 47 logger.addHandler(fh) 52 logger.addHandler(fh) 48 logger.info('START LOGGING') 53 logger.info('START LOGGING') 49 return logger 54 return logger 50 55 51 logger = setup_logging() 56 logger = setup_logging() 52 57 53 class AnnotaterApp(object): 58 class AnnotaterApp(object): 54 59 55 def __init__(self): 60 def __init__(self): 56 pass 61 pass 57 62 58 def __call__(self, environ, start_response): 63 def __call__(self, environ, start_response): 59 self.environ = environ 64 self.environ = environ 60 self.map = map 65 self.map = map 61 self.map.environ = environ 66 self.map.environ = environ 62 self.start_response = start_response 67 self.start_response = start_response 63 self.path = environ['PATH_INFO'] 68 self.path = environ['PATH_INFO'] 64 logger.debug(self.path) 69 logger.debug(self.path) 65 # special test cases 70 # special test cases 66 if self.path.startswith('/debug'): 71 if self.path.startswith('/debug'): 67 return wsgiref.simple_server.demo_app(environ, start_response) 72 return wsgiref.simple_server.demo_app(environ, start_response) 68 elif self.path.startswith('/_js/'): 73 elif self.path.startswith('/_js/'): 69 status = '200 OK' 74 status = '200 OK' 70 response_headers = [('Content-type','text/plain')] 75 response_headers = [('Content-type','text/plain')] 71 start_response(status, response_headers) 76 start_response(status, response_headers) 72 jspath = os.path.join(marginalia_path, self.path[5:]) 77 jspath = os.path.join(marginalia_path, self.path[5:]) 73 jsfile = file(jspath).read() 78 jsfile = file(jspath).read() 74 return [jsfile] 79 return [jsfile] 75 elif self.path.endswith('.js') or self.path.endswith('.css'): 80 elif self.path.endswith('.js') or self.path.endswith('.css'): 76 status = '200 OK' 81 status = '200 OK' 77 if self.path.endswith('.js'): filetype = 'text/javascript' 82 if self.path.endswith('.js'): filetype = 'text/javascript' 78 else: filetype = 'text/css' 83 else: filetype = 'text/css' 79 response_headers = [('Content-type', filetype)] 84 response_headers = [('Content-type', filetype)] 80 start_response(status, response_headers) 85 start_response(status, response_headers) 81 jspath = os.path.join(marginalia_path, self.path[1:]) 86 jspath = os.path.join(marginalia_path, self.path[1:]) 82 jsfile = file(jspath).read() 87 jsfile = file(jspath).read() 83 return [jsfile] 88 return [jsfile] 84 elif self.path.startswith('/example-annotations.xml'): 89 elif self.path.startswith('/example-annotations.xml'): 85 status = '200 OK' 90 status = '200 OK' 86 filetype = 'text/xml' 91 filetype = 'text/xml' 87 response_headers = [('Content-type', filetype)] 92 response_headers = [('Content-type', filetype)] 88 start_response(status, response_headers) 93 start_response(status, response_headers) 89 jspath = os.path.join(marginalia_path, self.path[1:]) 94 jspath = os.path.join(marginalia_path, self.path[1:]) 90 jsfile = file(jspath).read() 95 jsfile = file(jspath).read() 91 return [jsfile] 96 return [jsfile] 92 elif self.path.startswith(service_path): 97 elif self.path.startswith(service_path): 93 return self.annotate() 98 return self.annotate() 94 else: 99 else: 95 logger.info('Call to base url /') 100 logger.info('Call to base url /') 96 status = '200 OK' 101 status = '200 OK' 97 response_headers = [('Content-type','text/html')] 102 response_headers = [('Content-type','text/html')] 98 start_response(status, response_headers) 103 start_response(status, response_headers) 99 out = file(html_doc_path).read() 104 out = file(html_doc_path).read() 100 return [out] 105 return [out] 101 106 107 def _make_annotate_form(self, form_name, action_url, form_defaults): 108 from formencode import htmlfill 109 keys = [ 'url' , 'range', 'note' ] 110 vals = {} 111 for key in keys: 112 vals[key] = form_defaults.get(key, '') 113 formfields = '' 114 for key in keys: 115 formfields += \ 116 ''' <label for="%s">%s:</label><input name="%s" id="%s" /><br /> 117 ''' % (key, key, key, key) 118 119 120 form = \ 121 '''<html> 122 <head></head> 123 <body> 124 <form name="%s" action="%s" method="POST"> 125 %s 126 <input type="submit" name="submission" value="send the form" /> 127 </form> 128 </body> 129 </html>''' % (form_name, action_url, formfields) 130 131 form = htmlfill.render(form, vals) 132 return form 133 134 102 def annotate(self): 135 def annotate(self): 103 query_vals = paste.request.parse_formvars(self.environ) 136 query_vals = paste.request.parse_formvars(self.environ) 104 request_method = self.environ['REQUEST_METHOD'] 137 request_method = self.environ['REQUEST_METHOD'] 105 logger.debug('CALL TO ANNOTATE') 138 logger.debug('CALL TO ANNOTATE') 106 logger.debug(self.path) 139 logger.debug(self.path) 107 logger.debug(query_vals) 140 logger.debug(query_vals) 108 logger.debug(self.environ['QUERY_STRING']) 141 logger.debug(self.environ['QUERY_STRING']) 109 logger.debug(request_method) 142 logger.debug(request_method) 110 mapdict = self.map.match(self.path) 143 mapdict = self.map.match(self.path) 111 logger.debug('mapdict: %s' % mapdict) 144 logger.debug('mapdict: %s' % mapdict) 112 action = mapdict['action'] 145 action = mapdict['action'] 146 anno_schema = model.AnnotationSchema() 113 147 114 if action == 'index': 148 if action == 'index': 115 status = '200 OK' 149 status = '200 OK' 116 response_headers = [ 150 response_headers = [ 117 ('Content-type', 'text/plain'), 151 ('Content-type', 'text/plain'), 118 ] 152 ] 119 items = list(model.Annotation.select()) 153 items = list(model.Annotation.select()) 120 out = '' 154 out = '' 121 for item in items: 155 for item in items: 122 out += str(item) + '\n\n' 156 out += str(item) + '\n\n' 123 self.start_response(status, response_headers) 157 self.start_response(status, response_headers) 124 return [out] 158 return [out] 125 elif action == ' create':159 elif action == 'new': 126 status = '200 OK' 160 status = '200 OK' 127 response_headers = [ 161 response_headers = [ 128 ('Content-type', 'text/html'), 162 ('Content-type', 'text/html'), 129 ] 163 ] 130 posturl = self.map.generate(controller='annotat e', action='new')164 posturl = self.map.generate(controller='annotation', action='create') 131 form = \ 165 form = \ 132 '''<html> 166 '''<html> 133 <head></head> 167 <head></head> 134 <body> 168 <body> 135 <form name='annotation_create' action="%s" method="POST"> 169 <form name='annotation_create' action="%s" method="POST"> 136 <label>url:</label> <input name="url" id="url" /><br /> 170 <label>url:</label> <input name="url" id="url" /><br /> 137 <label>range:</label><input name="range" id="range" /> 171 <label>range:</label><input name="range" id="range" /><br /> 138 <label>note:</label><input name="note" id="note" /> 172 <label>note:</label><input name="note" id="note" /><br /> 139 <input type="submit" name="submission" value="send the form" /> 173 <input type="submit" name="submission" value="send the form" /> 140 </form> 174 </form> 141 </body> 175 </body> 142 </html>''' % posturl 176 </html>''' % posturl 143 self.start_response(status, response_headers) 177 self.start_response(status, response_headers) 144 return [ form ] 178 return [ form ] 145 elif action == ' new':179 elif action == 'create': 146 url = query_vals.get('url') 180 url = query_vals.get('url') 147 range = query_vals.get('range', 'NO RANGE') 181 range = query_vals.get('range', 'NO RANGE') 148 note = query_vals.get('note', 'NO NOTE') 182 note = query_vals.get('note', 'NO NOTE') 149 anno = model.Annotation( 183 anno = model.Annotation( 150 url=url, 184 url=url, 151 range=range, 185 range=range, 152 note=note) 186 note=note) 153 status = '201 Created' 187 status = '201 Created' 154 location = '/annotation/%s' % anno.id 188 location = '/annotation/%s' % anno.id 155 response_headers = [ 189 response_headers = [ 156 ('Content-type', 'text/html'), 190 ('Content-type', 'text/html'), 157 ('Location', location) 191 ('Location', location) 158 ] 192 ] 159 self.start_response(status, response_headers) 193 self.start_response(status, response_headers) 160 return [''] 194 return [''] 195 elif action == 'edit': 196 id = mapdict['id'] 197 try: 198 id = int(id) 199 except: 200 status = '400 Bad Request' 201 response_headers = [ 202 ('Content-type', 'text/html'), 203 ] 204 self.start_response(status, response_headers) 205 msg = '<h1>400 Bad Request</h1><p>No such annotation #%s</p>' % id 206 return [msg] 207 anno = model.Annotation.get(id) 208 posturl = self.map.generate(controller='annotation', 209 action='update', id=anno.id, method='POST') 210 print 'Post url:', posturl 211 form_defaults = anno_schema.from_python(anno) 212 form = self._make_annotate_form('annotate_edit', posturl, 213 form_defaults) 214 status = '200 OK' 215 response_headers = [ 216 ('Content-type', 'text/html'), 217 ] 218 self.start_response(status, response_headers) 219 return [ form ] 220 221 elif action == 'update': 222 id = mapdict['id'] 223 try: 224 id = int(id) 225 except: 226 status = '400 Bad Request' 227 response_headers = [ 228 ('Content-type', 'text/html'), 229 ] 230 self.start_response(status, response_headers) 231 msg = '<h1>400 Bad Request</h1><p>No such annotation #%s</p>' % id 232 return [msg] 233 new_values = dict(query_vals) 234 new_values['id'] = id 235 del new_values['submission'] 236 anno_edited = anno_schema.to_python(new_values) 237 status = '204 Updated' 238 response_headers = [] 239 self.start_response(status, response_headers) 240 return [''] 241 161 elif action == 'delete': 242 elif action == 'delete': 162 id = query_vals['id'] 243 id = mapdict['id'] 244 if id is None: 245 status = '400 Bad Request' 246 response_headers = [ 247 ('Content-type', 'text/html'), 248 ] 249 self.start_response(status, response_headers) 250 return ['<h1>400 Bad Request</h1><p>Bad ID</p>'] 251 else: 252 status = '204 Deleted' 253 response_headers = [] 254 try: 255 id = int(id) 256 model.Annotation.delete(id) 257 self.start_response(status, response_headers) 258 return [''] 259 except: 260 status = '500 Internal server error' 261 self.start_response(status, response_headers) 262 return ['<h1>500 Internal Server Error</h1>Delete failed'] 163 else: 263 else: 164 status = '404 Not Found' 264 status = '404 Not Found' 165 response_headers = [ 265 response_headers = [ 166 ('Content-type', 'text/ html'),266 ('Content-type', 'text/plain'), 167 ] 267 ] 168 self.start_response(status, response_headers) 268 self.start_response(status, response_headers) 169 return ['Not found ']269 return ['Not found or method not allowed'] 170 270 171 271 172 if __name__ == '__main__': 272 if __name__ == '__main__': 173 app = AnnotaterApp() 273 app = AnnotaterApp() 174 import paste.httpserver 274 import paste.httpserver 175 paste.httpserver.serve(app) 275 paste.httpserver.serve(app) sandbox/annotater/annotater_test.py
Revision 68 Revision 71 1 import os 1 import os 2 import shutil 2 import shutil 3 import tempfile 3 import tempfile 4 import commands 4 import commands 5 from StringIO import StringIO 5 from StringIO import StringIO 6 6 7 import twill 7 import twill 8 from twill import commands as web 8 from twill import commands as web 9 9 10 import annotater 10 import annotater 11 import model 11 import model 12 12 13 class TestMapper: 13 class TestMapper: 14 14 15 def test_match_1(self): 15 def test_match_new(self): 16 annotater.map.environ = { 'REQUEST_METHOD' : 'GET' } 16 annotater.map.environ = { 'REQUEST_METHOD' : 'GET' } 17 out = annotater.map.match('/annotate/create') 17 out = annotater.map.match('/annotation/new') 18 assert out['action'] == 'new' 19 20 def test_match_index(self): 21 annotater.map.environ = { 'REQUEST_METHOD' : 'GET' } 22 out = annotater.map.match('/annotation') 23 assert out['action'] == 'index' 24 25 def test_match_create(self): 26 annotater.map.environ = { 'REQUEST_METHOD' : 'POST' } 27 out = annotater.map.match('/annotation') 18 assert out['action'] == 'create' 28 assert out['action'] == 'create' 19 29 20 def test_match_2(self): 30 def test_match_delete(self): 21 annotater.map.environ = { 'REQUEST_METHOD' : 'GET' } 31 annotater.map.environ = { 'REQUEST_METHOD' : 'GET' } 22 out = annotater.map.match('/annotate') 32 out = annotater.map.match('/annotation/delete/1') 23 assert out['action'] == 'index' 33 assert out['action'] == 'delete' 24 34 assert out['id'] == '1' 25 def test_match_2(self): 35 annotater.map.environ = { 'REQUEST_METHOD' : 'DELETE' } 36 out = annotater.map.match('/annotation/1') 37 assert out['action'] == 'delete' 38 assert out['id'] == '1' 39 out = annotater.map.match('/annotation/') 40 assert out['id'] == None 41 42 def test_match_delete(self): 43 annotater.map.environ = { 'REQUEST_METHOD' : 'GET' } 44 out = annotater.map.match('/annotation/edit/1') 45 assert out['action'] == 'edit' 46 assert out['id'] == '1' 47 annotater.map.environ = { 'REQUEST_METHOD' : 'PUT' } 48 out = annotater.map.match('/annotation/1') 49 assert out['action'] == 'update' 50 assert out['id'] == '1' 26 annotater.map.environ = { 'REQUEST_METHOD' : 'POST' } 51 annotater.map.environ = { 'REQUEST_METHOD' : 'POST' } 27 out = annotater.map.match('/annotat e')52 out = annotater.map.match('/annotation/1') 28 assert out['action'] == ' new'53 assert out['action'] == 'update' 29 54 30 def test_url_for_ 1(self):55 def test_url_for_new(self): 31 offset = annotater.map.generate(controller='annotat e', action='create')56 offset = annotater.map.generate(controller='annotation', action='new') 32 exp = '/annotat e/create'57 exp = '/annotation/new' 33 assert offset == exp 58 assert offset == exp 34 59 35 def test_url_for_ 2(self):60 def test_url_for_create(self): 36 offset = annotater.map.generate(controller='annotat e', action='new',61 offset = annotater.map.generate(controller='annotation', action='create', 37 method='POST' ) 62 method='POST' ) 38 exp = '/annotate' 63 exp = '/annotation' 39 assert offset == exp 64 assert offset == exp 40 65 41 66 def test_url_for_delete(self): 42 class TestStuff: 67 offset = annotater.map.generate(controller='annotation', 68 action='delete', id=1, method='GET' ) 69 exp = '/annotation/delete/1' 70 assert offset == exp 71 offset = annotater.map.generate(controller='annotation', 72 action='delete', id=1, method='DELETE' ) 73 exp = '/annotation/1' 74 assert offset == exp 75 76 def test_url_for_edit(self): 77 offset = annotater.map.generate(controller='annotation', 78 action='edit', id=1, method='GET') 79 exp = '/annotation/edit/1' 80 assert offset == exp 81 82 class TestStatic: 83 84 def test__make_annotate_form(self): 85 app = annotater.AnnotaterApp() 86 defaults = { 'url' : 'http://www.blackandwhite.com' } 87 out = app._make_annotate_form(form_name='formname', action_url='.', 88 form_defaults=defaults) 89 exp1 = '<label for="url">url:</label><input name="url" id="url" \ 90 value="%s" /><br />' % defaults['url'] 91 assert exp1 in out 92 93 94 class TestWsgi: 95 96 # disabled = True 43 97 44 def setup_method(self, name=''): 98 def setup_method(self, name=''): 45 wsgi_app = annotater.AnnotaterApp() 99 wsgi_app = annotater.AnnotaterApp() 46 twill.add_wsgi_intercept('localhost', 8080, lambda : wsgi_app) 100 twill.add_wsgi_intercept('localhost', 8080, lambda : wsgi_app) 47 self.outp = StringIO() 101 self.outp = StringIO() 48 twill.set_output(self.outp) 102 twill.set_output(self.outp) 49 self.siteurl = 'http://localhost:8080/' 103 self.siteurl = 'http://localhost:8080/' 50 104 51 def teardown_method(self, name=''): 105 def teardown_method(self, name=''): 52 # remove intercept. 106 # remove intercept. 53 twill.remove_wsgi_intercept('localhost', 8080) 107 twill.remove_wsgi_intercept('localhost', 8080) 54 108 55 def test_js(self): 109 def test_js(self): 56 filename = 'domutil.js' 110 filename = 'domutil.js' 57 url = self.siteurl + '_js/' + filename 111 url = self.siteurl + '_js/' + filename 58 web.go(url) 112 web.go(url) 59 web.code(200) 113 web.code(200) 60 web.find('ELEMENT_NODE = 1;') 114 web.find('ELEMENT_NODE = 1;') 61 115 62 def test_js_2(self): 116 def test_js_2(self): 63 filename = 'domutil.js' 117 filename = 'domutil.js' 64 url = self.siteurl + filename 118 url = self.siteurl + filename 65 web.go(url) 119 web.go(url) 66 web.code(200) 120 web.code(200) 67 web.find('ELEMENT_NODE = 1;') 121 web.find('ELEMENT_NODE = 1;') 68 122 69 def test_show_root(self): 123 def test_show_root(self): 70 web.go(self.siteurl) 124 web.go(self.siteurl) 71 web.code(200) 125 web.code(200) 72 web.find('This is a demonstration of') 126 web.find('This is a demonstration of') 73 127 74 def test_annotate_get(self): 128 def test_annotate_get(self): 75 anno = model.Annotation( 129 anno = model.Annotation( 76 url='http://xyz.com', 130 url='http://xyz.com', 77 range='blah range', 131 range='blah range', 78 note='blah note', 132 note='blah note', 79 ) 133 ) 80 offset = annotater. url_for(controller='annotate', action='index')134 offset = annotater.map.generate(controller='annotation', action='index') 81 url = self.siteurl + offset[1:] 135 url = self.siteurl + offset[1:] 82 web.go(url) 136 web.go(url) 83 web.code(200) 137 web.code(200) 84 web.find(anno.url) 138 web.find(anno.url) 85 web.find(anno.range) 139 web.find(anno.range) 86 140 87 def test_annotate_create(self): 141 def test_annotate_new(self): 142 # exercises both create and new 88 import model 143 import model 89 model.rebuilddb() 144 model.rebuilddb() 90 offset = annotater. url_for(controller='annotate', action='create',145 offset = annotater.map.generate(controller='annotation', action='new', 91 method='GET') 146 method='GET') 92 url = self.siteurl + offset[1:] 147 url = self.siteurl + offset[1:] 93 web.go(url) 148 web.go(url) 94 web.code(200) 149 web.code(200) 95 note = 'any old thing' 150 note = 'any old thing' 96 web.fv('', 'url', 'http://localhost/') 151 web.fv('', 'url', 'http://localhost/') 97 web.fv('', 'note', note) 152 web.fv('', 'note', note) 98 web.submit() 153 web.submit() 99 web.code(201) 154 web.code(201) 100 # TODO make this test more selective 155 # TODO make this test more selective 101 items = model.Annotation.select() 156 items = model.Annotation.select() 102 items = list(items) 157 items = list(items) 103 assert len(items) == 1 158 assert len(items) == 1 104 assert items[0].note == note 159 assert items[0].note == note 105 160 161 def test_annotate_delete(self): 162 anno = model.Annotation( 163 url='http://xyz.com', 164 range='blah range', 165 note='blah note', 166 ) 167 offset = annotater.map.generate(controller='annotation', action='delete', 168 id=anno.id) 169 url = self.siteurl + offset[1:] 170 web.go(url) 171 web.code(204) 172 tmp = model.Annotation.select(model.Annotation.q.id == anno.id) 173 num = len(list(tmp)) 174 assert num == 0 175 176 def _create_annotation(self): 177 anno = model.Annotation( 178 url='http://xyz.com', 179 range='blah range', 180 note='blah note', 181 ) 182 return anno 183 184 def test_annotate_edit(self): 185 anno = self._create_annotation() 186 offset = annotater.map.generate(controller='annotation', action='edit', 187 id=anno.id, method='GET') 188 url = self.siteurl + offset[1:] 189 web.go(url) 190 web.code(200) 191 newnote = u'This is a NEW note, a NEW note I say.' 192 web.fv('', 'note', newnote) 193 web.submit() 194 web.code(204) 195 assert anno.note == newnote 196 197 def test_not_found(self): 198 offset = annotater.map.generate(controller='annotation') 199 url = self.siteurl + offset[1:] + '/blah' 200 web.go(url) 201 web.code(404) 202 203 def test_bad_request(self): 204 offset = annotater.map.generate(controller='annotation', action='edit', 205 method='GET') 206 url = self.siteurl + offset[1:] 207 web.go(url) 208 web.code(400) 209 210 sandbox/annotater/model.py
Revision 68 Revision 71 1 import sqlobject 1 import sqlobject 2 2 3 uri = 'sqlite:///Users/rgrp/svnroot/rgrp/code/annotater/sqlite.db' 3 import os 4 cwd = os.getcwd() 5 uri = 'sqlite://%s/sqlite.db' % cwd 4 # uri = 'sqlite:///:memory:' 6 # uri = 'sqlite:///:memory:' 5 __connection__ = sqlobject.connectionForURI(uri) 7 __connection__ = sqlobject.connectionForURI(uri) 6 8 7 # note we run this at bottom of module to auto create db tables on import 9 # note we run this at bottom of module to auto create db tables on import 8 def createdb(): 10 def createdb(): 9 Annotation.createTable(ifNotExists=True) 11 Annotation.createTable(ifNotExists=True) 10 12 11 def cleandb(): 13 def cleandb(): 12 Annotation.dropTable(ifExists=True) 14 Annotation.dropTable(ifExists=True) 13 15 14 def rebuilddb(): 16 def rebuilddb(): 15 cleandb() 17 cleandb() 16 createdb() 18 createdb() 17 19 18 class Annotation(sqlobject.SQLObject): 20 class Annotation(sqlobject.SQLObject): 19 21 20 url = sqlobject.UnicodeCol() 22 url = sqlobject.UnicodeCol() 21 range = sqlobject.UnicodeCol() 23 range = sqlobject.UnicodeCol() 22 note = sqlobject.UnicodeCol() 24 note = sqlobject.UnicodeCol() 23 25 24 # $url, $range, $note, $access, $quote, $quote_title, $quote_author ) 26 # $url, $range, $note, $access, $quote, $quote_title, $quote_author ) 25 27 28 from formencode import sqlschema 29 class AnnotationSchema(sqlschema.SQLSchema): 30 31 wrap = Annotation 26 32 27 createdb() 33 createdb()
