lsst-felis 27.2024.3100__tar.gz → 27.2024.3300__tar.gz
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.
- {lsst_felis-27.2024.3100/python/lsst_felis.egg-info → lsst_felis-27.2024.3300}/PKG-INFO +1 -1
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/python/felis/cli.py +8 -4
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/python/felis/metadata.py +12 -2
- lsst_felis-27.2024.3300/python/felis/version.py +2 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300/python/lsst_felis.egg-info}/PKG-INFO +1 -1
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/tests/test_cli.py +19 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/tests/test_metadata.py +35 -7
- lsst_felis-27.2024.3100/python/felis/version.py +0 -2
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/COPYRIGHT +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/LICENSE +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/README.rst +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/pyproject.toml +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/python/felis/__init__.py +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/python/felis/datamodel.py +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/python/felis/db/__init__.py +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/python/felis/db/dialects.py +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/python/felis/db/sqltypes.py +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/python/felis/db/utils.py +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/python/felis/db/variants.py +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/python/felis/py.typed +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/python/felis/tap.py +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/python/felis/tests/__init__.py +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/python/felis/tests/postgresql.py +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/python/felis/types.py +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/python/lsst_felis.egg-info/SOURCES.txt +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/python/lsst_felis.egg-info/dependency_links.txt +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/python/lsst_felis.egg-info/entry_points.txt +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/python/lsst_felis.egg-info/requires.txt +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/python/lsst_felis.egg-info/top_level.txt +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/python/lsst_felis.egg-info/zip-safe +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/setup.cfg +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/tests/test_datamodel.py +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/tests/test_postgresql.py +0 -0
- {lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/tests/test_tap.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: lsst-felis
|
|
3
|
-
Version: 27.2024.
|
|
3
|
+
Version: 27.2024.3300
|
|
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+)
|
|
@@ -71,7 +71,7 @@ def cli(log_level: str, log_file: str | None) -> None:
|
|
|
71
71
|
|
|
72
72
|
|
|
73
73
|
@cli.command("create", help="Create database objects from the Felis file")
|
|
74
|
-
@click.option("--engine-url", envvar="
|
|
74
|
+
@click.option("--engine-url", envvar="FELIS_ENGINE_URL", help="SQLAlchemy Engine URL", default="sqlite://")
|
|
75
75
|
@click.option("--schema-name", help="Alternate schema name to override Felis file")
|
|
76
76
|
@click.option(
|
|
77
77
|
"--initialize",
|
|
@@ -86,6 +86,7 @@ def cli(log_level: str, log_file: str | None) -> None:
|
|
|
86
86
|
@click.option(
|
|
87
87
|
"--output-file", "-o", type=click.File(mode="w"), help="Write SQL commands to a file instead of executing"
|
|
88
88
|
)
|
|
89
|
+
@click.option("--ignore-constraints", is_flag=True, help="Ignore constraints when creating tables")
|
|
89
90
|
@click.argument("file", type=click.File())
|
|
90
91
|
def create(
|
|
91
92
|
engine_url: str,
|
|
@@ -95,6 +96,7 @@ def create(
|
|
|
95
96
|
echo: bool,
|
|
96
97
|
dry_run: bool,
|
|
97
98
|
output_file: IO[str] | None,
|
|
99
|
+
ignore_constraints: bool,
|
|
98
100
|
file: IO,
|
|
99
101
|
) -> None:
|
|
100
102
|
"""Create database objects from the Felis file.
|
|
@@ -115,6 +117,8 @@ def create(
|
|
|
115
117
|
Dry run only to print out commands instead of executing.
|
|
116
118
|
output_file
|
|
117
119
|
Write SQL commands to a file instead of executing.
|
|
120
|
+
ignore_constraints
|
|
121
|
+
Ignore constraints when creating tables.
|
|
118
122
|
file
|
|
119
123
|
Felis file to read.
|
|
120
124
|
"""
|
|
@@ -132,7 +136,7 @@ def create(
|
|
|
132
136
|
dry_run = True
|
|
133
137
|
logger.info("Forcing dry run for non-sqlite engine URL with no host")
|
|
134
138
|
|
|
135
|
-
metadata = MetaDataBuilder(schema).build()
|
|
139
|
+
metadata = MetaDataBuilder(schema, ignore_constraints=ignore_constraints).build()
|
|
136
140
|
logger.debug(f"Created metadata with schema name: {metadata.schema}")
|
|
137
141
|
|
|
138
142
|
engine: Engine | MockConnection
|
|
@@ -208,7 +212,7 @@ def init_tap(
|
|
|
208
212
|
tables are created in the database schema specified by the engine URL,
|
|
209
213
|
which must be a PostgreSQL schema or MySQL database that already exists.
|
|
210
214
|
"""
|
|
211
|
-
engine = create_engine(engine_url
|
|
215
|
+
engine = create_engine(engine_url)
|
|
212
216
|
init_tables(
|
|
213
217
|
tap_schema_name,
|
|
214
218
|
tap_schemas_table,
|
|
@@ -221,7 +225,7 @@ def init_tap(
|
|
|
221
225
|
|
|
222
226
|
|
|
223
227
|
@cli.command("load-tap", help="Load metadata from a Felis file into a TAP_SCHEMA database")
|
|
224
|
-
@click.option("--engine-url", envvar="
|
|
228
|
+
@click.option("--engine-url", envvar="FELIS_ENGINE_URL", help="SQLAlchemy Engine URL")
|
|
225
229
|
@click.option("--schema-name", help="Alternate Schema Name for Felis file")
|
|
226
230
|
@click.option("--catalog-name", help="Catalog Name for Schema")
|
|
227
231
|
@click.option("--dry-run", is_flag=True, help="Dry Run Only. Prints out the DDL that would be executed")
|
|
@@ -127,10 +127,16 @@ class MetaDataBuilder:
|
|
|
127
127
|
Whether to apply the schema name to the metadata object.
|
|
128
128
|
apply_schema_to_tables
|
|
129
129
|
Whether to apply the schema name to the tables.
|
|
130
|
+
ignore_constraints
|
|
131
|
+
Whether to ignore constraints when building the metadata.
|
|
130
132
|
"""
|
|
131
133
|
|
|
132
134
|
def __init__(
|
|
133
|
-
self,
|
|
135
|
+
self,
|
|
136
|
+
schema: Schema,
|
|
137
|
+
apply_schema_to_metadata: bool = True,
|
|
138
|
+
apply_schema_to_tables: bool = True,
|
|
139
|
+
ignore_constraints: bool = False,
|
|
134
140
|
) -> None:
|
|
135
141
|
"""Initialize the metadata builder."""
|
|
136
142
|
self.schema = schema
|
|
@@ -141,6 +147,7 @@ class MetaDataBuilder:
|
|
|
141
147
|
self.metadata = MetaData(schema=schema.name if apply_schema_to_metadata else None)
|
|
142
148
|
self._objects: dict[str, Any] = {}
|
|
143
149
|
self.apply_schema_to_tables = apply_schema_to_tables
|
|
150
|
+
self.ignore_constraints = ignore_constraints
|
|
144
151
|
|
|
145
152
|
def build(self) -> MetaData:
|
|
146
153
|
"""Build the SQLAlchemy tables and constraints from the schema.
|
|
@@ -157,7 +164,10 @@ class MetaDataBuilder:
|
|
|
157
164
|
The SQLAlchemy metadata object.
|
|
158
165
|
"""
|
|
159
166
|
self.build_tables()
|
|
160
|
-
self.
|
|
167
|
+
if not self.ignore_constraints:
|
|
168
|
+
self.build_constraints()
|
|
169
|
+
else:
|
|
170
|
+
logger.warning("Ignoring constraints")
|
|
161
171
|
return self.metadata
|
|
162
172
|
|
|
163
173
|
def build_tables(self) -> None:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: lsst-felis
|
|
3
|
-
Version: 27.2024.
|
|
3
|
+
Version: 27.2024.3300
|
|
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+)
|
|
@@ -69,6 +69,25 @@ class CliTestCase(unittest.TestCase):
|
|
|
69
69
|
)
|
|
70
70
|
self.assertEqual(result.exit_code, 0)
|
|
71
71
|
|
|
72
|
+
def test_ignore_constraints(self) -> None:
|
|
73
|
+
"""Test ``--ignore-constraints`` flag of ``create`` command."""
|
|
74
|
+
url = f"sqlite:///{self.tmpdir}/tap.sqlite3"
|
|
75
|
+
|
|
76
|
+
runner = CliRunner()
|
|
77
|
+
result = runner.invoke(
|
|
78
|
+
cli,
|
|
79
|
+
[
|
|
80
|
+
"create",
|
|
81
|
+
"--schema-name=main",
|
|
82
|
+
"--ignore-constraints",
|
|
83
|
+
f"--engine-url={url}",
|
|
84
|
+
"--dry-run",
|
|
85
|
+
TEST_YAML,
|
|
86
|
+
],
|
|
87
|
+
catch_exceptions=False,
|
|
88
|
+
)
|
|
89
|
+
self.assertEqual(result.exit_code, 0)
|
|
90
|
+
|
|
72
91
|
def test_init_tap(self) -> None:
|
|
73
92
|
"""Test for ``init-tap`` command."""
|
|
74
93
|
url = f"sqlite:///{self.tmpdir}/tap.sqlite3"
|
|
@@ -25,6 +25,7 @@ import unittest
|
|
|
25
25
|
import yaml
|
|
26
26
|
from sqlalchemy import (
|
|
27
27
|
CheckConstraint,
|
|
28
|
+
Connection,
|
|
28
29
|
Constraint,
|
|
29
30
|
ForeignKeyConstraint,
|
|
30
31
|
Index,
|
|
@@ -52,11 +53,11 @@ class MetaDataTestCase(unittest.TestCase):
|
|
|
52
53
|
with open(TEST_YAML) as data:
|
|
53
54
|
self.yaml_data = yaml.safe_load(data)
|
|
54
55
|
|
|
55
|
-
def connection(self):
|
|
56
|
+
def connection(self) -> Connection:
|
|
56
57
|
"""Return a connection to the database."""
|
|
57
58
|
return self.engine.connect()
|
|
58
59
|
|
|
59
|
-
def test_create_all(self):
|
|
60
|
+
def test_create_all(self) -> None:
|
|
60
61
|
"""Create all tables in the schema using the metadata object and a
|
|
61
62
|
SQLite connection.
|
|
62
63
|
|
|
@@ -113,16 +114,25 @@ class MetaDataTestCase(unittest.TestCase):
|
|
|
113
114
|
self.assertEqual(md_constraint.name, md_db_constraint.name)
|
|
114
115
|
self.assertEqual(md_constraint.deferrable, md_db_constraint.deferrable)
|
|
115
116
|
self.assertEqual(md_constraint.initially, md_db_constraint.initially)
|
|
116
|
-
|
|
117
|
+
self.assertEqual(
|
|
118
|
+
type(md_constraint), type(md_db_constraint), "Constraint types do not match"
|
|
119
|
+
)
|
|
120
|
+
if isinstance(md_constraint, ForeignKeyConstraint) and isinstance(
|
|
121
|
+
md_db_constraint, ForeignKeyConstraint
|
|
122
|
+
):
|
|
117
123
|
md_fk: ForeignKeyConstraint = md_constraint
|
|
118
124
|
md_db_fk: ForeignKeyConstraint = md_db_constraint
|
|
119
125
|
self.assertEqual(md_fk.referred_table.name, md_db_fk.referred_table.name)
|
|
120
126
|
self.assertEqual(md_fk.column_keys, md_db_fk.column_keys)
|
|
121
|
-
elif isinstance(md_constraint, UniqueConstraint)
|
|
127
|
+
elif isinstance(md_constraint, UniqueConstraint) and isinstance(
|
|
128
|
+
md_db_constraint, UniqueConstraint
|
|
129
|
+
):
|
|
122
130
|
md_uniq: UniqueConstraint = md_constraint
|
|
123
131
|
md_db_uniq: UniqueConstraint = md_db_constraint
|
|
124
132
|
self.assertEqual(md_uniq.columns.keys(), md_db_uniq.columns.keys())
|
|
125
|
-
elif isinstance(md_constraint, CheckConstraint)
|
|
133
|
+
elif isinstance(md_constraint, CheckConstraint) and isinstance(
|
|
134
|
+
md_db_constraint, CheckConstraint
|
|
135
|
+
):
|
|
126
136
|
md_check: CheckConstraint = md_constraint
|
|
127
137
|
md_db_check: CheckConstraint = md_db_constraint
|
|
128
138
|
self.assertEqual(str(md_check.sqltext), str(md_db_check.sqltext))
|
|
@@ -139,7 +149,7 @@ class MetaDataTestCase(unittest.TestCase):
|
|
|
139
149
|
self.assertEqual(md_index.name, md_db_index.name)
|
|
140
150
|
self.assertEqual(md_index.columns.keys(), md_db_index.columns.keys())
|
|
141
151
|
|
|
142
|
-
def test_builder(self):
|
|
152
|
+
def test_builder(self) -> None:
|
|
143
153
|
"""Test that the information in the metadata object created by the
|
|
144
154
|
builder matches the data in the Felis schema used to create it.
|
|
145
155
|
"""
|
|
@@ -188,7 +198,7 @@ class MetaDataTestCase(unittest.TestCase):
|
|
|
188
198
|
for primary_key in primary_keys:
|
|
189
199
|
self.assertTrue(md_table.columns[primary_key].primary_key)
|
|
190
200
|
|
|
191
|
-
def test_timestamp(self):
|
|
201
|
+
def test_timestamp(self) -> None:
|
|
192
202
|
"""Test that the `timestamp` datatype is created correctly."""
|
|
193
203
|
for precision in [None, 6]:
|
|
194
204
|
col = dm.Column(
|
|
@@ -210,6 +220,24 @@ class MetaDataTestCase(unittest.TestCase):
|
|
|
210
220
|
self.assertEqual(mysql_timestamp.timezone, False)
|
|
211
221
|
self.assertEqual(mysql_timestamp.fsp, precision)
|
|
212
222
|
|
|
223
|
+
def test_ignore_constraints(self) -> None:
|
|
224
|
+
"""Test that constraints are not created when the
|
|
225
|
+
``ignore_constraints`` flag is set on the metadata builder.
|
|
226
|
+
"""
|
|
227
|
+
schema = Schema.model_validate(self.yaml_data)
|
|
228
|
+
schema.name = "main"
|
|
229
|
+
builder = MetaDataBuilder(schema, ignore_constraints=True)
|
|
230
|
+
md = builder.build()
|
|
231
|
+
for table in md.tables.values():
|
|
232
|
+
non_primary_key_constraints = [
|
|
233
|
+
c for c in table.constraints if not isinstance(c, PrimaryKeyConstraint)
|
|
234
|
+
]
|
|
235
|
+
self.assertEqual(
|
|
236
|
+
len(non_primary_key_constraints),
|
|
237
|
+
0,
|
|
238
|
+
msg=f"Table {table.name} has non-primary key constraints defined",
|
|
239
|
+
)
|
|
240
|
+
|
|
213
241
|
|
|
214
242
|
if __name__ == "__main__":
|
|
215
243
|
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/python/lsst_felis.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/python/lsst_felis.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
{lsst_felis-27.2024.3100 → lsst_felis-27.2024.3300}/python/lsst_felis.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|