meerschaum 2.7.2__py3-none-any.whl → 2.7.3__py3-none-any.whl

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.
meerschaum/utils/sql.py CHANGED
@@ -45,12 +45,12 @@ DROP_IF_EXISTS_FLAVORS = {
45
45
  }
46
46
  SKIP_AUTO_INCREMENT_FLAVORS = {'citus', 'duckdb'}
47
47
  COALESCE_UNIQUE_INDEX_FLAVORS = {'timescaledb', 'postgresql', 'citus'}
48
- update_queries = {
48
+ UPDATE_QUERIES = {
49
49
  'default': """
50
50
  UPDATE {target_table_name} AS f
51
51
  {sets_subquery_none}
52
52
  FROM {target_table_name} AS t
53
- INNER JOIN (SELECT DISTINCT {patch_cols_str} FROM {patch_table_name}) AS p
53
+ INNER JOIN (SELECT {patch_cols_str} FROM {patch_table_name}) AS p
54
54
  ON
55
55
  {and_subquery_t}
56
56
  WHERE
@@ -84,7 +84,7 @@ update_queries = {
84
84
  """,
85
85
  'mysql': """
86
86
  UPDATE {target_table_name} AS f
87
- JOIN (SELECT DISTINCT {patch_cols_str} FROM {patch_table_name}) AS p
87
+ JOIN (SELECT {patch_cols_str} FROM {patch_table_name}) AS p
88
88
  ON
89
89
  {and_subquery_f}
90
90
  {sets_subquery_f}
@@ -100,7 +100,7 @@ update_queries = {
100
100
  """,
101
101
  'mariadb': """
102
102
  UPDATE {target_table_name} AS f
103
- JOIN (SELECT DISTINCT {patch_cols_str} FROM {patch_table_name}) AS p
103
+ JOIN (SELECT {patch_cols_str} FROM {patch_table_name}) AS p
104
104
  ON
105
105
  {and_subquery_f}
106
106
  {sets_subquery_f}
@@ -179,13 +179,13 @@ update_queries = {
179
179
  WHERE ROWID IN (
180
180
  SELECT t.ROWID
181
181
  FROM {target_table_name} AS t
182
- INNER JOIN (SELECT DISTINCT * FROM {patch_table_name}) AS p
182
+ INNER JOIN (SELECT * FROM {patch_table_name}) AS p
183
183
  ON {and_subquery_t}
184
184
  );
185
185
  """,
186
186
  """
187
187
  INSERT INTO {target_table_name} AS f
188
- SELECT DISTINCT {patch_cols_str} FROM {patch_table_name} AS p
188
+ SELECT {patch_cols_str} FROM {patch_table_name} AS p
189
189
  """,
190
190
  ],
191
191
  }
@@ -573,21 +573,21 @@ def dateadd_str(
573
573
  Examples
574
574
  --------
575
575
  >>> dateadd_str(
576
- ... flavor = 'mssql',
577
- ... begin = datetime(2022, 1, 1, 0, 0),
578
- ... number = 1,
576
+ ... flavor='mssql',
577
+ ... begin=datetime(2022, 1, 1, 0, 0),
578
+ ... number=1,
579
579
  ... )
580
580
  "DATEADD(day, 1, CAST('2022-01-01 00:00:00' AS DATETIME2))"
581
581
  >>> dateadd_str(
582
- ... flavor = 'postgresql',
583
- ... begin = datetime(2022, 1, 1, 0, 0),
584
- ... number = 1,
582
+ ... flavor='postgresql',
583
+ ... begin=datetime(2022, 1, 1, 0, 0),
584
+ ... number=1,
585
585
  ... )
586
586
  "CAST('2022-01-01 00:00:00' AS TIMESTAMP) + INTERVAL '1 day'"
587
587
 
588
588
  """
589
589
  from meerschaum.utils.packages import attempt_import
590
- from meerschaum.utils.dtypes.sql import get_db_type_from_pd_type
590
+ from meerschaum.utils.dtypes.sql import get_db_type_from_pd_type, get_pd_type_from_db_type
591
591
  dateutil_parser = attempt_import('dateutil.parser')
592
592
  if 'int' in str(type(begin)).lower():
593
593
  return str(begin)
@@ -619,7 +619,14 @@ def dateadd_str(
619
619
  else f"'{begin}'"
620
620
  )
621
621
 
622
- dt_is_utc = begin_time.tzinfo is not None if begin_time is not None else '+' in str(begin)
622
+ dt_is_utc = (
623
+ begin_time.tzinfo is not None
624
+ if begin_time is not None
625
+ else ('+' in str(begin) or '-' in str(begin).split(':', maxsplit=1)[-1])
626
+ )
627
+ if db_type:
628
+ db_type_is_utc = 'utc' in get_pd_type_from_db_type(db_type).lower()
629
+ dt_is_utc = dt_is_utc or db_type_is_utc
623
630
  db_type = db_type or get_db_type_from_pd_type(
624
631
  ('datetime64[ns, UTC]' if dt_is_utc else 'datetime64[ns]'),
625
632
  flavor=flavor,
@@ -629,22 +636,32 @@ def dateadd_str(
629
636
  if flavor in ('postgresql', 'timescaledb', 'cockroachdb', 'citus'):
630
637
  begin = (
631
638
  f"CAST({begin} AS {db_type})" if begin != 'now'
632
- else "CAST(NOW() AT TIME ZONE 'utc' AS {db_type})"
639
+ else f"CAST(NOW() AT TIME ZONE 'utc' AS {db_type})"
633
640
  )
641
+ if dt_is_utc:
642
+ begin += " AT TIME ZONE 'UTC'"
634
643
  da = begin + (f" + INTERVAL '{number} {datepart}'" if number != 0 else '')
635
644
 
636
645
  elif flavor == 'duckdb':
637
646
  begin = f"CAST({begin} AS {db_type})" if begin != 'now' else 'NOW()'
647
+ if dt_is_utc:
648
+ begin += " AT TIME ZONE 'UTC'"
638
649
  da = begin + (f" + INTERVAL '{number} {datepart}'" if number != 0 else '')
639
650
 
640
651
  elif flavor in ('mssql',):
641
652
  if begin_time and begin_time.microsecond != 0 and not dt_is_utc:
642
653
  begin = begin[:-4] + "'"
643
654
  begin = f"CAST({begin} AS {db_type})" if begin != 'now' else 'GETUTCDATE()'
655
+ if dt_is_utc:
656
+ begin += " AT TIME ZONE 'UTC'"
644
657
  da = f"DATEADD({datepart}, {number}, {begin})" if number != 0 else begin
645
658
 
646
659
  elif flavor in ('mysql', 'mariadb'):
647
- begin = f"CAST({begin} AS DATETIME(6))" if begin != 'now' else 'UTC_TIMESTAMP(6)'
660
+ begin = (
661
+ f"CAST({begin} AS DATETIME(6))"
662
+ if begin != 'now'
663
+ else 'UTC_TIMESTAMP(6)'
664
+ )
648
665
  da = (f"DATE_ADD({begin}, INTERVAL {number} {datepart})" if number != 0 else begin)
649
666
 
650
667
  elif flavor == 'sqlite':
@@ -653,10 +670,10 @@ def dateadd_str(
653
670
  elif flavor == 'oracle':
654
671
  if begin == 'now':
655
672
  begin = str(
656
- datetime.now(timezone.utc).replace(tzinfo=None).strftime('%Y:%m:%d %M:%S.%f')
673
+ datetime.now(timezone.utc).replace(tzinfo=None).strftime(r'%Y:%m:%d %M:%S.%f')
657
674
  )
658
675
  elif begin_time:
659
- begin = str(begin_time.strftime('%Y-%m-%d %H:%M:%S.%f'))
676
+ begin = str(begin_time.strftime(r'%Y-%m-%d %H:%M:%S.%f'))
660
677
  dt_format = 'YYYY-MM-DD HH24:MI:SS.FF'
661
678
  _begin = f"'{begin}'" if begin_time else begin
662
679
  da = (
@@ -691,7 +708,7 @@ def test_connection(
691
708
  warnings.filterwarnings('ignore', 'Could not')
692
709
  try:
693
710
  return retry_connect(**_default_kw)
694
- except Exception as e:
711
+ except Exception:
695
712
  return False
696
713
 
697
714
 
@@ -784,7 +801,7 @@ def sql_item_name(item: str, flavor: str, schema: Optional[str] = None) -> str:
784
801
  ### NOTE: System-reserved words must be quoted.
785
802
  if truncated_item.lower() in (
786
803
  'float', 'varchar', 'nvarchar', 'clob',
787
- 'boolean', 'integer', 'table',
804
+ 'boolean', 'integer', 'table', 'row',
788
805
  ):
789
806
  wrappers = ('"', '"')
790
807
  else:
@@ -1494,9 +1511,9 @@ def get_update_queries(
1494
1511
  ):
1495
1512
  flavor = 'sqlite_delete_insert'
1496
1513
  flavor_key = (f'{flavor}-upsert' if upsert else flavor)
1497
- base_queries = update_queries.get(
1514
+ base_queries = UPDATE_QUERIES.get(
1498
1515
  flavor_key,
1499
- update_queries['default']
1516
+ UPDATE_QUERIES['default']
1500
1517
  )
1501
1518
  if not isinstance(base_queries, list):
1502
1519
  base_queries = [base_queries]
@@ -1577,6 +1594,12 @@ def get_update_queries(
1577
1594
  if not value_cols:
1578
1595
  return ''
1579
1596
 
1597
+ utc_value_cols = {
1598
+ c_name
1599
+ for c_name, c_type in value_cols
1600
+ if ('utc' in get_pd_type_from_db_type(c_type).lower())
1601
+ } if flavor not in TIMEZONE_NAIVE_FLAVORS else set()
1602
+
1580
1603
  cast_func_cols = {
1581
1604
  c_name: (
1582
1605
  ('', '', '')
@@ -1585,7 +1608,11 @@ def get_update_queries(
1585
1608
  and are_dtypes_equal(get_pd_type_from_db_type(c_type), 'bytes')
1586
1609
  )
1587
1610
  else (
1588
- ('CAST(', f" AS {c_type.replace('_', ' ')}", ')')
1611
+ ('CAST(', f" AS {c_type.replace('_', ' ')}", ')' + (
1612
+ " AT TIME ZONE 'UTC'"
1613
+ if c_name in utc_value_cols
1614
+ else ''
1615
+ ))
1589
1616
  if flavor != 'sqlite'
1590
1617
  else ('', '', '')
1591
1618
  )
@@ -1865,6 +1892,7 @@ def get_create_table_queries(
1865
1892
  flavor: str,
1866
1893
  schema: Optional[str] = None,
1867
1894
  primary_key: Optional[str] = None,
1895
+ primary_key_db_type: Optional[str] = None,
1868
1896
  autoincrement: bool = False,
1869
1897
  datetime_column: Optional[str] = None,
1870
1898
  ) -> List[str]:
@@ -1889,6 +1917,9 @@ def get_create_table_queries(
1889
1917
  primary_key: Optional[str], default None
1890
1918
  If provided, designate this column as the primary key in the new table.
1891
1919
 
1920
+ primary_key_db_type: Optional[str], default None
1921
+ If provided, alter the primary key to this type (to set NOT NULL constraint).
1922
+
1892
1923
  autoincrement: bool, default False
1893
1924
  If `True` and `primary_key` is provided, create the `primary_key` column
1894
1925
  as an auto-incrementing integer column.
@@ -1915,6 +1946,7 @@ def get_create_table_queries(
1915
1946
  flavor,
1916
1947
  schema=schema,
1917
1948
  primary_key=primary_key,
1949
+ primary_key_db_type=primary_key_db_type,
1918
1950
  autoincrement=(autoincrement and flavor not in SKIP_AUTO_INCREMENT_FLAVORS),
1919
1951
  datetime_column=datetime_column,
1920
1952
  )
@@ -1926,6 +1958,7 @@ def _get_create_table_query_from_dtypes(
1926
1958
  flavor: str,
1927
1959
  schema: Optional[str] = None,
1928
1960
  primary_key: Optional[str] = None,
1961
+ primary_key_db_type: Optional[str] = None,
1929
1962
  autoincrement: bool = False,
1930
1963
  datetime_column: Optional[str] = None,
1931
1964
  ) -> List[str]:
@@ -2015,6 +2048,7 @@ def _get_create_table_query_from_cte(
2015
2048
  flavor: str,
2016
2049
  schema: Optional[str] = None,
2017
2050
  primary_key: Optional[str] = None,
2051
+ primary_key_db_type: Optional[str] = None,
2018
2052
  autoincrement: bool = False,
2019
2053
  datetime_column: Optional[str] = None,
2020
2054
  ) -> List[str]:
@@ -2035,7 +2069,11 @@ def _get_create_table_query_from_cte(
2035
2069
  if primary_key
2036
2070
  else None
2037
2071
  )
2038
- primary_key_clustered = "CLUSTERED" if not datetime_column else "NONCLUSTERED"
2072
+ primary_key_clustered = (
2073
+ "CLUSTERED"
2074
+ if not datetime_column or datetime_column == primary_key
2075
+ else "NONCLUSTERED"
2076
+ )
2039
2077
  datetime_column_name = (
2040
2078
  sql_item_name(datetime_column, flavor)
2041
2079
  if datetime_column
@@ -2045,80 +2083,106 @@ def _get_create_table_query_from_cte(
2045
2083
  query = query.lstrip()
2046
2084
  if query.lower().startswith('with '):
2047
2085
  final_select_ix = query.lower().rfind('select')
2048
- create_table_query = (
2049
- query[:final_select_ix].rstrip() + ',\n'
2050
- + f"{create_cte_name} AS (\n"
2051
- + query[final_select_ix:]
2052
- + "\n)\n"
2053
- + f"SELECT *\nINTO {new_table_name}\nFROM {create_cte_name}"
2054
- )
2086
+ create_table_queries = [
2087
+ (
2088
+ query[:final_select_ix].rstrip() + ',\n'
2089
+ + f"{create_cte_name} AS (\n"
2090
+ + textwrap.indent(query[final_select_ix:], ' ')
2091
+ + "\n)\n"
2092
+ + f"SELECT *\nINTO {new_table_name}\nFROM {create_cte_name}"
2093
+ ),
2094
+ ]
2055
2095
  else:
2056
- create_table_query = f"""
2057
- SELECT *
2058
- INTO {new_table_name}
2059
- FROM ({query}) AS {create_cte_name}
2060
- """
2061
-
2062
- alter_type_query = f"""
2063
- ALTER TABLE {new_table_name}
2064
- ADD CONSTRAINT {primary_key_constraint_name} PRIMARY KEY {primary_key_clustered} ({primary_key_name})
2065
- """
2096
+ create_table_queries = [
2097
+ (
2098
+ "SELECT *\n"
2099
+ f"INTO {new_table_name}\n"
2100
+ f"FROM (\n{textwrap.indent(query, ' ')}\n) AS {create_cte_name}"
2101
+ ),
2102
+ ]
2103
+
2104
+ alter_type_queries = []
2105
+ if primary_key_db_type:
2106
+ alter_type_queries.extend([
2107
+ (
2108
+ f"ALTER TABLE {new_table_name}\n"
2109
+ f"ALTER COLUMN {primary_key_name} {primary_key_db_type} NOT NULL"
2110
+ ),
2111
+ ])
2112
+ alter_type_queries.extend([
2113
+ (
2114
+ f"ALTER TABLE {new_table_name}\n"
2115
+ f"ADD CONSTRAINT {primary_key_constraint_name} "
2116
+ f"PRIMARY KEY {primary_key_clustered} ({primary_key_name})"
2117
+ ),
2118
+ ])
2066
2119
  elif flavor in (None,):
2067
- create_table_query = f"""
2068
- WITH {create_cte_name} AS ({query})
2069
- CREATE TABLE {new_table_name} AS
2070
- SELECT *
2071
- FROM {create_cte_name}
2072
- """
2120
+ create_table_queries = [
2121
+ (
2122
+ f"WITH {create_cte_name} AS (\n{textwrap.index(query, ' ')}\n)\n"
2123
+ f"CREATE TABLE {new_table_name} AS\n"
2124
+ "SELECT *\n"
2125
+ f"FROM {create_cte_name}"
2126
+ ),
2127
+ ]
2073
2128
 
2074
- alter_type_query = f"""
2075
- ALTER TABLE {new_table_name}
2076
- ADD PRIMARY KEY ({primary_key_name})
2077
- """
2129
+ alter_type_queries = [
2130
+ (
2131
+ f"ALTER TABLE {new_table_name}\n"
2132
+ f"ADD PRIMARY KEY ({primary_key_name})"
2133
+ ),
2134
+ ]
2078
2135
  elif flavor in ('sqlite', 'mysql', 'mariadb', 'duckdb', 'oracle'):
2079
- create_table_query = f"""
2080
- CREATE TABLE {new_table_name} AS
2081
- SELECT *
2082
- FROM ({query})""" + (f""" AS {create_cte_name}""" if flavor != 'oracle' else '') + """
2083
- """
2136
+ create_table_queries = [
2137
+ (
2138
+ f"CREATE TABLE {new_table_name} AS\n"
2139
+ "SELECT *\n"
2140
+ f"FROM (\n{textwrap.indent(query, ' ')}\n)"
2141
+ + (f" AS {create_cte_name}" if flavor != 'oracle' else '')
2142
+ ),
2143
+ ]
2084
2144
 
2085
- alter_type_query = f"""
2086
- ALTER TABLE {new_table_name}
2087
- ADD PRIMARY KEY ({primary_key_name})
2088
- """
2145
+ alter_type_queries = [
2146
+ (
2147
+ f"ALTER TABLE {new_table_name}\n"
2148
+ "ADD PRIMARY KEY ({primary_key_name})"
2149
+ ),
2150
+ ]
2089
2151
  elif flavor == 'timescaledb' and datetime_column and datetime_column != primary_key:
2090
- create_table_query = f"""
2091
- SELECT *
2092
- INTO {new_table_name}
2093
- FROM ({query}) AS {create_cte_name}
2094
- """
2152
+ create_table_queries = [
2153
+ (
2154
+ "SELECT *\n"
2155
+ f"INTO {new_table_name}\n"
2156
+ f"FROM (\n{textwrap.indent(query, ' ')}\n) AS {create_cte_name}\n"
2157
+ ),
2158
+ ]
2095
2159
 
2096
- alter_type_query = f"""
2097
- ALTER TABLE {new_table_name}
2098
- ADD PRIMARY KEY ({datetime_column_name}, {primary_key_name})
2099
- """
2160
+ alter_type_queries = [
2161
+ (
2162
+ f"ALTER TABLE {new_table_name}\n"
2163
+ f"ADD PRIMARY KEY ({datetime_column_name}, {primary_key_name})"
2164
+ ),
2165
+ ]
2100
2166
  else:
2101
- create_table_query = f"""
2102
- SELECT *
2103
- INTO {new_table_name}
2104
- FROM ({query}) AS {create_cte_name}
2105
- """
2167
+ create_table_queries = [
2168
+ (
2169
+ "SELECT *\n"
2170
+ f"INTO {new_table_name}\n"
2171
+ f"FROM (\n{textwrap.indent(query, ' ')}\n) AS {create_cte_name}"
2172
+ ),
2173
+ ]
2106
2174
 
2107
- alter_type_query = f"""
2108
- ALTER TABLE {new_table_name}
2109
- ADD PRIMARY KEY ({primary_key_name})
2110
- """
2175
+ alter_type_queries = [
2176
+ (
2177
+ f"ALTER TABLE {new_table_name}\n"
2178
+ f"ADD PRIMARY KEY ({primary_key_name})"
2179
+ ),
2180
+ ]
2111
2181
 
2112
- create_table_query = textwrap.dedent(create_table_query).lstrip().rstrip()
2113
2182
  if not primary_key:
2114
- return [create_table_query]
2115
-
2116
- alter_type_query = textwrap.dedent(alter_type_query).lstrip().rstrip()
2183
+ return create_table_queries
2117
2184
 
2118
- return [
2119
- create_table_query,
2120
- alter_type_query,
2121
- ]
2185
+ return create_table_queries + alter_type_queries
2122
2186
 
2123
2187
 
2124
2188
  def wrap_query_with_cte(
@@ -2167,6 +2231,7 @@ def wrap_query_with_cte(
2167
2231
  ```
2168
2232
 
2169
2233
  """
2234
+ import textwrap
2170
2235
  sub_query = sub_query.lstrip()
2171
2236
  cte_name_quoted = sql_item_name(cte_name, flavor, None)
2172
2237
 
@@ -2190,7 +2255,7 @@ def wrap_query_with_cte(
2190
2255
 
2191
2256
  return (
2192
2257
  f"WITH {cte_name_quoted} AS (\n"
2193
- f" {sub_query}\n"
2258
+ f"{textwrap.indent(sub_query, ' ')}\n"
2194
2259
  f")\n{parent_query}"
2195
2260
  )
2196
2261
 
@@ -2269,6 +2334,8 @@ def session_execute(
2269
2334
  queries = [queries]
2270
2335
  successes, msgs, results = [], [], []
2271
2336
  for query in queries:
2337
+ if debug:
2338
+ dprint(query)
2272
2339
  query_text = sqlalchemy.text(query)
2273
2340
  fail_msg = "Failed to execute queries."
2274
2341
  try:
@@ -2283,6 +2350,8 @@ def session_execute(
2283
2350
  msgs.append(query_msg)
2284
2351
  results.append(result)
2285
2352
  if not query_success:
2353
+ if debug:
2354
+ dprint("Rolling back session.")
2286
2355
  session.rollback()
2287
2356
  break
2288
2357
  success, msg = all(successes), '\n'.join(msgs)
@@ -67,7 +67,6 @@ def activate_venv(
67
67
  return True
68
68
  import sys
69
69
  import os
70
- from meerschaum.config._paths import VIRTENV_RESOURCES_PATH
71
70
  if venv is not None:
72
71
  init_venv(venv=venv, debug=debug)
73
72
  with LOCKS['active_venvs']:
@@ -379,22 +378,47 @@ def init_venv(
379
378
  import os
380
379
  import pathlib
381
380
  import shutil
381
+ import time
382
382
 
383
383
  from meerschaum.config.static import STATIC_CONFIG
384
- from meerschaum.config._paths import VIRTENV_RESOURCES_PATH, VENVS_CACHE_RESOURCES_PATH
384
+ from meerschaum.config._paths import (
385
+ VIRTENV_RESOURCES_PATH,
386
+ VENVS_CACHE_RESOURCES_PATH,
387
+ )
385
388
  from meerschaum.utils.packages import is_uv_enabled
386
389
 
387
390
  venv_path = VIRTENV_RESOURCES_PATH / venv
388
391
  vtp = venv_target_path(venv=venv, allow_nonexistent=True, debug=debug)
389
392
  docker_home_venv_path = pathlib.Path('/home/meerschaum/venvs/mrsm')
390
-
393
+ lock_path = VENVS_CACHE_RESOURCES_PATH / (venv + '.lock')
391
394
  work_dir_env_var = STATIC_CONFIG['environment']['work_dir']
395
+
396
+ def update_lock(active: bool):
397
+ try:
398
+ if active:
399
+ lock_path.unlink()
400
+ else:
401
+ lock_path.touch()
402
+ except Exception:
403
+ pass
404
+
405
+ def wait_for_lock():
406
+ max_lock_seconds = 1.0
407
+ step_sleep_seconds = 0.1
408
+ init_venv_check_start = time.perf_counter()
409
+ while (time.perf_counter() - init_venv_check_start < max_lock_seconds):
410
+ if not lock_path.exists():
411
+ continue
412
+ time.sleep(step_sleep_seconds)
413
+ update_lock(False)
414
+
392
415
  if (
393
416
  not force
394
417
  and venv == 'mrsm'
395
418
  and os.environ.get(work_dir_env_var, None) is not None
396
419
  and docker_home_venv_path.exists()
397
420
  ):
421
+ wait_for_lock()
398
422
  shutil.move(docker_home_venv_path, venv_path)
399
423
  if verify:
400
424
  verify_venv(venv, debug=debug)
@@ -422,6 +446,9 @@ def init_venv(
422
446
  except FileExistsError:
423
447
  pass
424
448
 
449
+ wait_for_lock()
450
+ update_lock(True)
451
+
425
452
  if uv is not None:
426
453
  _venv_success = run_python_package(
427
454
  'uv',
@@ -437,7 +464,9 @@ def init_venv(
437
464
  _venv_success = run_python_package(
438
465
  'venv',
439
466
  [venv_path.as_posix()] + (
440
- ['--symlinks'] if platform.system() != 'Windows' else []
467
+ ['--symlinks']
468
+ if platform.system() != 'Windows'
469
+ else []
441
470
  ),
442
471
  venv=None, debug=debug
443
472
  ) == 0
@@ -447,8 +476,14 @@ def init_venv(
447
476
  _venv = None
448
477
  if not _venv_success:
449
478
  virtualenv = attempt_import(
450
- 'virtualenv', venv=None, lazy=False, install=(not tried_virtualenv), warn=False,
451
- check_update=False, color=False, debug=debug,
479
+ 'virtualenv',
480
+ venv=None,
481
+ lazy=False,
482
+ install=(not tried_virtualenv),
483
+ warn=False,
484
+ check_update=False,
485
+ color=False,
486
+ debug=debug,
452
487
  )
453
488
  if virtualenv is None:
454
489
  print(
@@ -457,6 +492,7 @@ def init_venv(
457
492
  )
458
493
  if rename_vtp and temp_vtp.exists():
459
494
  temp_vtp.rename(vtp)
495
+ update_lock(False)
460
496
  return False
461
497
 
462
498
  tried_virtualenv = True
@@ -495,6 +531,7 @@ def init_venv(
495
531
  traceback.print_exc()
496
532
  if rename_vtp and temp_vtp.exists():
497
533
  temp_vtp.rename(vtp)
534
+ update_lock(False)
498
535
  return False
499
536
  if verify:
500
537
  verify_venv(venv, debug=debug)
@@ -503,6 +540,7 @@ def init_venv(
503
540
  if rename_vtp and temp_vtp.exists():
504
541
  temp_vtp.rename(vtp)
505
542
 
543
+ update_lock(False)
506
544
  return True
507
545
 
508
546
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: meerschaum
3
- Version: 2.7.2
3
+ Version: 2.7.3
4
4
  Summary: Sync Time-Series Pipes with Meerschaum
5
5
  Home-page: https://meerschaum.io
6
6
  Author: Bennett Meares