sqlobject 3.13.1__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. sqlobject/__init__.py +15 -0
  2. sqlobject/__version__.py +8 -0
  3. sqlobject/boundattributes.py +124 -0
  4. sqlobject/cache.py +376 -0
  5. sqlobject/classregistry.py +138 -0
  6. sqlobject/col.py +2187 -0
  7. sqlobject/compat.py +59 -0
  8. sqlobject/conftest.py +64 -0
  9. sqlobject/constraints.py +77 -0
  10. sqlobject/converters.py +278 -0
  11. sqlobject/dbconnection.py +1137 -0
  12. sqlobject/dberrors.py +54 -0
  13. sqlobject/declarative.py +211 -0
  14. sqlobject/events.py +365 -0
  15. sqlobject/firebird/__init__.py +8 -0
  16. sqlobject/firebird/firebirdconnection.py +463 -0
  17. sqlobject/include/__init__.py +1 -0
  18. sqlobject/include/hashcol.py +109 -0
  19. sqlobject/include/tests/__init__.py +1 -0
  20. sqlobject/include/tests/test_hashcol.py +84 -0
  21. sqlobject/index.py +189 -0
  22. sqlobject/inheritance/__init__.py +551 -0
  23. sqlobject/inheritance/iteration.py +106 -0
  24. sqlobject/inheritance/tests/__init__.py +1 -0
  25. sqlobject/inheritance/tests/test_aggregates.py +23 -0
  26. sqlobject/inheritance/tests/test_asdict.py +48 -0
  27. sqlobject/inheritance/tests/test_deep_inheritance.py +114 -0
  28. sqlobject/inheritance/tests/test_destroy_cascade.py +23 -0
  29. sqlobject/inheritance/tests/test_foreignKey.py +94 -0
  30. sqlobject/inheritance/tests/test_indexes.py +42 -0
  31. sqlobject/inheritance/tests/test_inheritance.py +164 -0
  32. sqlobject/inheritance/tests/test_inheritance_tree.py +50 -0
  33. sqlobject/joins.py +656 -0
  34. sqlobject/main.py +1880 -0
  35. sqlobject/manager/__init__.py +1 -0
  36. sqlobject/manager/command.py +1309 -0
  37. sqlobject/maxdb/__init__.py +8 -0
  38. sqlobject/maxdb/maxdbconnection.py +320 -0
  39. sqlobject/maxdb/readme.txt +27 -0
  40. sqlobject/mssql/__init__.py +8 -0
  41. sqlobject/mssql/mssqlconnection.py +417 -0
  42. sqlobject/mysql/__init__.py +8 -0
  43. sqlobject/mysql/mysqlconnection.py +562 -0
  44. sqlobject/postgres/__init__.py +8 -0
  45. sqlobject/postgres/pgconnection.py +619 -0
  46. sqlobject/sqlbuilder.py +1655 -0
  47. sqlobject/sqlite/__init__.py +8 -0
  48. sqlobject/sqlite/sqliteconnection.py +418 -0
  49. sqlobject/sresults.py +377 -0
  50. sqlobject/styles.py +174 -0
  51. sqlobject/sybase/__init__.py +8 -0
  52. sqlobject/sybase/sybaseconnection.py +183 -0
  53. sqlobject/tests/__init__.py +1 -0
  54. sqlobject/tests/dbtest.py +363 -0
  55. sqlobject/tests/test_ForeignKey.py +133 -0
  56. sqlobject/tests/test_ForeignKey_cascade.py +150 -0
  57. sqlobject/tests/test_NoneValuedResultItem.py +33 -0
  58. sqlobject/tests/test_SQLMultipleJoin.py +65 -0
  59. sqlobject/tests/test_SQLRelatedJoin.py +114 -0
  60. sqlobject/tests/test_SingleJoin.py +30 -0
  61. sqlobject/tests/test_aggregates.py +75 -0
  62. sqlobject/tests/test_aliases.py +49 -0
  63. sqlobject/tests/test_asdict.py +18 -0
  64. sqlobject/tests/test_auto.py +218 -0
  65. sqlobject/tests/test_basic.py +359 -0
  66. sqlobject/tests/test_blob.py +34 -0
  67. sqlobject/tests/test_boundattributes.py +67 -0
  68. sqlobject/tests/test_cache.py +57 -0
  69. sqlobject/tests/test_class_hash.py +22 -0
  70. sqlobject/tests/test_columns_order.py +18 -0
  71. sqlobject/tests/test_combining_joins.py +47 -0
  72. sqlobject/tests/test_comparison.py +24 -0
  73. sqlobject/tests/test_compat.py +10 -0
  74. sqlobject/tests/test_complex_sorting.py +77 -0
  75. sqlobject/tests/test_constraints.py +43 -0
  76. sqlobject/tests/test_converters.py +276 -0
  77. sqlobject/tests/test_create_drop.py +29 -0
  78. sqlobject/tests/test_csvexport.py +101 -0
  79. sqlobject/tests/test_csvimport.py +21 -0
  80. sqlobject/tests/test_cyclic_reference.py +55 -0
  81. sqlobject/tests/test_datetime.py +171 -0
  82. sqlobject/tests/test_dbconnection.py +17 -0
  83. sqlobject/tests/test_decimal.py +63 -0
  84. sqlobject/tests/test_declarative.py +83 -0
  85. sqlobject/tests/test_default_style.py +65 -0
  86. sqlobject/tests/test_delete.py +74 -0
  87. sqlobject/tests/test_distinct.py +36 -0
  88. sqlobject/tests/test_empty.py +22 -0
  89. sqlobject/tests/test_enum.py +75 -0
  90. sqlobject/tests/test_events.py +142 -0
  91. sqlobject/tests/test_exceptions.py +40 -0
  92. sqlobject/tests/test_expire.py +29 -0
  93. sqlobject/tests/test_groupBy.py +45 -0
  94. sqlobject/tests/test_identity.py +29 -0
  95. sqlobject/tests/test_indexes.py +100 -0
  96. sqlobject/tests/test_inheritance.py +35 -0
  97. sqlobject/tests/test_joins.py +160 -0
  98. sqlobject/tests/test_joins_conditional.py +143 -0
  99. sqlobject/tests/test_jsonbcol.py +53 -0
  100. sqlobject/tests/test_jsoncol.py +56 -0
  101. sqlobject/tests/test_lazy.py +165 -0
  102. sqlobject/tests/test_md5.py +13 -0
  103. sqlobject/tests/test_mysql.py +50 -0
  104. sqlobject/tests/test_new_joins.py +165 -0
  105. sqlobject/tests/test_parse_uri.py +147 -0
  106. sqlobject/tests/test_paste.py +92 -0
  107. sqlobject/tests/test_perConnection.py +20 -0
  108. sqlobject/tests/test_pickle.py +42 -0
  109. sqlobject/tests/test_picklecol.py +44 -0
  110. sqlobject/tests/test_postgres.py +82 -0
  111. sqlobject/tests/test_reparent_sqlmeta.py +33 -0
  112. sqlobject/tests/test_schema.py +30 -0
  113. sqlobject/tests/test_select.py +218 -0
  114. sqlobject/tests/test_select_through.py +63 -0
  115. sqlobject/tests/test_setters.py +23 -0
  116. sqlobject/tests/test_slice.py +59 -0
  117. sqlobject/tests/test_sorting.py +80 -0
  118. sqlobject/tests/test_sqlbuilder.py +134 -0
  119. sqlobject/tests/test_sqlbuilder_dbspecific.py +66 -0
  120. sqlobject/tests/test_sqlbuilder_importproxy.py +55 -0
  121. sqlobject/tests/test_sqlbuilder_joins_instances.py +90 -0
  122. sqlobject/tests/test_sqlite.py +160 -0
  123. sqlobject/tests/test_sqlmeta_idName.py +52 -0
  124. sqlobject/tests/test_sqlobject_admin.py +38 -0
  125. sqlobject/tests/test_string_id.py +79 -0
  126. sqlobject/tests/test_style.py +36 -0
  127. sqlobject/tests/test_subqueries.py +142 -0
  128. sqlobject/tests/test_transactions.py +122 -0
  129. sqlobject/tests/test_unicode.py +84 -0
  130. sqlobject/tests/test_uuidcol.py +40 -0
  131. sqlobject/tests/test_validation.py +125 -0
  132. sqlobject/tests/test_views.py +159 -0
  133. sqlobject/util/__init__.py +1 -0
  134. sqlobject/util/csvexport.py +210 -0
  135. sqlobject/util/csvimport.py +366 -0
  136. sqlobject/util/moduleloader.py +35 -0
  137. sqlobject/util/threadinglocal.py +6 -0
  138. sqlobject/versioning/__init__.py +120 -0
  139. sqlobject/versioning/test/__init__.py +0 -0
  140. sqlobject/versioning/test/test_version.py +183 -0
  141. sqlobject/views.py +151 -0
  142. sqlobject/wsgi_middleware.py +109 -0
  143. sqlobject-3.13.1.data/scripts/sqlobject-admin +36 -0
  144. sqlobject-3.13.1.data/scripts/sqlobject-convertOldURI +19 -0
  145. sqlobject-3.13.1.dist-info/METADATA +177 -0
  146. sqlobject-3.13.1.dist-info/RECORD +149 -0
  147. sqlobject-3.13.1.dist-info/WHEEL +6 -0
  148. sqlobject-3.13.1.dist-info/entry_points.txt +4 -0
  149. sqlobject-3.13.1.dist-info/top_level.txt +1 -0
sqlobject/dberrors.py ADDED
@@ -0,0 +1,54 @@
1
+ """dberrors: database exception classes for SQLObject.
2
+
3
+ These classes are dictated by the DB API v2.0, see:
4
+ https://wiki.python.org/moin/DatabaseProgramming
5
+ """
6
+
7
+ from sqlobject.compat import PY2
8
+
9
+ if not PY2:
10
+ StandardError = Exception
11
+
12
+
13
+ class Error(StandardError):
14
+ pass
15
+
16
+
17
+ class Warning(StandardError):
18
+ pass
19
+
20
+
21
+ class InterfaceError(Error):
22
+ pass
23
+
24
+
25
+ class DatabaseError(Error):
26
+ pass
27
+
28
+
29
+ class InternalError(DatabaseError):
30
+ pass
31
+
32
+
33
+ class OperationalError(DatabaseError):
34
+ pass
35
+
36
+
37
+ class ProgrammingError(DatabaseError):
38
+ pass
39
+
40
+
41
+ class IntegrityError(DatabaseError):
42
+ pass
43
+
44
+
45
+ class DataError(DatabaseError):
46
+ pass
47
+
48
+
49
+ class NotSupportedError(DatabaseError):
50
+ pass
51
+
52
+
53
+ class DuplicateEntryError(IntegrityError):
54
+ pass
@@ -0,0 +1,211 @@
1
+ """
2
+ Declarative objects.
3
+
4
+ Declarative objects have a simple protocol: you can use classes in
5
+ lieu of instances and they are equivalent, and any keyword arguments
6
+ you give to the constructor will override those instance variables.
7
+ (So if a class is received, we'll simply instantiate an instance with
8
+ no arguments).
9
+
10
+ You can provide a variable __unpackargs__ (a list of strings), and if
11
+ the constructor is called with non-keyword arguments they will be
12
+ interpreted as the given keyword arguments.
13
+
14
+ If __unpackargs__ is ('*', name), then all the arguments will be put
15
+ in a variable by that name.
16
+
17
+ You can define a __classinit__(cls, new_attrs) method, which will be
18
+ called when the class is created (including subclasses). Note: you
19
+ can't use super() in __classinit__ because the class isn't bound to a
20
+ name. As an analog to __classinit__, Declarative adds
21
+ __instanceinit__ which is called with the same argument (new_attrs).
22
+ This is like __init__, but after __unpackargs__ and other factors have
23
+ been taken into account.
24
+
25
+ If __mutableattributes__ is defined as a sequence of strings, these
26
+ attributes will not be shared between superclasses and their
27
+ subclasses. E.g., if you have a class variable that contains a list
28
+ and you append to that list, changes to subclasses will effect
29
+ superclasses unless you add the attribute here.
30
+
31
+ Also defines classinstancemethod, which acts as either a class method
32
+ or an instance method depending on where it is called.
33
+ """
34
+
35
+ import copy
36
+ from . import events
37
+ from sqlobject.compat import with_metaclass
38
+
39
+ import itertools
40
+ counter = itertools.count()
41
+
42
+ __all__ = ('classinstancemethod', 'DeclarativeMeta', 'Declarative')
43
+
44
+
45
+ class classinstancemethod(object):
46
+ """
47
+ Acts like a class method when called from a class, like an
48
+ instance method when called by an instance. The method should
49
+ take two arguments, 'self' and 'cls'; one of these will be None
50
+ depending on how the method was called.
51
+ """
52
+
53
+ def __init__(self, func):
54
+ self.func = func
55
+
56
+ def __get__(self, obj, type=None):
57
+ return _methodwrapper(self.func, obj=obj, type=type)
58
+
59
+
60
+ class _methodwrapper(object):
61
+
62
+ def __init__(self, func, obj, type):
63
+ self.func = func
64
+ self.obj = obj
65
+ self.type = type
66
+
67
+ def __call__(self, *args, **kw):
68
+ assert 'self' not in kw and 'cls' not in kw, (
69
+ "You cannot use 'self' or 'cls' arguments to a "
70
+ "classinstancemethod")
71
+ return self.func(*((self.obj, self.type) + args), **kw)
72
+
73
+ def __repr__(self):
74
+ if self.obj is None:
75
+ return ('<bound class method %s.%s>'
76
+ % (self.type.__name__, self.func.__name__))
77
+ else:
78
+ return ('<bound method %s.%s of %r>'
79
+ % (self.type.__name__, self.func.__name__, self.obj))
80
+
81
+
82
+ class DeclarativeMeta(type):
83
+
84
+ def __new__(meta, class_name, bases, new_attrs):
85
+ post_funcs = []
86
+ early_funcs = []
87
+ events.send(events.ClassCreateSignal,
88
+ bases[0], class_name, bases, new_attrs,
89
+ post_funcs, early_funcs)
90
+ cls = type.__new__(meta, class_name, bases, new_attrs)
91
+ for func in early_funcs:
92
+ func(cls)
93
+ if '__classinit__' in new_attrs:
94
+ if hasattr(cls.__classinit__, '__func__'):
95
+ cls.__classinit__ = staticmethod(cls.__classinit__.__func__)
96
+ else:
97
+ cls.__classinit__ = staticmethod(cls.__classinit__)
98
+ cls.__classinit__(cls, new_attrs)
99
+ for func in post_funcs:
100
+ func(cls)
101
+ return cls
102
+
103
+
104
+ class Declarative(with_metaclass(DeclarativeMeta, object)):
105
+
106
+ __unpackargs__ = ()
107
+
108
+ __mutableattributes__ = ()
109
+
110
+ __restrict_attributes__ = None
111
+
112
+ def __classinit__(cls, new_attrs):
113
+ cls.declarative_count = next(counter)
114
+ for name in cls.__mutableattributes__:
115
+ if name not in new_attrs:
116
+ setattr(cls, copy.copy(getattr(cls, name)))
117
+
118
+ def __instanceinit__(self, new_attrs):
119
+ if self.__restrict_attributes__ is not None:
120
+ for name in new_attrs:
121
+ if name not in self.__restrict_attributes__:
122
+ raise TypeError(
123
+ '%s() got an unexpected keyword argument %r'
124
+ % (self.__class__.__name__, name))
125
+ for name, value in new_attrs.items():
126
+ setattr(self, name, value)
127
+ if 'declarative_count' not in new_attrs:
128
+ self.declarative_count = next(counter)
129
+
130
+ def __init__(self, *args, **kw):
131
+ if self.__unpackargs__ and self.__unpackargs__[0] == '*':
132
+ assert len(self.__unpackargs__) == 2, \
133
+ "When using __unpackargs__ = ('*', varname), " \
134
+ "you must only provide a single variable name " \
135
+ "(you gave %r)" % self.__unpackargs__
136
+ name = self.__unpackargs__[1]
137
+ if name in kw:
138
+ raise TypeError(
139
+ "keyword parameter '%s' was given by position and name"
140
+ % name)
141
+ kw[name] = args
142
+ else:
143
+ if len(args) > len(self.__unpackargs__):
144
+ raise TypeError(
145
+ '%s() takes at most %i arguments (%i given)'
146
+ % (self.__class__.__name__,
147
+ len(self.__unpackargs__),
148
+ len(args)))
149
+ for name, arg in zip(self.__unpackargs__, args):
150
+ if name in kw:
151
+ raise TypeError(
152
+ "keyword parameter '%s' was given by position and name"
153
+ % name)
154
+ kw[name] = arg
155
+ if '__alsocopy' in kw:
156
+ for name, value in kw['__alsocopy'].items():
157
+ if name not in kw:
158
+ if name in self.__mutableattributes__:
159
+ value = copy.copy(value)
160
+ kw[name] = value
161
+ del kw['__alsocopy']
162
+ self.__instanceinit__(kw)
163
+
164
+ def __call__(self, *args, **kw):
165
+ kw['__alsocopy'] = self.__dict__
166
+ return self.__class__(*args, **kw)
167
+
168
+ @classinstancemethod
169
+ def singleton(self, cls):
170
+ if self:
171
+ return self
172
+ name = '_%s__singleton' % cls.__name__
173
+ if not hasattr(cls, name):
174
+ setattr(cls, name, cls(declarative_count=cls.declarative_count))
175
+ return getattr(cls, name)
176
+
177
+ @classinstancemethod
178
+ def __repr__(self, cls):
179
+ if self:
180
+ name = '%s object' % self.__class__.__name__
181
+ v = self.__dict__.copy()
182
+ else:
183
+ name = '%s class' % cls.__name__
184
+ v = cls.__dict__.copy()
185
+ if 'declarative_count' in v:
186
+ name = '%s %i' % (name, v['declarative_count'])
187
+ del v['declarative_count']
188
+ # @@: simplifying repr:
189
+ # v = {}
190
+ names = v.keys()
191
+ args = []
192
+ for n in self._repr_vars(names):
193
+ args.append('%s=%r' % (n, v[n]))
194
+ if not args:
195
+ return '<%s>' % name
196
+ else:
197
+ return '<%s %s>' % (name, ' '.join(args))
198
+
199
+ @staticmethod
200
+ def _repr_vars(dictNames):
201
+ names = [n for n in dictNames
202
+ if not n.startswith('_')
203
+ and n != 'declarative_count']
204
+ names.sort()
205
+ return names
206
+
207
+
208
+ def setup_attributes(cls, new_attrs):
209
+ for name, value in new_attrs.items():
210
+ if hasattr(value, '__addtoclass__'):
211
+ value.__addtoclass__(cls, name)
sqlobject/events.py ADDED
@@ -0,0 +1,365 @@
1
+ from __future__ import print_function
2
+ import sys
3
+ import types
4
+ from pydispatch import dispatcher
5
+ from weakref import ref
6
+ from .compat import class_types
7
+
8
+
9
+ subclassClones = {}
10
+
11
+
12
+ def listen(receiver, soClass, signal, alsoSubclasses=True, weak=True):
13
+ """
14
+ Listen for the given ``signal`` on the SQLObject subclass
15
+ ``soClass``, calling ``receiver()`` when ``send(soClass, signal,
16
+ ...)`` is called.
17
+
18
+ If ``alsoSubclasses`` is true, receiver will also be called when
19
+ an event is fired on any subclass.
20
+ """
21
+ dispatcher.connect(receiver, signal=signal, sender=soClass, weak=weak)
22
+ weakReceiver = ref(receiver)
23
+ subclassClones.setdefault(soClass, []).append((weakReceiver, signal))
24
+
25
+ # We export this function:
26
+ send = dispatcher.send
27
+
28
+
29
+ class Signal(object):
30
+ """
31
+ Base event for all SQLObject events.
32
+
33
+ In general the sender for these methods is the class, not the
34
+ instance.
35
+ """
36
+
37
+
38
+ class ClassCreateSignal(Signal):
39
+ """
40
+ Signal raised after class creation. The sender is the superclass
41
+ (in case of multiple superclasses, the first superclass). The
42
+ arguments are ``(new_class_name, bases, new_attrs, post_funcs,
43
+ early_funcs)``. ``new_attrs`` is a dictionary and may be modified
44
+ (but ``new_class_name`` and ``bases`` are immutable).
45
+ ``post_funcs`` is an initially-empty list that can have callbacks
46
+ appended to it.
47
+
48
+ Note: at the time this event is called, the new class has not yet
49
+ been created. The functions in ``post_funcs`` will be called
50
+ after the class is created, with the single arguments of
51
+ ``(new_class)``. Also, ``early_funcs`` will be called at the
52
+ soonest possible time after class creation (``post_funcs`` is
53
+ called after the class's ``__classinit__``).
54
+ """
55
+
56
+
57
+ def _makeSubclassConnections(new_class_name, bases, new_attrs,
58
+ post_funcs, early_funcs):
59
+ early_funcs.insert(0, _makeSubclassConnectionsPost)
60
+
61
+
62
+ def _makeSubclassConnectionsPost(new_class):
63
+ for cls in new_class.__bases__:
64
+ for weakReceiver, signal in subclassClones.get(cls, []):
65
+ receiver = weakReceiver()
66
+ if not receiver:
67
+ continue
68
+ listen(receiver, new_class, signal)
69
+
70
+ dispatcher.connect(_makeSubclassConnections, signal=ClassCreateSignal)
71
+
72
+
73
+ # @@: Should there be a class reload event? This would allow modules
74
+ # to be reloaded, possibly. Or it could even be folded into
75
+ # ClassCreateSignal, since anything that listens to that needs to pay
76
+ # attention to reloads (or else it is probably buggy).
77
+
78
+
79
+ class RowCreateSignal(Signal):
80
+ """
81
+ Called before an instance is created, with the class as the
82
+ sender. Called with the arguments ``(instance, kwargs, post_funcs)``.
83
+ There may be a ``connection`` argument. ``kwargs``may be usefully
84
+ modified. ``post_funcs`` is a list of callbacks, intended to have
85
+ functions appended to it, and are called with the arguments
86
+ ``(new_instance)``.
87
+
88
+ Note: this is not called when an instance is created from an
89
+ existing database row.
90
+ """
91
+
92
+
93
+ class RowCreatedSignal(Signal):
94
+ """
95
+ Called after an instance is created, with the class as the
96
+ sender. Called with the arguments ``(instance, kwargs, post_funcs)``.
97
+ There may be a ``connection`` argument. ``kwargs``may be usefully
98
+ modified. ``post_funcs`` is a list of callbacks, intended to have
99
+ functions appended to it, and are called with the arguments
100
+ ``(new_instance)``.
101
+
102
+ Note: this is not called when an instance is created from an
103
+ existing database row.
104
+ """
105
+ # @@: An event for getting a row? But for each row, when doing a
106
+ # select? For .sync, .syncUpdate, .expire?
107
+
108
+
109
+ class RowDestroySignal(Signal):
110
+ """
111
+ Called before an instance is deleted. Sender is the instance's
112
+ class. Arguments are ``(instance, post_funcs)``.
113
+
114
+ ``post_funcs`` is a list of callbacks, intended to have
115
+ functions appended to it, and are called with arguments ``(instance)``.
116
+ If any of the post_funcs raises an exception, the deletion is only
117
+ affected if this will prevent a commit.
118
+
119
+ You cannot cancel the delete, but you can raise an exception (which will
120
+ probably cancel the delete, but also cause an uncaught exception if not
121
+ expected).
122
+
123
+ Note: this is not called when an instance is destroyed through
124
+ garbage collection.
125
+
126
+ @@: Should this allow ``instance`` to be a primary key, so that a
127
+ row can be deleted without first fetching it?
128
+ """
129
+
130
+
131
+ class RowDestroyedSignal(Signal):
132
+ """
133
+ Called after an instance is deleted. Sender is the instance's
134
+ class. Arguments are ``(instance)``.
135
+
136
+ This is called before the post_funcs of RowDestroySignal
137
+
138
+ Note: this is not called when an instance is destroyed through
139
+ garbage collection.
140
+ """
141
+
142
+
143
+ class RowUpdateSignal(Signal):
144
+ """
145
+ Called when an instance is updated through a call to ``.set()``
146
+ (or a column attribute assignment). The arguments are
147
+ ``(instance, kwargs)``. ``kwargs`` can be modified. This is run
148
+ *before* the instance is updated; if you want to look at the
149
+ current values, simply look at ``instance``.
150
+ """
151
+
152
+
153
+ class RowUpdatedSignal(Signal):
154
+ """
155
+ Called when an instance is updated through a call to ``.set()``
156
+ (or a column attribute assignment). The arguments are
157
+ ``(instance, post_funcs)``. ``post_funcs`` is a list of callbacks,
158
+ intended to have functions appended to it, and are called with the
159
+ arguments ``(new_instance)``. This is run *after* the instance is
160
+ updated; Works better with lazyUpdate = True.
161
+ """
162
+
163
+
164
+ class AddColumnSignal(Signal):
165
+ """
166
+ Called when a column is added to a class, with arguments ``(cls,
167
+ connection, column_name, column_definition, changeSchema,
168
+ post_funcs)``. This is called *after* the column has been added,
169
+ and is called for each column after class creation.
170
+
171
+ post_funcs are called with ``(cls, so_column_obj)``
172
+ """
173
+
174
+
175
+ class DeleteColumnSignal(Signal):
176
+ """
177
+ Called when a column is removed from a class, with the arguments
178
+ ``(cls, connection, column_name, so_column_obj, post_funcs)``.
179
+ Like ``AddColumnSignal`` this is called after the action has been
180
+ performed, and is called for subclassing (when a column is
181
+ implicitly removed by setting it to ``None``).
182
+
183
+ post_funcs are called with ``(cls, so_column_obj)``
184
+ """
185
+
186
+ # @@: Signals for indexes and joins? These are mostly event consumers,
187
+ # though.
188
+
189
+
190
+ class CreateTableSignal(Signal):
191
+ """
192
+ Called when a table is created. If ``ifNotExists==True`` and the
193
+ table exists, this event is not called.
194
+
195
+ Called with ``(cls, connection, extra_sql, post_funcs)``.
196
+ ``extra_sql`` is a list (which can be appended to) of extra SQL
197
+ statements to be run after the table is created. ``post_funcs``
198
+ functions are called with ``(cls, connection)`` after the table
199
+ has been created. Those functions are *not* called simply when
200
+ constructing the SQL.
201
+ """
202
+
203
+
204
+ class DropTableSignal(Signal):
205
+ """
206
+ Called when a table is dropped. If ``ifExists==True`` and the
207
+ table doesn't exist, this event is not called.
208
+
209
+ Called with ``(cls, connection, extra_sql, post_funcs)``.
210
+ ``post_funcs`` functions are called with ``(cls, connection)``
211
+ after the table has been dropped.
212
+ """
213
+
214
+
215
+ class CommitSignal(Signal):
216
+ """
217
+ Called on transaction commit
218
+ """
219
+
220
+
221
+ class RollbackSignal(Signal):
222
+ """
223
+ Called on transaction rollback
224
+ """
225
+
226
+
227
+ ############################################################
228
+ # Event Debugging
229
+ ############################################################
230
+
231
+
232
+ def summarize_events_by_sender(sender=None, output=None, indent=0):
233
+ """
234
+ Prints out a summary of the senders and listeners in the system,
235
+ for debugging purposes.
236
+ """
237
+ if output is None:
238
+ output = sys.stdout
239
+ leader = ' ' * indent
240
+ if sender is None:
241
+ send_list = [
242
+ (deref(dispatcher.senders.get(sid)), listeners)
243
+ for sid, listeners in dispatcher.connections.items()
244
+ if deref(dispatcher.senders.get(sid))]
245
+ for sender, listeners in sorted_items(send_list):
246
+ real_sender = deref(sender)
247
+ if not real_sender:
248
+ continue
249
+ header = 'Sender: %r' % real_sender
250
+ print(leader + header, file=output)
251
+ print(leader + ('=' * len(header)), file=output)
252
+ summarize_events_by_sender(real_sender, output=output,
253
+ indent=indent + 2)
254
+ else:
255
+ for signal, receivers in \
256
+ sorted_items(dispatcher.connections.get(id(sender), [])):
257
+ receivers = [deref(r) for r in receivers if deref(r)]
258
+ header = 'Signal: %s (%i receivers)' % (sort_name(signal),
259
+ len(receivers))
260
+ print(leader + header, file=output)
261
+ print(leader + ('-' * len(header)), file=output)
262
+ for receiver in sorted(receivers, key=sort_name):
263
+ print(leader + ' ' + nice_repr(receiver), file=output)
264
+
265
+
266
+ def deref(value):
267
+ if isinstance(value, dispatcher.WEAKREF_TYPES):
268
+ return value()
269
+ else:
270
+ return value
271
+
272
+
273
+ def sorted_items(a_dict):
274
+ if isinstance(a_dict, dict):
275
+ a_dict = a_dict.items()
276
+ return sorted(a_dict, key=lambda t: sort_name(t[0]))
277
+
278
+
279
+ def sort_name(value):
280
+ if isinstance(value, type):
281
+ return value.__name__
282
+ elif isinstance(value, types.FunctionType):
283
+ return value.__name__
284
+ else:
285
+ return str(value)
286
+
287
+ _real_dispatcher_send = dispatcher.send
288
+ _real_dispatcher_sendExact = dispatcher.sendExact
289
+ _real_dispatcher_connect = dispatcher.connect
290
+ _real_dispatcher_disconnect = dispatcher.disconnect
291
+ _debug_enabled = False
292
+
293
+
294
+ def debug_events():
295
+ global _debug_enabled, send
296
+ if _debug_enabled:
297
+ return
298
+ _debug_enabled = True
299
+ dispatcher.send = send = _debug_send
300
+ dispatcher.sendExact = _debug_sendExact
301
+ dispatcher.disconnect = _debug_disconnect
302
+ dispatcher.connect = _debug_connect
303
+
304
+
305
+ def _debug_send(signal=dispatcher.Any, sender=dispatcher.Anonymous,
306
+ *arguments, **named):
307
+ print("send %s from %s: %s" % (
308
+ nice_repr(signal), nice_repr(sender),
309
+ fmt_args(*arguments, **named)))
310
+ return _real_dispatcher_send(signal, sender, *arguments, **named)
311
+
312
+
313
+ def _debug_sendExact(signal=dispatcher.Any, sender=dispatcher.Anonymous,
314
+ *arguments, **named):
315
+ print("sendExact %s from %s: %s" % (
316
+ nice_repr(signal), nice_repr(sender), fmt_args(*arguments, **name)))
317
+ return _real_dispatcher_sendExact(signal, sender, *arguments, **named)
318
+
319
+
320
+ def _debug_connect(receiver, signal=dispatcher.Any, sender=dispatcher.Any,
321
+ weak=True):
322
+ print("connect %s to %s signal %s" % (
323
+ nice_repr(receiver), nice_repr(signal), nice_repr(sender)))
324
+ return _real_dispatcher_connect(receiver, signal, sender, weak)
325
+
326
+
327
+ def _debug_disconnect(receiver, signal=dispatcher.Any, sender=dispatcher.Any,
328
+ weak=True):
329
+ print("disconnecting %s from %s signal %s" % (
330
+ nice_repr(receiver), nice_repr(signal), nice_repr(sender)))
331
+ return _real_dispatcher_disconnect(receiver, signal, sender, weak)
332
+
333
+
334
+ def fmt_args(*arguments, **name):
335
+ args = [repr(a) for a in arguments]
336
+ args.extend([
337
+ '%s=%r' % (n, v) for n, v in sorted(name.items())])
338
+ return ', '.join(args)
339
+
340
+
341
+ def nice_repr(v):
342
+ """
343
+ Like repr(), but nicer for debugging here.
344
+ """
345
+ if isinstance(v, class_types):
346
+ return v.__module__ + '.' + v.__name__
347
+ elif isinstance(v, types.FunctionType):
348
+ if '__name__' in v.__globals__:
349
+ if getattr(sys.modules[v.__globals__['__name__']],
350
+ v.__name__, None) is v:
351
+ return '%s.%s' % (v.__globals__['__name__'], v.__name__)
352
+ return repr(v)
353
+ elif isinstance(v, types.MethodType):
354
+ return '%s.%s of %s' % (
355
+ nice_repr(v.__self__.__class__), v.__func__.__name__,
356
+ nice_repr(v.__self__))
357
+ else:
358
+ return repr(v)
359
+
360
+
361
+ __all__ = ['listen', 'send']
362
+ # Use copy() to avoid 'dictionary changed' issues on python 3
363
+ for name, value in globals().copy().items():
364
+ if isinstance(value, type) and issubclass(value, Signal):
365
+ __all__.append(name)
@@ -0,0 +1,8 @@
1
+ from sqlobject.dbconnection import registerConnection
2
+
3
+
4
+ def builder():
5
+ from . import firebirdconnection
6
+ return firebirdconnection.FirebirdConnection
7
+
8
+ registerConnection(['firebird', 'interbase'], builder)