From: Mike Bayer Date: Wed, 21 May 2025 21:14:37 +0000 (-0400) Subject: honor get_templates_path() first X-Git-Tag: rel_1_16_1~1^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a272da9a4b95170848a1cc64dbb5e3019d27c7a1;p=thirdparty%2Fsqlalchemy%2Falembic.git honor get_templates_path() first Fixed regression caused by the ``pathlib`` refactoring that removed the use of :meth:`.Config.get_template_directory` as the canonical source of templates; the method is still present however it no longer would be consulted for a custom config subclass, as was the case with flask-migrate. Fixed regression caused by the ``pathlib`` refactoring where the "missing template" error message failed to render the name of the template that could not be found. Fixes: #1659 Fixes: #1660 Change-Id: I1244f19c9f288eb52c8e9ffcc3835824d6b74bb6 --- diff --git a/alembic/command.py b/alembic/command.py index 6080f363..8e485474 100644 --- a/alembic/command.py +++ b/alembic/command.py @@ -68,7 +68,7 @@ def init( template_path = config._get_template_path() / template if not template_path.exists(): - raise util.CommandError("No such template {template_path}") + raise util.CommandError(f"No such template {template_path}") # left as os.access() to suit unit test mocking if not os.access(directory_path, os.F_OK): diff --git a/alembic/config.py b/alembic/config.py index eb98bcdf..11375788 100644 --- a/alembic/config.py +++ b/alembic/config.py @@ -264,7 +264,10 @@ class Config: commands. """ - return self._get_template_path().as_posix() + import alembic + + package_dir = Path(alembic.__file__).absolute().parent + return str(package_dir / "templates") def _get_template_path(self) -> Path: """Return the directory where Alembic setup templates are found. @@ -275,10 +278,7 @@ class Config: .. versionadded:: 1.16.0 """ - import alembic - - package_dir = Path(alembic.__file__).absolute().parent - return package_dir / "templates" + return Path(self.get_template_directory()) @overload def get_section( diff --git a/docs/build/unreleased/1660.rst b/docs/build/unreleased/1660.rst new file mode 100644 index 00000000..8184778e --- /dev/null +++ b/docs/build/unreleased/1660.rst @@ -0,0 +1,16 @@ +.. change:: + :tags: bug, command + :tickets: 1660 + + Fixed regression caused by the ``pathlib`` refactoring that removed the use + of :meth:`.Config.get_template_directory` as the canonical source of + templates; the method is still present however it no longer would be + consulted for a custom config subclass, as was the case with flask-migrate. + +.. change:: + :tags: bug, command + :tickets: 1659 + + Fixed regression caused by the ``pathlib`` refactoring where the "missing + template" error message failed to render the name of the template that + could not be found. diff --git a/tests/test_command.py b/tests/test_command.py index 44597d2e..167cfbee 100644 --- a/tests/test_command.py +++ b/tests/test_command.py @@ -7,6 +7,7 @@ from io import TextIOWrapper import os import pathlib import re +import shutil from typing import cast from sqlalchemy import exc as sqla_exc @@ -1145,7 +1146,6 @@ class CommandLineTest(TestBase): def setup_class(cls): cls.env = staging_env() cls.cfg = _sqlite_testing_config() - cls.a, cls.b, cls.c = three_rev_fixture(cls.cfg) def tearDown(self): os.environ.pop("ALEMBIC_CONFIG", None) @@ -1520,6 +1520,70 @@ class CommandLineTest(TestBase): ], ) + @testing.fixture + def custom_template_fixture(self): + templates_path = pathlib.Path( + _get_staging_directory(), "my_special_templates_place" + ) + + os.makedirs(templates_path / "mytemplate") + + with pathlib.Path(templates_path, "mytemplate", "myfile.txt").open( + "w" + ) as file_: + file_.write("This is myfile.txt") + with pathlib.Path(templates_path, "mytemplate", "README").open( + "w" + ) as file_: + file_.write("This is my template") + with pathlib.Path( + templates_path, "mytemplate", "alembic.ini.mako" + ).open("w") as file_: + file_.write("[alembic]\nscript_directory=%(here)s\n") + + class MyConfig(config.Config): + def get_template_directory(self) -> str: + return templates_path.as_posix() + + yield MyConfig(self.cfg.config_file_name) + + shutil.rmtree(templates_path) + + @testing.variation("cmd", ["list_templates", "init"]) + def test_init_custom_template_location(self, cmd, custom_template_fixture): + """test #1660""" + + cfg = custom_template_fixture + + if cmd.init: + path = pathlib.Path(_get_staging_directory(), "foobar") + command.init(cfg, directory=path.as_posix(), template="mytemplate") + + eq_( + (path / "myfile.txt").open().read(), + "This is myfile.txt", + ) + elif cmd.list_templates: + cfg.stdout = buf = StringIO() + command.list_templates(cfg) + assert buf.getvalue().startswith( + "Available templates:\n\nmytemplate - This is my template" + ) + + else: + cmd.fail() + + def test_init_no_such_template(self): + """test #1659""" + + path = os.path.join(_get_staging_directory(), "foobar") + + with expect_raises_message( + util.CommandError, + r"No such template .*asfd", + ): + command.init(self.cfg, directory=path, template="asfd") + def test_version_text(self): buf = StringIO() to_mock = "sys.stdout"