lsst-felis 27.2024.3300__py3-none-any.whl → 27.2024.3500__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/cli.py +15 -2
- felis/datamodel.py +158 -57
- felis/metadata.py +1 -2
- felis/tap.py +2 -3
- felis/version.py +1 -1
- {lsst_felis-27.2024.3300.dist-info → lsst_felis-27.2024.3500.dist-info}/METADATA +1 -1
- {lsst_felis-27.2024.3300.dist-info → lsst_felis-27.2024.3500.dist-info}/RECORD +13 -13
- {lsst_felis-27.2024.3300.dist-info → lsst_felis-27.2024.3500.dist-info}/WHEEL +1 -1
- {lsst_felis-27.2024.3300.dist-info → lsst_felis-27.2024.3500.dist-info}/COPYRIGHT +0 -0
- {lsst_felis-27.2024.3300.dist-info → lsst_felis-27.2024.3500.dist-info}/LICENSE +0 -0
- {lsst_felis-27.2024.3300.dist-info → lsst_felis-27.2024.3500.dist-info}/entry_points.txt +0 -0
- {lsst_felis-27.2024.3300.dist-info → lsst_felis-27.2024.3500.dist-info}/top_level.txt +0 -0
- {lsst_felis-27.2024.3300.dist-info → lsst_felis-27.2024.3500.dist-info}/zip-safe +0 -0
felis/cli.py
CHANGED
|
@@ -62,8 +62,16 @@ loglevel_choices = ["CRITICAL", "FATAL", "ERROR", "WARNING", "INFO", "DEBUG"]
|
|
|
62
62
|
envvar="FELIS_LOGFILE",
|
|
63
63
|
help="Felis log file path",
|
|
64
64
|
)
|
|
65
|
-
|
|
65
|
+
@click.option(
|
|
66
|
+
"--id-generation", is_flag=True, help="Generate IDs for all objects that do not have them", default=False
|
|
67
|
+
)
|
|
68
|
+
@click.pass_context
|
|
69
|
+
def cli(ctx: click.Context, log_level: str, log_file: str | None, id_generation: bool) -> None:
|
|
66
70
|
"""Felis command line tools"""
|
|
71
|
+
ctx.ensure_object(dict)
|
|
72
|
+
ctx.obj["id_generation"] = id_generation
|
|
73
|
+
if ctx.obj["id_generation"]:
|
|
74
|
+
logger.info("ID generation is enabled")
|
|
67
75
|
if log_file:
|
|
68
76
|
logging.basicConfig(filename=log_file, level=log_level)
|
|
69
77
|
else:
|
|
@@ -88,7 +96,9 @@ def cli(log_level: str, log_file: str | None) -> None:
|
|
|
88
96
|
)
|
|
89
97
|
@click.option("--ignore-constraints", is_flag=True, help="Ignore constraints when creating tables")
|
|
90
98
|
@click.argument("file", type=click.File())
|
|
99
|
+
@click.pass_context
|
|
91
100
|
def create(
|
|
101
|
+
ctx: click.Context,
|
|
92
102
|
engine_url: str,
|
|
93
103
|
schema_name: str | None,
|
|
94
104
|
initialize: bool,
|
|
@@ -124,7 +134,7 @@ def create(
|
|
|
124
134
|
"""
|
|
125
135
|
try:
|
|
126
136
|
yaml_data = yaml.safe_load(file)
|
|
127
|
-
schema = Schema.model_validate(yaml_data)
|
|
137
|
+
schema = Schema.model_validate(yaml_data, context={"id_generation": ctx.obj["id_generation"]})
|
|
128
138
|
url = make_url(engine_url)
|
|
129
139
|
if schema_name:
|
|
130
140
|
logger.info(f"Overriding schema name with: {schema_name}")
|
|
@@ -355,7 +365,9 @@ def load_tap(
|
|
|
355
365
|
default=False,
|
|
356
366
|
)
|
|
357
367
|
@click.argument("files", nargs=-1, type=click.File())
|
|
368
|
+
@click.pass_context
|
|
358
369
|
def validate(
|
|
370
|
+
ctx: click.Context,
|
|
359
371
|
check_description: bool,
|
|
360
372
|
check_redundant_datatypes: bool,
|
|
361
373
|
check_tap_table_indexes: bool,
|
|
@@ -402,6 +414,7 @@ def validate(
|
|
|
402
414
|
"check_redundant_datatypes": check_redundant_datatypes,
|
|
403
415
|
"check_tap_table_indexes": check_tap_table_indexes,
|
|
404
416
|
"check_tap_principal": check_tap_principal,
|
|
417
|
+
"id_generation": ctx.obj["id_generation"],
|
|
405
418
|
},
|
|
406
419
|
)
|
|
407
420
|
except ValidationError as e:
|
felis/datamodel.py
CHANGED
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
from __future__ import annotations
|
|
25
25
|
|
|
26
26
|
import logging
|
|
27
|
-
from collections.abc import
|
|
27
|
+
from collections.abc import Sequence
|
|
28
28
|
from enum import StrEnum, auto
|
|
29
|
-
from typing import Annotated, Any, TypeAlias
|
|
29
|
+
from typing import Annotated, Any, Literal, TypeAlias, Union
|
|
30
30
|
|
|
31
31
|
from astropy import units as units # type: ignore
|
|
32
32
|
from astropy.io.votable import ucd # type: ignore
|
|
@@ -390,20 +390,31 @@ class Constraint(BaseObject):
|
|
|
390
390
|
deferrable: bool = False
|
|
391
391
|
"""Whether this constraint will be declared as deferrable."""
|
|
392
392
|
|
|
393
|
-
initially:
|
|
393
|
+
initially: Literal["IMMEDIATE", "DEFERRED"] | None = None
|
|
394
394
|
"""Value for ``INITIALLY`` clause; only used if `deferrable` is
|
|
395
395
|
`True`."""
|
|
396
396
|
|
|
397
|
-
|
|
398
|
-
|
|
397
|
+
@model_validator(mode="after")
|
|
398
|
+
def check_deferrable(self) -> Constraint:
|
|
399
|
+
"""Check that the ``INITIALLY`` clause is only used if `deferrable` is
|
|
400
|
+
`True`.
|
|
399
401
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
+
Returns
|
|
403
|
+
-------
|
|
404
|
+
`Constraint`
|
|
405
|
+
The constraint being validated.
|
|
406
|
+
"""
|
|
407
|
+
if self.initially is not None and not self.deferrable:
|
|
408
|
+
raise ValueError("INITIALLY clause can only be used if deferrable is True")
|
|
409
|
+
return self
|
|
402
410
|
|
|
403
411
|
|
|
404
412
|
class CheckConstraint(Constraint):
|
|
405
413
|
"""Table check constraint model."""
|
|
406
414
|
|
|
415
|
+
type: Literal["Check"] = Field("Check", alias="@type")
|
|
416
|
+
"""Type of the constraint."""
|
|
417
|
+
|
|
407
418
|
expression: str
|
|
408
419
|
"""Expression for the check constraint."""
|
|
409
420
|
|
|
@@ -411,10 +422,35 @@ class CheckConstraint(Constraint):
|
|
|
411
422
|
class UniqueConstraint(Constraint):
|
|
412
423
|
"""Table unique constraint model."""
|
|
413
424
|
|
|
425
|
+
type: Literal["Unique"] = Field("Unique", alias="@type")
|
|
426
|
+
"""Type of the constraint."""
|
|
427
|
+
|
|
414
428
|
columns: list[str]
|
|
415
429
|
"""Columns in the unique constraint."""
|
|
416
430
|
|
|
417
431
|
|
|
432
|
+
class ForeignKeyConstraint(Constraint):
|
|
433
|
+
"""Table foreign key constraint model.
|
|
434
|
+
|
|
435
|
+
This constraint is used to define a foreign key relationship between two
|
|
436
|
+
tables in the schema.
|
|
437
|
+
|
|
438
|
+
Notes
|
|
439
|
+
-----
|
|
440
|
+
These relationships will be reflected in the TAP_SCHEMA ``keys`` and
|
|
441
|
+
``key_columns`` data.
|
|
442
|
+
"""
|
|
443
|
+
|
|
444
|
+
type: Literal["ForeignKey"] = Field("ForeignKey", alias="@type")
|
|
445
|
+
"""Type of the constraint."""
|
|
446
|
+
|
|
447
|
+
columns: list[str]
|
|
448
|
+
"""The columns comprising the foreign key."""
|
|
449
|
+
|
|
450
|
+
referenced_columns: list[str] = Field(alias="referencedColumns")
|
|
451
|
+
"""The columns referenced by the foreign key."""
|
|
452
|
+
|
|
453
|
+
|
|
418
454
|
class Index(BaseObject):
|
|
419
455
|
"""Table index model.
|
|
420
456
|
|
|
@@ -455,23 +491,10 @@ class Index(BaseObject):
|
|
|
455
491
|
return values
|
|
456
492
|
|
|
457
493
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
tables in the schema.
|
|
463
|
-
|
|
464
|
-
Notes
|
|
465
|
-
-----
|
|
466
|
-
These relationships will be reflected in the TAP_SCHEMA ``keys`` and
|
|
467
|
-
``key_columns`` data.
|
|
468
|
-
"""
|
|
469
|
-
|
|
470
|
-
columns: list[str]
|
|
471
|
-
"""The columns comprising the foreign key."""
|
|
472
|
-
|
|
473
|
-
referenced_columns: list[str] = Field(alias="referencedColumns")
|
|
474
|
-
"""The columns referenced by the foreign key."""
|
|
494
|
+
_ConstraintType = Annotated[
|
|
495
|
+
Union[CheckConstraint, ForeignKeyConstraint, UniqueConstraint], Field(discriminator="type")
|
|
496
|
+
]
|
|
497
|
+
"""Type alias for a constraint type."""
|
|
475
498
|
|
|
476
499
|
|
|
477
500
|
class Table(BaseObject):
|
|
@@ -480,7 +503,7 @@ class Table(BaseObject):
|
|
|
480
503
|
columns: Sequence[Column]
|
|
481
504
|
"""Columns in the table."""
|
|
482
505
|
|
|
483
|
-
constraints: list[
|
|
506
|
+
constraints: list[_ConstraintType] = Field(default_factory=list, discriminator="type")
|
|
484
507
|
"""Constraints on the table."""
|
|
485
508
|
|
|
486
509
|
indexes: list[Index] = Field(default_factory=list)
|
|
@@ -492,43 +515,12 @@ class Table(BaseObject):
|
|
|
492
515
|
tap_table_index: int | None = Field(None, alias="tap:table_index")
|
|
493
516
|
"""IVOA TAP_SCHEMA table index of the table."""
|
|
494
517
|
|
|
495
|
-
mysql_engine: str | None = Field(
|
|
518
|
+
mysql_engine: str | None = Field("MyISAM", alias="mysql:engine")
|
|
496
519
|
"""MySQL engine to use for the table."""
|
|
497
520
|
|
|
498
521
|
mysql_charset: str | None = Field(None, alias="mysql:charset")
|
|
499
522
|
"""MySQL charset to use for the table."""
|
|
500
523
|
|
|
501
|
-
@model_validator(mode="before")
|
|
502
|
-
@classmethod
|
|
503
|
-
def create_constraints(cls, values: dict[str, Any]) -> dict[str, Any]:
|
|
504
|
-
"""Create specific constraint types from the data in the
|
|
505
|
-
``constraints`` field of a table.
|
|
506
|
-
|
|
507
|
-
Parameters
|
|
508
|
-
----------
|
|
509
|
-
values
|
|
510
|
-
The values of the table containing the constraint data.
|
|
511
|
-
|
|
512
|
-
Returns
|
|
513
|
-
-------
|
|
514
|
-
`dict` [ `str`, `Any` ]
|
|
515
|
-
The values of the table with the constraints converted to their
|
|
516
|
-
respective types.
|
|
517
|
-
"""
|
|
518
|
-
if "constraints" in values:
|
|
519
|
-
new_constraints: list[Constraint] = []
|
|
520
|
-
for item in values["constraints"]:
|
|
521
|
-
if item["@type"] == "ForeignKey":
|
|
522
|
-
new_constraints.append(ForeignKeyConstraint(**item))
|
|
523
|
-
elif item["@type"] == "Unique":
|
|
524
|
-
new_constraints.append(UniqueConstraint(**item))
|
|
525
|
-
elif item["@type"] == "Check":
|
|
526
|
-
new_constraints.append(CheckConstraint(**item))
|
|
527
|
-
else:
|
|
528
|
-
raise ValueError(f"Unknown constraint type: {item['@type']}")
|
|
529
|
-
values["constraints"] = new_constraints
|
|
530
|
-
return values
|
|
531
|
-
|
|
532
524
|
@field_validator("columns", mode="after")
|
|
533
525
|
@classmethod
|
|
534
526
|
def check_unique_column_names(cls, columns: list[Column]) -> list[Column]:
|
|
@@ -723,6 +715,55 @@ class Schema(BaseObject):
|
|
|
723
715
|
id_map: dict[str, Any] = Field(default_factory=dict, exclude=True)
|
|
724
716
|
"""Map of IDs to objects."""
|
|
725
717
|
|
|
718
|
+
@model_validator(mode="before")
|
|
719
|
+
@classmethod
|
|
720
|
+
def generate_ids(cls, values: dict[str, Any], info: ValidationInfo) -> dict[str, Any]:
|
|
721
|
+
"""Generate IDs for objects that do not have them.
|
|
722
|
+
|
|
723
|
+
Parameters
|
|
724
|
+
----------
|
|
725
|
+
values
|
|
726
|
+
The values of the schema.
|
|
727
|
+
info
|
|
728
|
+
Validation context used to determine if ID generation is enabled.
|
|
729
|
+
|
|
730
|
+
Returns
|
|
731
|
+
-------
|
|
732
|
+
`dict` [ `str`, `Any` ]
|
|
733
|
+
The values of the schema with generated IDs.
|
|
734
|
+
"""
|
|
735
|
+
context = info.context
|
|
736
|
+
if not context or not context.get("id_generation", False):
|
|
737
|
+
logger.debug("Skipping ID generation")
|
|
738
|
+
return values
|
|
739
|
+
schema_name = values["name"]
|
|
740
|
+
if "@id" not in values:
|
|
741
|
+
values["@id"] = f"#{schema_name}"
|
|
742
|
+
logger.debug(f"Generated ID '{values['@id']}' for schema '{schema_name}'")
|
|
743
|
+
if "tables" in values:
|
|
744
|
+
for table in values["tables"]:
|
|
745
|
+
if "@id" not in table:
|
|
746
|
+
table["@id"] = f"#{table['name']}"
|
|
747
|
+
logger.debug(f"Generated ID '{table['@id']}' for table '{table['name']}'")
|
|
748
|
+
if "columns" in table:
|
|
749
|
+
for column in table["columns"]:
|
|
750
|
+
if "@id" not in column:
|
|
751
|
+
column["@id"] = f"#{table['name']}.{column['name']}"
|
|
752
|
+
logger.debug(f"Generated ID '{column['@id']}' for column '{column['name']}'")
|
|
753
|
+
if "constraints" in table:
|
|
754
|
+
for constraint in table["constraints"]:
|
|
755
|
+
if "@id" not in constraint:
|
|
756
|
+
constraint["@id"] = f"#{constraint['name']}"
|
|
757
|
+
logger.debug(
|
|
758
|
+
f"Generated ID '{constraint['@id']}' for constraint '{constraint['name']}'"
|
|
759
|
+
)
|
|
760
|
+
if "indexes" in table:
|
|
761
|
+
for index in table["indexes"]:
|
|
762
|
+
if "@id" not in index:
|
|
763
|
+
index["@id"] = f"#{index['name']}"
|
|
764
|
+
logger.debug(f"Generated ID '{index['@id']}' for index '{index['name']}'")
|
|
765
|
+
return values
|
|
766
|
+
|
|
726
767
|
@field_validator("tables", mode="after")
|
|
727
768
|
@classmethod
|
|
728
769
|
def check_unique_table_names(cls, tables: list[Table]) -> list[Table]:
|
|
@@ -773,6 +814,66 @@ class Schema(BaseObject):
|
|
|
773
814
|
table_indicies.add(table_index)
|
|
774
815
|
return self
|
|
775
816
|
|
|
817
|
+
@model_validator(mode="after")
|
|
818
|
+
def check_unique_constraint_names(self: Schema) -> Schema:
|
|
819
|
+
"""Check for duplicate constraint names in the schema.
|
|
820
|
+
|
|
821
|
+
Returns
|
|
822
|
+
-------
|
|
823
|
+
`Schema`
|
|
824
|
+
The schema being validated.
|
|
825
|
+
|
|
826
|
+
Raises
|
|
827
|
+
------
|
|
828
|
+
ValueError
|
|
829
|
+
Raised if duplicate constraint names are found in the schema.
|
|
830
|
+
"""
|
|
831
|
+
constraint_names = set()
|
|
832
|
+
duplicate_names = []
|
|
833
|
+
|
|
834
|
+
for table in self.tables:
|
|
835
|
+
for constraint in table.constraints:
|
|
836
|
+
constraint_name = constraint.name
|
|
837
|
+
if constraint_name in constraint_names:
|
|
838
|
+
duplicate_names.append(constraint_name)
|
|
839
|
+
else:
|
|
840
|
+
constraint_names.add(constraint_name)
|
|
841
|
+
|
|
842
|
+
if duplicate_names:
|
|
843
|
+
raise ValueError(f"Duplicate constraint names found in schema: {duplicate_names}")
|
|
844
|
+
|
|
845
|
+
return self
|
|
846
|
+
|
|
847
|
+
@model_validator(mode="after")
|
|
848
|
+
def check_unique_index_names(self: Schema) -> Schema:
|
|
849
|
+
"""Check for duplicate index names in the schema.
|
|
850
|
+
|
|
851
|
+
Returns
|
|
852
|
+
-------
|
|
853
|
+
`Schema`
|
|
854
|
+
The schema being validated.
|
|
855
|
+
|
|
856
|
+
Raises
|
|
857
|
+
------
|
|
858
|
+
ValueError
|
|
859
|
+
Raised if duplicate index names are found in the schema.
|
|
860
|
+
"""
|
|
861
|
+
index_names = set()
|
|
862
|
+
duplicate_names = []
|
|
863
|
+
|
|
864
|
+
for table in self.tables:
|
|
865
|
+
for index in table.indexes:
|
|
866
|
+
index_name = index.name
|
|
867
|
+
if index_name in index_names:
|
|
868
|
+
duplicate_names.append(index_name)
|
|
869
|
+
else:
|
|
870
|
+
index_names.add(index_name)
|
|
871
|
+
|
|
872
|
+
if duplicate_names:
|
|
873
|
+
raise ValueError(f"Duplicate index names found in schema: {duplicate_names}")
|
|
874
|
+
|
|
875
|
+
return self
|
|
876
|
+
|
|
776
877
|
def _create_id_map(self: Schema) -> Schema:
|
|
777
878
|
"""Create a map of IDs to objects.
|
|
778
879
|
|
felis/metadata.py
CHANGED
|
@@ -342,7 +342,6 @@ class MetaDataBuilder:
|
|
|
342
342
|
"initially": constraint_obj.initially or None,
|
|
343
343
|
}
|
|
344
344
|
constraint: Constraint
|
|
345
|
-
constraint_type = constraint_obj.type
|
|
346
345
|
|
|
347
346
|
if isinstance(constraint_obj, datamodel.ForeignKeyConstraint):
|
|
348
347
|
fk_obj: datamodel.ForeignKeyConstraint = constraint_obj
|
|
@@ -358,7 +357,7 @@ class MetaDataBuilder:
|
|
|
358
357
|
columns = [self._objects[column_id] for column_id in uniq_obj.columns]
|
|
359
358
|
constraint = UniqueConstraint(*columns, **args)
|
|
360
359
|
else:
|
|
361
|
-
raise ValueError(f"Unknown constraint type: {
|
|
360
|
+
raise ValueError(f"Unknown constraint type: {type(constraint_obj)}")
|
|
362
361
|
|
|
363
362
|
self._objects[constraint_obj.id] = constraint
|
|
364
363
|
|
felis/tap.py
CHANGED
|
@@ -37,7 +37,7 @@ from sqlalchemy.sql.expression import Insert, insert
|
|
|
37
37
|
|
|
38
38
|
from felis import datamodel
|
|
39
39
|
|
|
40
|
-
from .datamodel import Constraint, Index, Schema, Table
|
|
40
|
+
from .datamodel import Constraint, ForeignKeyConstraint, Index, Schema, Table
|
|
41
41
|
from .types import FelisType
|
|
42
42
|
|
|
43
43
|
__all__ = ["TapLoadingVisitor", "init_tables"]
|
|
@@ -480,10 +480,9 @@ class TapLoadingVisitor:
|
|
|
480
480
|
A tuple of the SQLAlchemy ORM objects for the TAP_SCHEMA ``key``
|
|
481
481
|
and ``key_columns`` data.
|
|
482
482
|
"""
|
|
483
|
-
constraint_type = constraint_obj.type
|
|
484
483
|
key = None
|
|
485
484
|
key_columns = []
|
|
486
|
-
if
|
|
485
|
+
if isinstance(constraint_obj, ForeignKeyConstraint):
|
|
487
486
|
constraint_name = constraint_obj.name
|
|
488
487
|
description = constraint_obj.description
|
|
489
488
|
utype = constraint_obj.votable_utype
|
felis/version.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
__all__ = ["__version__"]
|
|
2
|
-
__version__ = "27.2024.
|
|
2
|
+
__version__ = "27.2024.3500"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: lsst-felis
|
|
3
|
-
Version: 27.2024.
|
|
3
|
+
Version: 27.2024.3500
|
|
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,11 +1,11 @@
|
|
|
1
1
|
felis/__init__.py,sha256=THmRg3ylB4E73XhFjJX7YlnV_CM3lr_gZO_HqQFzIQ4,937
|
|
2
|
-
felis/cli.py,sha256=
|
|
3
|
-
felis/datamodel.py,sha256=
|
|
4
|
-
felis/metadata.py,sha256=
|
|
2
|
+
felis/cli.py,sha256=0qKk1cGsGcVXJL4fStvWLN5CPHgNwZdS8B2E9Y08wq8,14924
|
|
3
|
+
felis/datamodel.py,sha256=etwLIgzc8RyTVOunkfr7qQJWKqLJ5_HVBJT8jFHzjEY,30174
|
|
4
|
+
felis/metadata.py,sha256=MqNlBoFPMq18Kp0WUfyC8RtlxyBHTL_0SmHanAJgZWk,13698
|
|
5
5
|
felis/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
felis/tap.py,sha256=
|
|
6
|
+
felis/tap.py,sha256=uVmrVnxnVIIdt7MdIv3LhysuEIUJWYvRQLJKvSD03u0,21739
|
|
7
7
|
felis/types.py,sha256=m80GSGfNHQ3-NzRuTzKOyRXLJboPxdk9kzpp1SO8XdY,5510
|
|
8
|
-
felis/version.py,sha256=
|
|
8
|
+
felis/version.py,sha256=UJEaGxD7ag5N-gxngXVq2kv55Dxj7g0WkaPo_JF-goQ,55
|
|
9
9
|
felis/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
10
|
felis/db/dialects.py,sha256=n5La-shu-8fHLIyf8rrazHDyrzATmMCdELtKV_0ymxI,3517
|
|
11
11
|
felis/db/sqltypes.py,sha256=JJy97U8KzAOg5pFi2xZgSjvU8CXXgrzkvCsmo6FLRG4,11060
|
|
@@ -13,11 +13,11 @@ felis/db/utils.py,sha256=I8t9Yui98T8iPyrs0Q-qyjjaxVyX8kQkyizvzv-p4FE,11526
|
|
|
13
13
|
felis/db/variants.py,sha256=eahthrbVeV8ZdGamWQccNmWgx6CCscGrU0vQRs5HZK8,5260
|
|
14
14
|
felis/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
15
|
felis/tests/postgresql.py,sha256=B_xk4fLual5-viGDqP20r94okuc0pbSvytRH_L0fvMs,4035
|
|
16
|
-
lsst_felis-27.2024.
|
|
17
|
-
lsst_felis-27.2024.
|
|
18
|
-
lsst_felis-27.2024.
|
|
19
|
-
lsst_felis-27.2024.
|
|
20
|
-
lsst_felis-27.2024.
|
|
21
|
-
lsst_felis-27.2024.
|
|
22
|
-
lsst_felis-27.2024.
|
|
23
|
-
lsst_felis-27.2024.
|
|
16
|
+
lsst_felis-27.2024.3500.dist-info/COPYRIGHT,sha256=vJAFLFTSF1mhy9eIuA3P6R-3yxTWKQgpig88P-1IzRw,129
|
|
17
|
+
lsst_felis-27.2024.3500.dist-info/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
|
|
18
|
+
lsst_felis-27.2024.3500.dist-info/METADATA,sha256=XsAXbdKyRCr6P9j6mRgvRtzw5860yG6Ol3sd0FiD_kM,1288
|
|
19
|
+
lsst_felis-27.2024.3500.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
|
|
20
|
+
lsst_felis-27.2024.3500.dist-info/entry_points.txt,sha256=Gk2XFujA_Gp52VBk45g5kim8TDoMDJFPctsMqiq72EM,40
|
|
21
|
+
lsst_felis-27.2024.3500.dist-info/top_level.txt,sha256=F4SvPip3iZRVyISi50CHhwTIAokAhSxjWiVcn4IVWRI,6
|
|
22
|
+
lsst_felis-27.2024.3500.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
23
|
+
lsst_felis-27.2024.3500.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|