lsst-felis 27.2024.2500__py3-none-any.whl → 27.2024.2600__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.

Potentially problematic release.


This version of lsst-felis might be problematic. Click here for more details.

felis/db/dialects.py CHANGED
@@ -1,3 +1,5 @@
1
+ """Get SQLAlchemy dialects and their type modules."""
2
+
1
3
  # This file is part of felis.
2
4
  #
3
5
  # Developed for the LSST Data Management System.
@@ -19,8 +21,10 @@
19
21
  # You should have received a copy of the GNU General Public License
20
22
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
21
23
 
22
- import logging
23
- from types import ModuleType
24
+ from __future__ import annotations
25
+
26
+ from collections.abc import Mapping
27
+ from types import MappingProxyType, ModuleType
24
28
 
25
29
  from sqlalchemy import dialects
26
30
  from sqlalchemy.engine import Dialect
@@ -28,36 +32,85 @@ from sqlalchemy.engine.mock import create_mock_engine
28
32
 
29
33
  from .sqltypes import MYSQL, ORACLE, POSTGRES, SQLITE
30
34
 
31
- logger = logging.getLogger(__name__)
35
+ __all__ = ["get_supported_dialects", "get_dialect_module"]
36
+
37
+ _DIALECT_NAMES = (MYSQL, POSTGRES, SQLITE, ORACLE)
38
+ """List of supported dialect names.
32
39
 
33
- _DIALECT_NAMES = [MYSQL, POSTGRES, SQLITE, ORACLE]
40
+ This list is used to create the dialect and module dictionaries.
41
+ """
34
42
 
35
43
 
36
44
  def _dialect(dialect_name: str) -> Dialect:
37
- """Create the SQLAlchemy dialect for the given name."""
45
+ """Create the SQLAlchemy dialect for the given name using a mock engine.
46
+
47
+ Parameters
48
+ ----------
49
+ dialect_name
50
+ The name of the dialect to create.
51
+
52
+ Returns
53
+ -------
54
+ `~sqlalchemy.engine.Dialect`
55
+ The SQLAlchemy dialect.
56
+ """
38
57
  return create_mock_engine(f"{dialect_name}://", executor=None).dialect
39
58
 
40
59
 
41
- _DIALECTS = {name: _dialect(name) for name in _DIALECT_NAMES}
60
+ _DIALECTS = MappingProxyType({name: _dialect(name) for name in _DIALECT_NAMES})
42
61
  """Dictionary of dialect names to SQLAlchemy dialects."""
43
62
 
44
63
 
45
- def get_supported_dialects() -> dict[str, Dialect]:
46
- """Get a dictionary of the supported SQLAlchemy dialects."""
64
+ def get_supported_dialects() -> Mapping[str, Dialect]:
65
+ """Get a dictionary of the supported SQLAlchemy dialects.
66
+
67
+ Returns
68
+ -------
69
+ `dict` [ `str`, `~sqlalchemy.engine.Dialect`]
70
+ A dictionary of the supported SQLAlchemy dialects.
71
+
72
+ Notes
73
+ -----
74
+ The dictionary is keyed by the dialect name and the value is the SQLAlchemy
75
+ dialect object. This function is intended as the primary interface for
76
+ getting the supported dialects.
77
+ """
47
78
  return _DIALECTS
48
79
 
49
80
 
50
81
  def _dialect_module(dialect_name: str) -> ModuleType:
51
- """Get the SQLAlchemy dialect module for the given name."""
82
+ """Get the SQLAlchemy dialect module for the given name.
83
+
84
+ Parameters
85
+ ----------
86
+ dialect_name
87
+ The name of the dialect module to get from the SQLAlchemy package.
88
+ """
52
89
  return getattr(dialects, dialect_name)
53
90
 
54
91
 
55
- _DIALECT_MODULES = {name: _dialect_module(name) for name in _DIALECT_NAMES}
56
- """Dictionary of dialect names to SQLAlchemy modules for type instantiation."""
92
+ _DIALECT_MODULES = MappingProxyType({name: _dialect_module(name) for name in _DIALECT_NAMES})
93
+ """Dictionary of dialect names to SQLAlchemy modules."""
57
94
 
58
95
 
59
96
  def get_dialect_module(dialect_name: str) -> ModuleType:
60
- """Get the SQLAlchemy dialect module for the given name."""
97
+ """Get the SQLAlchemy dialect module for the given name.
98
+
99
+ Parameters
100
+ ----------
101
+ dialect_name
102
+ The name of the dialect module to get from the SQLAlchemy package.
103
+
104
+ Returns
105
+ -------
106
+ `~types.ModuleType`
107
+ The SQLAlchemy dialect module.
108
+
109
+ Raises
110
+ ------
111
+ ValueError
112
+ If the dialect name is not supported.
113
+ """
61
114
  if dialect_name not in _DIALECT_MODULES:
62
115
  raise ValueError(f"Unsupported dialect: {dialect_name}")
63
116
  return _DIALECT_MODULES[dialect_name]
felis/db/sqltypes.py CHANGED
@@ -1,3 +1,5 @@
1
+ """Map Felis types to SQLAlchemy types."""
2
+
1
3
  # This file is part of felis.
2
4
  #
3
5
  # Developed for the LSST Data Management System.
@@ -19,6 +21,8 @@
19
21
  # You should have received a copy of the GNU General Public License
20
22
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
21
23
 
24
+ from __future__ import annotations
25
+
22
26
  import builtins
23
27
  from collections.abc import Callable, Mapping
24
28
  from typing import Any
@@ -27,6 +31,23 @@ from sqlalchemy import SmallInteger, types
27
31
  from sqlalchemy.dialects import mysql, oracle, postgresql
28
32
  from sqlalchemy.ext.compiler import compiles
29
33
 
34
+ __all__ = [
35
+ "boolean",
36
+ "byte",
37
+ "short",
38
+ "int",
39
+ "long",
40
+ "float",
41
+ "double",
42
+ "char",
43
+ "string",
44
+ "unicode",
45
+ "text",
46
+ "binary",
47
+ "timestamp",
48
+ "get_type_func",
49
+ ]
50
+
30
51
  MYSQL = "mysql"
31
52
  ORACLE = "oracle"
32
53
  POSTGRES = "postgresql"
@@ -40,8 +61,28 @@ class TINYINT(SmallInteger):
40
61
 
41
62
 
42
63
  @compiles(TINYINT)
43
- def compile_tinyint(type_: Any, compiler: Any, **kw: Any) -> str:
44
- """Return type name for TINYINT."""
64
+ def compile_tinyint(type_: Any, compiler: Any, **kwargs: Any) -> str:
65
+ """Compile the non-standard ``TINYINT`` type to SQL.
66
+
67
+ Parameters
68
+ ----------
69
+ type_
70
+ The type object.
71
+ compiler
72
+ The compiler object.
73
+ **kwargs
74
+ Additional keyword arguments.
75
+
76
+ Returns
77
+ -------
78
+ `str`
79
+ The compiled SQL for TINYINT.
80
+
81
+ Notes
82
+ -----
83
+ This function returns the SQL for the the TINYINT type. The function
84
+ signature and parameters are defined by SQLAlchemy.
85
+ """
45
86
  return "TINYINT"
46
87
 
47
88
 
@@ -117,72 +158,245 @@ binary_map: _TypeMap = {
117
158
 
118
159
 
119
160
  def boolean(**kwargs: Any) -> types.TypeEngine:
120
- """Return SQLAlchemy type for boolean."""
161
+ """Get the SQL type for Felis `~felis.types.Boolean` with variants.
162
+
163
+ Parameters
164
+ ----------
165
+ **kwargs
166
+ Additional keyword arguments to pass to the type object.
167
+
168
+ Returns
169
+ -------
170
+ `~sqlalchemy.types.TypeEngine`
171
+ The SQL type for a Felis boolean.
172
+ """
121
173
  return _vary(types.BOOLEAN(), boolean_map, kwargs)
122
174
 
123
175
 
124
176
  def byte(**kwargs: Any) -> types.TypeEngine:
125
- """Return SQLAlchemy type for byte."""
177
+ """Get the SQL type for Felis `~felis.types.Byte` with variants.
178
+
179
+ Parameters
180
+ ----------
181
+ **kwargs
182
+ Additional keyword arguments to pass to the type object.
183
+
184
+ Returns
185
+ -------
186
+ `~sqlalchemy.types.TypeEngine`
187
+ The SQL type for a Felis byte.
188
+ """
126
189
  return _vary(TINYINT(), byte_map, kwargs)
127
190
 
128
191
 
129
192
  def short(**kwargs: Any) -> types.TypeEngine:
130
- """Return SQLAlchemy type for short integer."""
193
+ """Get the SQL type for Felis `~felis.types.Short` with variants.
194
+
195
+ Parameters
196
+ ----------
197
+ **kwargs
198
+ Additional keyword arguments to pass to the type object.
199
+
200
+ Returns
201
+ -------
202
+ `~sqlalchemy.types.TypeEngine`
203
+ The SQL type for a Felis short.
204
+ """
131
205
  return _vary(types.SMALLINT(), short_map, kwargs)
132
206
 
133
207
 
134
208
  def int(**kwargs: Any) -> types.TypeEngine:
135
- """Return SQLAlchemy type for integer."""
209
+ """Get the SQL type for Felis `~felis.types.Int` with variants.
210
+
211
+ Parameters
212
+ ----------
213
+ **kwargs
214
+ Additional keyword arguments to pass to the type object.
215
+
216
+ Returns
217
+ -------
218
+ `~sqlalchemy.types.TypeEngine`
219
+ The SQL type for a Felis int.
220
+ """
136
221
  return _vary(types.INTEGER(), int_map, kwargs)
137
222
 
138
223
 
139
224
  def long(**kwargs: Any) -> types.TypeEngine:
140
- """Return SQLAlchemy type for long integer."""
225
+ """Get the SQL type for Felis `~felis.types.Long` with variants.
226
+
227
+ Parameters
228
+ ----------
229
+ **kwargs
230
+ Additional keyword arguments to pass to the type object.
231
+
232
+ Returns
233
+ -------
234
+ `~sqlalchemy.types.TypeEngine`
235
+ The SQL type for a Felis long.
236
+ """
141
237
  return _vary(types.BIGINT(), long_map, kwargs)
142
238
 
143
239
 
144
240
  def float(**kwargs: Any) -> types.TypeEngine:
145
- """Return SQLAlchemy type for single precision float."""
241
+ """Get the SQL type for Felis `~felis.types.Float` with variants.
242
+
243
+ Parameters
244
+ ----------
245
+ **kwargs
246
+ Additional keyword arguments to pass to the type object.
247
+
248
+ Returns
249
+ -------
250
+ `~sqlalchemy.types.TypeEngine`
251
+ The SQL type for a Felis float.
252
+ """
146
253
  return _vary(types.FLOAT(), float_map, kwargs)
147
254
 
148
255
 
149
256
  def double(**kwargs: Any) -> types.TypeEngine:
150
- """Return SQLAlchemy type for double precision float."""
257
+ """Get the SQL type for Felis `~felis.types.Double` with variants.
258
+
259
+ Parameters
260
+ ----------
261
+ **kwargs
262
+ Additional keyword arguments to pass to the type object.
263
+
264
+ Returns
265
+ -------
266
+ `~sqlalchemy.types.TypeEngine`
267
+ The SQL type for a Felis double.
268
+ """
151
269
  return _vary(types.DOUBLE(), double_map, kwargs)
152
270
 
153
271
 
154
272
  def char(length: builtins.int, **kwargs: Any) -> types.TypeEngine:
155
- """Return SQLAlchemy type for character."""
273
+ """Get the SQL type for Felis `~felis.types.Char` with variants.
274
+
275
+ Parameters
276
+ ----------
277
+ length
278
+ The length of the character field.
279
+ **kwargs
280
+ Additional keyword arguments to pass to the type object.
281
+
282
+ Returns
283
+ -------
284
+ `~sqlalchemy.types.TypeEngine`
285
+ The SQL type for a Felis char.
286
+ """
156
287
  return _vary(types.CHAR(length), char_map, kwargs, length)
157
288
 
158
289
 
159
290
  def string(length: builtins.int, **kwargs: Any) -> types.TypeEngine:
160
- """Return SQLAlchemy type for string."""
291
+ """Get the SQL type for Felis `~felis.types.String` with variants.
292
+
293
+ Parameters
294
+ ----------
295
+ length
296
+ The length of the string field.
297
+ **kwargs
298
+ Additional keyword arguments to pass to the type object.
299
+
300
+ Returns
301
+ -------
302
+ `~sqlalchemy.types.TypeEngine`
303
+ The SQL type for a Felis string.
304
+ """
161
305
  return _vary(types.VARCHAR(length), string_map, kwargs, length)
162
306
 
163
307
 
164
308
  def unicode(length: builtins.int, **kwargs: Any) -> types.TypeEngine:
165
- """Return SQLAlchemy type for unicode string."""
309
+ """Get the SQL type for Felis `~felis.types.Unicode` with variants.
310
+
311
+ Parameters
312
+ ----------
313
+ length
314
+ The length of the unicode string field.
315
+ **kwargs
316
+ Additional keyword arguments to pass to the type object.
317
+
318
+ Returns
319
+ -------
320
+ `~sqlalchemy.types.TypeEngine`
321
+ The SQL type for a Felis unicode string.
322
+ """
166
323
  return _vary(types.NVARCHAR(length), unicode_map, kwargs, length)
167
324
 
168
325
 
169
326
  def text(**kwargs: Any) -> types.TypeEngine:
170
- """Return SQLAlchemy type for text."""
327
+ """Get the SQL type for Felis `~felis.types.Text` with variants.
328
+
329
+ Parameters
330
+ ----------
331
+ **kwargs
332
+ Additional keyword arguments to pass to the type object.
333
+
334
+ Returns
335
+ -------
336
+ `~sqlalchemy.types.TypeEngine`
337
+ The SQL type for Felis text.
338
+ """
171
339
  return _vary(types.TEXT(), text_map, kwargs)
172
340
 
173
341
 
174
342
  def binary(length: builtins.int, **kwargs: Any) -> types.TypeEngine:
175
- """Return SQLAlchemy type for binary."""
343
+ """Get the SQL type for Felis `~felis.types.Binary` with variants.
344
+
345
+ Parameters
346
+ ----------
347
+ length
348
+ The length of the binary field.
349
+ **kwargs
350
+ Additional keyword arguments to pass to the type object.
351
+
352
+ Returns
353
+ -------
354
+ `~sqlalchemy.types.TypeEngine`
355
+ The SQL type for Felis binary.
356
+ """
176
357
  return _vary(types.BLOB(length), binary_map, kwargs, length)
177
358
 
178
359
 
179
360
  def timestamp(**kwargs: Any) -> types.TypeEngine:
180
- """Return SQLAlchemy type for timestamp."""
361
+ """Get the SQL type for Felis `~felis.types.Timestamp` with variants.
362
+
363
+ Parameters
364
+ ----------
365
+ **kwargs
366
+ Additional keyword arguments to pass to the type object.
367
+
368
+ Returns
369
+ -------
370
+ `~sqlalchemy.types.TypeEngine`
371
+ The SQL type for a Felis timestamp.
372
+ """
181
373
  return types.TIMESTAMP()
182
374
 
183
375
 
184
376
  def get_type_func(type_name: str) -> Callable:
185
- """Return the function for the type with the given name."""
377
+ """Find the function which creates a specific SQL type by its Felis type
378
+ name.
379
+
380
+ Parameters
381
+ ----------
382
+ type_name
383
+ The name of the type function to get.
384
+
385
+ Returns
386
+ -------
387
+ `Callable`
388
+ The function for the type.
389
+
390
+ Raises
391
+ ------
392
+ ValueError
393
+ If the type name is not recognized.
394
+
395
+ Notes
396
+ -----
397
+ This maps the type name to the function that creates the SQL type. This is
398
+ the main way to get the type functions from the type names.
399
+ """
186
400
  if type_name not in globals():
187
401
  raise ValueError(f"Unknown type: {type_name}")
188
402
  return globals()[type_name]
@@ -194,6 +408,31 @@ def _vary(
194
408
  overrides: _TypeMap,
195
409
  *args: Any,
196
410
  ) -> types.TypeEngine:
411
+ """Add datatype variants and overrides to a SQLAlchemy type.
412
+
413
+ Parameters
414
+ ----------
415
+ type_
416
+ The base SQLAlchemy type object. This is essentially a default
417
+ SQLAlchemy ``TypeEngine`` object, which will apply if there is no
418
+ variant or type override from the schema.
419
+ variant_map
420
+ The dictionary of dialects to types. Each key is a string representing
421
+ a dialect name, and each value is either an instance of
422
+ ``TypeEngine`` representing the variant type object or a callable
423
+ reference to its class type that will be instantiated later.
424
+ overrides
425
+ The dictionary of dialects to types to override the defaults. Each key
426
+ is a string representing a dialect name and type with a similar
427
+ structure as the `variant_map`.
428
+ args
429
+ The extra arguments to pass to the type object.
430
+
431
+ Notes
432
+ -----
433
+ This function is intended for internal use only. It builds a SQLAlchemy
434
+ ``TypeEngine`` that includes variants and overrides defined by Felis.
435
+ """
197
436
  variants: dict[str, types.TypeEngine | type[types.TypeEngine]] = dict(variant_map)
198
437
  variants.update(overrides)
199
438
  for dialect, variant in variants.items():