lsst-felis 27.2024.2400__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/tap.py CHANGED
@@ -1,3 +1,5 @@
1
+ """Translate a Felis schema into a TAP_SCHEMA representation."""
2
+
1
3
  # This file is part of felis.
2
4
  #
3
5
  # Developed for the LSST Data Management System.
@@ -21,8 +23,6 @@
21
23
 
22
24
  from __future__ import annotations
23
25
 
24
- __all__ = ["Tap11Base", "TapLoadingVisitor", "init_tables"]
25
-
26
26
  import logging
27
27
  from collections.abc import Iterable, MutableMapping
28
28
  from typing import Any
@@ -39,9 +39,12 @@ from felis import datamodel
39
39
  from .datamodel import Constraint, Index, Schema, Table
40
40
  from .types import FelisType
41
41
 
42
- Tap11Base: Any = declarative_base() # Any to avoid mypy mess with SA 2
42
+ __all__ = ["TapLoadingVisitor", "init_tables"]
43
+
43
44
  logger = logging.getLogger(__name__)
44
45
 
46
+ Tap11Base: Any = declarative_base() # Any to avoid mypy mess with SA 2
47
+
45
48
  IDENTIFIER_LENGTH = 128
46
49
  SMALL_FIELD_LENGTH = 32
47
50
  SIMPLE_FIELD_LENGTH = 128
@@ -60,7 +63,30 @@ def init_tables(
60
63
  tap_keys_table: str | None = None,
61
64
  tap_key_columns_table: str | None = None,
62
65
  ) -> MutableMapping[str, Any]:
63
- """Generate definitions for TAP tables."""
66
+ """Generate definitions for TAP tables.
67
+
68
+ Parameters
69
+ ----------
70
+ tap_schema_name
71
+ Name of the TAP schema.
72
+ tap_tables_postfix
73
+ Postfix for table names.
74
+ tap_schemas_table
75
+ Name of the schemas table.
76
+ tap_tables_table
77
+ Name of the tables table.
78
+ tap_columns_table
79
+ Name of the columns table.
80
+ tap_keys_table
81
+ Name of the keys table.
82
+ tap_key_columns_table
83
+ Name of the key columns table.
84
+
85
+ Returns
86
+ -------
87
+ `dict` [ `str`, `Any`]
88
+ A dictionary of table definitions.
89
+ """
64
90
  postfix = tap_tables_postfix or ""
65
91
 
66
92
  # Dirty hack to enable this method to be called more than once, replaces
@@ -133,18 +159,21 @@ def init_tables(
133
159
 
134
160
 
135
161
  class TapLoadingVisitor:
136
- """Felis schema visitor for generating TAP schema.
162
+ """Generate TAP_SCHEMA data and insert it into a database using the
163
+ SQLAlchemy ORM.
137
164
 
138
165
  Parameters
139
166
  ----------
140
- engine : `sqlalchemy.engine.Engine` or `None`
167
+ engine
141
168
  SQLAlchemy engine instance.
142
- catalog_name : `str` or `None`
169
+ catalog_name
143
170
  Name of the database catalog.
144
- schema_name : `str` or `None`
145
- Name of the database schema.
146
- tap_tables : `~collections.abc.Mapping`
147
- Optional mapping of table name to its declarative base class.
171
+ schema_name
172
+ Name of the schema.
173
+ tap_tables
174
+ Mapping of TAP_SCHEMA table name to its SQLAlchemy table object.
175
+ tap_schema_index
176
+ The index of the schema for this TAP environment.
148
177
  """
149
178
 
150
179
  def __init__(
@@ -154,7 +183,8 @@ class TapLoadingVisitor:
154
183
  schema_name: str | None = None,
155
184
  tap_tables: MutableMapping[str, Any] | None = None,
156
185
  tap_schema_index: int | None = None,
157
- ):
186
+ ) -> None:
187
+ """Create a TAP loading visitor."""
158
188
  self.graph_index: MutableMapping[str, Any] = {}
159
189
  self.catalog_name = catalog_name
160
190
  self.schema_name = schema_name
@@ -172,12 +202,39 @@ class TapLoadingVisitor:
172
202
  tap_tables: MutableMapping[str, Any] | None = None,
173
203
  tap_schema_index: int | None = None,
174
204
  ) -> TapLoadingVisitor:
205
+ """Create a TAP visitor from a mock connection.
206
+
207
+ Parameters
208
+ ----------
209
+ mock_connection
210
+ Mock connection object.
211
+ catalog_name
212
+ Name of the database catalog.
213
+ schema_name
214
+ Name of the database schema.
215
+ tap_tables
216
+ Optional mapping of table name to its SQLAlchemy table object.
217
+ tap_schema_index
218
+ The index of the schema for this TAP environment.
219
+
220
+ Returns
221
+ -------
222
+ `TapLoadingVisitor`
223
+ The TAP loading visitor.
224
+ """
175
225
  visitor = cls(engine=None, catalog_name=catalog_name, schema_name=schema_name, tap_tables=tap_tables)
176
226
  visitor._mock_connection = mock_connection
177
227
  visitor.tap_schema_index = tap_schema_index
178
228
  return visitor
179
229
 
180
230
  def visit_schema(self, schema_obj: Schema) -> None:
231
+ """Visit a schema object and insert it into the TAP_SCHEMA database.
232
+
233
+ Parameters
234
+ ----------
235
+ schema_obj
236
+ The schema object to visit.
237
+ """
181
238
  schema = self.tables["schemas"]()
182
239
  # Override with default
183
240
  self.schema_name = self.schema_name or schema_obj.name
@@ -226,6 +283,18 @@ class TapLoadingVisitor:
226
283
  conn.execute(_insert(self.tables["key_columns"], key_column))
227
284
 
228
285
  def visit_constraints(self, schema_obj: Schema) -> tuple:
286
+ """Visit all constraints in a schema.
287
+
288
+ Parameters
289
+ ----------
290
+ schema_obj
291
+ The schema object to visit.
292
+
293
+ Returns
294
+ -------
295
+ `tuple`
296
+ A tuple of all TAP_SCHEMA keys and key columns that were created.
297
+ """
229
298
  all_keys = []
230
299
  all_key_columns = []
231
300
  for table_obj in schema_obj.tables:
@@ -238,6 +307,20 @@ class TapLoadingVisitor:
238
307
  return all_keys, all_key_columns
239
308
 
240
309
  def visit_table(self, table_obj: Table, schema_obj: Schema) -> tuple:
310
+ """Visit a table object and build its TAP_SCHEMA representation.
311
+
312
+ Parameters
313
+ ----------
314
+ table_obj
315
+ The table object to visit.
316
+ schema_obj
317
+ The schema object which the table belongs to.
318
+
319
+ Returns
320
+ -------
321
+ `tuple`
322
+ A tuple of the SQLAlchemy ORM objects for the tables and columns.
323
+ """
241
324
  table_id = table_obj.id
242
325
  table = self.tables["tables"]()
243
326
  table.schema_name = self._schema_name()
@@ -257,6 +340,20 @@ class TapLoadingVisitor:
257
340
  return table, columns
258
341
 
259
342
  def check_column(self, column_obj: datamodel.Column) -> None:
343
+ """Check consistency of VOTable attributes for a column.
344
+
345
+ Parameters
346
+ ----------
347
+ column_obj
348
+ The column object to check.
349
+
350
+ Notes
351
+ -----
352
+ This method checks that a column with a sized datatype has either a
353
+ ``votable:arraysize`` or a ``length`` attribute and issues a warning
354
+ message if not. It also checks if a column with a timestamp datatype
355
+ has a ``arraysize`` attribute and issues a warning if not.
356
+ """
260
357
  _id = column_obj.id
261
358
  datatype_name = column_obj.datatype
262
359
  felis_type = FelisType.felis_type(datatype_name.value)
@@ -283,6 +380,20 @@ class TapLoadingVisitor:
283
380
  )
284
381
 
285
382
  def visit_column(self, column_obj: datamodel.Column, table_obj: Table) -> Tap11Base:
383
+ """Visit a column object and build its TAP_SCHEMA representation.
384
+
385
+ Parameters
386
+ ----------
387
+ column_obj
388
+ The column object to visit.
389
+ table_obj
390
+ The table object which the column belongs to.
391
+
392
+ Returns
393
+ -------
394
+ ``Tap11Base``
395
+ The SQLAlchemy ORM object for the column.
396
+ """
286
397
  self.check_column(column_obj)
287
398
  column_id = column_obj.id
288
399
  table_name = self._table_name(table_obj.name)
@@ -321,6 +432,15 @@ class TapLoadingVisitor:
321
432
  return column
322
433
 
323
434
  def visit_primary_key(self, primary_key_obj: str | Iterable[str] | None, table_obj: Table) -> None:
435
+ """Visit a primary key object and update the TAP_SCHEMA representation.
436
+
437
+ Parameters
438
+ ----------
439
+ primary_key_obj
440
+ The primary key object to visit.
441
+ table_obj
442
+ The table object which the primary key belongs to.
443
+ """
324
444
  if primary_key_obj:
325
445
  if isinstance(primary_key_obj, str):
326
446
  primary_key_obj = [primary_key_obj]
@@ -328,9 +448,21 @@ class TapLoadingVisitor:
328
448
  # if just one column and it's indexed, update the object
329
449
  if len(columns) == 1:
330
450
  columns[0].indexed = 1
331
- return None
332
451
 
333
452
  def visit_constraint(self, constraint_obj: Constraint) -> tuple:
453
+ """Visit a constraint object and build its TAP_SCHEMA representation.
454
+
455
+ Parameters
456
+ ----------
457
+ constraint_obj
458
+ The constraint object to visit.
459
+
460
+ Returns
461
+ -------
462
+ `tuple`
463
+ A tuple of the SQLAlchemy ORM objects for the TAP_SCHEMA ``key``
464
+ and ``key_columns`` data.
465
+ """
334
466
  constraint_type = constraint_obj.type
335
467
  key = None
336
468
  key_columns = []
@@ -375,13 +507,36 @@ class TapLoadingVisitor:
375
507
  return key, key_columns
376
508
 
377
509
  def visit_index(self, index_obj: Index, table_obj: Table) -> None:
510
+ """Visit an index object and update the TAP_SCHEMA representation.
511
+
512
+ Parameters
513
+ ----------
514
+ index_obj
515
+ The index object to visit.
516
+ table_obj
517
+ The table object which the index belongs to.
518
+ """
378
519
  columns = [self.graph_index[col_id] for col_id in getattr(index_obj, "columns", [])]
379
520
  # if just one column and it's indexed, update the object
380
521
  if len(columns) == 1:
381
522
  columns[0].indexed = 1
382
523
  return None
383
524
 
384
- def _schema_name(self, schema_name: str | None = None) -> str | None:
525
+ def _schema_name(
526
+ self, schema_name: str | None = None
527
+ ) -> str | None: # DM-44870: Usage of this method needs to be better understood and possibly removed
528
+ """Return the schema name.
529
+
530
+ Parameters
531
+ ----------
532
+ schema_name
533
+ Name of the schema.
534
+
535
+ Returns
536
+ -------
537
+ schema_name
538
+ The schema name.
539
+ """
385
540
  # If _schema_name is None, SQLAlchemy will catch it
386
541
  _schema_name = schema_name or self.schema_name
387
542
  if self.catalog_name and _schema_name:
@@ -389,6 +544,13 @@ class TapLoadingVisitor:
389
544
  return _schema_name
390
545
 
391
546
  def _table_name(self, table_name: str) -> str:
547
+ """Return the table name.
548
+
549
+ Parameters
550
+ ----------
551
+ table_name
552
+ Name of the table.
553
+ """
392
554
  schema_name = self._schema_name()
393
555
  if schema_name:
394
556
  return ".".join([schema_name, table_name])
@@ -400,15 +562,15 @@ def _insert(table: Tap11Base, value: Any) -> Insert:
400
562
 
401
563
  Parameters
402
564
  ----------
403
- table : `Tap11Base`
565
+ table
404
566
  The table we are inserting into.
405
- value : `Any`
567
+ value
406
568
  An object representing the object we are inserting to the table.
407
569
 
408
570
  Returns
409
571
  -------
410
- statement
411
- A SQLAlchemy insert statement
572
+ `Insert`
573
+ SQLAlchemy insert statement.
412
574
  """
413
575
  values_dict = {}
414
576
  for i in table.__table__.columns:
felis/types.py CHANGED
@@ -1,3 +1,5 @@
1
+ """Define the supported Felis datatypes."""
2
+
1
3
  # This file is part of felis.
2
4
  #
3
5
  # Developed for the LSST Data Management System.
@@ -23,10 +25,29 @@ from __future__ import annotations
23
25
 
24
26
  from typing import Any
25
27
 
28
+ __all__ = [
29
+ "FelisType",
30
+ "Boolean",
31
+ "Byte",
32
+ "Short",
33
+ "Int",
34
+ "Long",
35
+ "Float",
36
+ "Double",
37
+ "Char",
38
+ "String",
39
+ "Unicode",
40
+ "Text",
41
+ "Binary",
42
+ "Timestamp",
43
+ ]
44
+
26
45
 
27
46
  class FelisType:
28
- """Base class for types that represent Felis column types.
47
+ """Base class for a representation of Felis column types.
29
48
 
49
+ Notes
50
+ -----
30
51
  This class plays a role of a metaclass without being an actual metaclass.
31
52
  It provides a method to retrieve a class (type) given Felis type name.
32
53
  There should be no instances of this class (or sub-classes), the utility
@@ -34,12 +55,22 @@ class FelisType:
34
55
  """
35
56
 
36
57
  felis_name: str
58
+ """Name of the type as defined in the Felis schema."""
59
+
37
60
  votable_name: str
61
+ """Name of the type as defined in VOTable."""
62
+
38
63
  is_numeric: bool
64
+ """Flag indicating if the type is numeric."""
65
+
39
66
  is_sized: bool
67
+ """Flag indicating if the type is sized, meaning it requires a length."""
68
+
40
69
  is_timestamp: bool
70
+ """Flag indicating if the type is a timestamp."""
41
71
 
42
72
  _types: dict[str, type[FelisType]] = {}
73
+ """Dictionary of all known Felis types."""
43
74
 
44
75
  @classmethod
45
76
  def __init_subclass__(
@@ -52,6 +83,23 @@ class FelisType:
52
83
  is_timestamp: bool = False,
53
84
  **kwargs: Any,
54
85
  ):
86
+ """Register a new Felis type.
87
+
88
+ Parameters
89
+ ----------
90
+ felis_name
91
+ Name of the type.
92
+ votable_name
93
+ Name of the type as defined in VOTable.
94
+ is_numeric
95
+ Flag indicating if the type is numeric.
96
+ is_sized
97
+ Flag indicating if the type is sized.
98
+ is_timestamp
99
+ Flag indicating if the type is a timestamp.
100
+ kwargs
101
+ Additional keyword arguments.
102
+ """
55
103
  super().__init_subclass__(**kwargs)
56
104
  cls.felis_name = felis_name
57
105
  cls.votable_name = votable_name
@@ -62,17 +110,17 @@ class FelisType:
62
110
 
63
111
  @classmethod
64
112
  def felis_type(cls, felis_name: str) -> type[FelisType]:
65
- """Return specific Felis type for a given type name.
113
+ """Return specific Felis type for a given name.
66
114
 
67
115
  Parameters
68
116
  ----------
69
- felis_name : `str`
70
- name of the felis type as defined in felis schema.
117
+ felis_name
118
+ Name of the felis type as defined in felis schema.
71
119
 
72
120
  Returns
73
121
  -------
74
- felis_type : `type`
75
- One of subclasses of `FelisType`.
122
+ `type` [ `FelisType` ]
123
+ A specific Felis type class.
76
124
 
77
125
  Raises
78
126
  ------
@@ -106,11 +154,11 @@ class Long(FelisType, felis_name="long", votable_name="long", is_numeric=True):
106
154
 
107
155
 
108
156
  class Float(FelisType, felis_name="float", votable_name="float", is_numeric=True):
109
- """Felis definition of single precision floating type."""
157
+ """Felis definition of single precision floating point type."""
110
158
 
111
159
 
112
160
  class Double(FelisType, felis_name="double", votable_name="double", is_numeric=True):
113
- """Felis definition of double precision floating type."""
161
+ """Felis definition of double precision floating point type."""
114
162
 
115
163
 
116
164
  class Char(FelisType, felis_name="char", votable_name="char", is_sized=True):
felis/version.py CHANGED
@@ -1,2 +1,2 @@
1
1
  __all__ = ["__version__"]
2
- __version__ = "27.2024.2400"
2
+ __version__ = "27.2024.2600"
@@ -1 +1 @@
1
- Copyright 2020-2022 The Board of Trustees of the Leland Stanford Junior University, through SLAC National Accelerator Laboratory
1
+ Copyright 2018-2024 The Board of Trustees of the Leland Stanford Junior University, through SLAC National Accelerator Laboratory
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lsst-felis
3
- Version: 27.2024.2400
3
+ Version: 27.2024.2600
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+)
@@ -25,7 +25,9 @@ Requires-Dist: pyyaml >=6
25
25
  Requires-Dist: pydantic <3,>=2
26
26
  Requires-Dist: lsst-utils
27
27
  Provides-Extra: dev
28
- Requires-Dist: documenteer[guide] ; extra == 'dev'
28
+ Requires-Dist: documenteer[guide] <2 ; extra == 'dev'
29
+ Requires-Dist: autodoc-pydantic ; extra == 'dev'
30
+ Requires-Dist: sphinx-click ; extra == 'dev'
29
31
  Provides-Extra: test
30
32
  Requires-Dist: pytest >=3.2 ; extra == 'test'
31
33
 
@@ -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=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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.43.0)
2
+ Generator: setuptools (70.1.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
felis/validation.py DELETED
@@ -1,103 +0,0 @@
1
- # This file is part of felis.
2
- #
3
- # Developed for the LSST Data Management System.
4
- # This product includes software developed by the LSST Project
5
- # (https://www.lsst.org).
6
- # See the COPYRIGHT file at the top-level directory of this distribution
7
- # for details of code ownership.
8
- #
9
- # This program is free software: you can redistribute it and/or modify
10
- # it under the terms of the GNU General Public License as published by
11
- # the Free Software Foundation, either version 3 of the License, or
12
- # (at your option) any later version.
13
- #
14
- # This program is distributed in the hope that it will be useful,
15
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
- # GNU General Public License for more details.
18
- #
19
- # You should have received a copy of the GNU General Public License
20
- # along with this program. If not, see <https://www.gnu.org/licenses/>.
21
-
22
- from __future__ import annotations
23
-
24
- import logging
25
- from collections.abc import Sequence
26
- from typing import Any
27
-
28
- from pydantic import Field, model_validator
29
-
30
- from .datamodel import Column, DescriptionStr, Schema, Table
31
-
32
- logger = logging.getLogger(__name__)
33
-
34
- __all__ = ["RspColumn", "RspSchema", "RspTable", "get_schema"]
35
-
36
-
37
- class RspColumn(Column):
38
- """Column for RSP data validation."""
39
-
40
- description: DescriptionStr
41
- """Redefine description to make it required."""
42
-
43
-
44
- class RspTable(Table):
45
- """Table for RSP data validation.
46
-
47
- The list of columns is overridden to use RspColumn instead of Column.
48
-
49
- Tables for the RSP must have a TAP table index and a valid description.
50
- """
51
-
52
- description: DescriptionStr
53
- """Redefine description to make it required."""
54
-
55
- tap_table_index: int = Field(..., alias="tap:table_index")
56
- """Redefine the TAP_SCHEMA table index so that it is required."""
57
-
58
- columns: Sequence[RspColumn]
59
- """Redefine columns to include RSP validation."""
60
-
61
- @model_validator(mode="after") # type: ignore[arg-type]
62
- @classmethod
63
- def check_tap_principal(cls: Any, tbl: RspTable) -> RspTable:
64
- """Check that at least one column is flagged as 'principal' for
65
- TAP purposes.
66
- """
67
- for col in tbl.columns:
68
- if col.tap_principal == 1:
69
- return tbl
70
- raise ValueError(f"Table '{tbl.name}' is missing at least one column designated as 'tap:principal'")
71
-
72
-
73
- class RspSchema(Schema):
74
- """Schema for RSP data validation.
75
-
76
- TAP table indexes must be unique across all tables.
77
- """
78
-
79
- tables: Sequence[RspTable]
80
- """Redefine tables to include RSP validation."""
81
-
82
- @model_validator(mode="after") # type: ignore[arg-type]
83
- @classmethod
84
- def check_tap_table_indexes(cls: Any, sch: RspSchema) -> RspSchema:
85
- """Check that the TAP table indexes are unique."""
86
- table_indicies = set()
87
- for table in sch.tables:
88
- table_index = table.tap_table_index
89
- if table_index is not None:
90
- if table_index in table_indicies:
91
- raise ValueError(f"Duplicate 'tap:table_index' value {table_index} found in schema")
92
- table_indicies.add(table_index)
93
- return sch
94
-
95
-
96
- def get_schema(schema_name: str) -> type[Schema]:
97
- """Get the schema class for the given name."""
98
- if schema_name == "default":
99
- return Schema
100
- elif schema_name == "RSP":
101
- return RspSchema
102
- else:
103
- raise ValueError(f"Unknown schema name '{schema_name}'")
@@ -1,22 +0,0 @@
1
- felis/__init__.py,sha256=THmRg3ylB4E73XhFjJX7YlnV_CM3lr_gZO_HqQFzIQ4,937
2
- felis/cli.py,sha256=wBALFf9bMYpL6-A58I3JtozaiMSSoi7Gu7YyGuUk8Uo,9997
3
- felis/datamodel.py,sha256=ECXmd78fufrYDBK4S0n3-wSQytWmz-vGLkNRjtrHPCE,19627
4
- felis/metadata.py,sha256=lSgKy9CksmyJp9zUkzkwOAzjk2Hzivb9VVbYfTPNmvY,12140
5
- felis/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- felis/tap.py,sha256=fVYvvIFk_vccXqbcFYdgK2yOfp4P5E4guvsSGktsNxs,16795
7
- felis/types.py,sha256=z_ECfSxpqiFSGppjxKwCO4fPP7TLBaIN3Qo1AGF16Go,4418
8
- felis/validation.py,sha256=Zq0gyCvPCwRlhfQ-w_p6ccDTkjcyhxSA1-Gr5plXiZI,3465
9
- felis/version.py,sha256=SKE5LZn31z5ONJXoQypgUH-1aa2Ar0owtNYSiqyaKog,55
10
- felis/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- felis/db/dialects.py,sha256=mSYgS8gqUJQGgZw3IA-zBfKlrJ2r4nEUR94wKZNRKZg,2267
12
- felis/db/sqltypes.py,sha256=yFlautQ1hv21MHF4AIfBp7_2m1-exKBfc76xYsMHBgk,5735
13
- felis/db/utils.py,sha256=oYPGOt5K_82GnScJOg8WarOyvval-Cu1nX7CduFxKss,9122
14
- felis/db/variants.py,sha256=Ti2oZf7nFTe8aFyG-GeFSW4bIb5ClNikm9xOJtRcxLY,3862
15
- lsst_felis-27.2024.2400.dist-info/COPYRIGHT,sha256=bUmNy19uUxqITMpjeHFe69q3IzQpjxvvBw6oV7kR7ho,129
16
- lsst_felis-27.2024.2400.dist-info/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
17
- lsst_felis-27.2024.2400.dist-info/METADATA,sha256=agi49bvO-Q3nN0a2chNJcvsKtz1mi9J_Az02n4wh_Og,1191
18
- lsst_felis-27.2024.2400.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
19
- lsst_felis-27.2024.2400.dist-info/entry_points.txt,sha256=Gk2XFujA_Gp52VBk45g5kim8TDoMDJFPctsMqiq72EM,40
20
- lsst_felis-27.2024.2400.dist-info/top_level.txt,sha256=F4SvPip3iZRVyISi50CHhwTIAokAhSxjWiVcn4IVWRI,6
21
- lsst_felis-27.2024.2400.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
22
- lsst_felis-27.2024.2400.dist-info/RECORD,,