-
Notifications
You must be signed in to change notification settings - Fork 310
Bug: Database fields not escaped when building URL #547
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
@LyndonFan I just wrote a test and tried to reproduce your issue: and yes it fails also on my machine, but not because of an character escaping problem. It fails because the mysql:8.0.27 Docker image does not support ARM CPUs. When I run the same test with mysql:8.3.0 image, test is green. Please check the images on Docker Hub:
Are you working on an M1, M2 or M3 MacBook? Then most likely that is the root cause of your problem. |
None of the above -- it's "2.3 GHz Quad-Core Intel Core i7" |
using |
@LyndonFan I just ran your sample code with mysql:8.3.0, test is green. Cannot reproduce. testcontainers-python=4.4.0 |
produces:
|
Thanks for the quick responses! I've updated testcontainers to 4.4.0, and updated my test to be based on David's. Note I changed the password to contain "%12", which is the same as # test.py
import sqlalchemy
from testcontainers.mysql import MySqlContainer
with MySqlContainer(
"mysql:8-oracle",
root_password="root%password",
password="pass%12word",
) as m:
url = m.get_connection_url()
print(url)
engine = sqlalchemy.create_engine(url)
with engine.connect() as connection:
result = connection.exec_driver_sql("select version()")
result = result.fetchall()
print(result) Running Full error logs (8-oracle)(testcontainers-issue-py3.11) MacBook-Pro-9:testcontainers-issue lyndonf$ python test.py
Pulling image testcontainers/ryuk:0.7.0
Container started: 5d3e0ab834c7
Waiting for container <Container: 5d3e0ab834c7> with image testcontainers/ryuk:0.7.0 to be ready ...
Pulling image mysql:8-oracle
Container started: 76c64d30abe8
Waiting for container <Container: 76c64d30abe8> with image mysql:8-oracle to be ready ...
mysql+pymysql://test:pass%12word@localhost:58703/test
Traceback (most recent call last):
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 146, in __init__
self._dbapi_connection = engine.raw_connection()
^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 3304, in raw_connection
return self.pool.connect()
^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 449, in connect
return _ConnectionFairy._checkout(self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 1263, in _checkout
fairy = _ConnectionRecord.checkout(pool)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 712, in checkout
rec = pool._do_get()
^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/impl.py", line 179, in _do_get
with util.safe_reraise():
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/util/langhelpers.py", line 146, in __exit__
raise exc_value.with_traceback(exc_tb)
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/impl.py", line 177, in _do_get
return self._create_connection()
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 390, in _create_connection
return _ConnectionRecord(self)
^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 674, in __init__
self.__connect()
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 900, in __connect
with util.safe_reraise():
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/util/langhelpers.py", line 146, in __exit__
raise exc_value.with_traceback(exc_tb)
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 896, in __connect
self.dbapi_connection = connection = pool._invoke_creator(self)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/engine/create.py", line 643, in connect
return dialect.connect(*cargs, **cparams)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/engine/default.py", line 617, in connect
return self.loaded_dbapi.connect(*cargs, **cparams)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/connections.py", line 358, in __init__
self.connect()
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/connections.py", line 664, in connect
self._request_authentication()
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/connections.py", line 976, in _request_authentication
auth_packet = _auth.caching_sha2_password_auth(self, auth_packet)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/_auth.py", line 267, in caching_sha2_password_auth
pkt = _roundtrip(conn, data)
^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/_auth.py", line 120, in _roundtrip
pkt = conn._read_packet()
^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/connections.py", line 772, in _read_packet
packet.raise_for_error()
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/protocol.py", line 221, in raise_for_error
err.raise_mysql_exception(self._data)
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/err.py", line 143, in raise_mysql_exception
raise errorclass(errno, errval)
pymysql.err.OperationalError: (1045, "Access denied for user 'test'@'172.17.0.1' (using password: YES)")
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/lyndonf/Desktop/testcontainers-issue/test.py", line 15, in <module>
with engine.connect() as connection:
^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 3280, in connect
return self._connection_cls(self)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 148, in __init__
Connection._handle_dbapi_exception_noconnection(
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 2444, in _handle_dbapi_exception_noconnection
raise sqlalchemy_exception.with_traceback(exc_info[2]) from e
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 146, in __init__
self._dbapi_connection = engine.raw_connection()
^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 3304, in raw_connection
return self.pool.connect()
^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 449, in connect
return _ConnectionFairy._checkout(self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 1263, in _checkout
fairy = _ConnectionRecord.checkout(pool)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 712, in checkout
rec = pool._do_get()
^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/impl.py", line 179, in _do_get
with util.safe_reraise():
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/util/langhelpers.py", line 146, in __exit__
raise exc_value.with_traceback(exc_tb)
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/impl.py", line 177, in _do_get
return self._create_connection()
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 390, in _create_connection
return _ConnectionRecord(self)
^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 674, in __init__
self.__connect()
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 900, in __connect
with util.safe_reraise():
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/util/langhelpers.py", line 146, in __exit__
raise exc_value.with_traceback(exc_tb)
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 896, in __connect
self.dbapi_connection = connection = pool._invoke_creator(self)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/engine/create.py", line 643, in connect
return dialect.connect(*cargs, **cparams)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/engine/default.py", line 617, in connect
return self.loaded_dbapi.connect(*cargs, **cparams)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/connections.py", line 358, in __init__
self.connect()
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/connections.py", line 664, in connect
self._request_authentication()
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/connections.py", line 976, in _request_authentication
auth_packet = _auth.caching_sha2_password_auth(self, auth_packet)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/_auth.py", line 267, in caching_sha2_password_auth
pkt = _roundtrip(conn, data)
^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/_auth.py", line 120, in _roundtrip
pkt = conn._read_packet()
^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/connections.py", line 772, in _read_packet
packet.raise_for_error()
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/protocol.py", line 221, in raise_for_error
err.raise_mysql_exception(self._data)
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/err.py", line 143, in raise_mysql_exception
raise errorclass(errno, errval)
sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (1045, "Access denied for user 'test'@'172.17.0.1' (using password: YES)")
(Background on this error at: https://sqlalche.me/e/20/e3q8) I modified the image to be Full error logs (for 8.3.0)(testcontainers-issue-py3.11) MacBook-Pro-9:testcontainers-issue lyndonf$ python test.py
Pulling image testcontainers/ryuk:0.7.0
Container started: c5a6220ddf6b
Waiting for container <Container: c5a6220ddf6b> with image testcontainers/ryuk:0.7.0 to be ready ...
Pulling image mysql:8.3.0
Container started: 8e64d1c48b5f
Waiting for container <Container: 8e64d1c48b5f> with image mysql:8.3.0 to be ready ...
mysql+pymysql://test:pass%12word@localhost:64340/test
Traceback (most recent call last):
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 146, in __init__
self._dbapi_connection = engine.raw_connection()
^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 3304, in raw_connection
return self.pool.connect()
^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 449, in connect
return _ConnectionFairy._checkout(self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 1263, in _checkout
fairy = _ConnectionRecord.checkout(pool)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 712, in checkout
rec = pool._do_get()
^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/impl.py", line 179, in _do_get
with util.safe_reraise():
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/util/langhelpers.py", line 146, in __exit__
raise exc_value.with_traceback(exc_tb)
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/impl.py", line 177, in _do_get
return self._create_connection()
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 390, in _create_connection
return _ConnectionRecord(self)
^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 674, in __init__
self.__connect()
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 900, in __connect
with util.safe_reraise():
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/util/langhelpers.py", line 146, in __exit__
raise exc_value.with_traceback(exc_tb)
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 896, in __connect
self.dbapi_connection = connection = pool._invoke_creator(self)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/engine/create.py", line 643, in connect
return dialect.connect(*cargs, **cparams)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/engine/default.py", line 617, in connect
return self.loaded_dbapi.connect(*cargs, **cparams)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/connections.py", line 358, in __init__
self.connect()
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/connections.py", line 664, in connect
self._request_authentication()
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/connections.py", line 976, in _request_authentication
auth_packet = _auth.caching_sha2_password_auth(self, auth_packet)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/_auth.py", line 267, in caching_sha2_password_auth
pkt = _roundtrip(conn, data)
^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/_auth.py", line 120, in _roundtrip
pkt = conn._read_packet()
^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/connections.py", line 772, in _read_packet
packet.raise_for_error()
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/protocol.py", line 221, in raise_for_error
err.raise_mysql_exception(self._data)
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/err.py", line 143, in raise_mysql_exception
raise errorclass(errno, errval)
pymysql.err.OperationalError: (1045, "Access denied for user 'test'@'172.17.0.1' (using password: YES)")
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/lyndonf/Desktop/testcontainers-issue/test.py", line 16, in <module>
with engine.connect() as connection:
^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 3280, in connect
return self._connection_cls(self)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 148, in __init__
Connection._handle_dbapi_exception_noconnection(
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 2444, in _handle_dbapi_exception_noconnection
raise sqlalchemy_exception.with_traceback(exc_info[2]) from e
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 146, in __init__
self._dbapi_connection = engine.raw_connection()
^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 3304, in raw_connection
return self.pool.connect()
^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 449, in connect
return _ConnectionFairy._checkout(self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 1263, in _checkout
fairy = _ConnectionRecord.checkout(pool)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 712, in checkout
rec = pool._do_get()
^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/impl.py", line 179, in _do_get
with util.safe_reraise():
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/util/langhelpers.py", line 146, in __exit__
raise exc_value.with_traceback(exc_tb)
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/impl.py", line 177, in _do_get
return self._create_connection()
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 390, in _create_connection
return _ConnectionRecord(self)
^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 674, in __init__
self.__connect()
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 900, in __connect
with util.safe_reraise():
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/util/langhelpers.py", line 146, in __exit__
raise exc_value.with_traceback(exc_tb)
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py", line 896, in __connect
self.dbapi_connection = connection = pool._invoke_creator(self)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/engine/create.py", line 643, in connect
return dialect.connect(*cargs, **cparams)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/sqlalchemy/engine/default.py", line 617, in connect
return self.loaded_dbapi.connect(*cargs, **cparams)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/connections.py", line 358, in __init__
self.connect()
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/connections.py", line 664, in connect
self._request_authentication()
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/connections.py", line 976, in _request_authentication
auth_packet = _auth.caching_sha2_password_auth(self, auth_packet)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/_auth.py", line 267, in caching_sha2_password_auth
pkt = _roundtrip(conn, data)
^^^^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/_auth.py", line 120, in _roundtrip
pkt = conn._read_packet()
^^^^^^^^^^^^^^^^^^^
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/connections.py", line 772, in _read_packet
packet.raise_for_error()
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/protocol.py", line 221, in raise_for_error
err.raise_mysql_exception(self._data)
File "/Users/lyndonf/Desktop/testcontainers-issue/.venv/lib/python3.11/site-packages/pymysql/err.py", line 143, in raise_mysql_exception
raise errorclass(errno, errval)
sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (1045, "Access denied for user 'test'@'172.17.0.1' (using password: YES)")
(Background on this error at: https://sqlalche.me/e/20/e3q8) Let me know if the above results help. I'm happy to work on a merge request to close this. |
yep, reproduces with %12 in the password, im editing my previous comment |
@LyndonFan just re-read your last comment and yeah if you want to open a PR that would be great! not sure when ill get to it but appreciate the offer and as above, a PR is welcome. we'd probably want to either add tests for postgres, sql server, oracle, etc as well or make this behavior opt-in or something. |
**Changes** Updated DbContainer to fix #547 by using `urllib.parse.quote`. I referenced sqlalchemy's implementation, but have not imported the library. I have chosen to make this behaviour occur at all times (can't opt in / out), as it is common, if not the standard for these urls. **Tests** Since DbContainer can't be tested on its own, I put the tests across various database containers. I have pasted the below as comment in the test files for the listed modules: ```python # This is a feature in the generic DbContainer class # but it can't be tested on its own # so is tested in various database modules: # - mysql / mariadb # - postgresql # - sqlserver # - mongodb ``` Note the discussion recommended me to test with oracle, but I was unable to spin the container up locally (even with colima), so opted to replace it with mongodb. Is there a template for PRs for the core library? I am unable to find one so have opted the above format. Please let me know if I have missed anything in this PR. Thanks!
Describe the bug
The
get_connection_url
function for database containers does not escape "%" properly.I was testing some code at work which connected to a database (MySQL), and noticed it was unable to do so. I found out it was because the password contained a "%" and we created the database url with f-strings like below. This meant the url got screwed up and the connection failed.
While I have only tested with MySql, from going through the repo, I suspect this could affect most (if not all) database containers, as the same method appears to be used in the library.
To Reproduce
See the simplified version of my test code.
mysql.start()
, as it is unable to connect to the container.Full error logs
Suggestions
urllib.parse.quote
to preprocess fields before putting them into the urlURL
fromsqlalchemy
to generate the url, though from previous history this option does not seem to be recommendedRuntime environment
Full environment details
The text was updated successfully, but these errors were encountered: