From 1e0180e85ad8959f474726d28886f01b23775666 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Wed, 9 Jul 2025 14:57:11 -0400 Subject: [PATCH] add boolean interpretation to config Fixed issue in new ``pyproject.toml`` support where boolean values, such as those used for the ``recursive_version_locations`` and ``sourceless`` configuration parameters, would not be accepted. Fixes: #1694 Change-Id: Ifeed46c599ab20db1713f306b7be9c3b5fe23485 --- alembic/config.py | 17 ++++++++++++- alembic/script/base.py | 6 ++--- alembic/testing/__init__.py | 1 + docs/build/unreleased/1694.rst | 8 +++++++ tests/test_config.py | 44 ++++++++++++++++++++++++++++++++++ 5 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 docs/build/unreleased/1694.rst diff --git a/alembic/config.py b/alembic/config.py index c1196657..dcc64a4c 100644 --- a/alembic/config.py +++ b/alembic/config.py @@ -455,6 +455,19 @@ class Config: else: return self._get_toml_config_value(name, default=default) + def get_alembic_boolean_option(self, name: str) -> bool: + if self.file_config.has_option(self.config_ini_section, name): + return ( + self.file_config.get(self.config_ini_section, name) == "true" + ) + else: + value = self.toml_alembic_config.get(name, False) + if not isinstance(value, bool): + raise util.CommandError( + f"boolean value expected for TOML parameter {name!r}" + ) + return value + def _get_toml_config_value( self, name: str, default: Optional[Any] = None ) -> Union[None, str, list[str], dict[str, str], list[dict[str, str]]]: @@ -483,7 +496,9 @@ class Config: {k: v % (self.toml_args) for k, v in value.items()}, ) else: - raise util.CommandError("unsupported TOML value type") + raise util.CommandError( + f"unsupported TOML value type for key: {name!r}" + ) return value @util.memoized_property diff --git a/alembic/script/base.py b/alembic/script/base.py index c3b1c311..94292316 100644 --- a/alembic/script/base.py +++ b/alembic/script/base.py @@ -186,16 +186,14 @@ class ScriptDirectory: if prepend_sys_path: sys.path[:0] = prepend_sys_path - rvl = ( - config.get_alembic_option("recursive_version_locations") == "true" - ) + rvl = config.get_alembic_boolean_option("recursive_version_locations") return ScriptDirectory( util.coerce_resource_to_filename(script_location), file_template=config.get_alembic_option( "file_template", _default_file_template ), truncate_slug_length=truncate_slug_length, - sourceless=config.get_alembic_option("sourceless") == "true", + sourceless=config.get_alembic_boolean_option("sourceless"), output_encoding=config.get_alembic_option( "output_encoding", "utf-8" ), diff --git a/alembic/testing/__init__.py b/alembic/testing/__init__.py index 316ea91b..32915081 100644 --- a/alembic/testing/__init__.py +++ b/alembic/testing/__init__.py @@ -9,6 +9,7 @@ from sqlalchemy.testing import uses_deprecated from sqlalchemy.testing.config import combinations from sqlalchemy.testing.config import fixture from sqlalchemy.testing.config import requirements as requires +from sqlalchemy.testing.config import Variation from sqlalchemy.testing.config import variation from .assertions import assert_raises diff --git a/docs/build/unreleased/1694.rst b/docs/build/unreleased/1694.rst new file mode 100644 index 00000000..b7f5a3c5 --- /dev/null +++ b/docs/build/unreleased/1694.rst @@ -0,0 +1,8 @@ +.. change:: + :tags: bug, config + :tickets: 1694 + + Fixed issue in new ``pyproject.toml`` support where boolean values, such as + those used for the ``recursive_version_locations`` and ``sourceless`` + configuration parameters, would not be accepted. + diff --git a/tests/test_config.py b/tests/test_config.py index 4827b635..40a22f71 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -542,6 +542,50 @@ my_list = [ ], ) + @testing.combinations( + "sourceless", "recursive_version_locations", argnames="paramname" + ) + @testing.variation("argtype", ["true", "false", "omit", "wrongvalue"]) + def test_bool( + self, pyproject_only_env, argtype: testing.Variation, paramname + ): + + cfg = pyproject_only_env + with cfg._toml_file_path.open("w") as file_: + + if argtype.true: + config_option = f"{paramname} = true" + elif argtype.false: + config_option = f"{paramname} = false" + elif argtype.omit: + config_option = "" + elif argtype.wrongvalue: + config_option = f"{paramname} = 'false'" + else: + argtype.fail() + + file_.write( + rf""" + +[tool.alembic] +script_location = "%(here)s/scripts" + +{config_option} +""" + ) + if "toml_alembic_config" in cfg.__dict__: + cfg.__dict__.pop("toml_alembic_config") + + if argtype.wrongvalue: + with expect_raises_message( + util.CommandError, + f"boolean value expected for TOML parameter '{paramname}'", + ): + sd = ScriptDirectory.from_config(cfg) + else: + sd = ScriptDirectory.from_config(cfg) + eq_(getattr(sd, paramname), bool(argtype.true)) + class StdoutOutputEncodingTest(TestBase): def test_plain(self): -- 2.47.2