-
Notifications
You must be signed in to change notification settings - Fork 331
Always dispose of engines in create_database and drop_database #795
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
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ashanbrown Thanks for submitting this.
Please add a test that demonstrates that this issue both exists and is fixed by this change. Thanks!
try: | ||
if dialect_name == 'postgresql': | ||
if not template: | ||
template = 'template1' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This kicks off a try/except
block that is larger than it should be.
I recommend modifying this so that the conditionals exclusively determine what the text
variable should be.
text = ''
if dialect_name == 'postgresql':
if not template:
template = 'template1'
text = "CREATE DATABASE {} CHARACTER SET = '{}'".format(
quote(conn, database), encoding
)
elif dialect_name == 'mysql':
...
text = ...
elif dialect_name == 'sqlite' and database != ':memory:':
if database:
text = 'CREATE TABLE DB(id int); DROP TABLE DB;'
else:
text = f'CREATE DATABASE {quote(conn, database)}'
and then reduce the try/except
block to something like this, which accommodates the possibility that text
is an empty string.
if text:
try:
with engine.begin() as conn:
conn.execute(sa.text(text))
finally:
engine.dispose()
(It's possible that engine.dispose()
still needs to be run, so please check whether the if text:
conditional should actually be inside the try
block.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At least one of the examples (sqlite), requires multiple executing multiple text
values, so this could possibly get a little messy. If we just had a context manager provide an engine that is always disposed, would that resolve your concern? Then we could also clean up duplicate code between create_database and drop_database.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I addressed that by putting both commands into the same line. I don't anticipate it being messy, but could be wrong.
elif dialect_name == 'sqlite' and database != ':memory:':
if database:
text = 'CREATE TABLE DB(id int); DROP TABLE DB;'
tests/functions/test_database.py
Outdated
pool = engine.pool | ||
|
||
# a disposed engine should not have the same pool | ||
assert engine.pool is not pool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could also mock the dispose method if this doesn't seem sufficient.
To ensure timely cleanup of resources, dispose of any engines after using them.
This need surfaced because psyopg3 reports a warning later if a connection if gc'd, making it desirable to dispose of the engine (and its connection pool) even if the command fails.
This pattern is already in place for
database_exists
, so I'm just suggesting we extend it forcreate_engine
anddrop_database
.