Changeset 3617
- Timestamp:
- 11/06/07 20:54:48 (1 year ago)
- Files:
-
- branches/1.0/turbogears/command/base.py (modified) (1 diff)
- branches/1.0/turbogears/command/sacommand.py (modified) (6 diffs)
- branches/1.0/turbogears/database.py (modified) (8 diffs)
- branches/1.0/turbogears/identity/saprovider.py (modified) (8 diffs)
- branches/1.0/turbogears/qstemplates/quickstart/+package+/model.py_tmpl (modified) (12 diffs)
- branches/1.0/turbogears/startup.py (modified) (1 diff)
- branches/1.0/turbogears/tests/test_sqlalchemy.py (modified) (5 diffs)
- branches/1.0/turbogears/testutil.py (modified) (1 diff)
- branches/1.0/turbogears/visit/savisit.py (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/1.0/turbogears/command/base.py
r3446 r3617 175 175 if config.get("sqlalchemy.dburi"): 176 176 using_sqlalchemy = True 177 database. bind_meta_data()177 database.get_engine() 178 178 locals.update(session=database.session, 179 179 metadata=database.metadata) branches/1.0/turbogears/command/sacommand.py
r3512 r3617 4 4 try: 5 5 from sqlalchemy import MetaData, exceptions, Table, String 6 from turbogears.database import bind_meta_data,metadata, get_engine6 from turbogears.database import metadata, get_engine 7 7 except ImportError: 8 8 pass … … 29 29 def create(command, args): 30 30 print "Creating tables at %s" % (config.get("sqlalchemy.dburi")) 31 bind_meta_data()31 get_engine() 32 32 get_model() 33 33 metadata.create_all() … … 52 52 [sacommand.when("command == 'status'")] 53 53 def status(command, args): 54 bind_meta_data()54 get_engine() 55 55 get_model() 56 56 ret = compare_metadata(metadata, MetaData(metadata.bind)) … … 75 75 rc.append("Change table " + pyt.fullname) 76 76 rc.extend(indent(ret) + ['']) 77 return rc 77 return rc 78 78 79 79 def compare_table(pyt, dbt): 80 rc = [] 80 rc = [] 81 81 dbcols = dict([(s.lower(), s) for s in dbt.columns.keys()]) 82 82 for pyc in pyt.columns: … … 92 92 for dbcol in dbcols: 93 93 rc.append("Remove column " + dbcol) 94 return rc 95 94 return rc 95 96 96 def compare_column(pyc, dbc): 97 97 rc = [] … … 105 105 if pyc.type.length != dbc.type.length: 106 106 rc.append('Change length to ' + str(pyc.type.length)) 107 107 108 108 # Check primary key 109 if dbc.primary_key != pyc.primary_key: 109 if dbc.primary_key != pyc.primary_key: 110 110 rc.append(pyc.primary_key and 'Make primary key' or 'Remove primary key') 111 111 112 112 # Check foreign keys 113 113 # TBD 114 114 115 115 # Check default - disabled for now (didn't work on SQLite) 116 116 #if dbc.default != pyc.default: 117 117 # rc.append('Change default to ' + str(pyc.default.arg)) 118 118 119 119 # Check index - disabled for now (didn't work on SQLite) 120 120 #if dbc.index != pyc.index: 121 # rc.append(pyc.index and 'Add index' or 'Remove index') 122 121 # rc.append(pyc.index and 'Add index' or 'Remove index') 122 123 123 return rc branches/1.0/turbogears/database.py
r3512 r3617 5 5 import time 6 6 import logging 7 8 import cherrypy 9 from cherrypy.filters.basefilter import BaseFilter 10 11 try: 12 import sqlalchemy 13 from sqlalchemy.orm import create_session as orm_create_session 14 except ImportError: 15 sqlalchemy = None 7 16 8 17 try: … … 13 22 sqlobject = None 14 23 15 import cherrypy16 from cherrypy.filters.basefilter import BaseFilter17 18 24 import dispatch 19 25 from turbogears import config … … 25 31 _engine = None 26 32 27 # Provide support for sqlalchemy 28 try: 29 import sqlalchemy 30 from sqlalchemy.ext import activemapper 31 from sqlalchemy.exceptions import InvalidRequestError 32 33 # Provide support for SQLAlchemy 34 if sqlalchemy: 33 35 def get_engine(): 34 36 """Retrieve the engine based on the current configuration.""" … … 39 41 if "sqlalchemy" in k: 40 42 alch_args[k.split(".")[-1]] = v 41 42 43 dburi = alch_args.pop('dburi') 43 44 if not dburi: 44 45 raise KeyError("No sqlalchemy database config found!") 45 46 46 _engine = sqlalchemy.create_engine(dburi, **alch_args) 47 if not metadata.is_bound(): 47 48 metadata.bind = _engine 48 49 elif not metadata.is_bound():50 metadata.bind = _engine51 52 49 return _engine 53 50 … … 55 52 """Create a session that uses the engine from thread-local metadata.""" 56 53 if not metadata.is_bound(): 57 bind_meta_data() 58 59 return sqlalchemy.orm.create_session() 60 61 metadata = activemapper.metadata 62 session = activemapper.Objectstore(create_session) 63 activemapper.objectstore = session 64 65 def bind_meta_data(): 66 get_engine() 67 68 except ImportError: 69 sqlalchemy = None 70 54 get_engine() 55 return orm_create_session() 56 57 metadata = sqlalchemy.MetaData() 58 try: 59 from sqlalchemy.orm import scoped_session 60 session = scoped_session(create_session) 61 mapper = session.mapper # use session-aware mapper 62 except ImportError: # SQLAlchemy < 0.4 63 from sqlalchemy.ext.sessioncontext import SessionContext 64 class Objectstore(object): 65 def __init__(self): 66 self.context = SessionContext(create_session) 67 def __getattr__(self, name): 68 return getattr(self.context.registry(), name) 69 session = property(lambda s: s.context.registry()) 70 session = Objectstore() 71 context = session.context 72 Query = sqlalchemy.Query 73 from sqlalchemy.orm import mapper as orm_mapper 74 def mapper(cls, *args, **kwargs): 75 validate = kwargs.pop('validate', False) 76 if not hasattr(getattr(cls, '__init__'), 'im_func'): 77 def __init__(self, **kwargs): 78 for key, value in kwargs.items(): 79 if validate and key not in self.mapper.props: 80 raise KeyError( 81 "Property does not exist: '%s'" % key) 82 setattr(self, key, value) 83 cls.__init__ = __init__ 84 m = orm_mapper(cls, extension=context.mapper_extension, 85 *args, **kwargs) 86 class query_property(object): 87 def __get__(self, instance, cls): 88 return Query(cls, session=context.current) 89 cls.query = query_property() 90 return m 91 92 else: 93 def get_engine(): 94 pass 95 96 def create_session(): 97 pass 98 99 metadata = session = mapper = None 71 100 72 101 try: … … 77 106 hub_registry = set() 78 107 79 # This dictionary stores the AutoConnectHubs used for each 80 # connection URI 81 _hubs = dict() 82 83 108 _hubs = dict() # stores the AutoConnectHubs used for each connection URI 109 110 # Provide support for SQLObject 84 111 if sqlobject: 85 112 def _mysql_timestamp_converter(raw): … … 397 424 req.sa_transaction = make_sa_transaction(session) 398 425 399 400 426 def sa_tr_active(tr): 401 if hasattr(session, 'context'): 427 if hasattr(session, 'context'): 402 428 # SA 0.3 403 429 return tr.session.transaction 404 else: 430 else: 405 431 # SA 0.4 (effectively always active - commit or rollback don't fail) 406 432 return True 407 408 433 409 434 def make_sa_transaction(session): 410 if hasattr(session, 'context'): 435 if hasattr(session, 'context'): 411 436 # SA 0.3 412 437 tr = session.create_transaction() 413 return tr 414 415 else: 416 # SA 0.4 438 return tr 439 440 else: 441 # SA 0.4 417 442 session.begin() 418 443 return session 419 420 444 421 445 def so_to_dict(sqlobj): … … 461 485 end_all() 462 486 463 __all__ = ["PackageHub", "AutoConnectHub", "set_db_uri", 487 __all__ = ["get_engine", "metadata", "session", "mapper", 488 "PackageHub", "AutoConnectHub", "set_db_uri", 464 489 "commit_all", "rollback_all", "end_all", "so_to_dict", 465 490 "so_columns", "so_joins", "EndTransactionsFilter"] 466 467 if sqlalchemy:468 __all__.extend(["metadata", "session", "bind_meta_data"])branches/1.0/turbogears/identity/saprovider.py
r3487 r3617 1 import cherrypy 2 import random 3 from datetime import * 4 5 import turbogears 6 from turbogears import identity 1 from sqlalchemy.orm import class_mapper 2 3 from turbogears import config, identity 4 from turbogears.database import session 7 5 from turbogears.util import load_class 8 from turbogears.database import session9 6 from turbojson.jsonify import * 10 from sqlalchemy.orm import class_mapper11 7 12 8 import logging … … 19 15 20 16 # Global class references -- 21 # these will be set when the Provider is initialised.17 # these will be set when the provider is initialised. 22 18 user_class = None 23 19 group_class = None … … 40 36 # Attempt to load the user. After this code executes, there *WILL* be 41 37 # a _user attribute, even if the value is None. 42 visit = session.query(visit_class).filter_by( 43 visit_key=self.visit_key).first() 38 visit = visit_class.query.filter_by(visit_key=self.visit_key).first() 44 39 if not visit: 45 40 self._user = None 46 41 return None 47 self._user = session.query(user_class).get(visit.user_id)42 self._user = user_class.query.get(visit.user_id) 48 43 return self._user 49 44 user = property(_get_user) … … 69 64 else: 70 65 self._permissions = frozenset([ 71 p.permission_name for p in self.user.permissions])66 p.permission_name for p in self.user.permissions]) 72 67 return self._permissions 73 68 permissions = property(_get_permissions) … … 93 88 return 94 89 try: 95 visit = session.query(visit_class).filter_by( 96 visit_key=self.visit_key).first() 90 visit = visit_class.query.filter_by(visit_key=self.visit_key).first() 97 91 session.delete(visit) 98 92 # Clear the current identity … … 112 106 def __init__(self): 113 107 super(SqlAlchemyIdentityProvider, self).__init__() 114 get =turbogears.config.get108 get = config.get 115 109 116 110 global user_class, group_class, permission_class, visit_class … … 155 149 permissions: a set of permission IDs 156 150 ''' 157 user = session.query(user_class).filter_by(user_name=user_name).first()151 user = user_class.query.filter_by(user_name=user_name).first() 158 152 if not user: 159 153 log.warning("No such user: %s", user_name) … … 166 160 visit_key) 167 161 # Link the user to the visit 168 link = session.query(visit_class).filter_by( 169 visit_key=visit_key).first() 170 162 link = visit_class.query.filter_by(visit_key=visit_key).first() 171 163 if not link: 172 164 link = visit_class() 173 165 link.visit_key = visit_key 174 166 link.user_id = user.user_id 175 session.save(link)176 177 167 else: 178 168 link.user_id = user.user_id 179 180 169 session.flush() 181 170 return SqlAlchemyIdentity(visit_key, user) branches/1.0/turbogears/qstemplates/quickstart/+package+/model.py_tmpl
r3515 r3617 1 #if $identity != "none"1 #if $identity != 'none' 2 2 from datetime import datetime 3 3 #end if … … 7 7 #end if 8 8 #if $sqlalchemy == 'True' 9 from sqlalchemy import (Table, Column, String, DateTime, Date, Integer, 10 DECIMAL, Unicode, ForeignKey, and_, or_) 9 from sqlalchemy import * 11 10 #if $elixir == 'True' 11 from turbogears.database import metadata, session 12 import elixir 13 elixir.metadata, elixir.session = metadata, session 12 14 from elixir import * 13 #end if 14 from turbogears.database import metadata, session 15 #if $elixir == 'False' 16 from sqlalchemy.orm import mapper, relation 17 #end if 18 #end if 19 #if $identity != "none" 15 #else 16 from turbogears.database import metadata, mapper 17 from sqlalchemy.orm import relation 18 #end if 19 #end if 20 #if $identity != 'none' 20 21 from turbogears import identity 21 22 #end if 22 23 23 #if $sql alchemy != "True"24 #if $sqlobject == 'True' 24 25 hub = PackageHub('${package}') 25 26 __connection__ = hub 26 27 28 # your data model 29 27 30 # class YourDataClass(SQLObject): 28 31 # pass 29 32 #end if 30 #if $sqlalchemy == "True" 31 #if $elixir == "True" 33 #if $sqlalchemy == 'True' 34 #if $elixir == 'True' 35 # your data model 36 32 37 # class YourDataClass(Entity): 33 38 # pass 34 39 #else 40 # your data tables 41 35 42 # your_table = Table('yourtable', metadata, 36 43 # Column('my_id', Integer, primary_key=True) 37 44 # ) 38 45 46 # your model classes 47 39 48 # class YourDataClass(object): 40 49 # pass 41 50 42 # session.mapper(YourDataClass, your_table)43 #end if 44 #end if 45 46 #if $identity == "sqlobject"47 ### 48 # identity models.49 ### 51 # mapper(YourDataClass, your_table) 52 #end if 53 #end if 54 55 #if $identity == 'sqlobject' 56 57 # the identity model 58 50 59 class Visit(SQLObject): 51 60 """ … … 152 161 otherColumn='group_id') 153 162 #end if 154 #if $identity == "sqlalchemy" and $elixir == "False" 155 # The identity schema. 163 #if $identity == 'sqlalchemy' and $elixir != 'True' 164 # the identity schema 165 156 166 visits_table = Table('visit', metadata, 157 167 Column('visit_key', String(40), primary_key=True), … … 189 199 user_group_table = Table('user_group', metadata, 190 200 Column('user_id', Integer, ForeignKey('tg_user.user_id', 191 onupdate= "CASCADE", ondelete="CASCADE")),201 onupdate='CASCADE', ondelete='CASCADE')), 192 202 Column('group_id', Integer, ForeignKey('tg_group.group_id', 193 onupdate= "CASCADE", ondelete="CASCADE"))203 onupdate='CASCADE', ondelete='CASCADE')) 194 204 ) 195 205 196 206 group_permission_table = Table('group_permission', metadata, 197 207 Column('group_id', Integer, ForeignKey('tg_group.group_id', 198 onupdate= "CASCADE", ondelete="CASCADE")),208 onupdate='CASCADE', ondelete='CASCADE')), 199 209 Column('permission_id', Integer, ForeignKey('permission.permission_id', 200 onupdate="CASCADE", ondelete="CASCADE")) 201 ) 202 203 # 204 # identity model 205 # 210 onupdate='CASCADE', ondelete='CASCADE')) 211 ) 212 213 # the identity model 214 206 215 class Visit(object): 207 216 """ … … 209 218 """ 210 219 def lookup_visit(cls, visit_key): 211 return session.query(Visit).get(visit_key)220 return cls.query.get(visit_key) 212 221 lookup_visit = classmethod(lookup_visit) 213 222 … … 226 235 class User(object): 227 236 """ 228 Reasonably basic User definition. Probably would want additional229 attributes.237 Reasonably basic User definition. 238 Probably would want additional attributes. 230 239 """ 231 240 def permissions(self): … … 236 245 permissions = property(permissions) 237 246 238 def by_email_address( klass, email):247 def by_email_address(cls, email): 239 248 """ 240 249 A class method that can be used to search users 241 250 based on their email addresses since it is unique. 242 251 """ 243 return session.query(klass).filter_by(email_address=email).first()252 return cls.query.filter_by(email_address=email).first() 244 253 245 254 by_email_address = classmethod(by_email_address) 246 255 247 def by_user_name( klass, username):256 def by_user_name(cls, username): 248 257 """ 249 258 A class method that permits to search users 250 259 based on their user_name attribute. 251 260 """ 252 return session.query(klass).filter_by(user_name=username).first()261 return cls.query.filter_by(user_name=username).first() 253 262 254 263 by_user_name = classmethod(by_user_name) … … 291 300 secondary=group_permission_table, backref='permissions'))) 292 301 #end if 293 #if $identity == "sqlalchemy" and $elixir == "True"302 #if $identity == 'sqlalchemy' and $elixir == 'True' 294 303 # 295 # identity model304 # the identity model 296 305 # 297 306 class Visit(Entity): 307 """ 308 A visit to your site 309 """ 298 310 has_field('visit_key', String(40), primary_key=True) 299 311 has_field('created', DateTime, nullable=False, default=datetime.now) … … 306 318 307 319 class VisitIdentity(Entity): 320 """ 321 A Visit that is link to a User object 322 """ 308 323 has_field('visit_key', String(40), primary_key=True) 309 324 belongs_to('user', of_kind='User', colname='user_id', use_alter=True) … … 311 326 312 327 class Group(Entity): 328 """ 329 An ultra-simple group definition. 330 """ 313 331 has_field('group_id', Integer, primary_key=True) 314 332 has_field('group_name', Unicode(16), unique=True) … … 320 338 321 339 class User(Entity): 340 """ 341 Reasonably basic User definition. 342 Probably would want additional attributes. 343 """ 322 344 has_field('user_id', Integer, primary_key=True) 323 345 has_field('user_name', Unicode(16), unique=True) … … 337 359 338 360 class Permission(Entity): 361 """ 362 A relationship that determines what each Group can do 363 """ 339 364 has_field('permission_id', Integer, primary_key=True) 340 365 has_field('permission_name', Unicode(16), unique=True) branches/1.0/turbogears/startup.py
r3366 r3617 225 225 226 226 if config.get("sqlalchemy.dburi"): 227 database. bind_meta_data()227 database.get_engine() 228 228 229 229 # Start all TurboGears extensions branches/1.0/turbogears/tests/test_sqlalchemy.py
r3512 r3617 5 5 from sqlalchemy import * 6 6 from sqlalchemy.orm import * 7 from sqlalchemy.ext.activemapper import ActiveMapper, column, one_to_many8 7 9 8 from turbogears import config, redirect, expose, database, errorhandling 10 9 from turbogears.testutil import create_request, capture_log, print_log, \ 11 10 sqlalchemy_cleanup 12 from turbogears.database import session, metadata, bind_meta_data11 from turbogears.database import session, metadata, get_engine 13 12 from turbogears.controllers import RootController 14 13 14 from sqlalchemy.ext import activemapper 15 activemapper.metadata, activemapper.objectstore = metadata, session 16 from sqlalchemy.ext.activemapper import ActiveMapper, column, one_to_many 17 15 18 config.update({"sqlalchemy.dburi" : "sqlite:///:memory:"}) 16 19 17 bind_meta_data()20 get_engine() 18 21 19 22 metadata.bind.echo = True … … 132 135 session.clear() # should be done automatically, but just in case 133 136 assert Person.query().get(21) is None 134 137 135 138 # Check that if a controller redirects, transactions are committed 136 139 def test_user_redirect(): … … 158 161 doerr = errorhandling.exception_handler(handerr)(doerr) 159 162 doerr = expose()(doerr) 160 163 161 164 def test_exc_rollback(): 162 165 cherrypy.root = RbRoot() … … 194 197 session.query(Test).get(1).val = 'b' 195 198 return dict() 196 test2 = expose()(test2) 199 test2 = expose()(test2) 197 200 def test3(self): 198 201 assert session.query(Test).get(1).val == 'b' … … 222 225 thrdb.start() 223 226 thrdb.join() 224 227 225 228 create_request("/test3") 226 229 print cherrypy.response.body[0] branches/1.0/turbogears/testutil.py
r3407 r3617 258 258 sqlalchemy.orm.clear_mappers() 259 259 database.metadata.clear() 260 database.metadata.dispose() 260 try: # if ThreadLocalMetaData is used 261 database.metadata.dispose() 262 except AttributeError: 263 pass 261 264 262 265 __all__ = ["create_request", "call", "DBTest", "createRequest", branches/1.0/turbogears/visit/savisit.py
r3484 r3617 1 import turbogears2 #from datetime import *3 1 from datetime import datetime 2 4 3 from sqlalchemy import * 5 from sqlalchemy.orm import mapper,class_mapper4 from sqlalchemy.orm import class_mapper 6 5 6 from turbogears import config 7 7 from turbogears.visit.api import BaseVisitManager, Visit 8 from turbogears import config 9 from turbogears.database import bind_meta_data, metadata, session, get_engine 8 from turbogears.database import get_engine, metadata, session, mapper 10 9 from turbogears.util import load_class 11 10 … … 29 28 log.error(msg) 30 29 31 bind_meta_data()30 get_engine() 32 31 if visit_class is TG_Visit: 33 32 mapper(visit_class, visits_table) … … 37 36 Create the Visit table if it doesn't already exist 38 37 ''' 39 class_mapper(visit_class).local_table.create(40 checkfirst=True)38 get_engine() 39 class_mapper(visit_class).local_table.create(checkfirst=True) 41 40 42 41 def new_visit_with_key(self, visit_key): … … 46 45 visit.created = created 47 46 visit.expiry = created + self.timeout 48 session.save(visit)49 47 session.flush() 50 48 return Visit(visit_key, True)