Files
deb-python-sqlalchemy-utils/sqlalchemy_utils/path.py
2014-02-18 13:53:08 +02:00

119 lines
3.1 KiB
Python

from sqlalchemy.orm.attributes import InstrumentedAttribute
from .utils import str_coercible
@str_coercible
class Path(object):
def __init__(self, path, separator='.'):
if isinstance(path, Path):
self.path = path.path
else:
self.path = path
self.separator = separator
def __iter__(self):
for part in self.path.split(self.separator):
yield part
def __len__(self):
return len(self.path.split(self.separator))
def __repr__(self):
return "%s('%s')" % (self.__class__.__name__, self.path)
def __getitem__(self, slice):
result = self.path.split(self.separator)[slice]
if isinstance(result, list):
return self.__class__(
self.separator.join(result),
separator=self.separator
)
return result
def __eq__(self, other):
return self.path == other.path and self.separator == other.separator
def __ne__(self, other):
return not (self == other)
def __unicode__(self):
return self.path
def get_attr(mixed, attr):
if isinstance(mixed, InstrumentedAttribute):
return getattr(
mixed.property.mapper.class_,
attr
)
else:
return getattr(mixed, attr)
@str_coercible
class AttrPath(object):
def __init__(self, class_, path):
self.class_ = class_
self.path = Path(path)
self.parts = []
last_attr = class_
for value in self.path:
last_attr = get_attr(last_attr, value)
self.parts.append(last_attr)
def __iter__(self):
for part in self.parts:
yield part
def __invert__(self):
def get_backref(part):
prop = part.property
backref = prop.backref
if backref is None:
raise Exception(
"Invert failed because property '%s' of class "
"%s has no backref." % (
prop.key,
prop.mapper.class_.__name__
)
)
return backref
return self.__class__(
self.parts[-1].mapper.class_,
'.'.join(map(get_backref, reversed(self.parts)))
)
def __getitem__(self, slice):
result = self.parts[slice]
if isinstance(result, list):
if result[0] is self.parts[0]:
class_ = self.class_
else:
class_ = result[0].mapper.class_
return self.__class__(
class_,
self.path[slice]
)
else:
return result
def __len__(self):
return len(self.path)
def __repr__(self):
return "%s(%r, %r)" % (
self.__class__.__name__,
self.class_,
self.path.path
)
def __eq__(self, other):
return self.path == other.path and self.class_ == other.class_
def __ne__(self, other):
return not (self == other)
def __unicode__(self):
return str(self.path)