-
Notifications
You must be signed in to change notification settings - Fork 96
Closed
Labels
Description
- What versions are you using?
python-oracledb 2.0.0on Python 3.12 andOracle Database XE 18c. Both run inside docker containers on Windows 11 23H2 with WSL 2 backend. The database container image is gvenzl/oracle-xe:18-faststart.
-
Is it an error or a hang or a crash?
Error. -
What error(s) or behavior you are seeing?
Usingconnect_async()with uvloop (a faster drop-in replacement forasyncio) throws the following exception:
(The first line is the success output ofasyncio.run(main()).)
('TEST',)
Traceback (most recent call last):
File "src/oracledb/impl/thin/connection.pyx", line 502, in oracledb.thin_impl.AsyncThinConnImpl._connect_with_address
File "src/oracledb/impl/thin/protocol.pyx", line 567, in _connect_phase_one
File "src/oracledb/impl/thin/protocol.pyx", line 730, in _connect_tcp
File "src/oracledb/impl/thin/transport.pyx", line 301, in oracledb.thin_impl.Transport.set_from_socket
AttributeError: 'uvloop.loop.TCPTransport' object has no attribute 'setsockopt'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<frozen runpy>", line 189, in _run_module_as_main
File "<frozen runpy>", line 148, in _get_module_details
File "<frozen runpy>", line 112, in _get_module_details
File "/app/example_service/__init__.py", line 18, in <module>
uvloop.run(main())
File "/app/.venv/lib/python3.12/site-packages/uvloop/__init__.py", line 109, in run
return __asyncio.run(
^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/asyncio/runners.py", line 194, in run
return runner.run(main)
^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/asyncio/runners.py", line 118, in run
return self._loop.run_until_complete(task)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "uvloop/loop.pyx", line 1517, in uvloop.loop.Loop.run_until_complete
File "/app/.venv/lib/python3.12/site-packages/uvloop/__init__.py", line 61, in wrapper
return await main
^^^^^^^^^^
File "/app/example_service/__init__.py", line 8, in main
async with oracledb.connect_async(
File "/app/.venv/lib/python3.12/site-packages/oracledb/connection.py", line 1398, in __aenter__
await self._connect_coroutine
File "/app/.venv/lib/python3.12/site-packages/oracledb/connection.py", line 1443, in _connect
await impl.connect(params_impl)
File "src/oracledb/impl/thin/connection.pyx", line 609, in connect
File "src/oracledb/impl/thin/connection.pyx", line 605, in oracledb.thin_impl.AsyncThinConnImpl.connect
File "src/oracledb/impl/thin/connection.pyx", line 563, in _connect_with_params
File "src/oracledb/impl/thin/connection.pyx", line 543, in _connect_with_description
File "src/oracledb/impl/thin/connection.pyx", line 512, in _connect_with_address
File "/app/.venv/lib/python3.12/site-packages/oracledb/errors.py", line 162, in _raise_err
raise exc_type(_Error(message)) from cause
oracledb.exceptions.OperationalError: DPY-6005: cannot connect to database (CONNECTION_ID=+o4qjIZQoVmu5EZP54G9xw==).
'uvloop.loop.TCPTransport' object has no attribute 'setsockopt'
- Does your application call init_oracle_client()?
No.
- Include a runnable Python script that shows the problem.
import asyncio
import oracledb
import uvloop
async def main():
async with oracledb.connect_async(
user="test", password="test", dsn="host.docker.internal/xepdb1"
) as connection:
with connection.cursor() as cursor:
await cursor.execute("select user from dual")
async for result in cursor:
print(result)
asyncio.run(main())
uvloop.run(main())- Cause
The thin mode transport implementation detects Async mode by checking if the suppliedtransportis an instance ofasyncio.Transport. To support alternative implementations without depending on them directly, we need to detect Async mode without hard-coded runtime instance checks. Maybe passing in an explicit flag variable?
python-oracledb/src/oracledb/impl/thin/transport.pyx
Lines 287 to 301 in 9645d4f
self._is_async = isinstance(transport, asyncio.Transport) if self._is_async: sock = transport.get_extra_info('socket') else: sock = transport if description.expire_time > 0: sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) if hasattr(socket, "TCP_KEEPIDLE") \ and hasattr(socket, "TCP_KEEPINTVL") \ and hasattr(socket, "TCP_KEEPCNT"): sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, description.expire_time * 60) sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 6) sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 10) sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)