joseph-bergin opened a new pull request, #72119:
URL: https://github.com/apache/airflow/pull/72119

   Migrates the exasol provider to pyexasol 2.x and removes the 
`pyexasol>=0.26.0,<2` cap added in #68933.
   
   ### What the cap was hiding
   
   pyexasol 2.x ships type information, so mypy now checks these calls. Against 
pyexasol 2.3.2 the hook reports 6 errors:
   
   - `ExaConnection.execute` / `export_to_pandas` are typed `query_params: dict 
| None`, but the hook forwarded `Iterable | Mapping[str, Any] | None` (lines 
148, 191, 208, 337).
   - `execute` is typed `query: str`, but `get_records` / `get_first` forwarded 
the `str | list[str]` that `DbApiHook` accepts (lines 191, 208).
   
   `get_conn` also reused one local for both the Airflow `Connection` and the 
`ExaConnection` returned by `pyexasol.connect`; that one only surfaces with 
Airflow's own sources on `mypy_path`, and is fixed here too.
   
   ### Changes
   
   - `get_conn` uses separate locals (`airflow_conn` and the returned 
connection).
   - `_to_query_params` passes `None` through, copies any mapping into a 
`dict`, and rejects sequences.
   - `_to_single_statement` unwraps the `str` and rejects a list.
   - Cap removed from `providers/exasol/pyproject.toml`.
   
   ### On the two rejected paths
   
   Both were already broken against a real Exasol, so only the error message 
changes:
   
   - `ExaStatement._format_query` does `self.connection.format.format(query, 
**query_params)`. A tuple or list there raises `TypeError: argument after ** 
must be a mapping, not tuple`, so positional parameters have never reached the 
driver intact.
   - `ExaConnection.execute` runs exactly one statement, so a `list[str]` was 
never executable in `get_records` / `get_first`. `run()` is the method that 
splits and loops, and the new message points there.
   
   `test_run_with_parameters` passed `("param1", "param2")` and passed only 
because the connection is a `MagicMock`. It now uses a mapping, with new 
coverage for mapping normalization and for both rejections.
   
   If you would rather keep those paths permissive and satisfy mypy with `cast` 
instead, I am happy to switch — I went with explicit errors because the status 
quo is a confusing failure deep inside the driver.
   
   ### Verification
   
   Against pyexasol 2.3.2, Python 3.11:
   
   - `mypy providers/exasol/src/` — 6 errors before, 0 after
   - `pytest providers/exasol/tests/unit/exasol/` — 58 passed (previously 53 
passed with 1 failing after the migration)
   - `ruff check` and `ruff format --check` at the pinned 0.16.3 — clean
   
   closes: #69123
   
   ---
   
   ##### Was generative AI tooling used to co-author this PR?
   
   - [X] Yes (please specify the tool below)
   
   Generated-by: Claude Code (Opus 5) following [the 
guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#gen-ai-assisted-contributions)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to