summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/ext/associationproxy.py2
-rw-r--r--lib/sqlalchemy/orm/attributes.py8
-rw-r--r--lib/sqlalchemy/orm/collections.py4
-rw-r--r--lib/sqlalchemy/orm/interfaces.py6
-rw-r--r--lib/sqlalchemy/orm/mapper.py2
-rw-r--r--lib/sqlalchemy/sql/operators.py9
-rw-r--r--lib/sqlalchemy/util.py36
7 files changed, 51 insertions, 16 deletions
diff --git a/lib/sqlalchemy/ext/associationproxy.py b/lib/sqlalchemy/ext/associationproxy.py
index 1e237a857..bbfb1bcda 100644
--- a/lib/sqlalchemy/ext/associationproxy.py
+++ b/lib/sqlalchemy/ext/associationproxy.py
@@ -448,7 +448,7 @@ class _AssociationList(object):
def __hash__(self):
raise TypeError("%s objects are unhashable" % type(self).__name__)
-_NotProvided = object()
+_NotProvided = util.symbol('_NotProvided')
class _AssociationDict(object):
"""Generic proxying list which proxies dict operations to a another dict,
converting association objects to and from a simplified value.
diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py
index b0f10c20b..5cc9cb309 100644
--- a/lib/sqlalchemy/orm/attributes.py
+++ b/lib/sqlalchemy/orm/attributes.py
@@ -12,10 +12,10 @@ from sqlalchemy.orm import interfaces, collections
from sqlalchemy.orm.util import identity_equal
from sqlalchemy import exceptions
-PASSIVE_NORESULT = object()
-ATTR_WAS_SET = object()
-NO_VALUE = object()
-NEVER_SET = object()
+PASSIVE_NORESULT = util.symbol('PASSIVE_NORESULT')
+ATTR_WAS_SET = util.symbol('ATTR_WAS_SET')
+NO_VALUE = util.symbol('NO_VALUE')
+NEVER_SET = util.symbol('NEVER_SET')
class InstrumentedAttribute(interfaces.PropComparator):
"""public-facing instrumented attribute, placed in the
diff --git a/lib/sqlalchemy/orm/collections.py b/lib/sqlalchemy/orm/collections.py
index 8f04fdf7a..7b78c240b 100644
--- a/lib/sqlalchemy/orm/collections.py
+++ b/lib/sqlalchemy/orm/collections.py
@@ -1011,7 +1011,7 @@ def _dict_decorators():
setattr(fn, '_sa_instrumented', True)
fn.__doc__ = getattr(getattr(dict, fn.__name__), '__doc__')
- Unspecified=object()
+ Unspecified=sautil.symbol('Unspecified')
def __setitem__(fn):
def __setitem__(self, key, value, _sa_initiator=None):
@@ -1107,7 +1107,7 @@ def _set_decorators():
setattr(fn, '_sa_instrumented', True)
fn.__doc__ = getattr(getattr(Set, fn.__name__), '__doc__')
- Unspecified=object()
+ Unspecified=sautil.symbol('Unspecified')
def add(fn):
def add(self, value, _sa_initiator=None):
diff --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py
index f510a3ffa..15f752314 100644
--- a/lib/sqlalchemy/orm/interfaces.py
+++ b/lib/sqlalchemy/orm/interfaces.py
@@ -14,7 +14,7 @@ ORM.
"""
from itertools import chain
-from sqlalchemy import exceptions, logging
+from sqlalchemy import exceptions, logging, util
from sqlalchemy.sql import expression
class_mapper = None
@@ -24,8 +24,8 @@ __all__ = ['EXT_CONTINUE', 'EXT_STOP', 'EXT_PASS', 'MapperExtension',
'ExtensionOption', 'PropertyOption',
'AttributeExtension', 'StrategizedOption', 'LoaderStrategy' ]
-EXT_CONTINUE = EXT_PASS = object()
-EXT_STOP = object()
+EXT_CONTINUE = EXT_PASS = util.symbol('EXT_CONTINUE')
+EXT_STOP = util.symbol('EXT_STOP')
class MapperExtension(object):
"""Base implementation for customizing Mapper behavior.
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index c0a15c427..62067fc35 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -30,7 +30,7 @@ global_extensions = []
# a constant returned by _get_attr_by_column to indicate
# this mapper is not handling an attribute for a particular
# column
-NO_ATTRIBUTE = object()
+NO_ATTRIBUTE = util.symbol('NO_ATTRIBUTE')
# lock used to synchronize the "mapper compile" step
_COMPILE_MUTEX = util.threading.Lock()
diff --git a/lib/sqlalchemy/sql/operators.py b/lib/sqlalchemy/sql/operators.py
index 19e0c484c..e31d27075 100644
--- a/lib/sqlalchemy/sql/operators.py
+++ b/lib/sqlalchemy/sql/operators.py
@@ -5,8 +5,7 @@
from operator import and_, or_, inv, add, mul, sub, div, mod, truediv, \
lt, le, ne, gt, ge, eq
-
-from sqlalchemy.util import Set
+from sqlalchemy.util import Set, symbol
def from_():
raise NotImplementedError()
@@ -74,9 +73,9 @@ def asc_op(a):
_commutative = Set([eq, ne, add, mul])
def is_commutative(op):
return op in _commutative
-
-_smallest = object()
-_largest = object()
+
+_smallest = symbol('_smallest')
+_largest = symbol('_largest')
_PRECEDENCE = {
from_:15,
diff --git a/lib/sqlalchemy/util.py b/lib/sqlalchemy/util.py
index 14c4c9f55..4e8a837c9 100644
--- a/lib/sqlalchemy/util.py
+++ b/lib/sqlalchemy/util.py
@@ -952,6 +952,42 @@ class ScopedRegistry(object):
def _get_key(self):
return self.scopefunc()
+class symbol(object):
+ """A constant symbol.
+
+ >>> symbol('foo') is symbol('foo')
+ True
+ >>> symbol('foo')
+ <symbol 'foo>
+
+ A slight refinement of the MAGICCOOKIE=object() pattern. The primary
+ advantage of symbol() is its repr(). They are also singletons.
+ """
+
+ symbols = {}
+ _lock = threading.Lock()
+
+ def __new__(cls, name):
+ try:
+ symbol._lock.acquire()
+ sym = cls.symbols.get(name)
+ if sym is None:
+ cls.symbols[name] = sym = object.__new__(cls, name)
+ return sym
+ finally:
+ symbol._lock.release()
+
+ def __init__(self, name):
+ """Construct a new named symbol.
+
+ Repeated calls of symbol('name') will all return the same instance.
+ """
+
+ assert isinstance(name, str)
+ self.name = name
+ def __repr__(self):
+ return "<symbol '%s>" % self.name
+
def warn(msg):
if isinstance(msg, basestring):
warnings.warn(msg, exceptions.SAWarning, stacklevel=3)