]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
make sure no-ini-file actually works
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 20 May 2025 19:17:54 +0000 (15:17 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 20 May 2025 19:37:30 +0000 (15:37 -0400)
because Config has an alembic.ini path in it by default, if the file
doesnt exist it will raise when you call get_main_option().  make sure
no alembic function calls upon get_main_option() directly at all so that
configparser is entirely not required

Change-Id: Idae5979778e67075b3b233c902bfa4c70a2e614e

alembic/command.py
alembic/config.py
tests/test_config.py

index dd507a8a2e979bf1525ddc73ab1ad50a69dd99d0..9b1a44cb9891c16da8cde0d3897ce837f78b74b1 100644 (file)
@@ -271,7 +271,9 @@ def revision(
         process_revision_directives=process_revision_directives,
     )
 
-    environment = util.asbool(config.get_main_option("revision_environment"))
+    environment = util.asbool(
+        config.get_alembic_option("revision_environment")
+    )
 
     if autogenerate:
         environment = True
@@ -411,7 +413,9 @@ def merge(
         # e.g. multiple databases
     }
 
-    environment = util.asbool(config.get_main_option("revision_environment"))
+    environment = util.asbool(
+        config.get_alembic_option("revision_environment")
+    )
 
     if environment:
 
@@ -584,7 +588,7 @@ def history(
         base = head = None
 
     environment = (
-        util.asbool(config.get_main_option("revision_environment"))
+        util.asbool(config.get_alembic_option("revision_environment"))
         or indicate_current
     )
 
index 7a555faf50acdef41b4aa0b01beacba4bec93f20..f1579928e89e7af658ee6818b24117ba8d7a995c 100644 (file)
@@ -501,7 +501,9 @@ class Config:
 
     def get_version_locations_list(self) -> Optional[list[str]]:
 
-        version_locations_str = self.get_main_option("version_locations")
+        version_locations_str = self.file_config.get(
+            self.config_ini_section, "version_locations", fallback=None
+        )
 
         if version_locations_str:
             split_char = self._get_file_separator_char(
@@ -530,8 +532,9 @@ class Config:
             return self.toml_alembic_config.get("version_locations", None)
 
     def get_prepend_sys_paths_list(self) -> Optional[list[str]]:
-
-        prepend_sys_path_str = self.get_main_option("prepend_sys_path")
+        prepend_sys_path_str = self.file_config.get(
+            self.config_ini_section, "prepend_sys_path", fallback=None
+        )
 
         if prepend_sys_path_str:
             split_char = self._get_file_separator_char("path_separator")
index cf85f516dc9c30895c4ffc926869f4e47b000feb..411aa112dd96a92a07c5c252486453d9be2ae177 100644 (file)
@@ -1,7 +1,9 @@
 import os
+import pathlib
 import sys
 import tempfile
 
+from alembic import command
 from alembic import config
 from alembic import testing
 from alembic import util
@@ -12,7 +14,9 @@ from alembic.testing import assert_raises_message
 from alembic.testing import eq_
 from alembic.testing import mock
 from alembic.testing.assertions import expect_raises_message
+from alembic.testing.env import _get_staging_directory
 from alembic.testing.env import _no_sql_testing_config
+from alembic.testing.env import _testing_config
 from alembic.testing.env import _write_config_file
 from alembic.testing.env import clear_staging_env
 from alembic.testing.env import staging_env
@@ -337,6 +341,65 @@ class ConfigTest(TestBase):
         )
 
 
+class PyprojectConfigTest(TestBase):
+    @testing.fixture
+    def pyproject_only_env(self):
+        cfg = _testing_config()
+        path = pathlib.Path(_get_staging_directory(), "scripts")
+        command.init(cfg, str(path), template="pyproject")
+        cfg._config_file_path.unlink()
+        yield cfg
+        clear_staging_env()
+
+    def test_revision_command_no_alembicini(self, pyproject_only_env):
+        cfg = pyproject_only_env
+        path = pathlib.Path(_get_staging_directory(), "scripts")
+        pyproject_path = path.parent / "pyproject.toml"
+        eq_(pyproject_path, cfg._toml_file_path)
+        assert pyproject_path.exists()
+        assert not cfg._config_file_path.exists()
+
+        # the cfg contains the path to alembic.ini but the file
+        # is not present. the idea here is that all the required config
+        # should go to pyproject.toml first before raising.
+
+        ScriptDirectory.from_config(cfg)
+
+        command.revision(cfg, message="x")
+
+        command.history(cfg)
+
+    def test_no_config_at_all_still_raises(self, pyproject_only_env):
+        cfg = pyproject_only_env
+        cfg._toml_file_path.unlink()
+        assert not cfg._toml_file_path.exists()
+        assert not cfg._config_file_path.exists()
+
+        with expect_raises_message(
+            util.CommandError,
+            r"No 'script_location' key found in configuration.",
+        ):
+            ScriptDirectory.from_config(cfg)
+
+    def test_get_main_option_raises(self, pyproject_only_env):
+        cfg = pyproject_only_env
+
+        with expect_raises_message(
+            util.CommandError,
+            r"No config file '.*test_alembic.ini' found, "
+            r"or file has no '\[alembic\]' section",
+        ):
+            cfg.get_main_option("asdf")
+
+    def test_get_main_ini_added(self, pyproject_only_env):
+        cfg = pyproject_only_env
+
+        with cfg._config_file_path.open("w") as file_:
+            file_.write("[alembic]\nasdf = back_at_ya")
+
+        eq_(cfg.get_main_option("asdf"), "back_at_ya")
+
+
 class StdoutOutputEncodingTest(TestBase):
     def test_plain(self):
         stdout = mock.Mock(encoding="latin-1")