4444
4545CONTEXT_SETTINGS = dict (help_option_names = ["-h" , "--help" ])
4646
47+
48+ def _register_db_for_cleanup (db ):
49+ """Register a database to be closed when the Click context is cleaned up."""
50+ ctx = click .get_current_context (silent = True )
51+ if ctx is None :
52+ return
53+ if not hasattr (ctx , "_databases_to_close" ):
54+ ctx ._databases_to_close = []
55+ ctx .call_on_close (lambda : _close_databases (ctx ))
56+ ctx ._databases_to_close .append (db )
57+
58+
59+ def _close_databases (ctx ):
60+ """Close all databases registered for cleanup."""
61+ if hasattr (ctx , "_databases_to_close" ):
62+ for db in ctx ._databases_to_close :
63+ try :
64+ db .close ()
65+ except Exception :
66+ pass
67+
68+
4769VALID_COLUMN_TYPES = ("INTEGER" , "TEXT" , "FLOAT" , "REAL" , "BLOB" )
4870
4971UNICODE_ERROR = """
@@ -183,6 +205,7 @@ def tables(
183205 sqlite-utils tables trees.db
184206 """
185207 db = sqlite_utils .Database (path )
208+ _register_db_for_cleanup (db )
186209 _load_extensions (db , load_extension )
187210 headers = ["view" if views else "table" ]
188211 if counts :
@@ -309,6 +332,7 @@ def optimize(path, tables, no_vacuum, load_extension):
309332 sqlite-utils optimize chickens.db
310333 """
311334 db = sqlite_utils .Database (path )
335+ _register_db_for_cleanup (db )
312336 _load_extensions (db , load_extension )
313337 if not tables :
314338 tables = db .table_names (fts4 = True ) + db .table_names (fts5 = True )
@@ -336,6 +360,7 @@ def rebuild_fts(path, tables, load_extension):
336360 sqlite-utils rebuild-fts chickens.db chickens
337361 """
338362 db = sqlite_utils .Database (path )
363+ _register_db_for_cleanup (db )
339364 _load_extensions (db , load_extension )
340365 if not tables :
341366 tables = db .table_names (fts4 = True ) + db .table_names (fts5 = True )
@@ -360,6 +385,7 @@ def analyze(path, names):
360385 sqlite-utils analyze chickens.db
361386 """
362387 db = sqlite_utils .Database (path )
388+ _register_db_for_cleanup (db )
363389 try :
364390 if names :
365391 for name in names :
@@ -384,7 +410,9 @@ def vacuum(path):
384410 \b
385411 sqlite-utils vacuum chickens.db
386412 """
387- sqlite_utils .Database (path ).vacuum ()
413+ db = sqlite_utils .Database (path )
414+ _register_db_for_cleanup (db )
415+ db .vacuum ()
388416
389417
390418@cli .command ()
@@ -403,6 +431,7 @@ def dump(path, load_extension):
403431 sqlite-utils dump chickens.db
404432 """
405433 db = sqlite_utils .Database (path )
434+ _register_db_for_cleanup (db )
406435 _load_extensions (db , load_extension )
407436 for line in db .iterdump ():
408437 click .echo (line )
@@ -464,6 +493,7 @@ def add_column(
464493 sqlite-utils add-column chickens.db chickens weight float
465494 """
466495 db = sqlite_utils .Database (path )
496+ _register_db_for_cleanup (db )
467497 _load_extensions (db , load_extension )
468498 try :
469499 db [table ].add_column (
@@ -501,6 +531,7 @@ def add_foreign_key(
501531 sqlite-utils add-foreign-key my.db books author_id authors id
502532 """
503533 db = sqlite_utils .Database (path )
534+ _register_db_for_cleanup (db )
504535 _load_extensions (db , load_extension )
505536 try :
506537 db [table ].add_foreign_key (column , other_table , other_column , ignore = ignore )
@@ -528,6 +559,7 @@ def add_foreign_keys(path, foreign_key, load_extension):
528559 authors country_id countries id
529560 """
530561 db = sqlite_utils .Database (path )
562+ _register_db_for_cleanup (db )
531563 _load_extensions (db , load_extension )
532564 if len (foreign_key ) % 4 != 0 :
533565 raise click .ClickException (
@@ -559,6 +591,7 @@ def index_foreign_keys(path, load_extension):
559591 sqlite-utils index-foreign-keys chickens.db
560592 """
561593 db = sqlite_utils .Database (path )
594+ _register_db_for_cleanup (db )
562595 _load_extensions (db , load_extension )
563596 db .index_foreign_keys ()
564597
@@ -603,6 +636,7 @@ def create_index(
603636 sqlite-utils create-index chickens.db chickens -- -name
604637 """
605638 db = sqlite_utils .Database (path )
639+ _register_db_for_cleanup (db )
606640 _load_extensions (db , load_extension )
607641 # Treat -prefix as descending for columns
608642 columns = []
@@ -660,6 +694,7 @@ def enable_fts(
660694 fts_version = "FTS4"
661695
662696 db = sqlite_utils .Database (path )
697+ _register_db_for_cleanup (db )
663698 _load_extensions (db , load_extension )
664699 try :
665700 db [table ].enable_fts (
@@ -691,6 +726,7 @@ def populate_fts(path, table, column, load_extension):
691726 sqlite-utils populate-fts chickens.db chickens name
692727 """
693728 db = sqlite_utils .Database (path )
729+ _register_db_for_cleanup (db )
694730 _load_extensions (db , load_extension )
695731 db [table ].populate_fts (column )
696732
@@ -712,6 +748,7 @@ def disable_fts(path, table, load_extension):
712748 sqlite-utils disable-fts chickens.db chickens
713749 """
714750 db = sqlite_utils .Database (path )
751+ _register_db_for_cleanup (db )
715752 _load_extensions (db , load_extension )
716753 db [table ].disable_fts ()
717754
@@ -734,6 +771,7 @@ def enable_wal(path, load_extension):
734771 """
735772 for path_ in path :
736773 db = sqlite_utils .Database (path_ )
774+ _register_db_for_cleanup (db )
737775 _load_extensions (db , load_extension )
738776 db .enable_wal ()
739777
@@ -756,6 +794,7 @@ def disable_wal(path, load_extension):
756794 """
757795 for path_ in path :
758796 db = sqlite_utils .Database (path_ )
797+ _register_db_for_cleanup (db )
759798 _load_extensions (db , load_extension )
760799 db .disable_wal ()
761800
@@ -777,6 +816,7 @@ def enable_counts(path, tables, load_extension):
777816 sqlite-utils enable-counts chickens.db
778817 """
779818 db = sqlite_utils .Database (path )
819+ _register_db_for_cleanup (db )
780820 _load_extensions (db , load_extension )
781821 if not tables :
782822 db .enable_counts ()
@@ -805,6 +845,7 @@ def reset_counts(path, load_extension):
805845 sqlite-utils reset-counts chickens.db
806846 """
807847 db = sqlite_utils .Database (path )
848+ _register_db_for_cleanup (db )
808849 _load_extensions (db , load_extension )
809850 db .reset_counts ()
810851
@@ -964,6 +1005,7 @@ def insert_upsert_implementation(
9641005 strict = False ,
9651006):
9661007 db = sqlite_utils .Database (path )
1008+ _register_db_for_cleanup (db )
9671009 _load_extensions (db , load_extension )
9681010 _maybe_register_functions (db , functions )
9691011 if (delimiter or quotechar or sniff or no_headers ) and not tsv :
@@ -1480,6 +1522,7 @@ def create_database(path, enable_wal, init_spatialite, load_extension):
14801522 sqlite-utils create-database trees.db
14811523 """
14821524 db = sqlite_utils .Database (path )
1525+ _register_db_for_cleanup (db )
14831526 if enable_wal :
14841527 db .enable_wal ()
14851528
@@ -1569,6 +1612,7 @@ def create_table(
15691612 Valid column types are text, integer, float and blob.
15701613 """
15711614 db = sqlite_utils .Database (path )
1615+ _register_db_for_cleanup (db )
15721616 _load_extensions (db , load_extension )
15731617 if len (columns ) % 2 == 1 :
15741618 raise click .ClickException (
@@ -1620,6 +1664,7 @@ def duplicate(path, table, new_table, ignore, load_extension):
16201664 Create a duplicate of this table, copying across the schema and all row data.
16211665 """
16221666 db = sqlite_utils .Database (path )
1667+ _register_db_for_cleanup (db )
16231668 _load_extensions (db , load_extension )
16241669 try :
16251670 db [table ].duplicate (new_table )
@@ -1643,6 +1688,7 @@ def rename_table(path, table, new_name, ignore, load_extension):
16431688 Rename this table.
16441689 """
16451690 db = sqlite_utils .Database (path )
1691+ _register_db_for_cleanup (db )
16461692 _load_extensions (db , load_extension )
16471693 try :
16481694 db .rename_table (table , new_name )
@@ -1671,6 +1717,7 @@ def drop_table(path, table, ignore, load_extension):
16711717 sqlite-utils drop-table chickens.db chickens
16721718 """
16731719 db = sqlite_utils .Database (path )
1720+ _register_db_for_cleanup (db )
16741721 _load_extensions (db , load_extension )
16751722 try :
16761723 db [table ].drop (ignore = ignore )
@@ -1707,6 +1754,7 @@ def create_view(path, view, select, ignore, replace, load_extension):
17071754 'select * from chickens where weight > 3'
17081755 """
17091756 db = sqlite_utils .Database (path )
1757+ _register_db_for_cleanup (db )
17101758 _load_extensions (db , load_extension )
17111759 # Does view already exist?
17121760 if view in db .view_names ():
@@ -1741,6 +1789,7 @@ def drop_view(path, view, ignore, load_extension):
17411789 sqlite-utils drop-view chickens.db heavy_chickens
17421790 """
17431791 db = sqlite_utils .Database (path )
1792+ _register_db_for_cleanup (db )
17441793 _load_extensions (db , load_extension )
17451794 try :
17461795 db [view ].drop (ignore = ignore )
@@ -1805,6 +1854,7 @@ def query(
18051854 -p age 1
18061855 """
18071856 db = sqlite_utils .Database (path )
1857+ _register_db_for_cleanup (db )
18081858 for alias , attach_path in attach :
18091859 db .attach (alias , attach_path )
18101860 _load_extensions (db , load_extension )
@@ -1939,6 +1989,8 @@ def memory(
19391989 sqlite-utils memory animals.csv --schema
19401990 """
19411991 db = sqlite_utils .Database (memory = True )
1992+ if not return_db :
1993+ _register_db_for_cleanup (db )
19421994
19431995 # If --dump or --save or --analyze used but no paths detected, assume SQL query is a path:
19441996 if (dump or save or schema or analyze ) and not paths :
@@ -2004,6 +2056,7 @@ def memory(
20042056
20052057 if save :
20062058 db2 = sqlite_utils .Database (save )
2059+ _register_db_for_cleanup (db2 )
20072060 for line in db .iterdump ():
20082061 db2 .execute (line )
20092062 return
@@ -2140,6 +2193,7 @@ def search(
21402193 sqlite-utils search data.db chickens lila
21412194 """
21422195 db = sqlite_utils .Database (path )
2196+ _register_db_for_cleanup (db )
21432197 _load_extensions (db , load_extension )
21442198 # Check table exists
21452199 table_obj = db [dbtable ]
@@ -2307,7 +2361,9 @@ def triggers(
23072361 """
23082362 sql = "select name, tbl_name as \" table\" , sql from sqlite_master where type = 'trigger'"
23092363 if tables :
2310- quote = sqlite_utils .Database (memory = True ).quote
2364+ _quote_db = sqlite_utils .Database (memory = True )
2365+ _register_db_for_cleanup (_quote_db )
2366+ quote = _quote_db .quote
23112367 sql += ' and "table" in ({})' .format (
23122368 ", " .join (quote (table ) for table in tables )
23132369 )
@@ -2372,7 +2428,9 @@ def indexes(
23722428 sqlite_master.type = 'table'
23732429 """
23742430 if tables :
2375- quote = sqlite_utils .Database (memory = True ).quote
2431+ _quote_db = sqlite_utils .Database (memory = True )
2432+ _register_db_for_cleanup (_quote_db )
2433+ quote = _quote_db .quote
23762434 sql += " and sqlite_master.name in ({})" .format (
23772435 ", " .join (quote (table ) for table in tables )
23782436 )
@@ -2415,6 +2473,7 @@ def schema(
24152473 sqlite-utils schema trees.db
24162474 """
24172475 db = sqlite_utils .Database (path )
2476+ _register_db_for_cleanup (db )
24182477 _load_extensions (db , load_extension )
24192478 if tables :
24202479 for table in tables :
@@ -2507,6 +2566,7 @@ def transform(
25072566 --rename column2 column_renamed
25082567 """
25092568 db = sqlite_utils .Database (path )
2569+ _register_db_for_cleanup (db )
25102570 _load_extensions (db , load_extension )
25112571 types = {}
25122572 kwargs = {}
@@ -2590,6 +2650,7 @@ def extract(
25902650 sqlite-utils extract trees.db Street_Trees species
25912651 """
25922652 db = sqlite_utils .Database (path )
2653+ _register_db_for_cleanup (db )
25932654 _load_extensions (db , load_extension )
25942655 kwargs = dict (
25952656 columns = columns ,
@@ -2734,6 +2795,7 @@ def _content_text(p):
27342795 yield row
27352796
27362797 db = sqlite_utils .Database (path )
2798+ _register_db_for_cleanup (db )
27372799 _load_extensions (db , load_extension )
27382800 try :
27392801 with db .conn :
@@ -2792,6 +2854,7 @@ def analyze_tables(
27922854 sqlite-utils analyze-tables data.db trees
27932855 """
27942856 db = sqlite_utils .Database (path )
2857+ _register_db_for_cleanup (db )
27952858 _load_extensions (db , load_extension )
27962859 _analyze (db , tables , columns , save , common_limit , no_most , no_least )
27972860
@@ -2991,6 +3054,7 @@ def convert(
29913054):
29923055 sqlite3 .enable_callback_tracebacks (True )
29933056 db = sqlite_utils .Database (db_path )
3057+ _register_db_for_cleanup (db )
29943058 if output is not None and len (columns ) > 1 :
29953059 raise click .ClickException ("Cannot use --output with more than one column" )
29963060 if multi and len (columns ) > 1 :
@@ -3133,6 +3197,7 @@ def add_geometry_column(
31333197 By default, this command will try to load the SpatiaLite extension from usual paths.
31343198 To load it from a specific path, use --load-extension."""
31353199 db = sqlite_utils .Database (db_path )
3200+ _register_db_for_cleanup (db )
31363201 if not db [table ].exists ():
31373202 raise click .ClickException (
31383203 "You must create a table before adding a geometry column"
@@ -3165,6 +3230,7 @@ def create_spatial_index(db_path, table, column_name, load_extension):
31653230 By default, this command will try to load the SpatiaLite extension from usual paths.
31663231 To load it from a specific path, use --load-extension."""
31673232 db = sqlite_utils .Database (db_path )
3233+ _register_db_for_cleanup (db )
31683234 if not db [table ].exists ():
31693235 raise click .ClickException (
31703236 "You must create a table and add a geometry column before creating a spatial index"
0 commit comments