execsql2 2.20.0__py3-none-any.whl → 2.21.0__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.
Files changed (22) hide show
  1. execsql/db/factory.py +1 -1
  2. execsql/db/postgres.py +20 -18
  3. {execsql2-2.20.0.dist-info → execsql2-2.21.0.dist-info}/METADATA +7 -7
  4. {execsql2-2.20.0.dist-info → execsql2-2.21.0.dist-info}/RECORD +22 -22
  5. {execsql2-2.20.0.data → execsql2-2.21.0.data}/data/execsql2_extras/README.md +0 -0
  6. {execsql2-2.20.0.data → execsql2-2.21.0.data}/data/execsql2_extras/config_settings.sqlite +0 -0
  7. {execsql2-2.20.0.data → execsql2-2.21.0.data}/data/execsql2_extras/example_config_prompt.sql +0 -0
  8. {execsql2-2.20.0.data → execsql2-2.21.0.data}/data/execsql2_extras/make_config_db.sql +0 -0
  9. {execsql2-2.20.0.data → execsql2-2.21.0.data}/data/execsql2_extras/md_compare.sql +0 -0
  10. {execsql2-2.20.0.data → execsql2-2.21.0.data}/data/execsql2_extras/md_glossary.sql +0 -0
  11. {execsql2-2.20.0.data → execsql2-2.21.0.data}/data/execsql2_extras/md_upsert.sql +0 -0
  12. {execsql2-2.20.0.data → execsql2-2.21.0.data}/data/execsql2_extras/pg_compare.sql +0 -0
  13. {execsql2-2.20.0.data → execsql2-2.21.0.data}/data/execsql2_extras/pg_glossary.sql +0 -0
  14. {execsql2-2.20.0.data → execsql2-2.21.0.data}/data/execsql2_extras/pg_upsert.sql +0 -0
  15. {execsql2-2.20.0.data → execsql2-2.21.0.data}/data/execsql2_extras/script_template.sql +0 -0
  16. {execsql2-2.20.0.data → execsql2-2.21.0.data}/data/execsql2_extras/ss_compare.sql +0 -0
  17. {execsql2-2.20.0.data → execsql2-2.21.0.data}/data/execsql2_extras/ss_glossary.sql +0 -0
  18. {execsql2-2.20.0.data → execsql2-2.21.0.data}/data/execsql2_extras/ss_upsert.sql +0 -0
  19. {execsql2-2.20.0.dist-info → execsql2-2.21.0.dist-info}/WHEEL +0 -0
  20. {execsql2-2.20.0.dist-info → execsql2-2.21.0.dist-info}/entry_points.txt +0 -0
  21. {execsql2-2.20.0.dist-info → execsql2-2.21.0.dist-info}/licenses/LICENSE.txt +0 -0
  22. {execsql2-2.20.0.dist-info → execsql2-2.21.0.dist-info}/licenses/NOTICE +0 -0
execsql/db/factory.py CHANGED
@@ -63,7 +63,7 @@ def db_Postgres(
63
63
  new_db: bool = False,
64
64
  password: str | None = None,
65
65
  ) -> PostgresDatabase:
66
- """Open a new PostgreSQL connection via psycopg2."""
66
+ """Open a new PostgreSQL connection via psycopg (psycopg3)."""
67
67
  return PostgresDatabase(server_name, database_name, user, pw_needed, port, new_db=new_db, password=password)
68
68
 
69
69
 
execsql/db/postgres.py CHANGED
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  """
4
4
  PostgreSQL database adapter for execsql.
5
5
 
6
- Implements :class:`PostgresDatabase`. Uses ``psycopg2`` for the
6
+ Implements :class:`PostgresDatabase`. Uses ``psycopg`` (psycopg3) for the
7
7
  connection, supports schema-qualified tables, server-side ``COPY`` for
8
8
  fast IMPORT, ``CREATE DATABASE`` when ``new_db=True``, ``ROLE_EXISTS``,
9
9
  and the ``PG_VACUUM`` metacommand (``vacuum()`` method). Corresponds to
@@ -26,7 +26,7 @@ DEFAULT_CONNECT_TIMEOUT = 30 # seconds
26
26
 
27
27
 
28
28
  class PostgresDatabase(Database):
29
- """PostgreSQL adapter using psycopg2, with schema support, server-side COPY, and keyring auth."""
29
+ """PostgreSQL adapter using psycopg (psycopg3), with schema support, server-side COPY, and keyring auth."""
30
30
 
31
31
  def __init__(
32
32
  self,
@@ -41,10 +41,11 @@ class PostgresDatabase(Database):
41
41
  connect_timeout: int = DEFAULT_CONNECT_TIMEOUT,
42
42
  ) -> None:
43
43
  try:
44
- import psycopg2 # noqa: F401
44
+ import psycopg # noqa: F401
45
45
  except Exception:
46
46
  fatal_error(
47
- "The psycopg2 module is required to connect to PostgreSQL. See http://initd.org/psycopg/",
47
+ "The psycopg module (psycopg3) is required to connect to PostgreSQL. "
48
+ "See https://www.psycopg.org/psycopg3/",
48
49
  )
49
50
  from execsql.types import dbt_postgres
50
51
 
@@ -73,23 +74,23 @@ class PostgresDatabase(Database):
73
74
 
74
75
  def open_db(self) -> None:
75
76
  """Open a connection to the PostgreSQL database."""
76
- import psycopg2
77
+ import psycopg
77
78
 
78
79
  def db_conn(db: PostgresDatabase, db_name: str):
79
80
  try:
80
81
  if db.user and db.password:
81
- return psycopg2.connect(
82
+ return psycopg.connect(
82
83
  host=str(db.server_name),
83
- database=str(db_name),
84
+ dbname=str(db_name),
84
85
  port=db.port,
85
86
  user=db.user,
86
87
  password=db.password,
87
88
  connect_timeout=db.connect_timeout,
88
89
  )
89
90
  else:
90
- return psycopg2.connect(
91
+ return psycopg.connect(
91
92
  host=str(db.server_name),
92
- database=db_name,
93
+ dbname=db_name,
93
94
  port=db.port,
94
95
  connect_timeout=db.connect_timeout,
95
96
  )
@@ -148,7 +149,7 @@ class PostgresDatabase(Database):
148
149
  msg = f"Failed to open PostgreSQL database {self.db_name} on {self.server_name}"
149
150
  raise ErrInfo(type="exception", exception_msg=exception_desc(), other_msg=msg) from e
150
151
  # (Re)set the encoding to match the database.
151
- self.encoding = self.conn.encoding
152
+ self.encoding = self.conn.info.encoding
152
153
 
153
154
  def exec_cmd(self, querycommand: str) -> None:
154
155
  """Execute a stored function by name."""
@@ -242,13 +243,13 @@ class PostgresDatabase(Database):
242
243
  but should not be exposed to untrusted input.
243
244
  """
244
245
  self.commit()
245
- self.conn.set_session(autocommit=True)
246
+ self.conn.autocommit = True
246
247
  curs = self.conn.cursor()
247
248
  try:
248
249
  curs.execute(f"VACUUM {argstring};")
249
250
  finally:
250
251
  curs.close()
251
- self.conn.set_session(autocommit=False)
252
+ self.conn.autocommit = False
252
253
 
253
254
  def import_tabular_file(
254
255
  self,
@@ -290,7 +291,7 @@ class PostgresDatabase(Database):
290
291
  import_cols = [self.type.quoted(col) for col in import_cols]
291
292
  csv_file_cols_q = [self.type.quoted(col) for col in csv_file_cols]
292
293
  input_col_list = ",".join(import_cols)
293
- # If encodings match, use copy_expert.
294
+ # If encodings match, use server-side COPY.
294
295
  # If encodings don't match, and the file encoding isn't recognized by CSV, read as CSV.
295
296
  enc_xlates = {
296
297
  "cp1252": "win1252",
@@ -319,7 +320,7 @@ class PostgresDatabase(Database):
319
320
  and not _state.conf.trim_strings
320
321
  and not _state.conf.replace_newlines
321
322
  ):
322
- # Use Postgres' COPY FROM method via psycopg2's copy_expert() method.
323
+ # Use Postgres' COPY FROM method via psycopg3's cursor.copy() context manager.
323
324
  rf = csv_file_obj.open("rt")
324
325
  if skipheader:
325
326
  next(rf)
@@ -346,7 +347,9 @@ class PostgresDatabase(Database):
346
347
  )
347
348
  with self._cursor() as curs:
348
349
  try:
349
- curs.copy_expert(copy_cmd, rf, _state.conf.import_buffer)
350
+ with curs.copy(copy_cmd) as copy:
351
+ while chunk := rf.read(_state.conf.import_buffer):
352
+ copy.write(chunk)
350
353
  except ErrInfo:
351
354
  raise
352
355
  except Exception as e:
@@ -461,12 +464,11 @@ class PostgresDatabase(Database):
461
464
  file_name: str,
462
465
  ) -> None:
463
466
  """Import an entire binary file into a single column of a table."""
464
- import psycopg2
465
-
466
467
  with open(file_name, "rb") as f:
467
468
  filedata = f.read()
468
469
  sq_name = self.schema_qualified_table_name(schema_name, table_name)
469
470
  quoted_col = self.quote_identifier(column_name)
470
471
  sql = f"insert into {sq_name} ({quoted_col}) values ({self.paramsubs(1)});"
471
472
  with self._cursor() as curs:
472
- curs.execute(sql, (psycopg2.Binary(filedata),))
473
+ # psycopg3 sends ``bytes`` to a ``bytea`` column directly; no Binary() wrapper.
474
+ curs.execute(sql, (filedata,))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: execsql2
3
- Version: 2.20.0
3
+ Version: 2.21.0
4
4
  Summary: Runs a SQL script against a PostgreSQL, SQLite, MariaDB/MySQL, DuckDB, Firebird, MS-Access, MS-SQL-Server, or Oracle database, or an ODBC DSN. Provides metacommands to import and export data, copy data between databases, conditionally execute SQL and metacommands, and dynamically alter SQL and metacommands with substitution variables.
5
5
  Project-URL: Homepage, https://execsql2.readthedocs.io
6
6
  Project-URL: Repository, https://github.com/geocoug/execsql
@@ -52,9 +52,9 @@ Requires-Dist: keyring>=25.0; extra == 'all'
52
52
  Requires-Dist: odfpy>=1.4; extra == 'all'
53
53
  Requires-Dist: openpyxl>=3.1; extra == 'all'
54
54
  Requires-Dist: oracledb>=3.0; extra == 'all'
55
- Requires-Dist: pg-upsert>=1.22.1; extra == 'all'
55
+ Requires-Dist: pg-upsert>=1.23.0; extra == 'all'
56
56
  Requires-Dist: polars>=1.0; extra == 'all'
57
- Requires-Dist: psycopg2-binary>=2.9; extra == 'all'
57
+ Requires-Dist: psycopg[binary]<4,>=3.1; extra == 'all'
58
58
  Requires-Dist: pymysql>=1.1; extra == 'all'
59
59
  Requires-Dist: pyodbc>=5.0; extra == 'all'
60
60
  Requires-Dist: pyyaml>=6.0; extra == 'all'
@@ -66,7 +66,7 @@ Provides-Extra: all-db
66
66
  Requires-Dist: duckdb>=1.0; extra == 'all-db'
67
67
  Requires-Dist: firebird-driver>=1.10; extra == 'all-db'
68
68
  Requires-Dist: oracledb>=3.0; extra == 'all-db'
69
- Requires-Dist: psycopg2-binary>=2.9; extra == 'all-db'
69
+ Requires-Dist: psycopg[binary]<4,>=3.1; extra == 'all-db'
70
70
  Requires-Dist: pymysql>=1.1; extra == 'all-db'
71
71
  Requires-Dist: pyodbc>=5.0; extra == 'all-db'
72
72
  Provides-Extra: auth
@@ -124,9 +124,9 @@ Requires-Dist: pyodbc>=5.0; extra == 'odbc'
124
124
  Provides-Extra: oracle
125
125
  Requires-Dist: oracledb>=3.0; extra == 'oracle'
126
126
  Provides-Extra: postgres
127
- Requires-Dist: psycopg2-binary>=2.9; extra == 'postgres'
127
+ Requires-Dist: psycopg[binary]<4,>=3.1; extra == 'postgres'
128
128
  Provides-Extra: upsert
129
- Requires-Dist: pg-upsert>=1.22.1; extra == 'upsert'
129
+ Requires-Dist: pg-upsert>=1.23.0; extra == 'upsert'
130
130
  Description-Content-Type: text/markdown
131
131
 
132
132
  > [!NOTE]
@@ -403,7 +403,7 @@ execsql-format --no-sql --in-place scripts/
403
403
  ```yaml
404
404
  repos:
405
405
  - repo: https://github.com/geocoug/execsql
406
- rev: v2.20.0
406
+ rev: v2.21.0
407
407
  hooks:
408
408
  - id: execsql-format
409
409
  ```
@@ -22,11 +22,11 @@ execsql/db/access.py,sha256=sRJOJJo1psSO5RV6QPsFY1YJE5wc5aNOYCFDtxIn_Wo,19413
22
22
  execsql/db/base.py,sha256=0Cy_M3GHdkQDJMbMeWpNyUIPux9m1cVDy21MGMjhJCI,35002
23
23
  execsql/db/dsn.py,sha256=CZd5NhUSVvK3irv2maeWsSqBsZjhFsTxIuT29Z0rP2A,6240
24
24
  execsql/db/duckdb.py,sha256=79lRzKRhw1Pjfqcrba27S4Oq8a8AbDO_d0XkaNKKPQo,3197
25
- execsql/db/factory.py,sha256=YHdgyqQYy16548O3fGyElLC5C7DdIgva4Z29OsDxXjs,5367
25
+ execsql/db/factory.py,sha256=C_cyi3GjNx0opuwc6maFFeCSkjfOfoUjuf68YT4VAHE,5377
26
26
  execsql/db/firebird.py,sha256=cV5wUzQHoz7yugHdNxAn8IW7fL3v1riIsGLykCZhZwA,9480
27
27
  execsql/db/mysql.py,sha256=Z0vI_nQ6vhG3sYa2fv5NOO3JmAsH6_jVjM8FuujQpqI,17961
28
28
  execsql/db/oracle.py,sha256=1_odb5xmlm8vjdJdQXz7SHm9dzIbZ5sxP_IxTklH3kA,12018
29
- execsql/db/postgres.py,sha256=UNzrXzMniEyT3Z7qjCA_HLEUY0PVr1cJShuhAxtl5l0,21241
29
+ execsql/db/postgres.py,sha256=CpMR3TamWAgI2DYkLQ5ZDD24hrt78znYi8rFnDbaDEE,21434
30
30
  execsql/db/sqlite.py,sha256=xooU6bvD9Y3frRpnbyesE63r6E1fwEHkkcN1YD_UIUE,11519
31
31
  execsql/db/sqlserver.py,sha256=j2ViLoBWzizgaL0u6V4iHfjinrlJ4rpBD3XZiKKdwSU,8968
32
32
  execsql/debug/__init__.py,sha256=j6EGUR0dHzUhWN1mHHtf1-Lhjq3Sb1V-vmnq2Ztgj1M,178
@@ -100,23 +100,23 @@ execsql/utils/numeric.py,sha256=xh02ANSRk3nUpQ-rtm66ILoMqoi7HtzCoRMIOT9U8QI,1570
100
100
  execsql/utils/regex.py,sha256=diEzTZqU_HHwVMadPAvN1Vgzhl7I03eVaEFGCXyGGL8,3770
101
101
  execsql/utils/strings.py,sha256=UQNjpRCEFa1UO6feU-M-9e24wWAvizs_iu_4fFusLxo,8516
102
102
  execsql/utils/timer.py,sha256=eDYf5VzCNFk7oo90InJucUm3XcBdhYMogjZMqeg9xzc,1899
103
- execsql2-2.20.0.data/data/execsql2_extras/README.md,sha256=vX4NTL095dUoA_hesyRMGYBorEZ_Y_tJ9qrd-MVV09I,5032
104
- execsql2-2.20.0.data/data/execsql2_extras/config_settings.sqlite,sha256=aY5cxR7Q7J6zJ4bC9lu5mHUrhy211Cq3MNKPQVCt02E,20480
105
- execsql2-2.20.0.data/data/execsql2_extras/example_config_prompt.sql,sha256=2e8KzzVWhho8KxYVHETSVmZdhW7wodioDsqBLSL6m4s,7487
106
- execsql2-2.20.0.data/data/execsql2_extras/make_config_db.sql,sha256=WwyC6dK-Eh5CAVppiBCDHqiI1_wEI9U95Ytpr4lsZkg,8726
107
- execsql2-2.20.0.data/data/execsql2_extras/md_compare.sql,sha256=qYYVAjSeHZzjszxV3Bv6bg8Ckbq2kMHl87_gh4sywMU,24140
108
- execsql2-2.20.0.data/data/execsql2_extras/md_glossary.sql,sha256=hkZ2Onn57LAKKsuXxzhR8tPtcWXkmWEQkwPE58-Tm2k,10796
109
- execsql2-2.20.0.data/data/execsql2_extras/md_upsert.sql,sha256=_CAK4BzEboRXTNy03SJR-oOjcEdSNMuRBPL6noWUptY,112560
110
- execsql2-2.20.0.data/data/execsql2_extras/pg_compare.sql,sha256=1zJd4hVUKHR0tncc2qTBC9B4qVV4Us2ITkJpsjN3tMw,24352
111
- execsql2-2.20.0.data/data/execsql2_extras/pg_glossary.sql,sha256=IKuwna-_8b20ljSkXZruuiQigrCpo7ueQdUqd1MXiuI,9908
112
- execsql2-2.20.0.data/data/execsql2_extras/pg_upsert.sql,sha256=HpPJtTHvpEjQy03j-3iPxDEOHMRkudOg7O4D4YR38UI,108315
113
- execsql2-2.20.0.data/data/execsql2_extras/script_template.sql,sha256=2J35ddZPguJ-vwTsz83wErv0jiWUyJcdW_JM0mNKDXA,11155
114
- execsql2-2.20.0.data/data/execsql2_extras/ss_compare.sql,sha256=j1qVNUPXQsEU7-DoVgDJCGcE0EuIl7whLBT3fgeiMAo,24833
115
- execsql2-2.20.0.data/data/execsql2_extras/ss_glossary.sql,sha256=2gLxv34xzKt0vy7hSzJH7a9JiMC3ETrv9MofxQwAibU,13065
116
- execsql2-2.20.0.data/data/execsql2_extras/ss_upsert.sql,sha256=G_8rQ0VzuKIZHWs24O_WrfzpC5S27R1JsL-bFBR3SUQ,117730
117
- execsql2-2.20.0.dist-info/METADATA,sha256=2j1tQ7oxlDAfsmIPQwgDxxn9O34FN7MbKT1nLznLi-M,22603
118
- execsql2-2.20.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
119
- execsql2-2.20.0.dist-info/entry_points.txt,sha256=sUOxkM-dN1eBGGpSpDLsAaE0yNXYQKWZAfxPOlMkQyk,90
120
- execsql2-2.20.0.dist-info/licenses/LICENSE.txt,sha256=LBdhuxejF8_bLCHZ2kWfmDXpDGUu914Gbd6_3JjCRe0,676
121
- execsql2-2.20.0.dist-info/licenses/NOTICE,sha256=McYzgxYav3U1OaVsY4Su1sfBrfmplpRdA9b6-gCDQCg,342
122
- execsql2-2.20.0.dist-info/RECORD,,
103
+ execsql2-2.21.0.data/data/execsql2_extras/README.md,sha256=vX4NTL095dUoA_hesyRMGYBorEZ_Y_tJ9qrd-MVV09I,5032
104
+ execsql2-2.21.0.data/data/execsql2_extras/config_settings.sqlite,sha256=aY5cxR7Q7J6zJ4bC9lu5mHUrhy211Cq3MNKPQVCt02E,20480
105
+ execsql2-2.21.0.data/data/execsql2_extras/example_config_prompt.sql,sha256=2e8KzzVWhho8KxYVHETSVmZdhW7wodioDsqBLSL6m4s,7487
106
+ execsql2-2.21.0.data/data/execsql2_extras/make_config_db.sql,sha256=WwyC6dK-Eh5CAVppiBCDHqiI1_wEI9U95Ytpr4lsZkg,8726
107
+ execsql2-2.21.0.data/data/execsql2_extras/md_compare.sql,sha256=qYYVAjSeHZzjszxV3Bv6bg8Ckbq2kMHl87_gh4sywMU,24140
108
+ execsql2-2.21.0.data/data/execsql2_extras/md_glossary.sql,sha256=hkZ2Onn57LAKKsuXxzhR8tPtcWXkmWEQkwPE58-Tm2k,10796
109
+ execsql2-2.21.0.data/data/execsql2_extras/md_upsert.sql,sha256=_CAK4BzEboRXTNy03SJR-oOjcEdSNMuRBPL6noWUptY,112560
110
+ execsql2-2.21.0.data/data/execsql2_extras/pg_compare.sql,sha256=1zJd4hVUKHR0tncc2qTBC9B4qVV4Us2ITkJpsjN3tMw,24352
111
+ execsql2-2.21.0.data/data/execsql2_extras/pg_glossary.sql,sha256=IKuwna-_8b20ljSkXZruuiQigrCpo7ueQdUqd1MXiuI,9908
112
+ execsql2-2.21.0.data/data/execsql2_extras/pg_upsert.sql,sha256=HpPJtTHvpEjQy03j-3iPxDEOHMRkudOg7O4D4YR38UI,108315
113
+ execsql2-2.21.0.data/data/execsql2_extras/script_template.sql,sha256=2J35ddZPguJ-vwTsz83wErv0jiWUyJcdW_JM0mNKDXA,11155
114
+ execsql2-2.21.0.data/data/execsql2_extras/ss_compare.sql,sha256=j1qVNUPXQsEU7-DoVgDJCGcE0EuIl7whLBT3fgeiMAo,24833
115
+ execsql2-2.21.0.data/data/execsql2_extras/ss_glossary.sql,sha256=2gLxv34xzKt0vy7hSzJH7a9JiMC3ETrv9MofxQwAibU,13065
116
+ execsql2-2.21.0.data/data/execsql2_extras/ss_upsert.sql,sha256=G_8rQ0VzuKIZHWs24O_WrfzpC5S27R1JsL-bFBR3SUQ,117730
117
+ execsql2-2.21.0.dist-info/METADATA,sha256=wEuDG-Eh-dlJ6kP3cGKUJfbaLQ0lJ0RnGKVfoP7tHpY,22612
118
+ execsql2-2.21.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
119
+ execsql2-2.21.0.dist-info/entry_points.txt,sha256=sUOxkM-dN1eBGGpSpDLsAaE0yNXYQKWZAfxPOlMkQyk,90
120
+ execsql2-2.21.0.dist-info/licenses/LICENSE.txt,sha256=LBdhuxejF8_bLCHZ2kWfmDXpDGUu914Gbd6_3JjCRe0,676
121
+ execsql2-2.21.0.dist-info/licenses/NOTICE,sha256=McYzgxYav3U1OaVsY4Su1sfBrfmplpRdA9b6-gCDQCg,342
122
+ execsql2-2.21.0.dist-info/RECORD,,