lsst-felis 27.2024.2500__tar.gz → 27.2024.2700__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.

Files changed (34) hide show
  1. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/COPYRIGHT +1 -1
  2. {lsst_felis-27.2024.2500/python/lsst_felis.egg-info → lsst_felis-27.2024.2700}/PKG-INFO +4 -2
  3. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/pyproject.toml +38 -2
  4. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/python/felis/cli.py +145 -29
  5. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/python/felis/datamodel.py +334 -89
  6. lsst_felis-27.2024.2700/python/felis/db/dialects.py +116 -0
  7. lsst_felis-27.2024.2700/python/felis/db/sqltypes.py +443 -0
  8. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/python/felis/db/utils.py +108 -52
  9. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/python/felis/db/variants.py +66 -8
  10. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/python/felis/metadata.py +70 -54
  11. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/python/felis/tap.py +180 -18
  12. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/python/felis/types.py +56 -8
  13. lsst_felis-27.2024.2700/python/felis/version.py +2 -0
  14. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700/python/lsst_felis.egg-info}/PKG-INFO +4 -2
  15. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/python/lsst_felis.egg-info/SOURCES.txt +0 -1
  16. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/python/lsst_felis.egg-info/requires.txt +3 -1
  17. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/tests/test_cli.py +7 -5
  18. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/tests/test_datamodel.py +141 -61
  19. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/tests/test_metadata.py +5 -6
  20. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/tests/test_tap.py +4 -3
  21. lsst_felis-27.2024.2500/python/felis/db/dialects.py +0 -63
  22. lsst_felis-27.2024.2500/python/felis/db/sqltypes.py +0 -204
  23. lsst_felis-27.2024.2500/python/felis/version.py +0 -2
  24. lsst_felis-27.2024.2500/tests/test_datatypes.py +0 -116
  25. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/LICENSE +0 -0
  26. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/README.rst +0 -0
  27. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/python/felis/__init__.py +0 -0
  28. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/python/felis/db/__init__.py +0 -0
  29. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/python/felis/py.typed +0 -0
  30. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/python/lsst_felis.egg-info/dependency_links.txt +0 -0
  31. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/python/lsst_felis.egg-info/entry_points.txt +0 -0
  32. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/python/lsst_felis.egg-info/top_level.txt +0 -0
  33. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/python/lsst_felis.egg-info/zip-safe +0 -0
  34. {lsst_felis-27.2024.2500 → lsst_felis-27.2024.2700}/setup.cfg +0 -0
@@ -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.2500
3
+ Version: 27.2024.2700
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+)
@@ -27,4 +27,6 @@ Requires-Dist: lsst-utils
27
27
  Provides-Extra: test
28
28
  Requires-Dist: pytest>=3.2; extra == "test"
29
29
  Provides-Extra: dev
30
- Requires-Dist: documenteer[guide]; extra == "dev"
30
+ Requires-Dist: documenteer[guide]<2; extra == "dev"
31
+ Requires-Dist: autodoc_pydantic; extra == "dev"
32
+ Requires-Dist: sphinx-click; extra == "dev"
@@ -40,7 +40,9 @@ test = [
40
40
  "pytest >= 3.2"
41
41
  ]
42
42
  dev = [
43
- "documenteer[guide]"
43
+ "documenteer[guide] < 2",
44
+ "autodoc_pydantic",
45
+ "sphinx-click",
44
46
  ]
45
47
 
46
48
  [tool.pytest.ini_options]
@@ -61,7 +63,6 @@ version = { attr = "lsst_versions.get_lsst_version" }
61
63
  [project.scripts]
62
64
  felis = "felis.cli:cli"
63
65
 
64
-
65
66
  [tool.towncrier]
66
67
  package = "felis"
67
68
  package_dir = "python"
@@ -152,6 +153,41 @@ select = [
152
153
  "UP", # pyupgrade
153
154
  ]
154
155
 
156
+ [tool.pydocstyle]
157
+ convention = "numpy"
158
+ # Our coding style does not require docstrings for magic methods (D105)
159
+ # Our docstyle documents __init__ at the class level (D107)
160
+ # We allow methods to inherit docstrings and this is not compatible with D102.
161
+ # Docstring at the very first line is not required
162
+ # D200, D205 and D400 all complain if the first sentence of the docstring does
163
+ # not fit on one line. We do not require docstrings in __init__ files (D104).
164
+ add-ignore = ["D107", "D105", "D102", "D100", "D200", "D205", "D400", "D104"]
165
+
166
+ [tool.ruff.lint.pycodestyle]
167
+ max-doc-length = 79
168
+
169
+ [tool.ruff.lint.pydocstyle]
170
+ convention = "numpy"
171
+
172
+ [tool.numpydoc_validation]
173
+ checks = [
174
+ "all", # All except the rules listed below.
175
+ "SA01", # See Also section.
176
+ "SA04", # We don't use descriptions with See Also.
177
+ "EX01", # Example section.
178
+ "SS06", # Summary can go into second line.
179
+ "GL01", # Summary text can start on same line as """
180
+ "GL08", # Do not require docstring.
181
+ "ES01", # No extended summary required.
182
+ "SS05", # pydocstyle is better at finding infinitive verb.
183
+ "PR04", # Sphinx does not require parameter type.
184
+ ]
185
+ exclude = [
186
+ "^test_.*", # Do not test docstrings in test code.
187
+ '^__init__$',
188
+ '\._[a-zA-Z_]+$', # Private methods.
189
+ ]
190
+
155
191
  [tool.pydeps]
156
192
  max_bacon = 2
157
193
  no_show = true
@@ -1,3 +1,5 @@
1
+ """Click command line interface."""
2
+
1
3
  # This file is part of felis.
2
4
  #
3
5
  # Developed for the LSST Data Management System.
@@ -38,6 +40,8 @@ from .db.utils import DatabaseContext
38
40
  from .metadata import MetaDataBuilder
39
41
  from .tap import Tap11Base, TapLoadingVisitor, init_tables
40
42
 
43
+ __all__ = ["cli"]
44
+
41
45
  logger = logging.getLogger("felis")
42
46
 
43
47
  loglevel_choices = ["CRITICAL", "FATAL", "ERROR", "WARNING", "INFO", "DEBUG"]
@@ -59,14 +63,14 @@ loglevel_choices = ["CRITICAL", "FATAL", "ERROR", "WARNING", "INFO", "DEBUG"]
59
63
  help="Felis log file path",
60
64
  )
61
65
  def cli(log_level: str, log_file: str | None) -> None:
62
- """Felis Command Line Tools."""
66
+ """Felis command line tools"""
63
67
  if log_file:
64
68
  logging.basicConfig(filename=log_file, level=log_level)
65
69
  else:
66
70
  logging.basicConfig(level=log_level)
67
71
 
68
72
 
69
- @cli.command("create")
73
+ @cli.command("create", help="Create database objects from the Felis file")
70
74
  @click.option("--engine-url", envvar="ENGINE_URL", help="SQLAlchemy Engine URL", default="sqlite://")
71
75
  @click.option("--schema-name", help="Alternate schema name to override Felis file")
72
76
  @click.option(
@@ -89,7 +93,34 @@ def create(
89
93
  output_file: IO[str] | None,
90
94
  file: IO,
91
95
  ) -> None:
92
- """Create database objects from the Felis file."""
96
+ """Create database objects from the Felis file.
97
+
98
+ Parameters
99
+ ----------
100
+ engine_url
101
+ SQLAlchemy Engine URL.
102
+ schema_name
103
+ Alternate schema name to override Felis file.
104
+ create_if_not_exists
105
+ Create the schema in the database if it does not exist.
106
+ drop_if_exists
107
+ Drop schema if it already exists in the database.
108
+ echo
109
+ Echo database commands as they are executed.
110
+ dry_run
111
+ Dry run only to print out commands instead of executing.
112
+ output_file
113
+ Write SQL commands to a file instead of executing.
114
+ file
115
+ Felis file to read.
116
+
117
+ Notes
118
+ -----
119
+ This command creates database objects from the Felis file. The
120
+ ``--create-if-not-exists`` or ``--drop-if-exists`` flags can be used to
121
+ create a new MySQL database or PostgreSQL schema if it does not exist
122
+ already.
123
+ """
93
124
  yaml_data = yaml.safe_load(file)
94
125
  schema = Schema.model_validate(yaml_data)
95
126
  url = make_url(engine_url)
@@ -130,13 +161,13 @@ def create(
130
161
  context.create_all()
131
162
 
132
163
 
133
- @cli.command("init-tap")
134
- @click.option("--tap-schema-name", help="Alt Schema Name for TAP_SCHEMA")
135
- @click.option("--tap-schemas-table", help="Alt Table Name for TAP_SCHEMA.schemas")
136
- @click.option("--tap-tables-table", help="Alt Table Name for TAP_SCHEMA.tables")
137
- @click.option("--tap-columns-table", help="Alt Table Name for TAP_SCHEMA.columns")
138
- @click.option("--tap-keys-table", help="Alt Table Name for TAP_SCHEMA.keys")
139
- @click.option("--tap-key-columns-table", help="Alt Table Name for TAP_SCHEMA.key_columns")
164
+ @cli.command("init-tap", help="Initialize TAP_SCHEMA objects in the database")
165
+ @click.option("--tap-schema-name", help="Alternate database schema name for 'TAP_SCHEMA'")
166
+ @click.option("--tap-schemas-table", help="Alternate table name for 'schemas'")
167
+ @click.option("--tap-tables-table", help="Alternate table name for 'tables'")
168
+ @click.option("--tap-columns-table", help="Alternate table name for 'columns'")
169
+ @click.option("--tap-keys-table", help="Alternate table name for 'keys'")
170
+ @click.option("--tap-key-columns-table", help="Alternate table name for 'key_columns'")
140
171
  @click.argument("engine-url")
141
172
  def init_tap(
142
173
  engine_url: str,
@@ -147,10 +178,31 @@ def init_tap(
147
178
  tap_keys_table: str,
148
179
  tap_key_columns_table: str,
149
180
  ) -> None:
150
- """Initialize TAP 1.1 TAP_SCHEMA objects.
181
+ """Initialize TAP_SCHEMA objects in the database.
182
+
183
+ Parameters
184
+ ----------
185
+ engine_url
186
+ SQLAlchemy Engine URL. The target PostgreSQL schema or MySQL database
187
+ must already exist and be referenced in the URL.
188
+ tap_schema_name
189
+ Alterate name for the database schema ``TAP_SCHEMA``.
190
+ tap_schemas_table
191
+ Alterate table name for ``schemas``.
192
+ tap_tables_table
193
+ Alterate table name for ``tables``.
194
+ tap_columns_table
195
+ Alterate table name for ``columns``.
196
+ tap_keys_table
197
+ Alterate table name for ``keys``.
198
+ tap_key_columns_table
199
+ Alterate table name for ``key_columns``.
151
200
 
152
- Please verify the schema/catalog you are executing this in in your
153
- engine URL.
201
+ Notes
202
+ -----
203
+ The supported version of TAP_SCHEMA in the SQLAlchemy metadata is 1.1. The
204
+ tables are created in the database schema specified by the engine URL,
205
+ which must be a PostgreSQL schema or MySQL database that already exists.
154
206
  """
155
207
  engine = create_engine(engine_url, echo=True)
156
208
  init_tables(
@@ -164,19 +216,19 @@ def init_tap(
164
216
  Tap11Base.metadata.create_all(engine)
165
217
 
166
218
 
167
- @cli.command("load-tap")
219
+ @cli.command("load-tap", help="Load metadata from a Felis file into a TAP_SCHEMA database")
168
220
  @click.option("--engine-url", envvar="ENGINE_URL", help="SQLAlchemy Engine URL to catalog")
169
221
  @click.option("--schema-name", help="Alternate Schema Name for Felis file")
170
222
  @click.option("--catalog-name", help="Catalog Name for Schema")
171
223
  @click.option("--dry-run", is_flag=True, help="Dry Run Only. Prints out the DDL that would be executed")
172
- @click.option("--tap-schema-name", help="Alt Schema Name for TAP_SCHEMA")
173
- @click.option("--tap-tables-postfix", help="Postfix for TAP table names")
174
- @click.option("--tap-schemas-table", help="Alt Table Name for TAP_SCHEMA.schemas")
175
- @click.option("--tap-tables-table", help="Alt Table Name for TAP_SCHEMA.tables")
176
- @click.option("--tap-columns-table", help="Alt Table Name for TAP_SCHEMA.columns")
177
- @click.option("--tap-keys-table", help="Alt Table Name for TAP_SCHEMA.keys")
178
- @click.option("--tap-key-columns-table", help="Alt Table Name for TAP_SCHEMA.key_columns")
179
- @click.option("--tap-schema-index", type=int, help="TAP_SCHEMA index of the schema")
224
+ @click.option("--tap-schema-name", help="Alternate schema name for 'TAP_SCHEMA'")
225
+ @click.option("--tap-tables-postfix", help="Postfix for TAP_SCHEMA table names")
226
+ @click.option("--tap-schemas-table", help="Alternate table name for 'schemas'")
227
+ @click.option("--tap-tables-table", help="Alternate table name for 'tables'")
228
+ @click.option("--tap-columns-table", help="Alternate table name for 'columns'")
229
+ @click.option("--tap-keys-table", help="Alternate table name for 'keys'")
230
+ @click.option("--tap-key-columns-table", help="Alternate table name for 'key_columns'")
231
+ @click.option("--tap-schema-index", type=int, help="TAP_SCHEMA index of the schema in this environment")
180
232
  @click.argument("file", type=click.File())
181
233
  def load_tap(
182
234
  engine_url: str,
@@ -193,10 +245,46 @@ def load_tap(
193
245
  tap_schema_index: int,
194
246
  file: io.TextIOBase,
195
247
  ) -> None:
196
- """Load TAP metadata from a Felis FILE.
248
+ """Load TAP metadata from a Felis file.
249
+
250
+ This command loads the associated TAP metadata from a Felis YAML file
251
+ into the TAP_SCHEMA tables.
197
252
 
198
- This command loads the associated TAP metadata from a Felis FILE
199
- to the TAP_SCHEMA tables.
253
+ Parameters
254
+ ----------
255
+ engine_url
256
+ SQLAlchemy Engine URL to catalog.
257
+ schema_name
258
+ Alternate schema name. This overrides the schema name in the
259
+ ``catalog`` field of the Felis file.
260
+ catalog_name
261
+ Catalog name for the schema. This possibly duplicates the
262
+ ``tap_schema_name`` argument (DM-44870).
263
+ dry_run
264
+ Dry run only to print out commands instead of executing.
265
+ tap_schema_name
266
+ Alternate name for the schema of TAP_SCHEMA in the database.
267
+ tap_tables_postfix
268
+ Postfix for TAP table names that will be automatically appended.
269
+ tap_schemas_table
270
+ Alternate table name for ``schemas``.
271
+ tap_tables_table
272
+ Alternate table name for ``tables``.
273
+ tap_columns_table
274
+ Alternate table name for ``columns``.
275
+ tap_keys_table
276
+ Alternate table name for ``keys``.
277
+ tap_key_columns_table
278
+ Alternate table name for ``key_columns``.
279
+ tap_schema_index
280
+ TAP_SCHEMA index of the schema in this TAP environment.
281
+ file
282
+ Felis file to read.
283
+
284
+ Notes
285
+ -----
286
+ The data will be loaded into the TAP_SCHEMA from the engine URL. The
287
+ tables must have already been initialized or an error will occur.
200
288
  """
201
289
  yaml_data = yaml.load(file, Loader=yaml.SafeLoader)
202
290
  schema = Schema.model_validate(yaml_data)
@@ -239,10 +327,12 @@ def load_tap(
239
327
  tap_visitor.visit_schema(schema)
240
328
 
241
329
 
242
- @cli.command("validate")
243
- @click.option("--check-description", is_flag=True, help="Require description for all objects", default=False)
330
+ @cli.command("validate", help="Validate one or more Felis YAML files")
331
+ @click.option(
332
+ "--check-description", is_flag=True, help="Check that all objects have a description", default=False
333
+ )
244
334
  @click.option(
245
- "--check-redundant-datatypes", is_flag=True, help="Check for redundant datatypes", default=False
335
+ "--check-redundant-datatypes", is_flag=True, help="Check for redundant datatype overrides", default=False
246
336
  )
247
337
  @click.option(
248
338
  "--check-tap-table-indexes",
@@ -264,7 +354,33 @@ def validate(
264
354
  check_tap_principal: bool,
265
355
  files: Iterable[io.TextIOBase],
266
356
  ) -> None:
267
- """Validate one or more felis YAML files."""
357
+ """Validate one or more felis YAML files.
358
+
359
+ Parameters
360
+ ----------
361
+ check_description
362
+ Check that all objects have a valid description.
363
+ check_redundant_datatypes
364
+ Check for redundant type overrides.
365
+ check_tap_table_indexes
366
+ Check that every table has a unique TAP table index.
367
+ check_tap_principal
368
+ Check that at least one column per table is flagged as TAP principal.
369
+ files
370
+ The Felis YAML files to validate.
371
+
372
+ Raises
373
+ ------
374
+ click.exceptions.Exit
375
+ If any validation errors are found. The ``ValidationError`` which is
376
+ thrown when a schema fails to validate will be logged as an error
377
+ message.
378
+
379
+ Notes
380
+ -----
381
+ All of the ``check`` flags are turned off by default and represent
382
+ optional validations controlled by the Pydantic context.
383
+ """
268
384
  rc = 0
269
385
  for file in files:
270
386
  file_name = getattr(file, "name", None)