From: Mike Bayer Date: Wed, 22 Dec 2010 02:37:52 +0000 (-0500) Subject: - another heap of inlinings and now I really have to be done with this X-Git-Tag: rel_0_7b1~126 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b79a5e7640fc1c8ca7acce5bfd2509ddf0102080;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - another heap of inlinings and now I really have to be done with this --- diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py index 1e5285b355..c1f9905b67 100644 --- a/lib/sqlalchemy/engine/base.py +++ b/lib/sqlalchemy/engine/base.py @@ -25,6 +25,7 @@ from itertools import izip from sqlalchemy import exc, schema, util, types, log, interfaces, \ event, events from sqlalchemy.sql import expression +from sqlalchemy import processors class Dialect(object): """Define the behavior of a specific database and DB-API combination. @@ -2225,7 +2226,7 @@ class ResultMetaData(object): coltype = rec[1] if dialect.description_encoding: - colname = colname.decode(dialect.description_encoding) + colname = dialect._description_decoder(colname) if context.result_map: try: diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py index 757e42d032..9efb5e5f40 100644 --- a/lib/sqlalchemy/engine/default.py +++ b/lib/sqlalchemy/engine/default.py @@ -15,7 +15,8 @@ as the base class for their own corresponding classes. import re, random from sqlalchemy.engine import base, reflection from sqlalchemy.sql import compiler, expression -from sqlalchemy import exc, types as sqltypes, util, pool +from sqlalchemy import exc, types as sqltypes, util, pool, processors +import codecs import weakref AUTOCOMMIT_REGEXP = re.compile( @@ -142,6 +143,12 @@ class DefaultDialect(base.Dialect): self, 'description_encoding', encoding) + + self._description_decoder = processors.to_unicode_processor_factory( + self.description_encoding + ) + self._encoder = codecs.getencoder(self.encoding) + self._decoder = processors.to_unicode_processor_factory(self.encoding) @util.memoized_property def _type_memos(self): @@ -345,7 +352,7 @@ class DefaultExecutionContext(base.ExecutionContext): if not dialect.supports_unicode_statements: self.unicode_statement = unicode(compiled) - self.statement = self.unicode_statement.encode(self.dialect.encoding) + self.statement = dialect._encoder(self.unicode_statement)[0] else: self.statement = self.unicode_statement = unicode(compiled) @@ -434,13 +441,12 @@ class DefaultExecutionContext(base.ExecutionContext): for compiled_params in self.compiled_parameters: param = {} if encode: - encoding = dialect.encoding for key in compiled_params: if key in processors: - param[key.encode(encoding)] = \ + param[dialect._encoder(key)[0]] = \ processors[key](compiled_params[key]) else: - param[key.encode(encoding)] = compiled_params[key] + param[dialect._encoder(key)[0]] = compiled_params[key] else: for key in compiled_params: if key in processors: @@ -477,7 +483,7 @@ class DefaultExecutionContext(base.ExecutionContext): self.parameters = parameters else: self.parameters= [ - dict((k.encode(dialect.encoding), d[k]) for k in d) + dict((dialect._encoder(k)[0], d[k]) for k in d) for d in parameters ] or [{}] else: @@ -488,7 +494,7 @@ class DefaultExecutionContext(base.ExecutionContext): if not dialect.supports_unicode_statements and isinstance(statement, unicode): self.unicode_statement = statement - self.statement = statement.encode(self.dialect.encoding) + self.statement = dialect._encoder(statement)[0] else: self.statement = self.unicode_statement = statement @@ -538,7 +544,7 @@ class DefaultExecutionContext(base.ExecutionContext): conn = self.root_connection if isinstance(stmt, unicode) and \ not self.dialect.supports_unicode_statements: - stmt = stmt.encode(self.dialect.encoding) + stmt = self.dialect._encoder(stmt)[0] if self.dialect.positional: default_params = self.dialect.execute_sequence_format() @@ -674,7 +680,7 @@ class DefaultExecutionContext(base.ExecutionContext): if dbtype is not None and (not exclude_types or dbtype not in exclude_types): if translate: key = translate.get(key, key) - inputsizes[key.encode(self.dialect.encoding)] = dbtype + inputsizes[self.dialect._encoder(key)[0]] = dbtype try: self.cursor.setinputsizes(**inputsizes) except Exception, e: diff --git a/lib/sqlalchemy/orm/events.py b/lib/sqlalchemy/orm/events.py index 718a18606a..6d1e8f7137 100644 --- a/lib/sqlalchemy/orm/events.py +++ b/lib/sqlalchemy/orm/events.py @@ -96,6 +96,11 @@ class InstanceEvents(event.Events): @classmethod def remove(cls, identifier, target, fn): raise NotImplementedError("Removal of instance events not yet implemented") + + def on_first_init(self, manager, cls): + """Called when the first instance of a particular mapping is called. + + """ def on_init(self, target, args, kwargs): """Receive an instance when it's constructor is called. diff --git a/lib/sqlalchemy/orm/identity.py b/lib/sqlalchemy/orm/identity.py index f1400a8c6b..c55db39dc5 100644 --- a/lib/sqlalchemy/orm/identity.py +++ b/lib/sqlalchemy/orm/identity.py @@ -151,7 +151,9 @@ class WeakInstanceDict(IdentityMap): self._remove_mutex.acquire() try: if dict.pop(self, state.key) is not state: - raise AssertionError("State %s is not present in this identity map" % state) + raise AssertionError( + "State %s is not present in this " + "identity map" % state) finally: self._remove_mutex.release() @@ -245,15 +247,20 @@ class StrongInstanceDict(IdentityMap): def add(self, state): if state.key in self: - if attributes.instance_state(dict.__getitem__(self, state.key)) is not state: - raise AssertionError("A conflicting state is already present in the identity map for key %r" % (state.key, )) + if attributes.instance_state(dict.__getitem__(self, + state.key)) is not state: + raise AssertionError('A conflicting state is already ' + 'present in the identity map for key %r' + % (state.key, )) else: dict.__setitem__(self, state.key, state.obj()) self._manage_incoming_state(state) def remove(self, state): - if attributes.instance_state(dict.pop(self, state.key)) is not state: - raise AssertionError("State %s is not present in this identity map" % state) + if attributes.instance_state(dict.pop(self, state.key)) \ + is not state: + raise AssertionError('State %s is not present in this ' + 'identity map' % state) self._manage_removed_state(state) def discard(self, state): diff --git a/lib/sqlalchemy/orm/instrumentation.py b/lib/sqlalchemy/orm/instrumentation.py index dba3a68307..9876dde3f0 100644 --- a/lib/sqlalchemy/orm/instrumentation.py +++ b/lib/sqlalchemy/orm/instrumentation.py @@ -166,11 +166,13 @@ class ClassManager(dict): self.uninstall_member('__init__') self.new_init = None - def _create_instance_state(self, instance): + @util.memoized_property + def _state_constructor(self): + self.dispatch.on_first_init(self, self.class_) if self.mutable_attributes: - return state.MutableAttrInstanceState(instance, self) + return state.MutableAttrInstanceState else: - return state.InstanceState(instance, self) + return state.InstanceState def manage(self): """Mark this instance as the manager for its class.""" @@ -290,12 +292,12 @@ class ClassManager(dict): def new_instance(self, state=None): instance = self.class_.__new__(self.class_) setattr(instance, self.STATE_ATTR, - state or self._create_instance_state(instance)) + state or self._state_constructor(instance, self)) return instance def setup_instance(self, instance, state=None): setattr(instance, self.STATE_ATTR, - state or self._create_instance_state(instance)) + state or self._state_constructor(instance, self)) def teardown_instance(self, instance): delattr(instance, self.STATE_ATTR) @@ -318,7 +320,7 @@ class ClassManager(dict): return self._subclass_manager(instance.__class__).\ _new_state_if_none(instance) else: - state = self._create_instance_state(instance) + state = self._state_constructor(instance, self) setattr(instance, self.STATE_ATTR, state) return state @@ -421,7 +423,7 @@ class _ClassInstrumentationAdapter(ClassManager): self._adapted.initialize_instance_dict(self.class_, instance) if state is None: - state = self._create_instance_state(instance) + state = self._state_constructor(instance, self) # the given instance is assumed to have no state self._adapted.install_state(self.class_, instance, state) diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 9bb84e86c3..91d512ad0d 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -400,6 +400,7 @@ class Mapper(object): if manager.info.get(_INSTRUMENTOR, False): return + event.listen(manager, 'on_first_init', _event_on_first_init, raw=True) event.listen(manager, 'on_init', _event_on_init, raw=True) event.listen(manager, 'on_resurrect', _event_on_resurrect, raw=True) @@ -2455,17 +2456,22 @@ def _event_on_load(state): instrumenting_mapper = state.manager.info[_INSTRUMENTOR] if instrumenting_mapper._reconstructor: instrumenting_mapper._reconstructor(state.obj()) - -def _event_on_init(state, args, kwargs): - """Trigger mapper compilation and run init_instance hooks.""" - instrumenting_mapper = state.manager.info.get(_INSTRUMENTOR) +def _event_on_first_init(manager, cls): + """Trigger mapper compilation.""" + + instrumenting_mapper = manager.info.get(_INSTRUMENTOR) if instrumenting_mapper: if _new_mappers: configure_mappers() - - if instrumenting_mapper._set_polymorphic_identity: - instrumenting_mapper._set_polymorphic_identity(state) + +def _event_on_init(state, args, kwargs): + """Run init_instance hooks.""" + + instrumenting_mapper = state.manager.info.get(_INSTRUMENTOR) + if instrumenting_mapper and \ + instrumenting_mapper._set_polymorphic_identity: + instrumenting_mapper._set_polymorphic_identity(state) def _event_on_resurrect(state): # re-populate the primary key elements diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index 9c0381f755..74678a8d2d 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -1721,9 +1721,10 @@ class Query(object): return self._execute_and_instances(context) def _execute_and_instances(self, querycontext): - result = self.session.execute( - querycontext.statement, params=self._params, - mapper=self._mapper_zero_or_none()) + result = self.session.connection( + mapper = self._mapper_zero_or_none(), + clause = querycontext.statement, + close_with_result=True).execute(querycontext.statement, self._params) return self.instances(result, querycontext) @property @@ -1795,7 +1796,7 @@ class Query(object): if filtered: if single_entity: - filter = lambda x: util.unique_list(x, util.IdentitySet) + filter = lambda x: util.unique_list(x, id) else: filter = util.unique_list else: diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index 325a94643a..eba4ace8c0 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -635,7 +635,8 @@ class Session(object): self.transaction.prepare() - def connection(self, mapper=None, clause=None): + def connection(self, mapper=None, clause=None, + close_with_result=False, **kw): """Return the active Connection. Retrieves the ``Connection`` managing the current transaction. Any @@ -657,7 +658,8 @@ class Session(object): Optional, any ``ClauseElement`` """ - return self._connection_for_bind(self.get_bind(mapper, clause)) + return self._connection_for_bind(self.get_bind(mapper, clause, **kw), + close_with_result=close_with_result) def _connection_for_bind(self, engine, **kwargs): if self.transaction is not None: diff --git a/lib/sqlalchemy/orm/state.py b/lib/sqlalchemy/orm/state.py index 909977cc47..52cde3a304 100644 --- a/lib/sqlalchemy/orm/state.py +++ b/lib/sqlalchemy/orm/state.py @@ -52,11 +52,7 @@ class InstanceState(object): return bool(self.key) def detach(self): - if self.session_id: - try: - del self.session_id - except AttributeError: - pass + self.session_id = None def dispose(self): self.detach() @@ -70,15 +66,8 @@ class InstanceState(object): except AssertionError: pass - # remove possible cycles - self.callables.clear() - - # inlining of self.dispose() - if self.session_id: - try: - del self.session_id - except AttributeError: - pass + self.callables = {} + self.session_id = None del self.obj def obj(self): @@ -102,14 +91,9 @@ class InstanceState(object): manager.dispatch.on_init(self, args, kwargs) - # LESSTHANIDEAL: - # adjust for the case where the InstanceState was created before - # mapper compilation, and this actually needs to be a MutableAttrInstanceState - if manager.mutable_attributes and self.__class__ is not MutableAttrInstanceState: - self.__class__ = MutableAttrInstanceState - self.obj = weakref.ref(self.obj(), self._cleanup) - self.mutable_dict = {} - + #if manager.mutable_attributes: + # assert self.__class__ is MutableAttrInstanceState + try: return manager.original_init(*mixed[1:], **kwargs) except: diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 3b43386d54..d5540ff835 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -324,7 +324,7 @@ class SQLCompiler(engine.Compiled): return "" def visit_grouping(self, grouping, asfrom=False, **kwargs): - return "(" + self.process(grouping.element, **kwargs) + ")" + return "(" + grouping.element._compiler_dispatch(self, **kwargs) + ")" def visit_label(self, label, result_map=None, within_label_clause=False, @@ -343,14 +343,14 @@ class SQLCompiler(engine.Compiled): (label.name, (label, label.element, labelname),\ label.type) - return self.process(label.element, + return label.element._compiler_dispatch(self, within_columns_clause=True, within_label_clause=True, **kw) + \ OPERATORS[operators.as_] + \ self.preparer.format_label(label, labelname) else: - return self.process(label.element, + return label.element._compiler_dispatch(self, within_columns_clause=False, **kw) @@ -359,33 +359,35 @@ class SQLCompiler(engine.Compiled): if name is None: raise exc.CompileError("Cannot compile Column object until " "it's 'name' is assigned.") - - if not column.is_literal and isinstance(name, sql._generated_label): + + is_literal = column.is_literal + if not is_literal and isinstance(name, sql._generated_label): name = self._truncated_identifier("colident", name) if result_map is not None: result_map[name.lower()] = (name, (column, ), column.type) - if column.is_literal: + if is_literal: name = self.escape_literal_column(name) else: name = self.preparer.quote(name, column.quote) - - if column.table is None or not column.table.named_with_column: + + table = column.table + if table is None or not table.named_with_column: return name else: - if column.table.schema: + if table.schema: schema_prefix = self.preparer.quote_schema( - column.table.schema, - column.table.quote_schema) + '.' + table.schema, + table.quote_schema) + '.' else: schema_prefix = '' - tablename = column.table.name + tablename = table.name if isinstance(tablename, sql._generated_label): tablename = self._truncated_identifier("alias", tablename) return schema_prefix + \ - self.preparer.quote(tablename, column.table.quote) + \ + self.preparer.quote(tablename, table.quote) + \ "." + name def escape_literal_column(self, text): @@ -435,31 +437,33 @@ class SQLCompiler(engine.Compiled): sep = OPERATORS[clauselist.operator] return sep.join( s for s in - (self.process(c, **kwargs) + (c._compiler_dispatch(self, **kwargs) for c in clauselist.clauses) if s is not None) def visit_case(self, clause, **kwargs): x = "CASE " if clause.value is not None: - x += self.process(clause.value, **kwargs) + " " + x += clause.value._compiler_dispatch(self, **kwargs) + " " for cond, result in clause.whens: - x += "WHEN " + self.process(cond, **kwargs) + \ - " THEN " + self.process(result, **kwargs) + " " + x += "WHEN " + cond._compiler_dispatch(self, **kwargs) + \ + " THEN " + \ + result._compiler_dispatch(self, **kwargs) + " " if clause.else_ is not None: - x += "ELSE " + self.process(clause.else_, **kwargs) + " " + x += "ELSE " + clause.else_._compiler_dispatch(self, **kwargs) + \ + " " x += "END" return x def visit_cast(self, cast, **kwargs): return "CAST(%s AS %s)" % \ - (self.process(cast.clause, **kwargs), - self.process(cast.typeclause, **kwargs)) + (cast.clause._compiler_dispatch(self, **kwargs), + cast.typeclause._compiler_dispatch(self, **kwargs)) def visit_extract(self, extract, **kwargs): field = self.extract_map.get(extract.field, extract.field) return "EXTRACT(%s FROM %s)" % (field, - self.process(extract.expr, **kwargs)) + extract.expr._compiler_dispatch(self, **kwargs)) def visit_function(self, func, result_map=None, **kwargs): if result_map is not None: @@ -474,7 +478,7 @@ class SQLCompiler(engine.Compiled): {'expr':self.function_argspec(func, **kwargs)} def function_argspec(self, func, **kwargs): - return self.process(func.clause_expr, **kwargs) + return func.clause_expr._compiler_dispatch(self, **kwargs) def visit_compound_select(self, cs, asfrom=False, parens=True, compound_index=1, **kwargs): @@ -484,12 +488,14 @@ class SQLCompiler(engine.Compiled): keyword = self.compound_keywords.get(cs.keyword) text = (" " + keyword + " ").join( - (self.process(c, asfrom=asfrom, parens=False, + (c._compiler_dispatch(self, + asfrom=asfrom, parens=False, compound_index=i, **kwargs) for i, c in enumerate(cs.selects)) ) - group_by = self.process(cs._group_by_clause, asfrom=asfrom, **kwargs) + group_by = cs._group_by_clause._compiler_dispatch( + self, asfrom=asfrom, **kwargs) if group_by: text += " GROUP BY " + group_by @@ -504,7 +510,7 @@ class SQLCompiler(engine.Compiled): return text def visit_unary(self, unary, **kw): - s = self.process(unary.element, **kw) + s = unary.element._compiler_dispatch(self, **kw) if unary.operator: s = OPERATORS[unary.operator] + s if unary.modifier: @@ -520,17 +526,18 @@ class SQLCompiler(engine.Compiled): return self._operator_dispatch(binary.operator, binary, - lambda opstr: self.process(binary.left, **kw) + + lambda opstr: binary.left._compiler_dispatch(self, **kw) + opstr + - self.process(binary.right, **kw), + binary.right._compiler_dispatch( + self, **kw), **kw ) def visit_like_op(self, binary, **kw): escape = binary.modifiers.get("escape", None) return '%s LIKE %s' % ( - self.process(binary.left, **kw), - self.process(binary.right, **kw)) \ + binary.left._compiler_dispatch(self, **kw), + binary.right._compiler_dispatch(self, **kw)) \ + (escape and (' ESCAPE ' + self.render_literal_value(escape, None)) or '') @@ -538,8 +545,8 @@ class SQLCompiler(engine.Compiled): def visit_notlike_op(self, binary, **kw): escape = binary.modifiers.get("escape", None) return '%s NOT LIKE %s' % ( - self.process(binary.left, **kw), - self.process(binary.right, **kw)) \ + binary.left._compiler_dispatch(self, **kw), + binary.right._compiler_dispatch(self, **kw)) \ + (escape and (' ESCAPE ' + self.render_literal_value(escape, None)) or '') @@ -547,8 +554,8 @@ class SQLCompiler(engine.Compiled): def visit_ilike_op(self, binary, **kw): escape = binary.modifiers.get("escape", None) return 'lower(%s) LIKE lower(%s)' % ( - self.process(binary.left, **kw), - self.process(binary.right, **kw)) \ + binary.left._compiler_dispatch(self, **kw), + binary.right._compiler_dispatch(self, **kw)) \ + (escape and (' ESCAPE ' + self.render_literal_value(escape, None)) or '') @@ -556,8 +563,8 @@ class SQLCompiler(engine.Compiled): def visit_notilike_op(self, binary, **kw): escape = binary.modifiers.get("escape", None) return 'lower(%s) NOT LIKE lower(%s)' % ( - self.process(binary.left, **kw), - self.process(binary.right, **kw)) \ + binary.left._compiler_dispatch(self, **kw), + binary.right._compiler_dispatch(self, **kw)) \ + (escape and (' ESCAPE ' + self.render_literal_value(escape, None)) or '') @@ -678,7 +685,8 @@ class SQLCompiler(engine.Compiled): def bindparam_string(self, name): if self.positional: self.positiontup.append(name) - return self.bindtemplate % {'name':name, 'position':len(self.positiontup)} + return self.bindtemplate % { + 'name':name, 'position':len(self.positiontup)} else: return self.bindtemplate % {'name':name} @@ -693,7 +701,8 @@ class SQLCompiler(engine.Compiled): if ashint: return self.preparer.format_alias(alias, alias_name) elif asfrom: - ret = self.process(alias.original, asfrom=True, **kwargs) + \ + ret = alias.original._compiler_dispatch(self, + asfrom=True, **kwargs) + \ " AS " + \ self.preparer.format_alias(alias, alias_name) @@ -704,7 +713,7 @@ class SQLCompiler(engine.Compiled): return ret else: - return self.process(alias.original, **kwargs) + return alias.original._compiler_dispatch(self, **kwargs) def label_select_column(self, select, column, asfrom): """label columns present in a select().""" @@ -712,10 +721,10 @@ class SQLCompiler(engine.Compiled): if isinstance(column, sql._Label): return column - if select is not None and select.use_labels and column._label: + elif select is not None and select.use_labels and column._label: return _CompileLabel(column, column._label) - if \ + elif \ asfrom and \ isinstance(column, sql.ColumnClause) and \ not column.is_literal and \ @@ -765,10 +774,10 @@ class SQLCompiler(engine.Compiled): # the actual list of columns to print in the SELECT column list. inner_columns = [ c for c in [ - self.process( - self.label_select_column(select, co, asfrom=asfrom), - within_columns_clause=True, - **column_clause_args) + self.label_select_column(select, co, asfrom=asfrom).\ + _compiler_dispatch(self, + within_columns_clause=True, + **column_clause_args) for co in util.unique_list(select.inner_columns) ] if c is not None @@ -779,7 +788,9 @@ class SQLCompiler(engine.Compiled): if select._hints: byfrom = dict([ (from_, hinttext % { - 'name':self.process(from_, ashint=True)}) + 'name':from_._compiler_dispatch( + self, ashint=True) + }) for (from_, dialect), hinttext in select._hints.iteritems() if dialect in ('*', self.dialect.name) @@ -790,7 +801,7 @@ class SQLCompiler(engine.Compiled): if select._prefixes: text += " ".join( - self.process(x, **kwargs) + x._compiler_dispatch(self, **kwargs) for x in select._prefixes) + " " text += self.get_select_precolumns(select) text += ', '.join(inner_columns) @@ -799,29 +810,30 @@ class SQLCompiler(engine.Compiled): text += " \nFROM " if select._hints: - text += ', '.join([self.process(f, + text += ', '.join([f._compiler_dispatch(self, asfrom=True, fromhints=byfrom, **kwargs) for f in froms]) else: - text += ', '.join([self.process(f, + text += ', '.join([f._compiler_dispatch(self, asfrom=True, **kwargs) for f in froms]) else: text += self.default_from() if select._whereclause is not None: - t = self.process(select._whereclause, **kwargs) + t = select._whereclause._compiler_dispatch(self, **kwargs) if t: text += " \nWHERE " + t if select._group_by_clause.clauses: - group_by = self.process(select._group_by_clause, **kwargs) + group_by = select._group_by_clause._compiler_dispatch( + self, **kwargs) if group_by: text += " GROUP BY " + group_by if select._having is not None: - t = self.process(select._having, **kwargs) + t = select._having._compiler_dispatch(self, **kwargs) if t: text += " \nHAVING " + t @@ -847,7 +859,7 @@ class SQLCompiler(engine.Compiled): return select._distinct and "DISTINCT " or "" def order_by_clause(self, select, **kw): - order_by = self.process(select._order_by_clause, **kw) + order_by = select._order_by_clause._compiler_dispatch(self, **kw) if order_by: return " ORDER BY " + order_by else: @@ -888,10 +900,13 @@ class SQLCompiler(engine.Compiled): return "" def visit_join(self, join, asfrom=False, **kwargs): - return (self.process(join.left, asfrom=True, **kwargs) + \ - (join.isouter and " LEFT OUTER JOIN " or " JOIN ") + \ - self.process(join.right, asfrom=True, **kwargs) + " ON " + \ - self.process(join.onclause, **kwargs)) + return ( + join.left._compiler_dispatch(self, asfrom=True, **kwargs) + + (join.isouter and " LEFT OUTER JOIN " or " JOIN ") + + join.right._compiler_dispatch(self, asfrom=True, **kwargs) + + " ON " + + join.onclause._compiler_dispatch(self, **kwargs) + ) def visit_sequence(self, seq): return None diff --git a/lib/sqlalchemy/util/_collections.py b/lib/sqlalchemy/util/_collections.py index 4ab52c3d6f..2735f5e80c 100644 --- a/lib/sqlalchemy/util/_collections.py +++ b/lib/sqlalchemy/util/_collections.py @@ -583,9 +583,16 @@ column_dict = dict ordered_column_set = OrderedSet populate_column_dict = PopulateDict -def unique_list(seq, compare_with=set): - seen = compare_with() - return [x for x in seq if x not in seen and not seen.add(x)] +def unique_list(seq, hashfunc=None): + seen = {} + if not hashfunc: + return [x for x in seq + if x not in seen + and not seen.__setitem__(x, True)] + else: + return [x for x in seq + if hashfunc(x) not in seen + and not seen.__setitem__(hashfunc(x), True)] class UniqueAppender(object): """Appends items to a collection ensuring uniqueness. @@ -596,19 +603,19 @@ class UniqueAppender(object): def __init__(self, data, via=None): self.data = data - self._unique = IdentitySet() + self._unique = {} if via: self._data_appender = getattr(data, via) elif hasattr(data, 'append'): self._data_appender = data.append elif hasattr(data, 'add'): - # TODO: we think its a set here. bypass unneeded uniquing logic ? self._data_appender = data.add def append(self, item): - if item not in self._unique: + id_ = id(item) + if id_ not in self._unique: self._data_appender(item) - self._unique.add(item) + self._unique[id_] = True def __iter__(self): return iter(self.data) diff --git a/test/aaa_profiling/test_compiler.py b/test/aaa_profiling/test_compiler.py index c0f8a151f6..5d32ee5812 100644 --- a/test/aaa_profiling/test_compiler.py +++ b/test/aaa_profiling/test_compiler.py @@ -1,6 +1,6 @@ from sqlalchemy import * from test.lib import * - +from sqlalchemy.engine import default class CompileTest(TestBase, AssertsExecutionResults): @classmethod @@ -29,23 +29,25 @@ class CompileTest(TestBase, AssertsExecutionResults): from sqlalchemy import types for t in types._type_map.values(): t._type_affinity - - @profiling.function_call_count(69, {'2.4': 44, + + cls.dialect = default.DefaultDialect() + + @profiling.function_call_count(58, {'2.4': 44, '3.0':77, '3.1':77}) def test_insert(self): - t1.insert().compile() + t1.insert().compile(dialect=self.dialect) - @profiling.function_call_count(69, {'2.4': 45}) + @profiling.function_call_count(49, {'2.4': 45}) def test_update(self): - t1.update().compile() + t1.update().compile(dialect=self.dialect) - @profiling.function_call_count(129, {'2.4': 81, '3':132}) + @profiling.function_call_count(110, {'2.4': 81, '3':132}) def test_update_whereclause(self): - t1.update().where(t1.c.c2==12).compile() + t1.update().where(t1.c.c2==12).compile(dialect=self.dialect) - @profiling.function_call_count(178, versions={'2.4':105, + @profiling.function_call_count(148, versions={'2.4':105, '3.0':208, '3.1':208}) def test_select(self): s = select([t1], t1.c.c2==t2.c.c1) - s.compile() + s.compile(dialect=self.dialect) diff --git a/test/aaa_profiling/test_orm.py b/test/aaa_profiling/test_orm.py index 0881ab183b..9f03b9cddd 100644 --- a/test/aaa_profiling/test_orm.py +++ b/test/aaa_profiling/test_orm.py @@ -53,7 +53,7 @@ class MergeTest(_base.MappedTest): # down from 185 on this this is a small slice of a usually # bigger operation so using a small variance - @profiling.function_call_count(86, variance=0.05, + @profiling.function_call_count(80, variance=0.05, versions={'2.4': 64, '2.5':94, '3': 89}) def go(): return sess2.merge(p1, load=False) @@ -80,8 +80,8 @@ class MergeTest(_base.MappedTest): # (py2.6) @profiling.function_call_count(1067, - versions={'2.5':1191, '2.6':1191, - '2.6+cextension':1194, + versions={'2.5':1050, '2.6':1050, + '2.6+cextension':1041, '2.4': 763} ) def go(): @@ -160,7 +160,7 @@ class LoadManyToOneFromIdentityTest(_base.MappedTest): parents = sess.query(Parent).all() - @profiling.function_call_count(138289, variance=.2) + @profiling.function_call_count(108019, variance=.2) def go(): for p in parents: p.child diff --git a/test/aaa_profiling/test_resultset.py b/test/aaa_profiling/test_resultset.py index d7f2beeb4c..e46411bdb1 100644 --- a/test/aaa_profiling/test_resultset.py +++ b/test/aaa_profiling/test_resultset.py @@ -34,15 +34,16 @@ class ResultSetTest(TestBase, AssertsExecutionResults): metadata.drop_all() @profiling.function_call_count(14416, versions={'2.4': 13214, - '2.6+cextension': 410, '2.7+cextension':401}) + '2.6+cextension': 385, + '2.7+cextension':401}) def test_string(self): [tuple(row) for row in t.select().execute().fetchall()] # sqlite3 returns native unicode. so shouldn't be an increase here. @profiling.function_call_count(14396, versions={'2.4': 13214, - '2.6+cextension': 409, - '2.7+cextension':409}) + '2.6+cextension': 385, + '2.7+cextension':385}) def test_unicode(self): [tuple(row) for row in t2.select().execute().fetchall()] diff --git a/test/aaa_profiling/test_zoomark.py b/test/aaa_profiling/test_zoomark.py index 5a93bda9a9..c4cffa87ad 100644 --- a/test/aaa_profiling/test_zoomark.py +++ b/test/aaa_profiling/test_zoomark.py @@ -361,7 +361,7 @@ class ZooMarkTest(TestBase): def test_profile_1_create_tables(self): self.test_baseline_1_create_tables() - @profiling.function_call_count(5045, {'2.6':5371, '2.4': 3650}) + @profiling.function_call_count(5045, {'2.6':5099, '2.4': 3650}) def test_profile_1a_populate(self): self.test_baseline_1a_populate() @@ -369,29 +369,31 @@ class ZooMarkTest(TestBase): def test_profile_2_insert(self): self.test_baseline_2_insert() - @profiling.function_call_count(3886, {'2.4': 2158}) + @profiling.function_call_count(3596, {'2.4': 2158}) def test_profile_3_properties(self): self.test_baseline_3_properties() - @profiling.function_call_count(13341, {'2.4': 7963, '2.6+cextension' + @profiling.function_call_count(11624, {'2.4': 7963, '2.6+cextension' : 12447, '2.7+cextension': 12447}, variance=0.10) def test_profile_4_expressions(self): self.test_baseline_4_expressions() - @profiling.function_call_count(1311, {'2.4': 904, '2.6+cextension' - : 1226, '2.7+cextension': 1226}, + @profiling.function_call_count(1059, {'2.4': 904, '2.6+cextension' + : 1027, '2.7+cextension': 1027}, variance=0.10) def test_profile_5_aggregates(self): self.test_baseline_5_aggregates() - @profiling.function_call_count(1904, {'2.4': 1118}) + @profiling.function_call_count(1788, {'2.4': 1118}) def test_profile_6_editing(self): self.test_baseline_6_editing() - @profiling.function_call_count(2598, {'2.4': 1673, - '2.7+cextension':2431, - '2.6+cextension': 2502}) + @profiling.function_call_count(2252, {'2.4': 1673, + '2.6':2412, + '2.7':2412, + '2.7+cextension':2252, + '2.6+cextension': 2252}) def test_profile_7_multiview(self): self.test_baseline_7_multiview() diff --git a/test/aaa_profiling/test_zoomark_orm.py b/test/aaa_profiling/test_zoomark_orm.py index 615c7472b0..c4dd0ae9fb 100644 --- a/test/aaa_profiling/test_zoomark_orm.py +++ b/test/aaa_profiling/test_zoomark_orm.py @@ -335,7 +335,7 @@ class ZooMarkTest(TestBase): def test_profile_1_create_tables(self): self.test_baseline_1_create_tables() - @profiling.function_call_count(6347) + @profiling.function_call_count(6324, {'2.7+cextension':5992, '2.6+cextension':5992}) def test_profile_1a_populate(self): self.test_baseline_1a_populate() @@ -346,17 +346,17 @@ class ZooMarkTest(TestBase): # this number... @profiling.function_call_count(6783, { - '2.6': 7094, - '2.7': 6250, - '2.7+cextension': 6170, - '2.6+cextension': 7184, + '2.6': 6058, + '2.7': 5922, + '2.7+cextension': 5714, + '2.6+cextension': 6058, }) def test_profile_3_properties(self): self.test_baseline_3_properties() # and this number go down slightly when using the C extensions - @profiling.function_call_count(19335, {'2.6': 22775, '2.7':20299}) + @profiling.function_call_count(17698, {'2.7+cextension':17698, '2.6': 18943, '2.7':19110}) def test_profile_4_expressions(self): self.test_baseline_4_expressions() @@ -366,7 +366,7 @@ class ZooMarkTest(TestBase): def test_profile_5_aggregates(self): self.test_baseline_5_aggregates() - @profiling.function_call_count(2550) + @profiling.function_call_count(2417) def test_profile_6_editing(self): self.test_baseline_6_editing()