FirebirdSQL / python3-driver

Firebird driver for Python that uses new Firebird API
https://www.firebirdsql.org/en/devel-python-driver/
MIT License
26 stars 10 forks source link

Alternative to register_server() ? #24

Closed fdcastel closed 10 months ago

fdcastel commented 1 year ago

I just realized that all my tests with firebird-driver used only local connections.

Now trying to connect to a remote database is failing with

self = <sqlalchemy_firebird.firebird.FBDialect_firebird object at 0x0000020EAE2C2750>, cargs = ()
cparams = {'database': '//C:/Temp/data.fdb', 'host': 'TEST', 'password': 'masterkey', 'user': 'SYSDBA'}

    def connect(self, *cargs, **cparams):
        # inherits the docstring from interfaces.Dialect.connect
>       return self.loaded_dbapi.connect(*cargs, **cparams)
E       TypeError: connect() got an unexpected keyword argument 'host'

According to PEP 249 .connect() must accept "a number of parameters which are database dependent". In other words, there are no standard keywords here.

How should we pass the server name in this case? We really need to use register_server? If yes, this would be awkward to integrate with other db_api libraries (SQLAlchemy in this case).

fdcastel commented 1 year ago

For reference, this is how we are currently translating SQLAlchemy urls to connect() arguments when using firebird-driver.

fdcastel commented 1 year ago

I other words:

1) Could we add a host argument to connect()?

2) If not, and we must rely on a previous call to register_server, when should we "unregister" it?

pcisar commented 1 year ago

As there could be many parameters (and the list is growing as Firebird evolves), the former driver FDB ended with extensive parameter list in connect(). The new firebird-driver uses different approach. The database parameters are stored in configuration, and the connect() method has only limited set of more "volatile" parameters like user, password, role etc. for cases when user wants to alternate these parameters from base config for particular connection, or parameters that couldn't be stored in configuration dues to security or technical reasons. The host (where database is located) is not such parameter, as databases as strictly bound to server where they reside, so this is done ONLY in configuration. The local vs. localhost is a special case where database is on the same computer, but the engine differs (embedded server is not the same as local server even if they run on the same computer). So, no, I'll not add the host parameter to connect as it will violate the diver design.

There are two methods how you can honor the design in your SQLAlchemy driver: 1) You can provide special handling for firebird driver configuration file (replacing the fb_client_library URL parameter handling as this is part of configuration anyway) that will load it via driver_config.read(), and the rest is as usual. 2) You don't need to do anything special in your driver (not even provide special handling for fb_client_library URL parameter), as firebird driver configuration is responsibility of the user. Either via some integration with used web framework or whatever. In your tests, just provide the configuration in your setup (if you use pytest, then in session fixture, or in some equivalent for other unittest systems). You ca do it in code via driver_config.register_server() / driver_config.register_database() and setting required parameters, or load it as a whole via driver_config.read() method (or similar, see https://firebird-driver.readthedocs.io/en/latest/ref-config.html#firebird.driver.config.DriverConfig)

pcisar commented 1 year ago

As for your second question, servers and databases does not need to be unregistered as there is generally no harm from their pure existence (unless you want to register the another one with the same name in different context, which will fail). In fact, there is no easy way to unregister them via some specific method. If you really insist to do so, you need to manipulate the driver_config.database / driver_config.servers lists.