diff options
Diffstat (limited to 'alembic')
-rw-r--r-- | alembic/script/base.py | 73 | ||||
-rw-r--r-- | alembic/templates/async/alembic.ini.mako | 5 | ||||
-rw-r--r-- | alembic/templates/generic/alembic.ini.mako | 5 | ||||
-rw-r--r-- | alembic/templates/multidb/alembic.ini.mako | 5 |
4 files changed, 62 insertions, 26 deletions
diff --git a/alembic/script/base.py b/alembic/script/base.py index 3c09cef..b6858b5 100644 --- a/alembic/script/base.py +++ b/alembic/script/base.py @@ -80,6 +80,7 @@ class ScriptDirectory: output_encoding: str = "utf-8", timezone: Optional[str] = None, hook_config: Optional[Dict[str, str]] = None, + recursive_version_locations: bool = False, ) -> None: self.dir = dir self.file_template = file_template @@ -90,6 +91,7 @@ class ScriptDirectory: self.revision_map = revision.RevisionMap(self._load_revisions) self.timezone = timezone self.hook_config = hook_config + self.recursive_version_locations = recursive_version_locations if not os.access(dir, os.F_OK): raise util.CommandError( @@ -128,16 +130,19 @@ class ScriptDirectory: dupes = set() for vers in paths: - for file_ in Script._list_py_dir(self, vers): - path = os.path.realpath(os.path.join(vers, file_)) - if path in dupes: + for file_path in Script._list_py_dir(self, vers): + real_path = os.path.realpath(file_path) + if real_path in dupes: util.warn( "File %s loaded twice! ignoring. Please ensure " - "version_locations is unique." % path + "version_locations is unique." % real_path ) continue - dupes.add(path) - script = Script._from_filename(self, vers, file_) + dupes.add(real_path) + + filename = os.path.basename(real_path) + dir_name = os.path.dirname(real_path) + script = Script._from_filename(self, dir_name, filename) if script is None: continue yield script @@ -207,6 +212,7 @@ class ScriptDirectory: _split_on_space_comma_colon.split(prepend_sys_path) ) + rvl = config.get_main_option("recursive_version_locations") == "true" return ScriptDirectory( util.coerce_resource_to_filename(script_location), file_template=config.get_main_option( @@ -218,6 +224,7 @@ class ScriptDirectory: version_locations=version_locations, timezone=config.get_main_option("timezone"), hook_config=config.get_section("post_write_hooks", {}), + recursive_version_locations=rvl, ) @contextmanager @@ -959,26 +966,40 @@ class Script(revision.Revision): @classmethod def _list_py_dir(cls, scriptdir: ScriptDirectory, path: str) -> List[str]: - if scriptdir.sourceless: - # read files in version path, e.g. pyc or pyo files - # in the immediate path - paths = os.listdir(path) - - names = {fname.split(".")[0] for fname in paths} - - # look for __pycache__ - if os.path.exists(os.path.join(path, "__pycache__")): - # add all files from __pycache__ whose filename is not - # already in the names we got from the version directory. - # add as relative paths including __pycache__ token - paths.extend( - os.path.join("__pycache__", pyc) - for pyc in os.listdir(os.path.join(path, "__pycache__")) - if pyc.split(".")[0] not in names - ) - return paths - else: - return os.listdir(path) + paths = [] + for root, dirs, files in os.walk(path, topdown=True): + if root.endswith("__pycache__"): + # a special case - we may include these files + # if a `sourceless` option is specified + continue + + for filename in sorted(files): + paths.append(os.path.join(root, filename)) + + if scriptdir.sourceless: + # look for __pycache__ + py_cache_path = os.path.join(root, "__pycache__") + if os.path.exists(py_cache_path): + # add all files from __pycache__ whose filename is not + # already in the names we got from the version directory. + # add as relative paths including __pycache__ token + names = {filename.split(".")[0] for filename in files} + paths.extend( + os.path.join(py_cache_path, pyc) + for pyc in os.listdir(py_cache_path) + if pyc.split(".")[0] not in names + ) + + if not scriptdir.recursive_version_locations: + break + + # the real script order is defined by revision, + # but it may be undefined if there are many files with a same + # `down_revision`, for a better user experience (ex. debugging), + # we use a deterministic order + dirs.sort() + + return paths @classmethod def _from_filename( diff --git a/alembic/templates/async/alembic.ini.mako b/alembic/templates/async/alembic.ini.mako index 5268e7c..64c7b6b 100644 --- a/alembic/templates/async/alembic.ini.mako +++ b/alembic/templates/async/alembic.ini.mako @@ -49,6 +49,11 @@ prepend_sys_path = . # version_path_separator = space version_path_separator = os # Use os.pathsep. Default configuration used for new projects. +# set to 'true' to search source files recursively +# in each "version_locations" directory +# new in Alembic version 1.10 +# recursive_version_locations = false + # the output encoding used when revision files # are written from script.py.mako # output_encoding = utf-8 diff --git a/alembic/templates/generic/alembic.ini.mako b/alembic/templates/generic/alembic.ini.mako index 8aa47b1..f541b17 100644 --- a/alembic/templates/generic/alembic.ini.mako +++ b/alembic/templates/generic/alembic.ini.mako @@ -51,6 +51,11 @@ prepend_sys_path = . # version_path_separator = space version_path_separator = os # Use os.pathsep. Default configuration used for new projects. +# set to 'true' to search source files recursively +# in each "version_locations" directory +# new in Alembic version 1.10 +# recursive_version_locations = false + # the output encoding used when revision files # are written from script.py.mako # output_encoding = utf-8 diff --git a/alembic/templates/multidb/alembic.ini.mako b/alembic/templates/multidb/alembic.ini.mako index 5adef39..4230fe1 100644 --- a/alembic/templates/multidb/alembic.ini.mako +++ b/alembic/templates/multidb/alembic.ini.mako @@ -51,6 +51,11 @@ prepend_sys_path = . # version_path_separator = space version_path_separator = os # Use os.pathsep. Default configuration used for new projects. +# set to 'true' to search source files recursively +# in each "version_locations" directory +# new in Alembic version 1.10 +# recursive_version_locations = false + # the output encoding used when revision files # are written from script.py.mako # output_encoding = utf-8 |