Skip to content
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

Asyncmy does not get the correct host and port using "read_default_file" #74

Open
pgamez opened this issue Jul 26, 2023 · 2 comments
Open

Comments

@pgamez
Copy link
Contributor

pgamez commented Jul 26, 2023

Hi,

I've tried to start a connection with asyncmy taking the connection parameters from a config file.

This is my config file (bug.cnf):

[client]
user = myuser
host = myhost
password = mypassword
database = mydatabase

I've prepared this script to show the problem:

#!/usr/bin/env python3

import asyncio

from asyncmy import connect


async def main():
    print("# Using asyncmy directly")
    try:
        conn = await connect(
            host="myhost",
            user="myuser",
            password="mypassword",
            database="mydatabase",
        )
    except Exception as e:
        print(e)

    print("# Using asyncmy directly with a config file")
    try:
        conn = await connect(read_default_file="bug.cnf")
    except Exception as e:
        print(e)


if __name__ == "__main__":
    asyncio.run(main())

This is the output of the script:

./bug.py 
# Using asyncmy directly
(2003, "Can't connect to MySQL server on 'myhost' ([Errno -2] Name or service not known)")
# Using asyncmy directly with a config file
(1045, "Access denied for user 'myuser'@'localhost' (using password: YES)")

You can see that:

  • In the first try, asyncmy tries to connect to host=myhost (correct)
  • In the second try, asyncmy tries to connect to user=myuser (correct) and host=localhost (wrong)

The reason of this bug is placed in the object Connection (connection.pyx). We have this function to read the data from the config file:

def _config(key, arg):
    if arg:
        return arg
    try:
        return cfg.get(read_default_group, key)
    except Exception:
        return arg

Note that the value of arg has a higher priority over the value obtained from the config file, which is requested only when arg is evaluated as False.

Then, we execute this function setting arg to the defaults:

host = _config("host", host)
port = int(_config("port", port))

but host and port defaults ('localhost' and 3306 respectively) are not evaluated to "False", so the corresponding values won't be readed from file:

def __init__(
    self,
    *,
    user=None,  # The first four arguments is based on DB-API 2.0 recommendation.
    password="",
    host='localhost',
    database=None,
    unix_socket=None,
    port=3306,
    ...
):

The solution is to set these defaults to:

  • host=None
  • port=0

In PyMySQL this bug is already fixed:

def __init__(
    self,
    ...
    host=None,
    ...
    port=0,
...
):
    ...
    self.host = host or "localhost"
    self.port = port or 3306
    ...

Thanks and greetings,

Pedro

@long2ice
Copy link
Owner

Thanks for report! PR welcome.

@pgamez
Copy link
Contributor Author

pgamez commented Jul 27, 2023

Done! Thank you :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants