Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DM-37744: Make daf_butler compatible with sqlalchemy 2 #788

Merged
merged 4 commits into from Feb 11, 2023

Conversation

andy-slac
Copy link
Contributor

Lots of changes everywhere to make it run with sqlalchemy 2. Many mypy fixes. I enabled sqlalchemy 2 in requirements, so GA should build with that.

Checklist

  • ran Jenkins
  • added a release note for user-visible changes to doc/changes

There are two issues fixed in this commit:
- SA now handles UUID internally for postgresql and returns UUID.
- Transaction handling needs more care as there is no autocommit.
- str(URL) replaces password with starts.
@codecov
Copy link

codecov bot commented Feb 10, 2023

Codecov Report

Base: 85.48% // Head: 85.49% // Increases project coverage by +0.01% 🎉

Coverage data is based on head (2c47f31) compared to base (e5ed552).
Patch coverage: 96.29% of modified lines in pull request are covered.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #788      +/-   ##
==========================================
+ Coverage   85.48%   85.49%   +0.01%     
==========================================
  Files         265      265              
  Lines       35043    35047       +4     
  Branches     7367     7370       +3     
==========================================
+ Hits        29957    29964       +7     
+ Misses       3770     3768       -2     
+ Partials     1316     1315       -1     
Impacted Files Coverage Δ
...thon/lsst/daf/butler/registry/bridge/monolithic.py 87.50% <ø> (ø)
...ython/lsst/daf/butler/registry/dimensions/table.py 92.81% <ø> (ø)
...n/lsst/daf/butler/registry/databases/postgresql.py 83.24% <80.00%> (+0.17%) ⬆️
python/lsst/daf/butler/core/ddl.py 84.61% <100.00%> (+0.13%) ⬆️
python/lsst/daf/butler/core/storedFileInfo.py 87.17% <100.00%> (ø)
python/lsst/daf/butler/registries/sql.py 83.50% <100.00%> (ø)
python/lsst/daf/butler/registry/attributes.py 100.00% <100.00%> (ø)
...ython/lsst/daf/butler/registry/connectionString.py 87.50% <100.00%> (+7.50%) ⬆️
...butler/registry/datasets/byDimensions/summaries.py 96.29% <100.00%> (ø)
...n/lsst/daf/butler/registry/interfaces/_database.py 87.65% <100.00%> (+0.02%) ⬆️
... and 6 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

Copy link
Member

@timj timj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Looks great. I can confirm that the tests no longer have any sqlalchemy warnings (and I believe we still have that env var turned on)

@@ -1763,7 +1774,9 @@ def query(
connection = self._engine.connect()
else:
connection = self._session_connection
result = connection.execute(sql, *args, **kwargs)
# TODO: SelectBase is not good for execute(), but it used everywhere,
# e.g. in daf_relation. We should switch to Executable at some point.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make a ticket for this if daf_relation is using some old syntax? cc/ @TallJimbo

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made DM-37971 for @TallJimbo, but you can reassign it to me if you don't have time to work on that.

if value is None:
return value
elif isinstance(value, uuid.UUID):
# sqlalchemy 2 converts to UUID internally
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does that mean in sqlalchemy 1.4 we can't do this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In 1.4 strings are returned for UUIDs for both Postgres and sqlite, strings are still handled in else clause below.

@@ -197,7 +200,7 @@ def _convertExclusionConstraintSpec(
metadata: sqlalchemy.MetaData,
) -> sqlalchemy.schema.Constraint:
# Docstring inherited.
args = []
args: list[tuple[sqlalchemy.schema.Column, str]] = []
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you surprised this method never gets called?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised. I'd expect this to be called whenever we register a calibration dataset type with a new set of dimensions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Grepping through the code it looks like that it is only called when TableSpec.exclusion is not empty, and that could only happen when timespan representation class hasExclusionConstraint() returns True. I found only one implementation of hasExclusionConstraint() which always returns False.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, interesting. The PostgreSQL-specific timespan representation should have hasExclusionConstraint() return True, as that's one of the things that btree_gist brings, and would avoid a table lock (IIRC) in certify (which I thought we were already avoiding for PostgreSQL).

But I'm not sure if we can just fix that without a migration now that we've made the mistake.

@@ -57,7 +58,9 @@
from .._exceptions import ConflictingDefinitionError


def _checkExistingTableDefinition(name: str, spec: ddl.TableSpec, inspection: List[Dict[str, Any]]) -> None:
# TODO: method is called with list[ReflectedColumn] in SA 2, and
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So when we get SA2 we can make the type annotation explicit about that list contents?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, we should clean it up when we decide to drop 1.4 support.

@andy-slac andy-slac merged commit 460accc into main Feb 11, 2023
@andy-slac andy-slac deleted the tickets/DM-37744 branch February 11, 2023 01:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants