From 482ac3fbfcce270f17685848db6cc828827ee274 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Tue, 28 May 2024 14:27:02 -0700 Subject: [PATCH] Refactor base.py and Dockerfile, and folder column migration (#2002) * refactor(base.py): handle ImportError when importing is_pre_release function from langflow.version module to prevent crashing the application feat(base.py): dynamically determine if the version is a pre-release version by checking for 'a', 'b', or 'rc' in the version number * fix(Dockerfile): add missing backslash to ensure proper chaining of commands * refactor: Update get_lifespan function to handle ImportError and dynamically determine the version number The get_lifespan function in main.py has been updated to handle ImportError when importing the __version__ attribute from the langflow.version module. If the import fails, the version number is dynamically determined using the importlib.metadata.version function. This change ensures that the application does not crash when the langflow.version module is not available. Note: This commit message follows the convention used in the recent user commits. * chore: Add langflow-pre.db and langflow.db to .dockerignore * chore: Update .dockerignore to include langflow-pre.db and langflow.db * refactor: Add folder_id column to flow table and handle folder column migration This commit adds the folder_id column to the flow table in the database. It also handles the migration of the folder column to the new folder_id column. This change allows for better organization and management of flows within folders. Note: This commit message follows the convention used in the recent user commits. * refactor: Update Dockerfiles to include user creation and environment variable This commit updates the Dockerfiles to include the creation of a user with UID 1000 and the necessary permissions for the /app/langflow directory. It also adds the user's local bin directory to the PATH environment variable. This change improves the security and isolation of the application within the container. Note: This commit message follows the convention used in the recent user commits. --- docker/.dockerignore | 4 +++- docker/build_and_push.Dockerfile | 11 +++++++---- docker/build_and_push_base.Dockerfile | 11 +++++++---- .../versions/012fb73ac359_add_folder_table.py | 12 +++++++----- .../7d2162acc8b2_adds_updated_at_and_folder_cols.py | 9 +++++++-- src/backend/base/langflow/main.py | 7 ++++++- src/backend/base/langflow/services/settings/base.py | 8 +++++++- 7 files changed, 44 insertions(+), 18 deletions(-) diff --git a/docker/.dockerignore b/docker/.dockerignore index 7cae75457..737244fba 100644 --- a/docker/.dockerignore +++ b/docker/.dockerignore @@ -4,4 +4,6 @@ node_modules **/node_modules/ dist/ **/build/ -src/backend/langflow/frontend \ No newline at end of file +src/backend/langflow/frontend +**/langflow-pre.db +**/langflow.db \ No newline at end of file diff --git a/docker/build_and_push.Dockerfile b/docker/build_and_push.Dockerfile index 6b3aff368..3a34db188 100644 --- a/docker/build_and_push.Dockerfile +++ b/docker/build_and_push.Dockerfile @@ -72,15 +72,18 @@ COPY Makefile ./ COPY README.md ./ RUN --mount=type=cache,target=/root/.cache \ curl -sSL https://install.python-poetry.org | python3 - +RUN useradd -m -u 1000 user && \ + mkdir -p /app/langflow && \ + chown -R user:user /app && \ + chmod -R u+w /app/langflow + +# Update PATH with home/user/.local/bin +ENV PATH="/home/user/.local/bin:${PATH}" RUN python -m pip install requests && cd ./scripts && python update_dependencies.py RUN $POETRY_HOME/bin/poetry lock RUN $POETRY_HOME/bin/poetry build # Copy virtual environment and built .tar.gz from builder base -RUN useradd -m -u 1000 user && \ - mkdir -p /app/langflow && \ - chown -R user:user /app \ - chmod -R u+w /app/langflow USER user # Install the package from the .tar.gz RUN python -m pip install /app/dist/*.tar.gz --user diff --git a/docker/build_and_push_base.Dockerfile b/docker/build_and_push_base.Dockerfile index 42f1e9984..f70a517da 100644 --- a/docker/build_and_push_base.Dockerfile +++ b/docker/build_and_push_base.Dockerfile @@ -78,13 +78,16 @@ RUN cd src/frontend && npm run build COPY src/backend ./src/backend RUN cp -r src/frontend/build src/backend/base/langflow/frontend RUN rm -rf src/backend/base/dist +RUN useradd -m -u 1000 user && \ + mkdir -p /app/langflow && \ + chown -R user:user /app && \ + chmod -R u+w /app/langflow + +# Update PATH with home/user/.local/bin +ENV PATH="/home/user/.local/bin:${PATH}" RUN cd src/backend/base && $POETRY_HOME/bin/poetry build # Copy virtual environment and built .tar.gz from builder base -RUN useradd -m -u 1000 user && \ - mkdir -p /app/langflow && \ - chown -R user:user /app \ - chmod -R u+w /app/langflow USER user # Install the package from the .tar.gz diff --git a/src/backend/base/langflow/alembic/versions/012fb73ac359_add_folder_table.py b/src/backend/base/langflow/alembic/versions/012fb73ac359_add_folder_table.py index 84ebd9ff7..a9b9b6c00 100644 --- a/src/backend/base/langflow/alembic/versions/012fb73ac359_add_folder_table.py +++ b/src/backend/base/langflow/alembic/versions/012fb73ac359_add_folder_table.py @@ -49,10 +49,11 @@ def upgrade() -> None: batch_op.create_index(batch_op.f("ix_folder_name"), ["name"], unique=False) column_names = [column["name"] for column in inspector.get_columns("flow")] - if "folder_id" not in column_names: - with op.batch_alter_table("flow", schema=None) as batch_op: + with op.batch_alter_table("flow", schema=None) as batch_op: + if "folder_id" not in column_names: batch_op.add_column(sa.Column("folder_id", sqlmodel.sql.sqltypes.GUID(), nullable=True)) batch_op.create_foreign_key("flow_folder_id_fkey", "folder", ["folder_id"], ["id"]) + if "folder" in column_names: batch_op.drop_column("folder") # ### end Alembic commands ### @@ -64,11 +65,12 @@ def downgrade() -> None: table_names = inspector.get_table_names() # ### commands auto generated by Alembic - please adjust! ### column_names = [column["name"] for column in inspector.get_columns("flow")] - if "folder_id" in column_names: - with op.batch_alter_table("flow", schema=None) as batch_op: + with op.batch_alter_table("flow", schema=None) as batch_op: + if "folder" not in column_names: batch_op.add_column(sa.Column("folder", sa.VARCHAR(), nullable=True)) - batch_op.drop_constraint("flow_folder_id_fkey", type_="foreignkey") + if "folder_id" in column_names: batch_op.drop_column("folder_id") + batch_op.drop_constraint("flow_folder_id_fkey", type_="foreignkey") indexes = inspector.get_indexes("folder") if "ix_folder_name" in [index["name"] for index in indexes]: diff --git a/src/backend/base/langflow/alembic/versions/7d2162acc8b2_adds_updated_at_and_folder_cols.py b/src/backend/base/langflow/alembic/versions/7d2162acc8b2_adds_updated_at_and_folder_cols.py index b46400899..7499b32ae 100644 --- a/src/backend/base/langflow/alembic/versions/7d2162acc8b2_adds_updated_at_and_folder_cols.py +++ b/src/backend/base/langflow/alembic/versions/7d2162acc8b2_adds_updated_at_and_folder_cols.py @@ -52,9 +52,14 @@ def upgrade() -> None: def downgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### try: + conn = op.get_bind() + inspector = Inspector.from_engine(conn) # type: ignore + column_names = [column["name"] for column in inspector.get_columns("flow")] with op.batch_alter_table("flow", schema=None) as batch_op: - batch_op.drop_column("folder") - batch_op.drop_column("updated_at") + if "folder" in column_names: + batch_op.drop_column("folder") + if "updated_at" in column_names: + batch_op.drop_column("updated_at") except Exception as e: print(e) pass diff --git a/src/backend/base/langflow/main.py b/src/backend/base/langflow/main.py index 697cfa226..07ecae396 100644 --- a/src/backend/base/langflow/main.py +++ b/src/backend/base/langflow/main.py @@ -34,7 +34,12 @@ class JavaScriptMIMETypeMiddleware(BaseHTTPMiddleware): def get_lifespan(fix_migration=False, socketio_server=None): - from langflow.version import __version__ # type: ignore + try: + from langflow.version import __version__ # type: ignore + except ImportError: + from importlib.metadata import version + + __version__ = version("langflow-base") @asynccontextmanager async def lifespan(app: FastAPI): diff --git a/src/backend/base/langflow/services/settings/base.py b/src/backend/base/langflow/services/settings/base.py index f62ccacd4..f7c6440f2 100644 --- a/src/backend/base/langflow/services/settings/base.py +++ b/src/backend/base/langflow/services/settings/base.py @@ -146,7 +146,13 @@ class Settings(BaseSettings): # if there is a database in that location if not info.data["config_dir"]: raise ValueError("config_dir not set, please set it or provide a database_url") - from langflow.version import is_pre_release # type: ignore + try: + from langflow.version import is_pre_release # type: ignore + except ImportError: + from importlib import metadata + + version = metadata.version("langflow-base") + is_pre_release = "a" in version or "b" in version or "rc" in version if info.data["save_db_in_config_dir"]: database_dir = info.data["config_dir"]