Repository navigation
feat: PostgreSQL is the default backend - #1629
Draft
dimitri-yatsenko wants to merge 1 commit into
Draft
dimitri-yatsenko wants to merge 1 commit into
dimitri-yatsenko wants to merge 1 commit into
Conversation
database.backend defaulted to "mysql", so a connection made without configuring a backend went to MySQL. It now defaults to "postgresql" on port 5432. MySQL stays a fully supported backend, selected with one setting. The port follows the backend unless it is set. The port was derived from the backend only when the settings were first built, so a backend set later, in datajoint.json or by assignment, kept the other backend's port: with the new default, backend "mysql" in datajoint.json would have connected to port 5432. The validator now recomputes a port that was not set whenever the backend changes. A port set by DJ_PORT, datajoint.json, or assignment is kept, and setting it to None returns it to the backend's default. When a connection fails and the backend is still the default, so that neither the backend argument nor the configuration chose one, the error is re-raised as a DataJointError that keeps the original message and adds: The default backend is postgresql since DataJoint 2.4; set database.backend='mysql' (DJ_BACKEND=mysql) for a MySQL server. The same applies when the adapter cannot be created, as when psycopg2 is not installed. The settings record which fields were set (pydantic's model_fields_set), so DJ_BACKEND, datajoint.json, dj.config assignment, and Instance(backend=...) all count as chosen, and with any of them the original error is raised unchanged. Instance no longer passes its config's backend to Connection as an argument, which hid whether it was chosen; Connection reads it from that config. save_template writes "backend": "postgresql" and port 5432. The settings docstring, the Connection and Instance docstrings, the CLI help, docker-compose.yaml, and CONTRIBUTING.md list PostgreSQL first. In the compose file the app service's DJ_HOST, DJ_USER, and DJ_PASS name the MySQL service, which the test suite reads as its MySQL server, so the service now sets DJ_BACKEND=mysql to match. Migration for MySQL users: select the backend with DJ_BACKEND=mysql, "backend": "mysql" under "database" in datajoint.json, dj.config["database.backend"] = "mysql" before connecting, or dj.Instance(..., backend="mysql"). The port then defaults to 3306; an explicit port is kept. A MySQL setup that sets no backend fails to connect with the message above. Tests: the MySQL-only fixtures no longer rely on the default. A session fixture, mysql_backend_config, selects MySQL in dj.config for the tests that connect through db_creds_root and db_creds_test. connection_root_bare and connection_test pass backend="mysql". The CLI test's subprocess sets DJ_BACKEND=mysql. connection_by_backend falls back to "postgresql". New unit tests, which need no server, check the default backend and port, that a port not set follows the backend (including backend "mysql" in datajoint.json), that a port that was set survives a change of backend, and that the hint appears for a failed connection or missing driver with the default backend. They also check that it does not appear when the backend comes from the argument, assignment, DJ_BACKEND, or datajoint.json, using a stub adapter and a real refused connection to a closed local port.
dimitri-yatsenko
requested review from
MilagrosMarin,
lum-agilyti and
ttngu207
October 17, 2026 23:49
MilagrosMarin
left a comment
Contributor
There was a problem hiding this comment.
Thanks @dimitri-yatsenko, the default-backend hint is a nice touch for the migration, and keying it off model_fields_set is a neat way to tell "chosen" from "defaulted".
Verified locally:
✅ Unit suite passes on this branch, and on master + #1628 + #1629 merged together
✅ An unset port follows the backend both ways; port=None returns it to the backend default; Instance(backend="mysql") and dj.conn() pick up the backend from config
One issue:
config.override()restores values withsetattr, which marks them as explicitly set. Afterthe port stays 5432 (now inwith dj.config.override(database__port=1234): ... dj.config["database.backend"] = "mysql"
model_fields_set), so it no longer follows the backend. The same restore marksbackendas set afteroverride(database__backend=...), which turns the hint off for the rest of the session. Saving and restoring each field'smodel_fields_setmembership inoverride()would fix both.
Minor:
- With the default backend, unrelated connect failures (e.g. a wrong password on a real PostgreSQL server) also get the MySQL hint. Fine by me given the migration, just noting it.
- CI ran before #1596 merged, so the py3.15 legs haven't run here. A rebase/re-run would confirm.
- On the docs side,
configure-database.md,reference/configuration.md,tutorials/index.md, andinstallation.mdstill show 3306 / MySQL as the default. I'll fold those into the docs PR for #1628.
Let me know what you think!
dimitri-yatsenko
marked this pull request as draft
October 21, 2026 16:46
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1627.
Summary
database.backendnow defaults to"postgresql"on port 5432. MySQL remains a fully supported backend, selected withDJ_BACKEND=mysqlordatabase.backend = "mysql". A connection that fails while the backend is still the default says so:Changes
settings.py).backenddefaults to"postgresql", and the docstring examples and field descriptions match.datajoint.jsonor by assignment, kept the other backend's port. With the new default,{"database": {"backend": "mysql"}}would have connected to 5432.DJ_PORT,datajoint.json, or assignment is kept. Setting it toNonereturns it to the backend default.test_port_auto_detection_on_initialization) is replaced.connection.py). The hint applies when the backend is still the default: nobackendargument was passed, anddatabase.backendis not in the settings'model_fields_set. In that case, a failure to create the adapter or to connect is re-raised as aDataJointErrorthat keeps the original message, appends the hint, and chains the original error. The adapter failure covers a missing psycopg2.DJ_BACKEND,datajoint.json,dj.configassignment, thebackendargument, orInstance(backend=...)raises the original error unchanged.backendargument toConnection. Passing its config's value made every backend look chosen, soConnectionnow reads the backend from that config."backend": "postgresql"and"port": 5432.DJ_BACKEND=mysqlfor MySQL.docker-compose.yaml: service order,depends_on, and header comments.CONTRIBUTING.md: test descriptions, external-container recipes, and environment variable tables.appservice. ItsDJ_HOST/DJ_USER/DJ_PASSname the MySQL service, which the test suite reads as its MySQL server. The service now setsDJ_BACKEND=mysqlto match.Tests that relied on MySQL being the default
tests/conftest.py:mysql_backend_config, selects MySQL indj.configfor every test that connects throughdb_creds_root/db_creds_test, asdj.conn(**db_creds_root)anddj.Connection(**db_creds_test)do.connection_root_bareandconnection_testpassbackend="mysql".connection_by_backendfallback is"postgresql".tests/integration/test_cli.py::test_cli_schemasstartspython -m datajoint.cliagainst the MySQL test server. Its subprocess now setsDJ_BACKEND=mysql.tests/unit/test_settings.py,tests/unit/test_thread_safe.py: these expect the new default and port, and they isolateDJ_BACKEND/DJ_PORTwhere they assert defaults.New tests (no server needed)
tests/unit/test_connection_backend_hint.py:DJ_BACKEND, ordatajoint.json.tests/unit/test_settings.py, covering the port:backend: "mysql"indatajoint.jsonwithout a port gives 3306.Nonereturns it to the default.tests/unit/test_thread_safe.py:Instance(backend="mysql")connects on 3306.Full suite (testcontainers, local): 1170 passed, 14 skipped.
Checked against real servers, with this branch merged with the drivers-as-extras PR and installed in clean virtual environments (no
datajoint.json):[postgres][mysql]DJ_BACKEND=mysql[mysql]datajoint[postgres], plus the hint[postgres]Migration for MySQL users
Use any one of:
export DJ_BACKEND=mysqldatajoint.json:{"database": {"backend": "mysql", "host": "..."}}dj.config["database.backend"] = "mysql"before connectingdj.Instance(host=..., user=..., password=..., backend="mysql")The port then defaults to 3306, and an explicit port is kept.
Notes for review
DataJointErrorchanges the exception type only when the backend is the default. Code that catches a driver exception (for examplepymysql.err.OperationalError) arounddj.conn()sees it unchanged once the backend is set.