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
@@ -0,0 +1,210 @@
1
+ """
2
+ Exports a SQLObject class (possibly annotated) to a CSV file.
3
+ """
4
+ import csv
5
+ import os
6
+ try:
7
+ from cStringIO import StringIO
8
+ except ImportError:
9
+ try:
10
+ from StringIO import StringIO
11
+ except ImportError:
12
+ from io import StringIO, BytesIO
13
+ import sqlobject
14
+ from sqlobject.compat import PY2, string_type
15
+
16
+ __all__ = ['export_csv', 'export_csv_zip']
17
+
18
+
19
+ def export_csv(soClass, select=None, writer=None, connection=None,
20
+ orderBy=None):
21
+ """
22
+ Export the SQLObject class ``soClass`` to a CSV file.
23
+
24
+ ``soClass`` can also be a SelectResults object, as returned by
25
+ ``.select()``. If it is a class, all objects will be retrieved,
26
+ ordered by ``orderBy`` if given, or the ``.csvOrderBy`` attribute
27
+ if present (but csvOrderBy will only be applied when no select
28
+ result is given).
29
+
30
+ You can also pass in select results (or simply a list of
31
+ instances) in ``select`` -- if you have a list of objects (not a
32
+ SelectResults instance, as produced by ``.select()``) then you must
33
+ pass it in with ``select`` and pass the class in as the first
34
+ argument.
35
+
36
+ ``writer`` is a ``csv.writer()`` object, or a file-like object.
37
+ If not given, the string of the file will be returned.
38
+
39
+ Uses ``connection`` as the data source, if given, otherwise the
40
+ default connection.
41
+
42
+ Columns can be annotated with ``.csvTitle`` attributes, which will
43
+ form the attributes of the columns, or 'title' (secondarily), or
44
+ if nothing then the column attribute name.
45
+
46
+ If a column has a ``.noCSV`` attribute which is true, then the
47
+ column will be suppressed.
48
+
49
+ Additionally a class can have an ``.extraCSVColumns`` attribute,
50
+ which should be a list of strings/tuples. If a tuple, it should
51
+ be like ``(attribute, title)``, otherwise it is the attribute,
52
+ which will also be the title. These will be appended to the end
53
+ of the CSV file; the attribute will be retrieved from instances.
54
+
55
+ Also a ``.csvColumnOrder`` attribute can be on the class, which is
56
+ the string names of attributes in the order they should be
57
+ presented.
58
+ """
59
+
60
+ return_fileobj = None
61
+ if not writer:
62
+ return_fileobj = StringIO()
63
+ writer = csv.writer(return_fileobj)
64
+ elif not hasattr(writer, 'writerow'):
65
+ writer = csv.writer(writer)
66
+
67
+ if isinstance(soClass, sqlobject.SQLObject.SelectResultsClass):
68
+ assert select is None, (
69
+ "You cannot pass in a select argument (%r) "
70
+ "and a SelectResults argument (%r) for soClass" %
71
+ (select, soClass))
72
+ select = soClass
73
+ soClass = select.sourceClass
74
+ elif select is None:
75
+ select = soClass.select()
76
+ if getattr(soClass, 'csvOrderBy', None):
77
+ select = select.orderBy(soClass.csvOrderBy)
78
+
79
+ if orderBy:
80
+ select = select.orderBy(orderBy)
81
+ if connection:
82
+ select = select.connection(connection)
83
+
84
+ _actually_export_csv(soClass, select, writer)
85
+
86
+ if return_fileobj:
87
+ # They didn't pass any writer or file object in, so we return
88
+ # the string result:
89
+ return return_fileobj.getvalue()
90
+
91
+
92
+ def _actually_export_csv(soClass, select, writer):
93
+ attributes, titles = _find_columns(soClass)
94
+ writer.writerow(titles)
95
+ for soInstance in select:
96
+ row = [getattr(soInstance, attr)
97
+ for attr in attributes]
98
+ writer.writerow(row)
99
+
100
+
101
+ def _find_columns(soClass):
102
+ order = []
103
+ attrs = {}
104
+ for col in soClass.sqlmeta.columnList:
105
+ if getattr(col, 'noCSV', False):
106
+ continue
107
+ order.append(col.name)
108
+ title = col.name
109
+ if hasattr(col, 'csvTitle'):
110
+ title = col.csvTitle
111
+ elif getattr(col, 'title', None) is not None:
112
+ title = col.title
113
+ attrs[col.name] = title
114
+
115
+ for attrDesc in getattr(soClass, 'extraCSVColumns', []):
116
+ if isinstance(attrDesc, (list, tuple)):
117
+ attr, title = attrDesc
118
+ else:
119
+ attr = title = attrDesc
120
+ order.append(attr)
121
+ attrs[attr] = title
122
+
123
+ if hasattr(soClass, 'csvColumnOrder'):
124
+ oldOrder = order
125
+ order = soClass.csvColumnOrder
126
+ for attr in order:
127
+ if attr not in oldOrder:
128
+ raise KeyError(
129
+ "Attribute %r in csvColumnOrder (on class %r) "
130
+ "does not exist as a column or in .extraCSVColumns "
131
+ "(I have: %r)" % (attr, soClass, oldOrder))
132
+ oldOrder.remove(attr)
133
+ order.extend(oldOrder)
134
+
135
+ titles = [attrs[attr] for attr in order]
136
+ return order, titles
137
+
138
+
139
+ def export_csv_zip(soClasses, file=None, zip=None, filename_prefix='',
140
+ connection=None):
141
+ """
142
+ Export several SQLObject classes into a .zip file. Each
143
+ item in the ``soClasses`` list may be a SQLObject class,
144
+ select result, or ``(soClass, select)`` tuple.
145
+
146
+ Each file in the zip will be named after the class name (with
147
+ ``.csv`` appended), or using the filename in the ``.csvFilename``
148
+ attribute.
149
+
150
+ If ``file`` is given, the zip will be written to that. ``file``
151
+ may be a string (a filename) or a file-like object. If not given,
152
+ a string will be returnd.
153
+
154
+ If ``zip`` is given, then the files will be written to that zip
155
+ file.
156
+
157
+ All filenames will be prefixed with ``filename_prefix`` (which may
158
+ be a directory name, for instance).
159
+ """
160
+ import zipfile
161
+ close_file_when_finished = False
162
+ close_zip_when_finished = True
163
+ return_when_finished = False
164
+ if file:
165
+ if isinstance(file, string_type):
166
+ close_file_when_finished = True
167
+ file = open(file, 'wb')
168
+ elif zip:
169
+ close_zip_when_finished = False
170
+ else:
171
+ return_when_finished = True
172
+ if PY2:
173
+ file = StringIO()
174
+ else:
175
+ # zipfile on python3 requires BytesIO
176
+ file = BytesIO()
177
+
178
+ if not zip:
179
+ zip = zipfile.ZipFile(file, mode='w')
180
+
181
+ try:
182
+ _actually_export_classes(soClasses, zip, filename_prefix,
183
+ connection)
184
+ finally:
185
+ if close_zip_when_finished:
186
+ zip.close()
187
+ if close_file_when_finished:
188
+ file.close()
189
+
190
+ if return_when_finished:
191
+ return file.getvalue()
192
+
193
+
194
+ def _actually_export_classes(soClasses, zip, filename_prefix,
195
+ connection):
196
+ for classDesc in soClasses:
197
+ if isinstance(classDesc, (tuple, list)):
198
+ soClass, select = classDesc
199
+ elif isinstance(classDesc, sqlobject.SQLObject.SelectResultsClass):
200
+ select = classDesc
201
+ soClass = select.sourceClass
202
+ else:
203
+ soClass = classDesc
204
+ select = None
205
+ filename = getattr(soClass, 'csvFilename', soClass.__name__)
206
+ if not os.path.splitext(filename)[1]:
207
+ filename += '.csv'
208
+ filename = filename_prefix + filename
209
+ zip.writestr(filename,
210
+ export_csv(soClass, select, connection=connection))
@@ -0,0 +1,366 @@
1
+ """
2
+ Import from a CSV file or directory of files.
3
+
4
+ CSV files should have a header line that lists columns. Headers can
5
+ also be appended with ``:type`` to indicate the type of the field.
6
+ ``escaped`` is the default, though it can be overridden by the importer.
7
+ Supported types:
8
+
9
+ ``:python``:
10
+ A python expression, run through ``eval()``. This can be a
11
+ security risk, pass in ``allow_python=False`` if you don't want to
12
+ allow it.
13
+
14
+ ``:int``:
15
+ Integer
16
+
17
+ ``:float``:
18
+ Float
19
+
20
+ ``:str``:
21
+ String
22
+
23
+ ``:escaped``:
24
+ A string with backslash escapes (note that you don't put quotation
25
+ marks around the value)
26
+
27
+ ``:base64``:
28
+ A base64-encoded string
29
+
30
+ ``:date``:
31
+ ISO date, like YYYY-MM-DD; this can also be ``NOW+days`` or
32
+ ``NOW-days``
33
+
34
+ ``:datetime``:
35
+ ISO date/time like YYYY-MM-DDTHH:MM:SS (either T or a space can be
36
+ used to separate the time, and seconds are optional). This can
37
+ also be ``NOW+seconds`` or ``NOW-seconds``
38
+
39
+ ``:bool``:
40
+ Converts true/false/yes/no/on/off/1/0 to boolean value
41
+
42
+ ``:ref``:
43
+ This will be resolved to the ID of the object named in this column
44
+ (None if the column is empty). @@: Since there's no ordering,
45
+ there's no way to promise the object already exists.
46
+
47
+ You can also get back references to the objects if you have a special
48
+ ``[name]`` column.
49
+
50
+ Any column named ``[comment]`` or with no name will be ignored.
51
+
52
+ In any column you can put ``[default]`` to exclude the value and use
53
+ whatever default the class wants. ``[null]`` will use NULL.
54
+
55
+ Lines that begin with ``[comment]`` are ignored.
56
+ """
57
+
58
+ import csv
59
+ from datetime import datetime, date, timedelta
60
+ import os
61
+ import time
62
+ import types
63
+
64
+ __all__ = ['load_csv_from_directory',
65
+ 'load_csv',
66
+ 'create_data']
67
+
68
+
69
+ DEFAULT_TYPE = 'escaped'
70
+
71
+
72
+ def create_data(data, class_getter, keyorder=None):
73
+ """
74
+ Create the ``data``, which is the return value from
75
+ ``load_csv()``. Classes will be resolved with the callable
76
+ ``class_getter``; or if ``class_getter`` is a module then the
77
+ class names will be attributes of that.
78
+
79
+ Returns a dictionary of ``{object_name: object(s)}``, using the
80
+ names from the ``[name]`` columns (if there are any). If a name
81
+ is used multiple times, you get a list of objects, not a single
82
+ object.
83
+
84
+ If ``keyorder`` is given, then the keys will be retrieved in that
85
+ order. It can be a list/tuple of names, or a sorting function.
86
+ If not given and ``class_getter`` is a module and has a
87
+ ``soClasses`` function, then that will be used for the order.
88
+ """
89
+ objects = {}
90
+ classnames = data.keys()
91
+ if (not keyorder and isinstance(class_getter, types.ModuleType)
92
+ and hasattr(class_getter, 'soClasses')):
93
+ keyorder = [c.__name__ for c in class_getter.soClasses]
94
+ if not keyorder:
95
+ classnames.sort()
96
+ elif isinstance(keyorder, (list, tuple)):
97
+ all = classnames
98
+ classnames = [name for name in keyorder if name in classnames]
99
+ for name in all:
100
+ if name not in classnames:
101
+ classnames.append(name)
102
+ else:
103
+ classnames.sort(keyorder)
104
+ for classname in classnames:
105
+ items = data[classname]
106
+ if not items:
107
+ continue
108
+ if isinstance(class_getter, types.ModuleType):
109
+ soClass = getattr(class_getter, classname)
110
+ else:
111
+ soClass = class_getter(classname)
112
+ for item in items:
113
+ for key, value in item.items():
114
+ if isinstance(value, Reference):
115
+ resolved = objects.get(value.name)
116
+ if not resolved:
117
+ raise ValueError(
118
+ "Object reference to %r does not have target"
119
+ % value.name)
120
+ elif (isinstance(resolved, list) and len(resolved) > 1):
121
+ raise ValueError(
122
+ "Object reference to %r is ambiguous (got %r)"
123
+ % (value.name, resolved))
124
+ item[key] = resolved.id
125
+ if '[name]' in item:
126
+ name = item.pop('[name]').strip()
127
+ else:
128
+ name = None
129
+ inst = soClass(**item)
130
+ if name:
131
+ if name in objects:
132
+ if isinstance(objects[name], list):
133
+ objects[name].append(inst)
134
+ else:
135
+ objects[name] = [objects[name], inst]
136
+ else:
137
+ objects[name] = inst
138
+ return objects
139
+
140
+
141
+ def load_csv_from_directory(directory,
142
+ allow_python=True, default_type=DEFAULT_TYPE,
143
+ allow_multiple_classes=True):
144
+ """
145
+ Load the data from all the files in a directory. Filenames
146
+ indicate the class, with ``general.csv`` for data not associated
147
+ with a class. Return data just like ``load_csv`` does.
148
+
149
+ This might cause problems on case-insensitive filesystems.
150
+ """
151
+ results = {}
152
+ for filename in os.listdir(directory):
153
+ base, ext = os.path.splitext(filename)
154
+ if ext.lower() != '.csv':
155
+ continue
156
+ f = open(os.path.join(directory, filename), 'rb')
157
+ csvreader = csv.reader(f)
158
+ data = load_csv(csvreader, allow_python=allow_python,
159
+ default_type=default_type,
160
+ default_class=base,
161
+ allow_multiple_classes=allow_multiple_classes)
162
+ f.close()
163
+ for classname, items in data.items():
164
+ results.setdefault(classname, []).extend(items)
165
+ return results
166
+
167
+
168
+ def load_csv(csvreader, allow_python=True, default_type=DEFAULT_TYPE,
169
+ default_class=None, allow_multiple_classes=True):
170
+ """
171
+ Loads the CSV file, returning a list of dictionaries with types
172
+ coerced.
173
+ """
174
+ current_class = default_class
175
+ current_headers = None
176
+ results = {}
177
+
178
+ for row in csvreader:
179
+ if not [cell for cell in row if cell.strip()]:
180
+ # empty row
181
+ continue
182
+
183
+ if row and row[0].strip() == 'CLASS:':
184
+ if not allow_multiple_classes:
185
+ raise ValueError(
186
+ "CLASS: line in CSV file, but multiple classes "
187
+ "are not allowed in this file (line: %r)" % row)
188
+ if not row[1:]:
189
+ raise ValueError(
190
+ "CLASS: in line in CSV file, with no class name "
191
+ "in next column (line: %r)" % row)
192
+ current_class = row[1]
193
+ current_headers = None
194
+ continue
195
+
196
+ if not current_class:
197
+ raise ValueError(
198
+ "No CLASS: line given, and there is no default class "
199
+ "for this file (line: %r)" % row)
200
+
201
+ if current_headers is None:
202
+ current_headers = _parse_headers(row, default_type,
203
+ allow_python=allow_python)
204
+ continue
205
+
206
+ if row[0] == '[comment]':
207
+ continue
208
+
209
+ # Pad row with empty strings:
210
+ row += [''] * (len(current_headers) - len(row))
211
+ row_converted = {}
212
+ for value, (name, coercer, args) in zip(row, current_headers):
213
+ if name is None:
214
+ # Comment
215
+ continue
216
+ if value == '[default]':
217
+ continue
218
+ if value == '[null]':
219
+ row_converted[name] = None
220
+ continue
221
+ args = (value,) + args
222
+ row_converted[name] = coercer(*args)
223
+
224
+ results.setdefault(current_class, []).append(row_converted)
225
+
226
+ return results
227
+
228
+
229
+ def _parse_headers(header_row, default_type, allow_python=True):
230
+ headers = []
231
+ for name in header_row:
232
+ original_name = name
233
+ if ':' in name:
234
+ name, type = name.split(':', 1)
235
+ else:
236
+ type = default_type
237
+ if type == 'python' and not allow_python:
238
+ raise ValueError(
239
+ ":python header given when python headers are not allowed "
240
+ "(with header %r)" % original_name)
241
+ name = name.strip()
242
+ if name == '[comment]' or not name:
243
+ headers.append((None, None, None))
244
+ continue
245
+ type = type.strip().lower()
246
+ if '(' in type:
247
+ type, arg = type.split('(', 1)
248
+ if not arg.endswith(')'):
249
+ raise ValueError(
250
+ "Arguments (in ()'s) do not end with ): %r"
251
+ % original_name)
252
+ args = (arg[:-1],)
253
+ else:
254
+ args = ()
255
+ if name == '[name]':
256
+ type = 'str'
257
+ coercer, args = get_coercer(type)
258
+ headers.append((name, coercer, args))
259
+ return headers
260
+
261
+
262
+ _coercers = {}
263
+
264
+
265
+ def get_coercer(type):
266
+ if type not in _coercers:
267
+ raise ValueError(
268
+ "Coercion type %r not known (I know: %s)"
269
+ % (type, ', '.join(_coercers.keys())))
270
+ return _coercers[type]
271
+
272
+
273
+ def register_coercer(type, coercer, *args):
274
+ _coercers[type] = (coercer, args)
275
+
276
+
277
+ def identity(v):
278
+ return v
279
+
280
+ register_coercer('str', identity)
281
+ register_coercer('string', identity)
282
+
283
+
284
+ def decode_string(v, encoding):
285
+ return v.decode(encoding)
286
+
287
+ register_coercer('escaped', decode_string, 'string_escape')
288
+ register_coercer('strescaped', decode_string, 'string_escape')
289
+ register_coercer('base64', decode_string, 'base64')
290
+
291
+ register_coercer('int', int)
292
+ register_coercer('float', float)
293
+
294
+
295
+ def parse_python(v):
296
+ return eval(v, {}, {})
297
+
298
+ register_coercer('python', parse_python)
299
+
300
+
301
+ def parse_date(v):
302
+ v = v.strip()
303
+ if not v:
304
+ return None
305
+ if v.startswith('NOW-') or v.startswith('NOW+'):
306
+ days = int(v[3:])
307
+ now = date.today()
308
+ return now + timedelta(days)
309
+ else:
310
+ parsed = time.strptime(v, '%Y-%m-%d')
311
+ return date.fromtimestamp(time.mktime(parsed))
312
+
313
+ register_coercer('date', parse_date)
314
+
315
+
316
+ def parse_datetime(v):
317
+ v = v.strip()
318
+ if not v:
319
+ return None
320
+ if v.startswith('NOW-') or v.startswith('NOW+'):
321
+ seconds = int(v[3:])
322
+ now = datetime.now()
323
+ return now + timedelta(0, seconds)
324
+ else:
325
+ fmts = ['%Y-%m-%dT%H:%M:%S',
326
+ '%Y-%m-%d %H:%M:%S',
327
+ '%Y-%m-%dT%H:%M',
328
+ '%Y-%m-%d %H:%M']
329
+ for fmt in fmts[:-1]:
330
+ try:
331
+ parsed = time.strptime(v, fmt)
332
+ break
333
+ except ValueError:
334
+ pass
335
+ else:
336
+ parsed = time.strptime(v, fmts[-1])
337
+ return datetime.fromtimestamp(time.mktime(parsed))
338
+
339
+ register_coercer('datetime', parse_datetime)
340
+
341
+
342
+ class Reference(object):
343
+ def __init__(self, name):
344
+ self.name = name
345
+
346
+
347
+ def parse_ref(v):
348
+ if not v.strip():
349
+ return None
350
+ else:
351
+ return Reference(v)
352
+
353
+ register_coercer('ref', parse_ref)
354
+
355
+
356
+ def parse_bool(v):
357
+ v = v.strip().lower()
358
+ if v in ('y', 'yes', 't', 'true', 'on', '1'):
359
+ return True
360
+ elif v in ('n', 'no', 'f', 'false', 'off', '0'):
361
+ return False
362
+ raise ValueError(
363
+ "Value is not boolean-like: %r" % v)
364
+
365
+ register_coercer('bool', parse_bool)
366
+ register_coercer('boolean', parse_bool)
@@ -0,0 +1,35 @@
1
+ import os
2
+ import sys
3
+ from sqlobject.compat import load_module_from_file
4
+
5
+
6
+ def load_module(module_name):
7
+ mod = __import__(module_name)
8
+ components = module_name.split('.')
9
+ for comp in components[1:]:
10
+ mod = getattr(mod, comp)
11
+ return mod
12
+
13
+
14
+ def load_module_from_name(filename, module_name):
15
+ if module_name in sys.modules:
16
+ return sys.modules[module_name]
17
+ init_filename = os.path.join(os.path.dirname(filename), '__init__.py')
18
+ if not os.path.exists(init_filename):
19
+ try:
20
+ f = open(init_filename, 'w')
21
+ except (OSError, IOError) as e:
22
+ raise IOError(
23
+ 'Cannot write __init__.py file into directory %s (%s)\n'
24
+ % (os.path.dirname(filename), e))
25
+ f.write('#\n')
26
+ f.close()
27
+ if module_name in sys.modules:
28
+ return sys.modules[module_name]
29
+ if '.' in module_name:
30
+ parent_name = '.'.join(module_name.split('.')[:-1])
31
+ base_name = module_name.split('.')[-1]
32
+ load_module_from_name(os.path.dirname(filename), parent_name)
33
+ else:
34
+ base_name = module_name
35
+ return load_module_from_file(base_name, module_name, filename)
@@ -0,0 +1,6 @@
1
+ try:
2
+ from threading import local
3
+ except ImportError:
4
+ # No threads, so "thread local" means process-global
5
+ class local(object):
6
+ pass