From: Gord Thompson Date: Sat, 12 Jun 2021 21:12:17 +0000 (-0600) Subject: Support version_locations paths with spaces X-Git-Tag: rel_1_7_0~22^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d7d358e4ca5e4eab69f2d6e983aa8d026a776ae3;p=thirdparty%2Fsqlalchemy%2Falembic.git Support version_locations paths with spaces Fixes: #842 Change-Id: Icae7899cecc137eaba26cd14ded9da89df35aae1 --- diff --git a/alembic/script/base.py b/alembic/script/base.py index 723c0116..f6c5070f 100644 --- a/alembic/script/base.py +++ b/alembic/script/base.py @@ -140,7 +140,40 @@ class ScriptDirectory(object): version_locations = config.get_main_option("version_locations") if version_locations: - version_locations = _split_on_space_comma.split(version_locations) + version_path_separator = config.get_main_option( + "version_path_separator" + ) + + split_on_path = { + None: None, + "space": " ", + "os": os.pathsep, + ":": ":", + ";": ";", + } + + try: + split_char = split_on_path[version_path_separator] + except KeyError as ke: + util.raise_( + ValueError( + "'%s' is not a valid value for " + "version_path_separator; " + "expected 'space', 'os', ':', ';'" + % version_path_separator + ), + from_=ke, + ) + else: + if split_char is None: + # legacy behaviour for backwards compatibility + version_locations = _split_on_space_comma.split( + version_locations + ) + else: + version_locations = [ + x for x in version_locations.split(split_char) if x + ] prepend_sys_path = config.get_main_option("prepend_sys_path") if prepend_sys_path: diff --git a/alembic/templates/async/alembic.ini.mako b/alembic/templates/async/alembic.ini.mako index 64af3018..fa44a8f8 100644 --- a/alembic/templates/async/alembic.ini.mako +++ b/alembic/templates/async/alembic.ini.mako @@ -32,10 +32,19 @@ prepend_sys_path = . # versions/ directory # sourceless = false -# version location specification; this defaults +# version location specification; This defaults # to ${script_location}/versions. When using multiple version -# directories, initial revisions must be specified with --version-path -# version_locations = %(here)s/bar %(here)s/bat ${script_location}/versions +# directories, initial revisions must be specified with --version-path. +# The path separator used here should be the separator specified by "version_path_separator" +# version_locations = %(here)s/bar:%(here)s/bat:${script_location}/versions + +# version path separator; As mentioned above, this is the character used to split +# version_locations. Valid values are: +# +# version_path_separator = : +# version_path_separator = ; +# version_path_separator = space +version_path_separator = os # default: use os.pathsep # the output encoding used when revision files # are written from script.py.mako diff --git a/alembic/templates/generic/alembic.ini.mako b/alembic/templates/generic/alembic.ini.mako index 64af3018..fa44a8f8 100644 --- a/alembic/templates/generic/alembic.ini.mako +++ b/alembic/templates/generic/alembic.ini.mako @@ -32,10 +32,19 @@ prepend_sys_path = . # versions/ directory # sourceless = false -# version location specification; this defaults +# version location specification; This defaults # to ${script_location}/versions. When using multiple version -# directories, initial revisions must be specified with --version-path -# version_locations = %(here)s/bar %(here)s/bat ${script_location}/versions +# directories, initial revisions must be specified with --version-path. +# The path separator used here should be the separator specified by "version_path_separator" +# version_locations = %(here)s/bar:%(here)s/bat:${script_location}/versions + +# version path separator; As mentioned above, this is the character used to split +# version_locations. Valid values are: +# +# version_path_separator = : +# version_path_separator = ; +# version_path_separator = space +version_path_separator = os # default: use os.pathsep # the output encoding used when revision files # are written from script.py.mako diff --git a/alembic/templates/multidb/alembic.ini.mako b/alembic/templates/multidb/alembic.ini.mako index c3b0ec0f..1f76ab56 100644 --- a/alembic/templates/multidb/alembic.ini.mako +++ b/alembic/templates/multidb/alembic.ini.mako @@ -32,10 +32,19 @@ prepend_sys_path = . # versions/ directory # sourceless = false -# version location specification; this defaults +# version location specification; This defaults # to ${script_location}/versions. When using multiple version -# directories, initial revisions must be specified with --version-path -# version_locations = %(here)s/bar %(here)s/bat ${script_location}/versions +# directories, initial revisions must be specified with --version-path. +# The path separator used here should be the separator specified by "version_path_separator" +# version_locations = %(here)s/bar:%(here)s/bat:${script_location}/versions + +# version path separator; As mentioned above, this is the character used to split +# version_locations. Valid values are: +# +# version_path_separator = : +# version_path_separator = ; +# version_path_separator = space +version_path_separator = os # default: use os.pathsep # the output encoding used when revision files # are written from script.py.mako diff --git a/alembic/templates/pylons/alembic.ini.mako b/alembic/templates/pylons/alembic.ini.mako index aa745a8a..c7313547 100644 --- a/alembic/templates/pylons/alembic.ini.mako +++ b/alembic/templates/pylons/alembic.ini.mako @@ -32,10 +32,19 @@ prepend_sys_path = . # versions/ directory # sourceless = false -# version location specification; this defaults +# version location specification; This defaults # to ${script_location}/versions. When using multiple version -# directories, initial revisions must be specified with --version-path -# version_locations = %(here)s/bar %(here)s/bat ${script_location}/versions +# directories, initial revisions must be specified with --version-path. +# The path separator used here should be the separator specified by "version_path_separator" +# version_locations = %(here)s/bar:%(here)s/bat:${script_location}/versions + +# version path separator; As mentioned above, this is the character used to split +# version_locations. Valid values are: +# +# version_path_separator = : +# version_path_separator = ; +# version_path_separator = space +version_path_separator = os # default: use os.pathsep # the output encoding used when revision files # are written from script.py.mako diff --git a/docs/build/branches.rst b/docs/build/branches.rst index 19640784..f3e5f4b9 100644 --- a/docs/build/branches.rst +++ b/docs/build/branches.rst @@ -524,6 +524,7 @@ directory as one of them:: # version location specification; this defaults # to foo/versions. When using multiple version # directories, initial revisions must be specified with --version-path + version_path_separator = space version_locations = %(here)s/model/networking %(here)s/alembic/versions The new directory ``%(here)s/model/networking`` is in terms of where diff --git a/docs/build/tutorial.rst b/docs/build/tutorial.rst index f575fc7b..c07a3b96 100644 --- a/docs/build/tutorial.rst +++ b/docs/build/tutorial.rst @@ -159,10 +159,19 @@ The file generated with the "generic" configuration looks like:: # versions/ directory # sourceless = false - # version location specification; this defaults - # to alembic/versions. When using multiple version - # directories, initial revisions must be specified with --version-path - # version_locations = %(here)s/bar %(here)s/bat alembic/versions + # version location specification; This defaults + # to ${script_location}/versions. When using multiple version + # directories, initial revisions must be specified with --version-path. + # The path separator used here should be the separator specified by "version_path_separator" + # version_locations = %(here)s/bar:%(here)s/bat:${script_location}/versions + + # version path separator; As mentioned above, this is the character used to split + # version_locations. Valid values are: + # + # version_path_separator = : + # version_path_separator = ; + # version_path_separator = space + version_path_separator = os # default: use os.pathsep # the output encoding used when revision files # are written from script.py.mako diff --git a/docs/build/unreleased/842.rst b/docs/build/unreleased/842.rst new file mode 100644 index 00000000..15f534fd --- /dev/null +++ b/docs/build/unreleased/842.rst @@ -0,0 +1,9 @@ +.. change:: + :tags: bug, environment + :tickets: 842 + + Enhance ``version_locations`` parsing to handle paths containing spaces. + The new configuration option ``version_path_separator`` specifies the + character to use when splitting the ``version_locations`` string. The + default for new configurations is ``version_path_separator = os``, + which will use ``os.pathsep`` (e.g., ``;`` on Windows). diff --git a/tests/test_config.py b/tests/test_config.py index 3b2e957a..fdb837ed 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,7 +1,9 @@ #!coding: utf-8 - +import os +import tempfile from alembic import config +from alembic import testing from alembic import util from alembic.migration import MigrationContext from alembic.operations import Operations @@ -9,6 +11,7 @@ from alembic.script import ScriptDirectory 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 _no_sql_testing_config from alembic.testing.env import _write_config_file from alembic.testing.env import clear_staging_env @@ -108,6 +111,91 @@ class ConfigTest(TestBase): cfg.attributes["connection"] = m2 eq_(cfg.attributes, {"m1": m1, "connection": m2}) + @testing.combinations( + ( + "legacy raw string 1", + None, + "/foo", + ["/foo"], + ), + ( + "legacy raw string 2", + None, + "/foo /bar", + ["/foo", "/bar"], + ), + ( + "legacy raw string 3", + "space", + "/foo", + ["/foo"], + ), + ( + "legacy raw string 4", + "space", + "/foo /bar", + ["/foo", "/bar"], + ), + ( + "Linux pathsep 1", + ":", + "/Project A", + ["/Project A"], + ), + ( + "Linux pathsep 2", + ":", + "/Project A:/Project B", + ["/Project A", "/Project B"], + ), + ( + "Windows pathsep 1", + ";", + r"C:\Project A", + [r"C:\Project A"], + ), + ( + "Windows pathsep 2", + ";", + r"C:\Project A;C:\Project B", + [r"C:\Project A", r"C:\Project B"], + ), + ( + "os pathsep", + "os", + r"path_number_one%(sep)spath_number_two%(sep)s" + % {"sep": os.pathsep}, + [r"path_number_one", r"path_number_two"], + ), + ( + "invalid pathsep 2", + "|", + "/foo|/bar", + ValueError( + "'|' is not a valid value for version_path_separator; " + "expected 'space', 'os', ':', ';'" + ), + ), + id_="iaaa", + argnames="separator, string_value, expected_result", + ) + def test_version_locations(self, separator, string_value, expected_result): + cfg = config.Config() + if separator is not None: + cfg.set_main_option( + "version_path_separator", + separator, + ) + cfg.set_main_option("script_location", tempfile.gettempdir()) + cfg.set_main_option("version_locations", string_value) + + if isinstance(expected_result, ValueError): + with expect_raises_message(ValueError, expected_result.args[0]): + ScriptDirectory.from_config(cfg) + else: + s = ScriptDirectory.from_config(cfg) + eq_(s.version_locations, expected_result) + class StdoutOutputEncodingTest(TestBase): def test_plain(self):