| 1 |
"""Exception classes for Dejavu.""" |
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
class DejavuError(Exception): |
|---|
| 5 |
"""Base class for errors which occur within Dejavu.""" |
|---|
| 6 |
def __init__(self, *args): |
|---|
| 7 |
Exception.__init__(self) |
|---|
| 8 |
self.args = args |
|---|
| 9 |
|
|---|
| 10 |
def __str__(self): |
|---|
| 11 |
return u'\n'.join([unicode(arg) for arg in self.args]) |
|---|
| 12 |
|
|---|
| 13 |
class AssociationError(DejavuError): |
|---|
| 14 |
"""Exception raised when a Unit association fails.""" |
|---|
| 15 |
pass |
|---|
| 16 |
|
|---|
| 17 |
class UnrecallableError(DejavuError): |
|---|
| 18 |
"""Exception raised when a Unit was sought but not recalled.""" |
|---|
| 19 |
pass |
|---|
| 20 |
|
|---|
| 21 |
class StorageWarning(UserWarning): |
|---|
| 22 |
"""Warning about functionality which is not supported by all SM's.""" |
|---|
| 23 |
pass |
|---|
| 24 |
|
|---|
| 25 |
class MappingError(DejavuError): |
|---|
| 26 |
"""Exception raised when a Unit class cannot be mapped to storage. |
|---|
| 27 |
|
|---|
| 28 |
This exception should be raised when a consumer attempts to build |
|---|
| 29 |
a map between a Unit class and existing internal storage structures. |
|---|
| 30 |
Other exceptions may be raised when trying to find such a map after |
|---|
| 31 |
it has already (supposedly) been created. That is, the questions |
|---|
| 32 |
"do we have a map?" and "can we create a map?" are distinct. |
|---|
| 33 |
The latter should raise this exception whenever possible. |
|---|
| 34 |
The behavior of the former is not specified. |
|---|
| 35 |
""" |
|---|
| 36 |
pass |
|---|
| 37 |
|
|---|
| 38 |
|
|---|
| 39 |
|
|---|
| 40 |
|
|---|
| 41 |
|
|---|
| 42 |
|
|---|
| 43 |
class ConflictHandler(object): |
|---|
| 44 |
"""Dispatcher for behavior upon encountering a mapping conflict. |
|---|
| 45 |
|
|---|
| 46 |
When MappingErrors are encountered, a singleton instance of this class |
|---|
| 47 |
is used to respond to the error based upon a supplied mode. You can add |
|---|
| 48 |
failure modes (and their corresponding behaviors) by adding methods to |
|---|
| 49 |
this class. |
|---|
| 50 |
|
|---|
| 51 |
In general, only leaf nodes need call this object; pure proxies and |
|---|
| 52 |
storage mixers which simply pass calls through to (possibly multiple) |
|---|
| 53 |
child storage nodes may safely rely on the behavior of their child |
|---|
| 54 |
nodes by passing the 'conflicts' argument through to all children. |
|---|
| 55 |
""" |
|---|
| 56 |
|
|---|
| 57 |
def __call__(self, mode, msg): |
|---|
| 58 |
"""React to a conflict according to the given mode. |
|---|
| 59 |
|
|---|
| 60 |
mode: This argument determines what happens when there are |
|---|
| 61 |
discrepancies between the Dejavu model and the actual database. |
|---|
| 62 |
|
|---|
| 63 |
If 'error' (the default), MappingError is raised for the |
|---|
| 64 |
first issue and the call is aborted. |
|---|
| 65 |
|
|---|
| 66 |
If 'warn', then a StorageWarning is raised (instead of an error) |
|---|
| 67 |
for each issue, and the call is not aborted. This allows you to |
|---|
| 68 |
see all errors at once, without having to stop and fix each one |
|---|
| 69 |
and then execute the call again. |
|---|
| 70 |
|
|---|
| 71 |
If 'repair', then each issue will be resolved by changing |
|---|
| 72 |
the database to match the model. Not all calls support this |
|---|
| 73 |
mode for all errors; any which do not support this mode will |
|---|
| 74 |
error instead. |
|---|
| 75 |
|
|---|
| 76 |
If 'ignore', any model conflicts are silently ignored. |
|---|
| 77 |
Use of this mode causes mandelbugs. You have been warned. |
|---|
| 78 |
""" |
|---|
| 79 |
func = getattr(self, mode, None) |
|---|
| 80 |
if func is None: |
|---|
| 81 |
raise ValueError("Conflict mode %r not recognized." % mode) |
|---|
| 82 |
return func(msg) |
|---|
| 83 |
|
|---|
| 84 |
def warn(self, msg): |
|---|
| 85 |
import warnings |
|---|
| 86 |
warnings.warn(msg, StorageWarning, stacklevel=3) |
|---|
| 87 |
|
|---|
| 88 |
def ignore(self, msg): |
|---|
| 89 |
pass |
|---|
| 90 |
|
|---|
| 91 |
def error(self, msg): |
|---|
| 92 |
raise MappingError(msg) |
|---|
| 93 |
|
|---|
| 94 |
conflict = ConflictHandler() |
|---|
| 95 |
|
|---|