lsst-felis 29.2025.2600__py3-none-any.whl → 29.2025.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
@@ -618,7 +618,9 @@ class ForeignKeyConstraint(Constraint):
618
618
  """Table foreign key constraint model.
619
619
 
620
620
  This constraint is used to define a foreign key relationship between two
621
- tables in the schema.
621
+ tables in the schema. There must be at least one column in the
622
+ `columns` list, and at least one column in the `referenced_columns` list
623
+ or a validation error will be raised.
622
624
 
623
625
  Notes
624
626
  -----
@@ -629,10 +631,10 @@ class ForeignKeyConstraint(Constraint):
629
631
  type: Literal["ForeignKey"] = Field("ForeignKey", alias="@type")
630
632
  """Type of the constraint."""
631
633
 
632
- columns: list[str]
634
+ columns: list[str] = Field(min_length=1)
633
635
  """The columns comprising the foreign key."""
634
636
 
635
- referenced_columns: list[str] = Field(alias="referencedColumns")
637
+ referenced_columns: list[str] = Field(alias="referencedColumns", min_length=1)
636
638
  """The columns referenced by the foreign key."""
637
639
 
638
640
  on_delete: Literal["CASCADE", "SET NULL", "SET DEFAULT", "RESTRICT", "NO ACTION"] | None = None
@@ -657,6 +659,28 @@ class ForeignKeyConstraint(Constraint):
657
659
  """
658
660
  return value
659
661
 
662
+ @model_validator(mode="after")
663
+ def check_column_lengths(self) -> ForeignKeyConstraint:
664
+ """Check that the `columns` and `referenced_columns` lists have the
665
+ same length.
666
+
667
+ Returns
668
+ -------
669
+ `ForeignKeyConstraint`
670
+ The foreign key constraint being validated.
671
+
672
+ Raises
673
+ ------
674
+ ValueError
675
+ Raised if the `columns` and `referenced_columns` lists do not have
676
+ the same length.
677
+ """
678
+ if len(self.columns) != len(self.referenced_columns):
679
+ raise ValueError(
680
+ "Columns and referencedColumns must have the same length for a ForeignKey constraint"
681
+ )
682
+ return self
683
+
660
684
 
661
685
  _ConstraintType = Annotated[
662
686
  CheckConstraint | ForeignKeyConstraint | UniqueConstraint, Field(discriminator="type")
felis/diff.py CHANGED
@@ -112,8 +112,10 @@ class FormattedSchemaDiff(SchemaDiff):
112
112
  handler(self.diff[change_type])
113
113
 
114
114
  def _print_header(self, id_dict: dict[str, Any], keys: list[int | str]) -> None:
115
- id = self._get_id(id_dict, keys)
116
- print(f"{id} @ {self._get_key_display(keys)}")
115
+ # id = self._get_id(id_dict, keys)
116
+ # Don't display ID here for now; it is always just the schema ID.
117
+ print(f"{self._get_key_display(keys)}")
118
+ # print(f"{id} @ {self._get_key_display(keys)}")
117
119
 
118
120
  def _handle_values_changed(self, changes: dict[str, Any]) -> None:
119
121
  for key in changes:
@@ -156,13 +158,21 @@ class FormattedSchemaDiff(SchemaDiff):
156
158
 
157
159
  @staticmethod
158
160
  def _get_id(values: dict, keys: list[str | int]) -> str:
159
- value = values
161
+ # Unused for now, pending updates to diff tool in DM-49446.
162
+ value: list | dict = values
160
163
  last_id = None
161
164
 
162
165
  for key in keys:
166
+ logger.debug(f"Processing key <{key}> with type {type(key)}")
167
+ logger.debug(f"Type of value: {type(value)}")
163
168
  if isinstance(value, dict) and "id" in value:
164
169
  last_id = value["id"]
165
- value = value[key]
170
+ elif isinstance(value, list) and isinstance(key, int):
171
+ if 0 <= key < len(value):
172
+ value = value[key]
173
+ else:
174
+ raise ValueError(f"Index '{key}' is out of range for list of length {len(value)}")
175
+ value = value[key]
166
176
 
167
177
  if isinstance(value, dict) and "id" in value:
168
178
  last_id = value["id"]
felis/tap_schema.py CHANGED
@@ -470,7 +470,7 @@ class DataLoader:
470
470
  logger.info("Dry run - not loading data into database")
471
471
 
472
472
  def _insert_schemas(self) -> None:
473
- """Insert the schema data into the schemas table."""
473
+ """Insert the schema data into the ``schemas`` table."""
474
474
  schema_record = {
475
475
  "schema_name": self.schema.name,
476
476
  "utype": self.schema.votable_utype,
@@ -495,7 +495,7 @@ class DataLoader:
495
495
  return f"{self.schema.name}.{table.name}"
496
496
 
497
497
  def _insert_tables(self) -> None:
498
- """Insert the table data into the tables table."""
498
+ """Insert the table data into the ``tables`` table."""
499
499
  for table in self.schema.tables:
500
500
  table_record = {
501
501
  "schema_name": self.schema.name,
@@ -508,7 +508,7 @@ class DataLoader:
508
508
  self._insert("tables", table_record)
509
509
 
510
510
  def _insert_columns(self) -> None:
511
- """Insert the column data into the columns table."""
511
+ """Insert the column data into the ``columns`` table."""
512
512
  for table in self.schema.tables:
513
513
  for column in table.columns:
514
514
  felis_type = FelisType.felis_type(column.datatype.value)
@@ -563,11 +563,15 @@ class DataLoader:
563
563
  return key_id
564
564
 
565
565
  def _insert_keys(self) -> None:
566
- """Insert the foreign keys into the keys and key_columns tables."""
566
+ """Insert the foreign keys into the ``keys`` and ``key_columns``
567
+ tables.
568
+ """
567
569
  for table in self.schema.tables:
568
570
  for constraint in table.constraints:
569
571
  if isinstance(constraint, datamodel.ForeignKeyConstraint):
572
+ ###########################################################
570
573
  # Handle keys table
574
+ ###########################################################
571
575
  referenced_column = self.schema.find_object_by_id(
572
576
  constraint.referenced_columns[0], datamodel.Column
573
577
  )
@@ -582,17 +586,23 @@ class DataLoader:
582
586
  }
583
587
  self._insert("keys", key_record)
584
588
 
589
+ ###########################################################
585
590
  # Handle key_columns table
586
- from_column = self.schema.find_object_by_id(constraint.columns[0], datamodel.Column)
587
- target_column = self.schema.find_object_by_id(
588
- constraint.referenced_columns[0], datamodel.Column
589
- )
590
- key_columns_record = {
591
- "key_id": key_id,
592
- "from_column": from_column.name,
593
- "target_column": target_column.name,
594
- }
595
- self._insert("key_columns", key_columns_record)
591
+ ###########################################################
592
+ # Loop over the corresponding columns and referenced
593
+ # columns and insert a record for each pair. This is
594
+ # necessary for proper handling of composite keys.
595
+ for from_column_id, target_column_id in zip(
596
+ constraint.columns, constraint.referenced_columns
597
+ ):
598
+ from_column = self.schema.find_object_by_id(from_column_id, datamodel.Column)
599
+ target_column = self.schema.find_object_by_id(target_column_id, datamodel.Column)
600
+ key_columns_record = {
601
+ "key_id": key_id,
602
+ "from_column": from_column.name,
603
+ "target_column": target_column.name,
604
+ }
605
+ self._insert("key_columns", key_columns_record)
596
606
 
597
607
  def _generate_all_inserts(self) -> None:
598
608
  """Generate the inserts for all the data."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lsst-felis
3
- Version: 29.2025.2600
3
+ Version: 29.2025.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+)
@@ -1,10 +1,10 @@
1
1
  felis/__init__.py,sha256=HnwWzLaPOSnPzAoppSIHzTrGfixEgvkzJdBxa8-03cw,1294
2
2
  felis/cli.py,sha256=g6OrBrIylNLiflSvrLlef86BjoiehV3L5eAvVPrxPog,16911
3
- felis/datamodel.py,sha256=HKg4Ut0qPX7sV6q-Mw9U3BKgjVQFAnhhAUmo9Woh7v8,51228
4
- felis/diff.py,sha256=z4ZzUocFYVa2y22BWUAMkeeLORmMtaWIDGTVaUE1OIM,7181
3
+ felis/datamodel.py,sha256=VAJ9DqOBtfu3fWtpDOcpg4Ca1jfq8NMG6MHH8GbHpl0,52135
4
+ felis/diff.py,sha256=ZzjOJ57p5ZwFn6eem7CYoPjSnxti5OZY33B6Ds5Q-Rg,7797
5
5
  felis/metadata.py,sha256=79YcaIqeFP-pj9zhWpqXlvw_piUTUwuLrV5_8eVYalQ,13763
6
6
  felis/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- felis/tap_schema.py,sha256=uu2imuzxyuIUbmW4liC6_h4TW5MW2t4SI9rjtMxcyfI,26372
7
+ felis/tap_schema.py,sha256=Kfpnv6AO_ni_B-DEgi3PRSkGKkTEybuYfWlA9gOMM_I,27071
8
8
  felis/types.py,sha256=ifZQjc-Uw5CM3L7hmFUb7wcHY1O_HgJCw6HPqyUkHvk,5510
9
9
  felis/config/tap_schema/columns.csv,sha256=9RsyuPObUQ_6myux9vKtlQ-aJgs7rvvxoLf6yYSRWqc,3272
10
10
  felis/config/tap_schema/key_columns.csv,sha256=dRezco5ltcM1mG--2DvPsbOxB6cwVaBwczwi3It2vag,210
@@ -21,11 +21,11 @@ felis/db/variants.py,sha256=eahthrbVeV8ZdGamWQccNmWgx6CCscGrU0vQRs5HZK8,5260
21
21
  felis/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  felis/tests/postgresql.py,sha256=B_xk4fLual5-viGDqP20r94okuc0pbSvytRH_L0fvMs,4035
23
23
  felis/tests/run_cli.py,sha256=Gg8loUIGj9t6KlkRKrEc9Z9b5dtlkpJy94ORuj4BrxU,2503
24
- lsst_felis-29.2025.2600.dist-info/licenses/COPYRIGHT,sha256=vJAFLFTSF1mhy9eIuA3P6R-3yxTWKQgpig88P-1IzRw,129
25
- lsst_felis-29.2025.2600.dist-info/licenses/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
26
- lsst_felis-29.2025.2600.dist-info/METADATA,sha256=olXZcNPImhvS5QjMr8uoEyq_Br5GjLRaBjE4OsujeJM,1433
27
- lsst_felis-29.2025.2600.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
28
- lsst_felis-29.2025.2600.dist-info/entry_points.txt,sha256=Gk2XFujA_Gp52VBk45g5kim8TDoMDJFPctsMqiq72EM,40
29
- lsst_felis-29.2025.2600.dist-info/top_level.txt,sha256=F4SvPip3iZRVyISi50CHhwTIAokAhSxjWiVcn4IVWRI,6
30
- lsst_felis-29.2025.2600.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
31
- lsst_felis-29.2025.2600.dist-info/RECORD,,
24
+ lsst_felis-29.2025.2800.dist-info/licenses/COPYRIGHT,sha256=vJAFLFTSF1mhy9eIuA3P6R-3yxTWKQgpig88P-1IzRw,129
25
+ lsst_felis-29.2025.2800.dist-info/licenses/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
26
+ lsst_felis-29.2025.2800.dist-info/METADATA,sha256=Vj9HPVwpzi8ozYwAD0xVyrGvKzBEtKBK-9FiAR_eoBM,1433
27
+ lsst_felis-29.2025.2800.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
28
+ lsst_felis-29.2025.2800.dist-info/entry_points.txt,sha256=Gk2XFujA_Gp52VBk45g5kim8TDoMDJFPctsMqiq72EM,40
29
+ lsst_felis-29.2025.2800.dist-info/top_level.txt,sha256=F4SvPip3iZRVyISi50CHhwTIAokAhSxjWiVcn4IVWRI,6
30
+ lsst_felis-29.2025.2800.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
31
+ lsst_felis-29.2025.2800.dist-info/RECORD,,