lsst-felis 27.2024.2600__py3-none-any.whl → 27.2024.2800__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/datamodel.py CHANGED
@@ -141,6 +141,13 @@ class Column(BaseObject):
141
141
  length: int | None = Field(None, gt=0)
142
142
  """Length of the column."""
143
143
 
144
+ precision: int | None = Field(None, ge=0)
145
+ """The numerical precision of the column.
146
+
147
+ For timestamps, this is the number of fractional digits retained in the
148
+ seconds field.
149
+ """
150
+
144
151
  nullable: bool = True
145
152
  """Whether the column can be ``NULL``."""
146
153
 
@@ -363,6 +370,19 @@ class Column(BaseObject):
363
370
  )
364
371
  return self
365
372
 
373
+ @model_validator(mode="after")
374
+ def check_precision(self) -> Column:
375
+ """Check that precision is only valid for timestamp columns.
376
+
377
+ Returns
378
+ -------
379
+ `Column`
380
+ The column being validated.
381
+ """
382
+ if self.precision is not None and self.datatype != "timestamp":
383
+ raise ValueError("Precision is only valid for timestamp columns")
384
+ return self
385
+
366
386
 
367
387
  class Constraint(BaseObject):
368
388
  """Table constraint model."""
felis/db/sqltypes.py CHANGED
@@ -156,6 +156,11 @@ binary_map: _TypeMap = {
156
156
  POSTGRES: postgresql.BYTEA,
157
157
  }
158
158
 
159
+ timestamp_map: _TypeMap = {
160
+ MYSQL: mysql.DATETIME(timezone=False),
161
+ POSTGRES: postgresql.TIMESTAMP(timezone=False),
162
+ }
163
+
159
164
 
160
165
  def boolean(**kwargs: Any) -> types.TypeEngine:
161
166
  """Get the SQL type for Felis `~felis.types.Boolean` with variants.
@@ -370,7 +375,7 @@ def timestamp(**kwargs: Any) -> types.TypeEngine:
370
375
  `~sqlalchemy.types.TypeEngine`
371
376
  The SQL type for a Felis timestamp.
372
377
  """
373
- return types.TIMESTAMP()
378
+ return _vary(types.TIMESTAMP(timezone=False), timestamp_map, kwargs)
374
379
 
375
380
 
376
381
  def get_type_func(type_name: str) -> Callable:
felis/db/utils.py CHANGED
@@ -299,6 +299,6 @@ class DatabaseContext:
299
299
  The mock connection object.
300
300
  """
301
301
  writer = SQLWriter(output_file)
302
- engine = create_mock_engine(engine_url, executor=writer.write)
302
+ engine = create_mock_engine(engine_url, executor=writer.write, paramstyle="pyformat")
303
303
  writer.dialect = engine.dialect
304
304
  return engine
felis/metadata.py CHANGED
@@ -40,6 +40,7 @@ from sqlalchemy import (
40
40
  UniqueConstraint,
41
41
  text,
42
42
  )
43
+ from sqlalchemy.dialects import mysql, postgresql
43
44
  from sqlalchemy.types import TypeEngine
44
45
 
45
46
  from felis.datamodel import Schema
@@ -54,6 +55,28 @@ __all__ = ("MetaDataBuilder", "get_datatype_with_variants")
54
55
  logger = logging.getLogger(__name__)
55
56
 
56
57
 
58
+ def _handle_timestamp_column(column_obj: datamodel.Column, variant_dict: dict[str, TypeEngine[Any]]) -> None:
59
+ """Handle columns with the timestamp datatype.
60
+
61
+ Parameters
62
+ ----------
63
+ column_obj
64
+ The column object representing the timestamp.
65
+ variant_dict
66
+ The dictionary of variant overrides for the datatype.
67
+
68
+ Notes
69
+ -----
70
+ This function updates the variant dictionary with the appropriate
71
+ timestamp type for the column object but only if the precision is set.
72
+ Otherwise, the default timestamp objects defined in the Felis type system
73
+ will be used instead.
74
+ """
75
+ if column_obj.precision is not None:
76
+ args: Any = [False, column_obj.precision] # Turn off timezone.
77
+ variant_dict.update({"postgresql": postgresql.TIMESTAMP(*args), "mysql": mysql.DATETIME(*args)})
78
+
79
+
57
80
  def get_datatype_with_variants(column_obj: datamodel.Column) -> TypeEngine:
58
81
  """Use the Felis type system to get a SQLAlchemy datatype with variant
59
82
  overrides from the information in a Felis column object.
@@ -71,18 +94,23 @@ def get_datatype_with_variants(column_obj: datamodel.Column) -> TypeEngine:
71
94
  Raises
72
95
  ------
73
96
  ValueError
74
- If the column has a sized type but no length.
97
+ If the column has a sized type but no length or if the datatype is
98
+ invalid.
75
99
  """
76
100
  variant_dict = make_variant_dict(column_obj)
77
101
  felis_type = FelisType.felis_type(column_obj.datatype.value)
78
- datatype_fun = getattr(sqltypes, column_obj.datatype.value)
102
+ datatype_fun = getattr(sqltypes, column_obj.datatype.value, None)
103
+ if datatype_fun is None:
104
+ raise ValueError(f"Unknown datatype: {column_obj.datatype.value}")
105
+ args = []
79
106
  if felis_type.is_sized:
107
+ # Add length argument for size types.
80
108
  if not column_obj.length:
81
109
  raise ValueError(f"Column {column_obj.name} has sized type '{column_obj.datatype}' but no length")
82
- datatype = datatype_fun(column_obj.length, **variant_dict)
83
- else:
84
- datatype = datatype_fun(**variant_dict)
85
- return datatype
110
+ args = [column_obj.length]
111
+ if felis_type.is_timestamp:
112
+ _handle_timestamp_column(column_obj, variant_dict)
113
+ return datatype_fun(*args, **variant_dict)
86
114
 
87
115
 
88
116
  _VALID_SERVER_DEFAULTS = ("CURRENT_TIMESTAMP", "NOW()", "LOCALTIMESTAMP", "NULL")
felis/version.py CHANGED
@@ -1,2 +1,2 @@
1
1
  __all__ = ["__version__"]
2
- __version__ = "27.2024.2600"
2
+ __version__ = "27.2024.2800"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lsst-felis
3
- Version: 27.2024.2600
3
+ Version: 27.2024.2800
4
4
  Summary: A vocabulary for describing catalogs and acting on those descriptions
5
5
  Author-email: Rubin Observatory Data Management <dm-admin@lists.lsst.org>
6
6
  License: GNU General Public License v3 or later (GPLv3+)
@@ -0,0 +1,21 @@
1
+ felis/__init__.py,sha256=THmRg3ylB4E73XhFjJX7YlnV_CM3lr_gZO_HqQFzIQ4,937
2
+ felis/cli.py,sha256=i5FlA9OBecqHP4SISngaveQ7YbWH8pxRGHeOzMOOMyg,14086
3
+ felis/datamodel.py,sha256=BajYwp2rk0j3P4KSc2T9Acnk9p9pjzXiKgZG2c_OuZI,26517
4
+ felis/metadata.py,sha256=8r2LM86kdJLSuI0_t--oE3OtRPf-s5aH3FeIDDDAPZ8,13414
5
+ felis/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ felis/tap.py,sha256=YBWl1CicdN4jW_KhPJQ7-TuhOfFFTIYIH4tTJ8P_o1c,21035
7
+ felis/types.py,sha256=m80GSGfNHQ3-NzRuTzKOyRXLJboPxdk9kzpp1SO8XdY,5510
8
+ felis/version.py,sha256=yUl4M-EIGpU6iDSDVfXNp4Wf1kDc1_9Neo9VCBg7Ph8,55
9
+ felis/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ felis/db/dialects.py,sha256=IsjdD_2n7tucUdR7TMyRd2gWtnD-2kXPAJUUQdbUe_Q,3526
11
+ felis/db/sqltypes.py,sha256=VuBfstnBGOnr0RuSN0XhzXjSr2MaAmgJWuiWuf_7g2A,11418
12
+ felis/db/utils.py,sha256=_vWVsPsq_kVl-WQuDeoLY3ZxElGCCEzPp3tfBTENGB8,10200
13
+ felis/db/variants.py,sha256=o5m101upQQbWZD_l8qlB8gt-ZQ9-VqsWZrmxQO1eEQA,5246
14
+ lsst_felis-27.2024.2800.dist-info/COPYRIGHT,sha256=vJAFLFTSF1mhy9eIuA3P6R-3yxTWKQgpig88P-1IzRw,129
15
+ lsst_felis-27.2024.2800.dist-info/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
16
+ lsst_felis-27.2024.2800.dist-info/METADATA,sha256=B5KUETflTJuITLE5h9ljJ6aDsA9mtlHemnxJfi7StW4,1288
17
+ lsst_felis-27.2024.2800.dist-info/WHEEL,sha256=Z4pYXqR_rTB7OWNDYFOm1qRk0RX6GFP2o8LgvP453Hk,91
18
+ lsst_felis-27.2024.2800.dist-info/entry_points.txt,sha256=Gk2XFujA_Gp52VBk45g5kim8TDoMDJFPctsMqiq72EM,40
19
+ lsst_felis-27.2024.2800.dist-info/top_level.txt,sha256=F4SvPip3iZRVyISi50CHhwTIAokAhSxjWiVcn4IVWRI,6
20
+ lsst_felis-27.2024.2800.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
21
+ lsst_felis-27.2024.2800.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (70.1.1)
2
+ Generator: setuptools (70.3.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,21 +0,0 @@
1
- felis/__init__.py,sha256=THmRg3ylB4E73XhFjJX7YlnV_CM3lr_gZO_HqQFzIQ4,937
2
- felis/cli.py,sha256=i5FlA9OBecqHP4SISngaveQ7YbWH8pxRGHeOzMOOMyg,14086
3
- felis/datamodel.py,sha256=k0wAZpIhwOWVvAlHLLpzCOYYxY5iD8jpjlOu_lpzv-4,25902
4
- felis/metadata.py,sha256=W1Y4s7izAEiH3MLJkKQpvxHsGE5Dbu4lhhNCzWlfl0o,12290
5
- felis/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- felis/tap.py,sha256=YBWl1CicdN4jW_KhPJQ7-TuhOfFFTIYIH4tTJ8P_o1c,21035
7
- felis/types.py,sha256=m80GSGfNHQ3-NzRuTzKOyRXLJboPxdk9kzpp1SO8XdY,5510
8
- felis/version.py,sha256=aahBy2OK7EjIKUv__rAtLwgu_sqkTymTjJ8WETh6OXg,55
9
- felis/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- felis/db/dialects.py,sha256=IsjdD_2n7tucUdR7TMyRd2gWtnD-2kXPAJUUQdbUe_Q,3526
11
- felis/db/sqltypes.py,sha256=sDzkqemYwILp8hk0yfg3H0ZK7bGnIJR9x6ntd2coASc,11248
12
- felis/db/utils.py,sha256=TgNJTBv2Jt4Qq_RtOO_jWj_02tb-fEA2QeOOHYS1GyU,10177
13
- felis/db/variants.py,sha256=o5m101upQQbWZD_l8qlB8gt-ZQ9-VqsWZrmxQO1eEQA,5246
14
- lsst_felis-27.2024.2600.dist-info/COPYRIGHT,sha256=vJAFLFTSF1mhy9eIuA3P6R-3yxTWKQgpig88P-1IzRw,129
15
- lsst_felis-27.2024.2600.dist-info/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
16
- lsst_felis-27.2024.2600.dist-info/METADATA,sha256=9To3B_2DA9ZePgBiyIx999RjfjcXgwNyUd1IH81yOdo,1288
17
- lsst_felis-27.2024.2600.dist-info/WHEEL,sha256=mguMlWGMX-VHnMpKOjjQidIo1ssRlCFu4a4mBpz1s2M,91
18
- lsst_felis-27.2024.2600.dist-info/entry_points.txt,sha256=Gk2XFujA_Gp52VBk45g5kim8TDoMDJFPctsMqiq72EM,40
19
- lsst_felis-27.2024.2600.dist-info/top_level.txt,sha256=F4SvPip3iZRVyISi50CHhwTIAokAhSxjWiVcn4IVWRI,6
20
- lsst_felis-27.2024.2600.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
21
- lsst_felis-27.2024.2600.dist-info/RECORD,,