diff --git a/docker/base.Dockerfile b/docker/base.Dockerfile index 709e6dc0423..e0562d13f40 100644 --- a/docker/base.Dockerfile +++ b/docker/base.Dockerfile @@ -81,6 +81,9 @@ RUN python3 -m venv $VIRTUAL_ENV ENV PATH="$VIRTUAL_ENV/bin:$PATH" # Determine the package name based on ZENML_NIGHTLY +# IMPORTANT: We want to keep the alembic version in the server image consistent. +# That's why, we to pin it to 1.15.2 here, as it is the highest version +# that is compatible with the ZenML version we are using. RUN if [ "$ZENML_NIGHTLY" = "true" ]; then \ PACKAGE_NAME="zenml-nightly"; \ else \ @@ -88,7 +91,7 @@ RUN if [ "$ZENML_NIGHTLY" = "true" ]; then \ fi \ && pip install --upgrade pip \ && pip install --upgrade uv \ - && uv pip install "${PACKAGE_NAME}[server,secrets-aws,secrets-gcp,secrets-azure,secrets-hashicorp,s3fs,gcsfs,adlfs,connectors-aws,connectors-gcp,connectors-azure,azureml,sagemaker,vertex]${ZENML_VERSION:+==$ZENML_VERSION}" \ + && uv pip install "${PACKAGE_NAME}[server,secrets-aws,secrets-gcp,secrets-azure,secrets-hashicorp,s3fs,gcsfs,adlfs,connectors-aws,connectors-gcp,connectors-azure,azureml,sagemaker,vertex]${ZENML_VERSION:+==$ZENML_VERSION}" "alembic==1.15.2" \ && pip freeze > requirements.txt FROM base AS client diff --git a/docker/zenml-server-dev.Dockerfile b/docker/zenml-server-dev.Dockerfile index 097256074e9..88d4b0bf0ba 100644 --- a/docker/zenml-server-dev.Dockerfile +++ b/docker/zenml-server-dev.Dockerfile @@ -87,7 +87,7 @@ COPY --chown=$USERNAME:$USER_GID src/zenml/__init__.py ./src/zenml/ # final stage RUN pip install --upgrade pip \ && pip install uv \ - && uv pip install .[server,secrets-aws,secrets-gcp,secrets-azure,secrets-hashicorp,s3fs,gcsfs,adlfs,connectors-aws,connectors-gcp,connectors-azure,azureml,sagemaker,vertex] \ + && uv pip install .[server,secrets-aws,secrets-gcp,secrets-azure,secrets-hashicorp,s3fs,gcsfs,adlfs,connectors-aws,connectors-gcp,connectors-azure,azureml,sagemaker,vertex] "alembic==1.15.2" \ && uv pip uninstall zenml \ && uv pip freeze > requirements.txt diff --git a/pyproject.toml b/pyproject.toml index 33300bc8b3d..06a12d14e4b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,7 @@ include = ["src/zenml", "*.txt", "*.sh", "*.md"] zenml = "zenml.cli.cli:cli" [tool.poetry.dependencies] -alembic = { version = "~1.8.1" } +alembic = { version = ">=1.8.1,<=1.15.2" } bcrypt = { version = "4.0.1" } click = "^8.0.1,<8.1.8" cloudpickle = ">=2.0.0,<3" diff --git a/src/zenml/zen_stores/migrations/alembic.py b/src/zenml/zen_stores/migrations/alembic.py index 65430cafc69..99cafa6da79 100644 --- a/src/zenml/zen_stores/migrations/alembic.py +++ b/src/zenml/zen_stores/migrations/alembic.py @@ -39,7 +39,7 @@ def include_object( - object: Any, name: str, type_: str, *args: Any, **kwargs: Any + object: Any, name: Optional[str], type_: str, *args: Any, **kwargs: Any ) -> bool: """Function used to exclude tables from the migration scripts. @@ -135,6 +135,7 @@ def run_migrations( fn_context_args["fn"] = fn with self.engine.connect() as connection: + # Configure the context with our metadata self.environment_context.configure( connection=connection, target_metadata=self.metadata, @@ -180,9 +181,15 @@ def current_revisions(self) -> List[str]: def do_get_current_rev(rev: _RevIdType, context: Any) -> List[Any]: nonlocal current_revisions - for r in self.script_directory.get_all_current( - rev # type:ignore [arg-type] - ): + # Handle rev parameter in a way that's compatible with different alembic versions + rev_input: Any + if isinstance(rev, str): + rev_input = rev + else: + rev_input = tuple(str(r) for r in rev) + + # Get current revision(s) + for r in self.script_directory.get_all_current(rev_input): if r is None: continue current_revisions.append(r.revision) @@ -200,7 +207,13 @@ def stamp(self, revision: str) -> None: """ def do_stamp(rev: _RevIdType, context: Any) -> List[Any]: - return self.script_directory._stamp_revs(revision, rev) + # Handle rev parameter in a way that's compatible with different alembic versions + if isinstance(rev, str): + return self.script_directory._stamp_revs(revision, rev) + else: + # Convert to tuple for compatibility + rev_tuple = tuple(str(r) for r in rev) + return self.script_directory._stamp_revs(revision, rev_tuple) self.run_migrations(do_stamp) @@ -212,10 +225,16 @@ def upgrade(self, revision: str = "heads") -> None: """ def do_upgrade(rev: _RevIdType, context: Any) -> List[Any]: - return self.script_directory._upgrade_revs( - revision, - rev, # type:ignore [arg-type] - ) + # Handle rev parameter in a way that's compatible with different alembic versions + if isinstance(rev, str): + return self.script_directory._upgrade_revs(revision, rev) + else: + if rev: + # Use first element or revs for compatibility + return self.script_directory._upgrade_revs( + revision, str(rev[0]) + ) + return [] self.run_migrations(do_upgrade) @@ -227,9 +246,14 @@ def downgrade(self, revision: str) -> None: """ def do_downgrade(rev: _RevIdType, context: Any) -> List[Any]: - return self.script_directory._downgrade_revs( - revision, - rev, # type:ignore [arg-type] - ) + # Handle rev parameter in a way that's compatible with different alembic versions + if isinstance(rev, str): + return self.script_directory._downgrade_revs(revision, rev) + else: + if rev: + return self.script_directory._downgrade_revs( + revision, str(rev[0]) + ) + return self.script_directory._downgrade_revs(revision, None) self.run_migrations(do_downgrade)