feat: Update SQLModel dependency and improve UUID handling (#4891)

* Update sqlmodel dependency to version 0.0.20 in pyproject.toml

* Handle UUID conversion for message IDs in memory update logic

* Refactor Alembic migrations to use `sa.inspect` and update GUID to Uuid type

* refactor: Change flow_id parameter type from str to uuid.UUID in graph building functions

* refactor: Ensure UUID handling for flow_id and user_id across various services and models

* refactor: improve UUID handling and graph caching for compatibility with sqlmodel 0.0.20

* fix: update message assertion in component events test

* chore: update sqlmodel dependency to version 0.0.22 in uv.lock and pyproject.toml

* fix: enhance flow_id validation to ensure valid UUID format in MessageBase model

* fix: add error handling for cache directory cleanup

* refactor: improve flow_id type handling in message storage

* refactor: enhance flow_id handling in message functions to support UUID type

* refactor: integrate Properties into message creation in component event tests

* update test durations

* fix: correct flow_id parameter in database query

* refactor: update session_id and flow_id parameters to support UUID type across message handling functions and models

* fix: handle message data update in SQLModel update method

* refactor: improve flow_id assignment in message update method to enhance UUID handling
This commit is contained in:
Gabriel Luiz Freitas Almeida 2024-12-12 09:58:27 -03:00 • committed by GitHub
commit 3de42f4575
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
55 changed files with 1035 additions and 898 deletions

View file

@ -8,6 +8,7 @@ Create Date: 2023-12-13 18:55:52.587360
from typing import Sequence, Union from typing import Sequence, Union
import sqlalchemy as sa
from alembic import op from alembic import op
from sqlalchemy.engine.reflection import Inspector from sqlalchemy.engine.reflection import Inspector
@ -21,7 +22,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
api_key_constraints = inspector.get_unique_constraints("apikey") api_key_constraints = inspector.get_unique_constraints("apikey")
flow_constraints = inspector.get_unique_constraints("flow") flow_constraints = inspector.get_unique_constraints("flow")
user_constraints = inspector.get_unique_constraints("user") user_constraints = inspector.get_unique_constraints("user")
@ -45,7 +46,7 @@ def upgrade() -> None:
def downgrade() -> None: def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
api_key_constraints = inspector.get_unique_constraints("apikey") api_key_constraints = inspector.get_unique_constraints("apikey")
flow_constraints = inspector.get_unique_constraints("flow") flow_constraints = inspector.get_unique_constraints("flow")
user_constraints = inspector.get_unique_constraints("user") user_constraints = inspector.get_unique_constraints("user")

View file

@ -22,7 +22,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
table_names = inspector.get_table_names() table_names = inspector.get_table_names()
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
if "folder" not in table_names: if "folder" not in table_names:
@ -30,9 +30,9 @@ def upgrade() -> None:
"folder", "folder",
sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("description", sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column("description", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("id", sqlmodel.sql.sqltypes.GUID(), nullable=False), sa.Column("id", sqlmodel.sql.sqltypes.types.Uuid(), nullable=False),
sa.Column("parent_id", sqlmodel.sql.sqltypes.GUID(), nullable=True), sa.Column("parent_id", sqlmodel.sql.sqltypes.types.Uuid(), nullable=True),
sa.Column("user_id", sqlmodel.sql.sqltypes.GUID(), nullable=True), sa.Column("user_id", sqlmodel.sql.sqltypes.types.Uuid(), nullable=True),
sa.ForeignKeyConstraint( sa.ForeignKeyConstraint(
["parent_id"], ["parent_id"],
["folder.id"], ["folder.id"],
@ -51,7 +51,7 @@ def upgrade() -> None:
column_names = [column["name"] for column in inspector.get_columns("flow")] column_names = [column["name"] for column in inspector.get_columns("flow")]
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: if "folder_id" not in column_names:
batch_op.add_column(sa.Column("folder_id", sqlmodel.sql.sqltypes.GUID(), nullable=True)) batch_op.add_column(sa.Column("folder_id", sqlmodel.sql.sqltypes.types.Uuid(), nullable=True))
batch_op.create_foreign_key("flow_folder_id_fkey", "folder", ["folder_id"], ["id"]) batch_op.create_foreign_key("flow_folder_id_fkey", "folder", ["folder_id"], ["id"])
if "folder" in column_names: if "folder" in column_names:
batch_op.drop_column("folder") batch_op.drop_column("folder")
@ -61,7 +61,7 @@ def upgrade() -> None:
def downgrade() -> None: def downgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
table_names = inspector.get_table_names() table_names = inspector.get_table_names()
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
column_names = [column["name"] for column in inspector.get_columns("flow")] column_names = [column["name"] for column in inspector.get_columns("flow")]

View file

@ -7,12 +7,13 @@ Create Date: 2024-10-04 17:30:12.924809
""" """
from typing import Sequence, Union from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
import sqlmodel import sqlmodel
from sqlalchemy.engine.reflection import Inspector from alembic import op
from langflow.utils import migration
from sqlalchemy.dialects import sqlite from sqlalchemy.dialects import sqlite
from sqlalchemy.engine.reflection import Inspector
from langflow.utils import migration
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision: str = '0ae3a2674f32' revision: str = '0ae3a2674f32'
@ -23,7 +24,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
with op.batch_alter_table("vertex_build", schema=None) as batch_op: with op.batch_alter_table("vertex_build", schema=None) as batch_op:
if migration.column_exists(table_name="vertex_build", column_name="params", conn=conn): if migration.column_exists(table_name="vertex_build", column_name="params", conn=conn):
@ -49,7 +50,7 @@ def upgrade() -> None:
def downgrade() -> None: def downgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
with op.batch_alter_table("message", schema=None) as batch_op: with op.batch_alter_table("message", schema=None) as batch_op:
if migration.column_exists(table_name="message", column_name="text", conn=conn): if migration.column_exists(table_name="message", column_name="text", conn=conn):
columns = inspector.get_columns("message") columns = inspector.get_columns("message")
@ -67,4 +68,4 @@ def downgrade() -> None:
batch_op.alter_column( batch_op.alter_column(
"params", existing_type=sa.VARCHAR(), type_=sa.Text(), existing_nullable=True "params", existing_type=sa.VARCHAR(), type_=sa.Text(), existing_nullable=True
) )
# ### end Alembic commands ### # ### end Alembic commands ###

View file

@ -8,6 +8,9 @@ Create Date: 2024-01-17 10:32:56.686287
from typing import Sequence, Union from typing import Sequence, Union
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision: str = "0b8757876a7c" revision: str = "0b8757876a7c"
down_revision: Union[str, None] = "006b3990db50" down_revision: Union[str, None] = "006b3990db50"

View file

@ -8,11 +8,11 @@ Create Date: 2024-07-26 11:41:31.274271
from typing import Sequence, Union from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
import sqlmodel import sqlmodel
from langflow.utils import migration from alembic import op
from langflow.utils import migration
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision: str = "0d60fcbd4e8e" revision: str = "0d60fcbd4e8e"
@ -31,8 +31,8 @@ def upgrade() -> None:
sa.Column("data", sa.JSON(), nullable=True), sa.Column("data", sa.JSON(), nullable=True),
sa.Column("artifacts", sa.JSON(), nullable=True), sa.Column("artifacts", sa.JSON(), nullable=True),
sa.Column("params", sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column("params", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("build_id", sqlmodel.sql.sqltypes.GUID(), nullable=False), sa.Column("build_id", sqlmodel.sql.sqltypes.types.Uuid(), nullable=False),
sa.Column("flow_id", sqlmodel.sql.sqltypes.GUID(), nullable=False), sa.Column("flow_id", sqlmodel.sql.sqltypes.types.Uuid(), nullable=False),
sa.Column("valid", sa.BOOLEAN(), nullable=False), sa.Column("valid", sa.BOOLEAN(), nullable=False),
sa.ForeignKeyConstraint( sa.ForeignKeyConstraint(
["flow_id"], ["flow_id"],

View file

@ -22,7 +22,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
table_names = inspector.get_table_names() table_names = inspector.get_table_names()
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
if "variable" not in table_names: if "variable" not in table_names:
@ -31,10 +31,10 @@ def upgrade() -> None:
sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("value", sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column("value", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("type", sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column("type", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("id", sqlmodel.sql.sqltypes.GUID(), nullable=False), sa.Column("id", sqlmodel.sql.sqltypes.types.Uuid(), nullable=False),
sa.Column("created_at", sa.DateTime(), nullable=False), sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(), nullable=True), sa.Column("updated_at", sa.DateTime(), nullable=True),
sa.Column("user_id", sqlmodel.sql.sqltypes.GUID(), nullable=False), sa.Column("user_id", sqlmodel.sql.sqltypes.types.Uuid(), nullable=False),
sa.ForeignKeyConstraint(["user_id"], ["user.id"], name="fk_variable_user_id"), sa.ForeignKeyConstraint(["user_id"], ["user.id"], name="fk_variable_user_id"),
sa.PrimaryKeyConstraint("id"), sa.PrimaryKeyConstraint("id"),
) )
@ -45,7 +45,7 @@ def upgrade() -> None:
def downgrade() -> None: def downgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
table_names = inspector.get_table_names() table_names = inspector.get_table_names()
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
if "credential" not in table_names: if "credential" not in table_names:

View file

@ -8,6 +8,7 @@ Create Date: 2024-05-29 23:12:09.146880
from typing import Sequence, Union from typing import Sequence, Union
import sqlalchemy as sa
from alembic import op from alembic import op
from sqlalchemy.engine.reflection import Inspector from sqlalchemy.engine.reflection import Inspector
@ -20,7 +21,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
constraints_names = [constraint["name"] for constraint in inspector.get_unique_constraints("folder")] constraints_names = [constraint["name"] for constraint in inspector.get_unique_constraints("folder")]
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table("folder", schema=None) as batch_op: with op.batch_alter_table("folder", schema=None) as batch_op:
@ -32,7 +33,7 @@ def upgrade() -> None:
def downgrade() -> None: def downgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
constraints_names = [constraint["name"] for constraint in inspector.get_unique_constraints("folder")] constraints_names = [constraint["name"] for constraint in inspector.get_unique_constraints("folder")]
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table("folder", schema=None) as batch_op: with op.batch_alter_table("folder", schema=None) as batch_op:

View file

@ -10,9 +10,10 @@ from typing import Sequence, Union
import sqlalchemy as sa import sqlalchemy as sa
from alembic import op from alembic import op
from langflow.utils import migration
from sqlalchemy.engine.reflection import Inspector from sqlalchemy.engine.reflection import Inspector
from langflow.utils import migration
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision: str = "4522eb831f5c" revision: str = "4522eb831f5c"
down_revision: Union[str, None] = "0d60fcbd4e8e" down_revision: Union[str, None] = "0d60fcbd4e8e"
@ -23,7 +24,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
with op.batch_alter_table("flow", schema=None) as batch_op: with op.batch_alter_table("flow", schema=None) as batch_op:
if migration.column_exists(table_name="flow", column_name="description", conn=conn): if migration.column_exists(table_name="flow", column_name="description", conn=conn):
@ -49,7 +50,7 @@ def upgrade() -> None:
def downgrade() -> None: def downgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
with op.batch_alter_table("folder", schema=None) as batch_op: with op.batch_alter_table("folder", schema=None) as batch_op:
if migration.column_exists(table_name="folder", column_name="description", conn=conn): if migration.column_exists(table_name="folder", column_name="description", conn=conn):
columns = inspector.get_columns("folder") columns = inspector.get_columns("folder")

View file

@ -21,7 +21,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
table_names = inspector.get_table_names() # noqa table_names = inspector.get_table_names() # noqa
column_names = [column["name"] for column in inspector.get_columns("message")] column_names = [column["name"] for column in inspector.get_columns("message")]
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
@ -38,7 +38,7 @@ def upgrade() -> None:
def downgrade() -> None: def downgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
table_names = inspector.get_table_names() # noqa table_names = inspector.get_table_names() # noqa
column_names = [column["name"] for column in inspector.get_columns("message")] column_names = [column["name"] for column in inspector.get_columns("message")]
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###

View file

@ -26,7 +26,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table("apikey", schema=None) as batch_op: with op.batch_alter_table("apikey", schema=None) as batch_op:
@ -42,7 +42,7 @@ def upgrade() -> None:
def downgrade() -> None: def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
with op.batch_alter_table("apikey", schema=None) as batch_op: with op.batch_alter_table("apikey", schema=None) as batch_op:
if migration.column_exists(table_name="apikey", column_name="name", conn=conn): if migration.column_exists(table_name="apikey", column_name="name", conn=conn):

View file

@ -21,7 +21,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
column_names = [column["name"] for column in inspector.get_columns("variable")] column_names = [column["name"] for column in inspector.get_columns("variable")]
with op.batch_alter_table("variable", schema=None) as batch_op: with op.batch_alter_table("variable", schema=None) as batch_op:
@ -33,7 +33,7 @@ def upgrade() -> None:
def downgrade() -> None: def downgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
column_names = [column["name"] for column in inspector.get_columns("variable")] column_names = [column["name"] for column in inspector.get_columns("variable")]
with op.batch_alter_table("variable", schema=None) as batch_op: with op.batch_alter_table("variable", schema=None) as batch_op:

View file

@ -24,7 +24,7 @@ def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
# List existing tables # List existing tables
existing_tables = inspector.get_table_names() existing_tables = inspector.get_table_names()
# Drop 'flowstyle' table if it exists # Drop 'flowstyle' table if it exists
@ -48,7 +48,7 @@ def upgrade() -> None:
if "user" not in existing_tables: if "user" not in existing_tables:
op.create_table( op.create_table(
"user", "user",
sa.Column("id", sqlmodel.sql.sqltypes.GUID(), nullable=False), sa.Column("id", sqlmodel.sql.sqltypes.types.Uuid(), nullable=False),
sa.Column("username", sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column("username", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("password", sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column("password", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("is_active", sa.Boolean(), nullable=False), sa.Column("is_active", sa.Boolean(), nullable=False),
@ -70,9 +70,9 @@ def upgrade() -> None:
sa.Column("last_used_at", sa.DateTime(), nullable=True), sa.Column("last_used_at", sa.DateTime(), nullable=True),
sa.Column("total_uses", sa.Integer(), nullable=False, default=0), sa.Column("total_uses", sa.Integer(), nullable=False, default=0),
sa.Column("is_active", sa.Boolean(), nullable=False, default=True), sa.Column("is_active", sa.Boolean(), nullable=False, default=True),
sa.Column("id", sqlmodel.sql.sqltypes.GUID(), nullable=False), sa.Column("id", sqlmodel.sql.sqltypes.types.Uuid(), nullable=False),
sa.Column("api_key", sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column("api_key", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("user_id", sqlmodel.sql.sqltypes.GUID(), nullable=False), sa.Column("user_id", sqlmodel.sql.sqltypes.types.Uuid(), nullable=False),
sa.ForeignKeyConstraint(["user_id"], ["user.id"], name="fk_apikey_user_id_user"), sa.ForeignKeyConstraint(["user_id"], ["user.id"], name="fk_apikey_user_id_user"),
sa.PrimaryKeyConstraint("id", name="pk_apikey"), sa.PrimaryKeyConstraint("id", name="pk_apikey"),
sa.UniqueConstraint("id", name="uq_apikey_id"), sa.UniqueConstraint("id", name="uq_apikey_id"),
@ -87,8 +87,8 @@ def upgrade() -> None:
sa.Column("data", sa.JSON(), nullable=True), sa.Column("data", sa.JSON(), nullable=True),
sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("description", sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column("description", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("id", sqlmodel.sql.sqltypes.GUID(), nullable=False), sa.Column("id", sqlmodel.sql.sqltypes.types.Uuid(), nullable=False),
sa.Column("user_id", sqlmodel.sql.sqltypes.GUID(), nullable=False), sa.Column("user_id", sqlmodel.sql.sqltypes.types.Uuid(), nullable=False),
sa.ForeignKeyConstraint(["user_id"], ["user.id"], name="fk_flow_user_id_user"), sa.ForeignKeyConstraint(["user_id"], ["user.id"], name="fk_flow_user_id_user"),
sa.PrimaryKeyConstraint("id", name="pk_flow"), sa.PrimaryKeyConstraint("id", name="pk_flow"),
sa.UniqueConstraint("id", name="uq_flow_id"), sa.UniqueConstraint("id", name="uq_flow_id"),
@ -105,7 +105,7 @@ def upgrade() -> None:
batch_op.add_column( batch_op.add_column(
sa.Column( sa.Column(
"user_id", "user_id",
sqlmodel.sql.sqltypes.GUID(), sqlmodel.sql.sqltypes.types.Uuid(),
nullable=True, # This should be False, but we need to allow NULL values for now nullable=True, # This should be False, but we need to allow NULL values for now
) )
) )
@ -126,7 +126,7 @@ def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
# List existing tables # List existing tables
existing_tables = inspector.get_table_names() existing_tables = inspector.get_table_names()
if "flow" in existing_tables: if "flow" in existing_tables:

View file

@ -8,6 +8,7 @@ Create Date: 2024-05-21 09:23:48.772367
from typing import Sequence, Union from typing import Sequence, Union
import sqlalchemy as sa
from alembic import op from alembic import op
from sqlalchemy.engine.reflection import Inspector from sqlalchemy.engine.reflection import Inspector
@ -19,7 +20,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
indexes = inspector.get_indexes("flow") indexes = inspector.get_indexes("flow")
with op.batch_alter_table("flow", schema=None) as batch_op: with op.batch_alter_table("flow", schema=None) as batch_op:
@ -32,7 +33,7 @@ def upgrade() -> None:
def downgrade() -> None: def downgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
indexes = inspector.get_indexes("flow") indexes = inspector.get_indexes("flow")
with op.batch_alter_table("flow", schema=None) as batch_op: with op.batch_alter_table("flow", schema=None) as batch_op:

View file

@ -23,7 +23,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
tables = inspector.get_table_names() tables = inspector.get_table_names()
try: try:
if "credential" not in tables: if "credential" not in tables:
@ -32,8 +32,8 @@ def upgrade() -> None:
sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("value", sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column("value", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("provider", sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column("provider", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("user_id", sqlmodel.sql.sqltypes.GUID(), nullable=False), sa.Column("user_id", sqlmodel.sql.sqltypes.types.Uuid(), nullable=False),
sa.Column("id", sqlmodel.sql.sqltypes.GUID(), nullable=False), sa.Column("id", sqlmodel.sql.sqltypes.types.Uuid(), nullable=False),
sa.Column("created_at", sa.DateTime(), nullable=False), sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(), nullable=True), sa.Column("updated_at", sa.DateTime(), nullable=True),
sa.PrimaryKeyConstraint("id"), sa.PrimaryKeyConstraint("id"),

View file

@ -8,6 +8,7 @@ Create Date: 2024-05-29 23:08:43.935040
from typing import Sequence, Union from typing import Sequence, Union
import sqlalchemy as sa
from alembic import op from alembic import op
from sqlalchemy.engine.reflection import Inspector from sqlalchemy.engine.reflection import Inspector
@ -20,7 +21,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
indexes_names = [index["name"] for index in inspector.get_indexes("flow")] indexes_names = [index["name"] for index in inspector.get_indexes("flow")]
constraints_names = [constraint["name"] for constraint in inspector.get_unique_constraints("flow")] constraints_names = [constraint["name"] for constraint in inspector.get_unique_constraints("flow")]
@ -38,7 +39,7 @@ def upgrade() -> None:
def downgrade() -> None: def downgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
indexes_names = [index["name"] for index in inspector.get_indexes("flow")] indexes_names = [index["name"] for index in inspector.get_indexes("flow")]
constraints_names = [constraint["name"] for constraint in inspector.get_unique_constraints("flow")] constraints_names = [constraint["name"] for constraint in inspector.get_unique_constraints("flow")]

View file

@ -23,7 +23,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
table_names = inspector.get_table_names() table_names = inspector.get_table_names()
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
if "apikey" in table_names: if "apikey" in table_names:
@ -77,7 +77,7 @@ def upgrade() -> None:
def downgrade() -> None: def downgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
table_names = inspector.get_table_names() table_names = inspector.get_table_names()
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
if "variable" in table_names: if "variable" in table_names:

View file

@ -26,7 +26,7 @@ depends_on = None
def upgrade(): def upgrade():
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) inspector = sa.inspect(conn)
tables = ["apikey", "variable"] # List of tables to modify tables = ["apikey", "variable"] # List of tables to modify
for table_name in tables: for table_name in tables:
@ -35,7 +35,7 @@ def upgrade():
def downgrade(): def downgrade():
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) inspector = sa.inspect(conn)
tables = ["apikey", "variable"] # List of tables to revert tables = ["apikey", "variable"] # List of tables to revert
for table_name in tables: for table_name in tables:

View file

@ -21,7 +21,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
table_names = inspector.get_table_names() table_names = inspector.get_table_names()
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
column_names = [column["name"] for column in inspector.get_columns("flow")] column_names = [column["name"] for column in inspector.get_columns("flow")]
@ -34,7 +34,7 @@ def upgrade() -> None:
def downgrade() -> None: def downgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
table_names = inspector.get_table_names() table_names = inspector.get_table_names()
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
column_names = [column["name"] for column in inspector.get_columns("flow")] column_names = [column["name"] for column in inspector.get_columns("flow")]

View file

@ -22,7 +22,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
table_names = inspector.get_table_names() # noqa table_names = inspector.get_table_names() # noqa
column_names = [column["name"] for column in inspector.get_columns("flow")] column_names = [column["name"] for column in inspector.get_columns("flow")]
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
@ -37,7 +37,7 @@ def upgrade() -> None:
def downgrade() -> None: def downgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
table_names = inspector.get_table_names() # noqa table_names = inspector.get_table_names() # noqa
column_names = [column["name"] for column in inspector.get_columns("flow")] column_names = [column["name"] for column in inspector.get_columns("flow")]
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###

View file

@ -24,7 +24,7 @@ def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
try: try:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
if "user" in inspector.get_table_names() and "profile_image" not in [ if "user" in inspector.get_table_names() and "profile_image" not in [
column["name"] for column in inspector.get_columns("user") column["name"] for column in inspector.get_columns("user")
]: ]:
@ -45,7 +45,7 @@ def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
try: try:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
if "user" in inspector.get_table_names() and "profile_image" in [ if "user" in inspector.get_table_names() and "profile_image" in [
column["name"] for column in inspector.get_columns("user") column["name"] for column in inspector.get_columns("user")
]: ]:

View file

@ -21,7 +21,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
# table_names = inspector.get_table_names() # table_names = inspector.get_table_names()
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
columns = inspector.get_columns("apikey") columns = inspector.get_columns("apikey")
@ -41,7 +41,7 @@ def upgrade() -> None:
def downgrade() -> None: def downgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
# table_names = inspector.get_table_names() # table_names = inspector.get_table_names()
columns = inspector.get_columns("apikey") columns = inspector.get_columns("apikey")
column_names = {column["name"]: column for column in columns} column_names = {column["name"]: column for column in columns}

View file

@ -23,7 +23,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
flow_columns = [column["name"] for column in inspector.get_columns("flow")] flow_columns = [column["name"] for column in inspector.get_columns("flow")]
user_columns = [column["name"] for column in inspector.get_columns("user")] user_columns = [column["name"] for column in inspector.get_columns("user")]
try: try:

View file

@ -10,9 +10,9 @@ from typing import Sequence, Union
import sqlalchemy as sa import sqlalchemy as sa
from alembic import op from alembic import op
from loguru import logger
from sqlalchemy.dialects import postgresql from sqlalchemy.dialects import postgresql
from sqlalchemy.engine.reflection import Inspector from sqlalchemy.engine.reflection import Inspector
from loguru import logger
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision: str = "79e675cb6752" revision: str = "79e675cb6752"
@ -23,7 +23,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
table_names = inspector.get_table_names() table_names = inspector.get_table_names()
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
if "apikey" in table_names: if "apikey" in table_names:
@ -77,7 +77,7 @@ def upgrade() -> None:
def downgrade() -> None: def downgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
table_names = inspector.get_table_names() table_names = inspector.get_table_names()
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
if "variable" in table_names: if "variable" in table_names:

View file

@ -23,7 +23,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
api_key_columns = [column["name"] for column in inspector.get_columns("apikey")] api_key_columns = [column["name"] for column in inspector.get_columns("apikey")]
flow_columns = [column["name"] for column in inspector.get_columns("flow")] flow_columns = [column["name"] for column in inspector.get_columns("flow")]
@ -53,7 +53,7 @@ def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
try: try:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
column_names = [column["name"] for column in inspector.get_columns("flow")] column_names = [column["name"] for column in inspector.get_columns("flow")]
with op.batch_alter_table("flow", schema=None) as batch_op: with op.batch_alter_table("flow", schema=None) as batch_op:
if "folder" in column_names: if "folder" in column_names:

View file

@ -8,11 +8,11 @@ Create Date: 2024-07-24 11:37:48.532933
from typing import Sequence, Union from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
import sqlmodel import sqlmodel
from langflow.utils import migration from alembic import op
from langflow.utils import migration
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision: str = "90be8e2ed91e" revision: str = "90be8e2ed91e"
@ -32,8 +32,8 @@ def upgrade() -> None:
sa.Column("inputs", sa.JSON(), nullable=True), sa.Column("inputs", sa.JSON(), nullable=True),
sa.Column("outputs", sa.JSON(), nullable=True), sa.Column("outputs", sa.JSON(), nullable=True),
sa.Column("status", sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column("status", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("id", sqlmodel.sql.sqltypes.GUID(), nullable=False), sa.Column("id", sqlmodel.sql.sqltypes.types.Uuid(), nullable=False),
sa.Column("flow_id", sqlmodel.sql.sqltypes.GUID(), nullable=False), sa.Column("flow_id", sqlmodel.sql.sqltypes.types.Uuid(), nullable=False),
sa.Column("error", sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column("error", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.ForeignKeyConstraint( sa.ForeignKeyConstraint(
["flow_id"], ["flow_id"],

View file

@ -22,7 +22,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
column_names = [column["name"] for column in inspector.get_columns("flow")] column_names = [column["name"] for column in inspector.get_columns("flow")]
indexes = inspector.get_indexes("flow") indexes = inspector.get_indexes("flow")
@ -38,7 +38,7 @@ def upgrade() -> None:
def downgrade() -> None: def downgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
column_names = [column["name"] for column in inspector.get_columns("flow")] column_names = [column["name"] for column in inspector.get_columns("flow")]
indexes = inspector.get_indexes("flow") indexes = inspector.get_indexes("flow")

View file

@ -24,7 +24,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
tables = inspector.get_table_names() tables = inspector.get_table_names()
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
try: try:
@ -39,7 +39,7 @@ def upgrade() -> None:
if "folder" not in flow_columns: if "folder" not in flow_columns:
batch_op.add_column(sa.Column("folder", sqlmodel.sql.sqltypes.AutoString(), nullable=True)) batch_op.add_column(sa.Column("folder", sqlmodel.sql.sqltypes.AutoString(), nullable=True))
if "user_id" not in flow_columns: if "user_id" not in flow_columns:
batch_op.add_column(sa.Column("user_id", sqlmodel.sql.sqltypes.GUID(), nullable=True)) batch_op.add_column(sa.Column("user_id", sqlmodel.sql.sqltypes.types.Uuid(), nullable=True))
indices = inspector.get_indexes("flow") indices = inspector.get_indexes("flow")
indices_names = [index["name"] for index in indices] indices_names = [index["name"] for index in indices]
if "ix_flow_user_id" not in indices_names: if "ix_flow_user_id" not in indices_names:
@ -54,7 +54,7 @@ def upgrade() -> None:
def downgrade() -> None: def downgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
try: try:
# Re-create the dropped table 'flowstyle' if it was previously dropped in upgrade # Re-create the dropped table 'flowstyle' if it was previously dropped in upgrade
if "flowstyle" not in inspector.get_table_names(): if "flowstyle" not in inspector.get_table_names():
@ -62,8 +62,8 @@ def downgrade() -> None:
"flowstyle", "flowstyle",
sa.Column("color", sa.String(), nullable=False), sa.Column("color", sa.String(), nullable=False),
sa.Column("emoji", sa.String(), nullable=False), sa.Column("emoji", sa.String(), nullable=False),
sa.Column("flow_id", sqlmodel.sql.sqltypes.GUID(), nullable=True), sa.Column("flow_id", sqlmodel.sql.sqltypes.types.Uuid(), nullable=True),
sa.Column("id", sqlmodel.sql.sqltypes.GUID(), nullable=False), sa.Column("id", sqlmodel.sql.sqltypes.types.Uuid(), nullable=False),
sa.ForeignKeyConstraint(["flow_id"], ["flow.id"]), sa.ForeignKeyConstraint(["flow_id"], ["flow.id"]),
sa.PrimaryKeyConstraint("id"), sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("id"), sa.UniqueConstraint("id"),

View file

@ -22,7 +22,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
flow_columns = {column["name"] for column in inspector.get_columns("flow")} flow_columns = {column["name"] for column in inspector.get_columns("flow")}
flow_indexes = {index["name"] for index in inspector.get_indexes("flow")} flow_indexes = {index["name"] for index in inspector.get_indexes("flow")}
flow_fks = {fk["name"] for fk in inspector.get_foreign_keys("flow")} flow_fks = {fk["name"] for fk in inspector.get_foreign_keys("flow")}
@ -35,7 +35,7 @@ def upgrade() -> None:
if "folder" not in flow_columns: if "folder" not in flow_columns:
batch_op.add_column(sa.Column("folder", sqlmodel.sql.sqltypes.AutoString(), nullable=True)) batch_op.add_column(sa.Column("folder", sqlmodel.sql.sqltypes.AutoString(), nullable=True))
if "user_id" not in flow_columns: if "user_id" not in flow_columns:
batch_op.add_column(sa.Column("user_id", sqlmodel.sql.sqltypes.GUID(), nullable=True)) batch_op.add_column(sa.Column("user_id", sqlmodel.sql.sqltypes.types.Uuid(), nullable=True))
if "ix_flow_user_id" not in flow_indexes: if "ix_flow_user_id" not in flow_indexes:
batch_op.create_index(batch_op.f("ix_flow_user_id"), ["user_id"], unique=False) batch_op.create_index(batch_op.f("ix_flow_user_id"), ["user_id"], unique=False)
if "flow_user_id_fkey" not in flow_fks: if "flow_user_id_fkey" not in flow_fks:
@ -44,7 +44,7 @@ def upgrade() -> None:
def downgrade() -> None: def downgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
flow_columns = {column["name"] for column in inspector.get_columns("flow")} flow_columns = {column["name"] for column in inspector.get_columns("flow")}
flow_indexes = {index["name"] for index in inspector.get_indexes("flow")} flow_indexes = {index["name"] for index in inspector.get_indexes("flow")}
flow_fks = {fk["name"] for fk in inspector.get_foreign_keys("flow")} flow_fks = {fk["name"] for fk in inspector.get_foreign_keys("flow")}

View file

@ -21,7 +21,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
columns = inspector.get_columns("variable") columns = inspector.get_columns("variable")
with op.batch_alter_table("variable", schema=None) as batch_op: with op.batch_alter_table("variable", schema=None) as batch_op:
@ -38,7 +38,7 @@ def upgrade() -> None:
def downgrade() -> None: def downgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
columns = inspector.get_columns("variable") columns = inspector.get_columns("variable")
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table("variable", schema=None) as batch_op: with op.batch_alter_table("variable", schema=None) as batch_op:

View file

@ -32,8 +32,8 @@ def upgrade() -> None:
sa.Column("sender_name", sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column("sender_name", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("session_id", sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column("session_id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("text", sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column("text", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("id", sqlmodel.sql.sqltypes.GUID(), nullable=False), sa.Column("id", sqlmodel.sql.sqltypes.types.Uuid(), nullable=False),
sa.Column("flow_id", sqlmodel.sql.sqltypes.GUID(), nullable=True), sa.Column("flow_id", sqlmodel.sql.sqltypes.types.Uuid(), nullable=True),
sa.Column("files", sa.JSON(), nullable=True), sa.Column("files", sa.JSON(), nullable=True),
sa.ForeignKeyConstraint( sa.ForeignKeyConstraint(
["flow_id"], ["flow_id"],

View file

@ -21,7 +21,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
table_names = inspector.get_table_names() table_names = inspector.get_table_names()
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
if "variable" not in table_names: if "variable" not in table_names:
@ -47,7 +47,7 @@ def upgrade() -> None:
def downgrade() -> None: def downgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
table_names = inspector.get_table_names() table_names = inspector.get_table_names()
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
if "variable" not in table_names: if "variable" not in table_names:

View file

@ -24,7 +24,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
with op.batch_alter_table("vertex_build", schema=None) as batch_op: with op.batch_alter_table("vertex_build", schema=None) as batch_op:
if migration.column_exists(table_name="vertex_build", column_name="id", conn=conn): if migration.column_exists(table_name="vertex_build", column_name="id", conn=conn):
columns = inspector.get_columns("vertex_build") columns = inspector.get_columns("vertex_build")
@ -38,7 +38,7 @@ def upgrade() -> None:
def downgrade() -> None: def downgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
with op.batch_alter_table("vertex_build", schema=None) as batch_op: with op.batch_alter_table("vertex_build", schema=None) as batch_op:
if migration.column_exists(table_name="vertex_build", column_name="id", conn=conn): if migration.column_exists(table_name="vertex_build", column_name="id", conn=conn):
columns = inspector.get_columns("vertex_build") columns = inspector.get_columns("vertex_build")

View file

@ -21,7 +21,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
table_names = inspector.get_table_names() # noqa table_names = inspector.get_table_names() # noqa
column_names = [column["name"] for column in inspector.get_columns("message")] column_names = [column["name"] for column in inspector.get_columns("message")]
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
@ -36,7 +36,7 @@ def upgrade() -> None:
def downgrade() -> None: def downgrade() -> None:
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
table_names = inspector.get_table_names() # noqa table_names = inspector.get_table_names() # noqa
column_names = [column["name"] for column in inspector.get_columns("message")] column_names = [column["name"] for column in inspector.get_columns("message")]
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###

View file

@ -8,6 +8,7 @@ Create Date: 2023-11-24 15:07:37.566516
from typing import Optional, Sequence, Union from typing import Optional, Sequence, Union
import sqlalchemy as sa
from alembic import op from alembic import op
from sqlalchemy.engine.reflection import Inspector from sqlalchemy.engine.reflection import Inspector
@ -21,7 +22,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
tables = inspector.get_table_names() tables = inspector.get_table_names()
foreign_keys_names = [] foreign_keys_names = []
if "credential" in tables: if "credential" in tables:
@ -42,7 +43,7 @@ def upgrade() -> None:
def downgrade() -> None: def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind() conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore inspector = sa.inspect(conn) # type: ignore
tables = inspector.get_table_names() tables = inspector.get_table_names()
foreign_keys_names: list[Optional[str]] = [] foreign_keys_names: list[Optional[str]] = []
if "credential" in tables: if "credential" in tables:

View file

@ -140,7 +140,7 @@ def format_elapsed_time(elapsed_time: float) -> str:
return f"{minutes} {minutes_unit}, {seconds} {seconds_unit}" return f"{minutes} {minutes_unit}, {seconds} {seconds_unit}"
async def _get_flow_name(flow_id: str) -> str: async def _get_flow_name(flow_id: uuid.UUID) -> str:
async with async_session_scope() as session: async with async_session_scope() as session:
flow = await session.get(Flow, flow_id) flow = await session.get(Flow, flow_id)
if flow is None: if flow is None:
@ -149,20 +149,21 @@ async def _get_flow_name(flow_id: str) -> str:
return flow.name return flow.name
async def build_graph_from_data(flow_id: str, payload: dict, **kwargs): async def build_graph_from_data(flow_id: uuid.UUID | str, payload: dict, **kwargs):
"""Build and cache the graph.""" """Build and cache the graph."""
# Get flow name # Get flow name
if "flow_name" not in kwargs: if "flow_name" not in kwargs:
flow_name = await _get_flow_name(flow_id) flow_name = await _get_flow_name(flow_id if isinstance(flow_id, uuid.UUID) else uuid.UUID(flow_id))
kwargs["flow_name"] = flow_name kwargs["flow_name"] = flow_name
graph = Graph.from_payload(payload, flow_id, **kwargs) str_flow_id = str(flow_id)
graph = Graph.from_payload(payload, str_flow_id, **kwargs)
for vertex_id in graph.has_session_id_vertices: for vertex_id in graph.has_session_id_vertices:
vertex = graph.get_vertex(vertex_id) vertex = graph.get_vertex(vertex_id)
if vertex is None: if vertex is None:
msg = f"Vertex {vertex_id} not found" msg = f"Vertex {vertex_id} not found"
raise ValueError(msg) raise ValueError(msg)
if not vertex.raw_params.get("session_id"): if not vertex.raw_params.get("session_id"):
vertex.update_raw_params({"session_id": flow_id}, overwrite=True) vertex.update_raw_params({"session_id": str_flow_id}, overwrite=True)
run_id = uuid.uuid4() run_id = uuid.uuid4()
graph.set_run_id(run_id) graph.set_run_id(run_id)
@ -171,7 +172,7 @@ async def build_graph_from_data(flow_id: str, payload: dict, **kwargs):
return graph return graph
async def build_graph_from_db_no_cache(flow_id: str, session: AsyncSession): async def build_graph_from_db_no_cache(flow_id: uuid.UUID, session: AsyncSession):
"""Build and cache the graph.""" """Build and cache the graph."""
flow: Flow | None = await session.get(Flow, flow_id) flow: Flow | None = await session.get(Flow, flow_id)
if not flow or not flow.data: if not flow or not flow.data:
@ -180,20 +181,22 @@ async def build_graph_from_db_no_cache(flow_id: str, session: AsyncSession):
return await build_graph_from_data(flow_id, flow.data, flow_name=flow.name, user_id=str(flow.user_id)) return await build_graph_from_data(flow_id, flow.data, flow_name=flow.name, user_id=str(flow.user_id))
async def build_graph_from_db(flow_id: str, session: AsyncSession, chat_service: ChatService): async def build_graph_from_db(flow_id: uuid.UUID, session: AsyncSession, chat_service: ChatService):
graph = await build_graph_from_db_no_cache(flow_id, session) graph = await build_graph_from_db_no_cache(flow_id=flow_id, session=session)
await chat_service.set_cache(flow_id, graph) await chat_service.set_cache(str(flow_id), graph)
return graph return graph
async def build_and_cache_graph_from_data( async def build_and_cache_graph_from_data(
flow_id: str, flow_id: uuid.UUID | str,
chat_service: ChatService, chat_service: ChatService,
graph_data: dict, graph_data: dict,
): # -> Graph | Any: ): # -> Graph | Any:
"""Build and cache the graph.""" """Build and cache the graph."""
graph = Graph.from_payload(graph_data, flow_id) # Convert flow_id to str if it's UUID
await chat_service.set_cache(flow_id, graph) str_flow_id = str(flow_id) if isinstance(flow_id, uuid.UUID) else flow_id
graph = Graph.from_payload(graph_data, str_flow_id)
await chat_service.set_cache(str_flow_id, graph)
return graph return graph

View file

@ -22,7 +22,6 @@ from langflow.api.utils import (
build_and_cache_graph_from_data, build_and_cache_graph_from_data,
build_graph_from_data, build_graph_from_data,
build_graph_from_db, build_graph_from_db,
build_graph_from_db_no_cache,
format_elapsed_time, format_elapsed_time,
format_exception_message, format_exception_message,
get_top_level_vertices, get_top_level_vertices,
@ -100,13 +99,12 @@ async def retrieve_vertices_order(
start_time = time.perf_counter() start_time = time.perf_counter()
components_count = None components_count = None
try: try:
flow_id_str = str(flow_id)
# First, we need to check if the flow_id is in the cache # First, we need to check if the flow_id is in the cache
if not data: if not data:
graph = await build_graph_from_db(flow_id=flow_id_str, session=session, chat_service=chat_service) graph = await build_graph_from_db(flow_id=flow_id, session=session, chat_service=chat_service)
else: else:
graph = await build_and_cache_graph_from_data( graph = await build_and_cache_graph_from_data(
flow_id=flow_id_str, graph_data=data.model_dump(), chat_service=chat_service flow_id=flow_id, graph_data=data.model_dump(), chat_service=chat_service
) )
graph = graph.prepare(stop_component_id, start_component_id) graph = graph.prepare(stop_component_id, start_component_id)
@ -166,13 +164,13 @@ async def build_flow(
try: try:
flow_id_str = str(flow_id) flow_id_str = str(flow_id)
if not data: if not data:
graph = await build_graph_from_db_no_cache(flow_id=flow_id_str, session=session) graph = await build_graph_from_db(flow_id=flow_id, session=session, chat_service=chat_service)
else: else:
async with async_session_scope() as new_session: async with async_session_scope() as new_session:
result = await new_session.exec(select(Flow.name).where(Flow.id == flow_id_str)) result = await new_session.exec(select(Flow.name).where(Flow.id == flow_id))
flow_name = result.first() flow_name = result.first()
graph = await build_graph_from_data( graph = await build_graph_from_data(
flow_id_str, data.model_dump(), user_id=str(current_user.id), flow_name=flow_name flow_id=flow_id_str, payload=data.model_dump(), user_id=str(current_user.id), flow_name=flow_name
) )
graph.validate_stream() graph.validate_stream()
if stop_component_id or start_component_id: if stop_component_id or start_component_id:
@ -195,6 +193,7 @@ async def build_flow(
# and return the same structure but only with the ids # and return the same structure but only with the ids
components_count = len(graph.vertices) components_count = len(graph.vertices)
vertices_to_run = list(graph.vertices_to_run.union(get_top_level_vertices(graph, graph.vertices_to_run))) vertices_to_run = list(graph.vertices_to_run.union(get_top_level_vertices(graph, graph.vertices_to_run)))
await chat_service.set_cache(flow_id_str, graph)
background_tasks.add_task( background_tasks.add_task(
telemetry_service.log_package_playground, telemetry_service.log_package_playground,
PlaygroundPayload( PlaygroundPayload(
@ -217,12 +216,10 @@ async def build_flow(
raise HTTPException(status_code=400, detail=str(exc)) from exc raise HTTPException(status_code=400, detail=str(exc)) from exc
logger.exception("Error checking build status") logger.exception("Error checking build status")
raise HTTPException(status_code=500, detail=str(exc)) from exc raise HTTPException(status_code=500, detail=str(exc)) from exc
return first_layer, vertices_to_run, graph return first_layer, vertices_to_run, graph
async def _build_vertex(vertex_id: str, graph: Graph, event_manager: EventManager) -> VertexBuildResponse: async def _build_vertex(vertex_id: str, graph: Graph, event_manager: EventManager) -> VertexBuildResponse:
flow_id_str = str(flow_id) flow_id_str = str(flow_id)
next_runnable_vertices = [] next_runnable_vertices = []
top_level_vertices = [] top_level_vertices = []
start_time = time.perf_counter() start_time = time.perf_counter()
@ -506,13 +503,18 @@ async def build_vertex(
top_level_vertices = [] top_level_vertices = []
start_time = time.perf_counter() start_time = time.perf_counter()
error_message = None error_message = None
try:
graph: Graph = await chat_service.get_cache(flow_id_str)
except KeyError as exc:
raise HTTPException(status_code=404, detail="Graph not found") from exc
try: try:
cache = await chat_service.get_cache(flow_id_str) cache = await chat_service.get_cache(flow_id_str)
if isinstance(cache, CacheMiss): if isinstance(cache, CacheMiss):
# If there's no cache # If there's no cache
logger.warning(f"No cache found for {flow_id_str}. Building graph starting at {vertex_id}") logger.warning(f"No cache found for {flow_id_str}. Building graph starting at {vertex_id}")
graph: Graph = await build_graph_from_db( graph = await build_graph_from_db(
flow_id=flow_id_str, session=await anext(get_session()), chat_service=chat_service flow_id=flow_id, session=await anext(get_session()), chat_service=chat_service
) )
else: else:
graph = cache.get("result") graph = cache.get("result")

View file

@ -12,7 +12,8 @@ from fastapi.responses import StreamingResponse
from langflow.api.utils import CurrentActiveUser, DbSession from langflow.api.utils import CurrentActiveUser, DbSession
from langflow.api.v1.schemas import UploadFileResponse from langflow.api.v1.schemas import UploadFileResponse
from langflow.services.database.models.flow import Flow from langflow.services.database.models.flow import Flow
from langflow.services.deps import get_storage_service from langflow.services.deps import get_settings_service, get_storage_service
from langflow.services.settings.service import SettingsService
from langflow.services.storage.service import StorageService from langflow.services.storage.service import StorageService
from langflow.services.storage.utils import build_content_type_from_extension from langflow.services.storage.utils import build_content_type_from_extension
@ -22,36 +23,39 @@ router = APIRouter(tags=["Files"], prefix="/files")
# Create dep that gets the flow_id from the request # Create dep that gets the flow_id from the request
# then finds it in the database and returns it while # then finds it in the database and returns it while
# using the current user as the owner # using the current user as the owner
async def get_flow_id( async def get_flow(
flow_id: UUID, flow_id: UUID,
current_user: CurrentActiveUser, current_user: CurrentActiveUser,
session: DbSession, session: DbSession,
): ):
flow_id_str = str(flow_id)
# AttributeError: 'SelectOfScalar' object has no attribute 'first' # AttributeError: 'SelectOfScalar' object has no attribute 'first'
flow = await session.get(Flow, flow_id_str) flow = await session.get(Flow, flow_id)
if not flow: if not flow:
raise HTTPException(status_code=404, detail="Flow not found") raise HTTPException(status_code=404, detail="Flow not found")
if flow.user_id != current_user.id: if flow.user_id != current_user.id:
raise HTTPException(status_code=403, detail="You don't have access to this flow") raise HTTPException(status_code=403, detail="You don't have access to this flow")
return flow_id_str return flow
@router.post("/upload/{flow_id}", status_code=HTTPStatus.CREATED) @router.post("/upload/{flow_id}", status_code=HTTPStatus.CREATED)
async def upload_file( async def upload_file(
*, *,
file: UploadFile, file: UploadFile,
flow_id: Annotated[UUID, Depends(get_flow_id)], flow: Annotated[Flow, Depends(get_flow)],
current_user: CurrentActiveUser, current_user: CurrentActiveUser,
session: DbSession,
storage_service: Annotated[StorageService, Depends(get_storage_service)], storage_service: Annotated[StorageService, Depends(get_storage_service)],
settings_service: Annotated[SettingsService, Depends(get_settings_service)],
) -> UploadFileResponse: ) -> UploadFileResponse:
try: try:
flow_id_str = str(flow_id) max_file_size_upload = settings_service.settings.max_file_size_upload
flow = await session.get(Flow, flow_id_str)
except Exception as e: except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e raise HTTPException(status_code=500, detail=str(e)) from e
if file.size > max_file_size_upload * 1024 * 1024:
raise HTTPException(
status_code=413, detail=f"File size is larger than the maximum file size {max_file_size_upload}MB."
)
if flow.user_id != current_user.id: if flow.user_id != current_user.id:
raise HTTPException(status_code=403, detail="You don't have access to this flow") raise HTTPException(status_code=403, detail="You don't have access to this flow")
@ -60,9 +64,9 @@ async def upload_file(
timestamp = datetime.now(tz=timezone.utc).astimezone().strftime("%Y-%m-%d_%H-%M-%S") timestamp = datetime.now(tz=timezone.utc).astimezone().strftime("%Y-%m-%d_%H-%M-%S")
file_name = file.filename or hashlib.sha256(file_content).hexdigest() file_name = file.filename or hashlib.sha256(file_content).hexdigest()
full_file_name = f"{timestamp}_{file_name}" full_file_name = f"{timestamp}_{file_name}"
folder = flow_id_str folder = str(flow.id)
await storage_service.save_file(flow_id=folder, file_name=full_file_name, data=file_content) await storage_service.save_file(flow_id=folder, file_name=full_file_name, data=file_content)
return UploadFileResponse(flow_id=flow_id_str, file_path=f"{folder}/{full_file_name}") return UploadFileResponse(flow_id=str(flow.id), file_path=f"{folder}/{full_file_name}")
except Exception as e: except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e raise HTTPException(status_code=500, detail=str(e)) from e
@ -164,12 +168,11 @@ async def list_profile_pictures():
@router.get("/list/{flow_id}") @router.get("/list/{flow_id}")
async def list_files( async def list_files(
flow_id: Annotated[UUID, Depends(get_flow_id)], flow: Annotated[Flow, Depends(get_flow)],
storage_service: Annotated[StorageService, Depends(get_storage_service)], storage_service: Annotated[StorageService, Depends(get_storage_service)],
): ):
try: try:
flow_id_str = str(flow_id) files = await storage_service.list_files(flow_id=str(flow.id))
files = await storage_service.list_files(flow_id=flow_id_str)
except Exception as e: except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e raise HTTPException(status_code=500, detail=str(e)) from e
@ -179,12 +182,11 @@ async def list_files(
@router.delete("/delete/{flow_id}/{file_name}") @router.delete("/delete/{flow_id}/{file_name}")
async def delete_file( async def delete_file(
file_name: str, file_name: str,
flow_id: Annotated[UUID, Depends(get_flow_id)], flow: Annotated[Flow, Depends(get_flow)],
storage_service: Annotated[StorageService, Depends(get_storage_service)], storage_service: Annotated[StorageService, Depends(get_storage_service)],
): ):
try: try:
flow_id_str = str(flow_id) await storage_service.delete_file(flow_id=str(flow.id), file_name=file_name)
await storage_service.delete_file(flow_id=flow_id_str, file_name=file_name)
except Exception as e: except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e raise HTTPException(status_code=500, detail=str(e)) from e

View file

@ -3,6 +3,7 @@ import json
import zipfile import zipfile
from datetime import datetime, timezone from datetime import datetime, timezone
from typing import Annotated from typing import Annotated
from uuid import UUID
import orjson import orjson
from fastapi import APIRouter, Depends, File, HTTPException, Response, UploadFile, status from fastapi import APIRouter, Depends, File, HTTPException, Response, UploadFile, status
@ -114,7 +115,7 @@ async def read_folders(
async def read_folder( async def read_folder(
*, *,
session: DbSession, session: DbSession,
folder_id: str, folder_id: UUID,
current_user: CurrentActiveUser, current_user: CurrentActiveUser,
params: Annotated[Params | None, Depends(custom_params)], params: Annotated[Params | None, Depends(custom_params)],
is_component: bool = False, is_component: bool = False,
@ -165,7 +166,7 @@ async def read_folder(
async def update_folder( async def update_folder(
*, *,
session: DbSession, session: DbSession,
folder_id: str, folder_id: UUID,
folder: FolderUpdate, # Assuming FolderUpdate is a Pydantic model defining updatable fields folder: FolderUpdate, # Assuming FolderUpdate is a Pydantic model defining updatable fields
current_user: CurrentActiveUser, current_user: CurrentActiveUser,
): ):
@ -226,7 +227,7 @@ async def update_folder(
async def delete_folder( async def delete_folder(
*, *,
session: DbSession, session: DbSession,
folder_id: str, folder_id: UUID,
current_user: CurrentActiveUser, current_user: CurrentActiveUser,
): ):
try: try:
@ -258,7 +259,7 @@ async def delete_folder(
async def download_file( async def download_file(
*, *,
session: DbSession, session: DbSession,
folder_id: str, folder_id: UUID,
current_user: CurrentActiveUser, current_user: CurrentActiveUser,
): ):
"""Download all flows from folder as a zip file.""" """Download all flows from folder as a zip file."""

View file

@ -7,6 +7,7 @@ from collections.abc import AsyncIterator, Iterator
from copy import deepcopy from copy import deepcopy
from textwrap import dedent from textwrap import dedent
from typing import TYPE_CHECKING, Any, ClassVar, NamedTuple, get_type_hints from typing import TYPE_CHECKING, Any, ClassVar, NamedTuple, get_type_hints
from uuid import UUID
import nanoid import nanoid
import yaml import yaml
@ -1006,7 +1007,10 @@ class Component(CustomComponent):
async def send_message(self, message: Message, id_: str | None = None): async def send_message(self, message: Message, id_: str | None = None):
if (hasattr(self, "graph") and self.graph.session_id) and (message is not None and not message.session_id): if (hasattr(self, "graph") and self.graph.session_id) and (message is not None and not message.session_id):
message.session_id = self.graph.session_id session_id = (
UUID(self.graph.session_id) if isinstance(self.graph.session_id, str) else self.graph.session_id
)
message.session_id = session_id
stored_message = await self._store_message(message) stored_message = await self._store_message(message)
self._stored_message_id = stored_message.id self._stored_message_id = stored_message.id
@ -1031,13 +1035,16 @@ class Component(CustomComponent):
return stored_message return stored_message
async def _store_message(self, message: Message) -> Message: async def _store_message(self, message: Message) -> Message:
flow_id = self.graph.flow_id if hasattr(self, "graph") else None flow_id: str | None = None
messages = await astore_message(message, flow_id=flow_id) if hasattr(self, "graph"):
if len(messages) != 1: # Convert UUID to str if needed
flow_id = str(self.graph.flow_id) if self.graph.flow_id else None
stored_messages = await astore_message(message, flow_id=flow_id)
if len(stored_messages) != 1:
msg = "Only one message can be stored at a time." msg = "Only one message can be stored at a time."
raise ValueError(msg) raise ValueError(msg)
stored_message = stored_messages[0]
return messages[0] return await Message.create(**stored_message.model_dump())
async def _send_message_event(self, message: Message, id_: str | None = None, category: str | None = None) -> None: async def _send_message_event(self, message: Message, id_: str | None = None, category: str | None = None) -> None:
if hasattr(self, "_event_manager") and self._event_manager: if hasattr(self, "_event_manager") and self._event_manager:
@ -1065,10 +1072,20 @@ class Component(CustomComponent):
and not isinstance(original_message.text, str) and not isinstance(original_message.text, str)
) )
async def _update_stored_message(self, stored_message: Message) -> Message: async def _update_stored_message(self, message: Message) -> Message:
message_tables = await aupdate_messages(stored_message) """Update the stored message."""
if len(message_tables) != 1: if hasattr(self, "_vertex") and self._vertex is not None and hasattr(self._vertex, "graph"):
msg = "Only one message can be updated at a time." flow_id = (
UUID(self._vertex.graph.flow_id)
if isinstance(self._vertex.graph.flow_id, str)
else self._vertex.graph.flow_id
)
message.flow_id = flow_id
message_tables = await aupdate_messages(message)
if not message_tables:
msg = "Failed to update message"
raise ValueError(msg) raise ValueError(msg)
message_table = message_tables[0] message_table = message_tables[0]
return await Message.create(**message_table.model_dump()) return await Message.create(**message_table.model_dump())

View file

@ -33,8 +33,9 @@ def list_flows(*, user_id: str | None = None) -> list[Data]:
raise ValueError(msg) raise ValueError(msg)
try: try:
with session_scope() as session: with session_scope() as session:
uuid_user_id = UUID(user_id) if isinstance(user_id, str) else user_id
flows = session.exec( flows = session.exec(
select(Flow).where(Flow.user_id == user_id).where(Flow.is_component == False) # noqa: E712 select(Flow).where(Flow.user_id == uuid_user_id).where(Flow.is_component == False) # noqa: E712
).all() ).all()
return [flow.to_data() for flow in flows] return [flow.to_data() for flow in flows]

View file

@ -18,7 +18,7 @@ from langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_USER
def _get_variable_query( def _get_variable_query(
sender: str | None = None, sender: str | None = None,
sender_name: str | None = None, sender_name: str | None = None,
session_id: str | None = None, session_id: str | UUID | None = None,
order_by: str | None = "timestamp", order_by: str | None = "timestamp",
order: str | None = "DESC", order: str | None = "DESC",
flow_id: UUID | None = None, flow_id: UUID | None = None,
@ -44,7 +44,7 @@ def _get_variable_query(
def get_messages( def get_messages(
sender: str | None = None, sender: str | None = None,
sender_name: str | None = None, sender_name: str | None = None,
session_id: str | None = None, session_id: str | UUID | None = None,
order_by: str | None = "timestamp", order_by: str | None = "timestamp",
order: str | None = "DESC", order: str | None = "DESC",
flow_id: UUID | None = None, flow_id: UUID | None = None,
@ -73,7 +73,7 @@ def get_messages(
async def aget_messages( async def aget_messages(
sender: str | None = None, sender: str | None = None,
sender_name: str | None = None, sender_name: str | None = None,
session_id: str | None = None, session_id: str | UUID | None = None,
order_by: str | None = "timestamp", order_by: str | None = "timestamp",
order: str | None = "DESC", order: str | None = "DESC",
flow_id: UUID | None = None, flow_id: UUID | None = None,
@ -99,7 +99,7 @@ async def aget_messages(
return [await Message.create(**d.model_dump()) for d in messages] return [await Message.create(**d.model_dump()) for d in messages]
def add_messages(messages: Message | list[Message], flow_id: str | None = None): def add_messages(messages: Message | list[Message], flow_id: str | UUID | None = None):
"""Add a message to the monitor service.""" """Add a message to the monitor service."""
if not isinstance(messages, list): if not isinstance(messages, list):
messages = [messages] messages = [messages]
@ -110,6 +110,10 @@ def add_messages(messages: Message | list[Message], flow_id: str | None = None):
raise ValueError(msg) raise ValueError(msg)
try: try:
# Convert flow_id to UUID if it's a string
if isinstance(flow_id, str):
flow_id = UUID(flow_id)
messages_models = [MessageTable.from_message(msg, flow_id=flow_id) for msg in messages] messages_models = [MessageTable.from_message(msg, flow_id=flow_id) for msg in messages]
with session_scope() as session: with session_scope() as session:
messages_models = add_messagetables(messages_models, session) messages_models = add_messagetables(messages_models, session)
@ -119,7 +123,7 @@ def add_messages(messages: Message | list[Message], flow_id: str | None = None):
raise raise
async def aadd_messages(messages: Message | list[Message], flow_id: str | None = None): async def aadd_messages(messages: Message | list[Message], flow_id: str | UUID | None = None):
"""Add a message to the monitor service.""" """Add a message to the monitor service."""
if not isinstance(messages, list): if not isinstance(messages, list):
messages = [messages] messages = [messages]
@ -146,9 +150,15 @@ def update_messages(messages: Message | list[Message]) -> list[Message]:
with session_scope() as session: with session_scope() as session:
updated_messages: list[MessageTable] = [] updated_messages: list[MessageTable] = []
for message in messages: for message in messages:
msg = session.get(MessageTable, message.id) message_id = UUID(message.id) if isinstance(message.id, str) else message.id
msg = session.get(MessageTable, message_id)
if msg: if msg:
msg.sqlmodel_update(message.model_dump(exclude_unset=True, exclude_none=True)) if hasattr(message, "data"):
msg = msg.sqlmodel_update(message.data)
else:
msg = msg.sqlmodel_update(message.model_dump(exclude_unset=True, exclude_none=True))
if isinstance(msg.flow_id, str):
msg.flow_id = UUID(msg.flow_id)
session.add(msg) session.add(msg)
session.commit() session.commit()
session.refresh(msg) session.refresh(msg)
@ -167,7 +177,10 @@ async def aupdate_messages(messages: Message | list[Message]) -> list[Message]:
for message in messages: for message in messages:
msg = await session.get(MessageTable, message.id) msg = await session.get(MessageTable, message.id)
if msg: if msg:
msg.sqlmodel_update(message.model_dump(exclude_unset=True, exclude_none=True)) if hasattr(message, "data"):
msg = msg.sqlmodel_update(message.data)
else:
msg = msg.sqlmodel_update(message.model_dump(exclude_unset=True, exclude_none=True))
session.add(msg) session.add(msg)
await session.commit() await session.commit()
await session.refresh(msg) await session.refresh(msg)
@ -262,13 +275,13 @@ async def delete_message(id_: str) -> None:
def store_message( def store_message(
message: Message, message: Message,
flow_id: str | None = None, flow_id: str | UUID | None = None,
) -> list[Message]: ) -> list[Message]:
"""Stores a message in the memory. """Stores a message in the memory.
Args: Args:
message (Message): The message to store. message (Message): The message to store.
flow_id (Optional[str]): The flow ID associated with the message. flow_id (Optional[str | UUID]): The flow ID associated with the message.
When running from the CustomComponent you can access this using `self.graph.flow_id`. When running from the CustomComponent you can access this using `self.graph.flow_id`.
Returns: Returns:
@ -281,6 +294,10 @@ def store_message(
logger.warning("No message provided.") logger.warning("No message provided.")
return [] return []
# Convert flow_id to UUID if it's a string
if isinstance(flow_id, str):
flow_id = UUID(flow_id)
required_fields = ["session_id", "sender", "sender_name"] required_fields = ["session_id", "sender", "sender_name"]
missing_fields = [field for field in required_fields if not getattr(message, field)] missing_fields = [field for field in required_fields if not getattr(message, field)]
if missing_fields: if missing_fields:
@ -302,7 +319,7 @@ def store_message(
async def astore_message( async def astore_message(
message: Message, message: Message,
flow_id: str | None = None, flow_id: str | UUID | None = None,
) -> list[Message]: ) -> list[Message]:
"""Stores a message in the memory. """Stores a message in the memory.

View file

@ -40,7 +40,7 @@ class Message(Data):
sender: str | None = None sender: str | None = None
sender_name: str | None = None sender_name: str | None = None
files: list[str | Image] | None = Field(default=[]) files: list[str | Image] | None = Field(default=[])
session_id: str | None = Field(default="") session_id: str | UUID | None = Field(default="")
timestamp: Annotated[str, timestamp_to_str_validator] = Field( timestamp: Annotated[str, timestamp_to_str_validator] = Field(
default_factory=lambda: datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S %Z") default_factory=lambda: datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S %Z")
) )

View file

@ -1,11 +1,22 @@
from collections.abc import AsyncIterator, Generator, Iterator from collections.abc import AsyncIterator, Generator, Iterator
from datetime import datetime from datetime import datetime
from typing import Annotated
from uuid import UUID
from loguru import logger from loguru import logger
from pydantic import BaseModel from pydantic import BaseModel, BeforeValidator
from pydantic.v1 import BaseModel as BaseModelV1 from pydantic.v1 import BaseModel as BaseModelV1
def str_to_uuid(v: str | UUID) -> UUID:
if isinstance(v, str):
return UUID(v)
return v
UUIDstr = Annotated[UUID, BeforeValidator(str_to_uuid)]
def recursive_serialize_or_str(obj): def recursive_serialize_or_str(obj):
try: try:
if isinstance(obj, type) and issubclass(obj, BaseModel | BaseModelV1): if isinstance(obj, type) and issubclass(obj, BaseModel | BaseModelV1):

View file

@ -1,10 +1,12 @@
from datetime import datetime, timezone from datetime import datetime, timezone
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from uuid import UUID, uuid4 from uuid import uuid4
from pydantic import field_validator from pydantic import field_validator
from sqlmodel import Column, DateTime, Field, Relationship, SQLModel, func from sqlmodel import Column, DateTime, Field, Relationship, SQLModel, func
from langflow.schema.serialize import UUIDstr
if TYPE_CHECKING: if TYPE_CHECKING:
from langflow.services.database.models.user import User from langflow.services.database.models.user import User
@ -21,14 +23,14 @@ class ApiKeyBase(SQLModel):
class ApiKey(ApiKeyBase, table=True): # type: ignore[call-arg] class ApiKey(ApiKeyBase, table=True): # type: ignore[call-arg]
id: UUID = Field(default_factory=uuid4, primary_key=True, unique=True) id: UUIDstr = Field(default_factory=uuid4, primary_key=True, unique=True)
created_at: datetime | None = Field( created_at: datetime | None = Field(
default=None, sa_column=Column(DateTime(timezone=True), server_default=func.now(), nullable=False) default=None, sa_column=Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
) )
api_key: str = Field(index=True, unique=True) api_key: str = Field(index=True, unique=True)
# User relationship # User relationship
# Delete API keys when user is deleted # Delete API keys when user is deleted
user_id: UUID = Field(index=True, foreign_key="user.id") user_id: UUIDstr = Field(index=True, foreign_key="user.id")
user: "User" = Relationship( user: "User" = Relationship(
back_populates="api_keys", back_populates="api_keys",
) )
@ -36,7 +38,7 @@ class ApiKey(ApiKeyBase, table=True): # type: ignore[call-arg]
class ApiKeyCreate(ApiKeyBase): class ApiKeyCreate(ApiKeyBase):
api_key: str | None = None api_key: str | None = None
user_id: UUID | None = None user_id: UUIDstr | None = None
created_at: datetime | None = Field(default_factory=utc_now) created_at: datetime | None = Field(default_factory=utc_now)
@field_validator("created_at", mode="before") @field_validator("created_at", mode="before")
@ -46,15 +48,15 @@ class ApiKeyCreate(ApiKeyBase):
class UnmaskedApiKeyRead(ApiKeyBase): class UnmaskedApiKeyRead(ApiKeyBase):
id: UUID id: UUIDstr
api_key: str = Field() api_key: str = Field()
user_id: UUID = Field() user_id: UUIDstr = Field()
class ApiKeyRead(ApiKeyBase): class ApiKeyRead(ApiKeyBase):
id: UUID id: UUIDstr
api_key: str = Field(schema_extra={"validate_default": True}) api_key: str = Field(schema_extra={"validate_default": True})
user_id: UUID = Field() user_id: UUIDstr = Field()
created_at: datetime = Field() created_at: datetime = Field()
@field_validator("api_key") @field_validator("api_key")

View file

@ -47,7 +47,10 @@ class MessageBase(SQLModel):
for file in message.files: for file in message.files:
if hasattr(file, "path") and hasattr(file, "url") and file.path: if hasattr(file, "path") and hasattr(file, "url") and file.path:
session_id = message.session_id session_id = message.session_id
image_paths.append(f"{session_id}{file.path.split(session_id)[1]}") if session_id:
image_paths.append(f"{session_id}{file.path.split(str(session_id))[1]}")
else:
image_paths.append(file.path)
if image_paths: if image_paths:
message.files = image_paths message.files = image_paths
@ -76,6 +79,13 @@ class MessageBase(SQLModel):
content = content_block.model_dump_json() if hasattr(content_block, "model_dump_json") else content_block content = content_block.model_dump_json() if hasattr(content_block, "model_dump_json") else content_block
content_blocks.append(content) content_blocks.append(content)
if isinstance(flow_id, str):
try:
flow_id = UUID(flow_id)
except ValueError as exc:
msg = f"Flow ID {flow_id} is not a valid UUID"
raise ValueError(msg) from exc
return cls( return cls(
sender=message.sender, sender=message.sender,
sender_name=message.sender_name, sender_name=message.sender_name,

View file

@ -17,6 +17,8 @@ async def get_user_by_username(db: AsyncSession, username: str) -> User | None:
async def get_user_by_id(db: AsyncSession, user_id: UUID) -> User | None: async def get_user_by_id(db: AsyncSession, user_id: UUID) -> User | None:
if isinstance(user_id, str):
user_id = UUID(user_id)
stmt = select(User).where(User.id == user_id) stmt = select(User).where(User.id == user_id)
return (await db.exec(stmt)).first() return (await db.exec(stmt)).first()

View file

@ -4,6 +4,8 @@ from uuid import UUID, uuid4
from sqlmodel import Field, Relationship, SQLModel from sqlmodel import Field, Relationship, SQLModel
from langflow.schema.serialize import UUIDstr
if TYPE_CHECKING: if TYPE_CHECKING:
from langflow.services.database.models.api_key import ApiKey from langflow.services.database.models.api_key import ApiKey
from langflow.services.database.models.flow import Flow from langflow.services.database.models.flow import Flow
@ -12,7 +14,7 @@ if TYPE_CHECKING:
class User(SQLModel, table=True): # type: ignore[call-arg] class User(SQLModel, table=True): # type: ignore[call-arg]
id: UUID = Field(default_factory=uuid4, primary_key=True, unique=True) id: UUIDstr = Field(default_factory=uuid4, primary_key=True, unique=True)
username: str = Field(index=True, unique=True) username: str = Field(index=True, unique=True)
password: str = Field() password: str = Field()
profile_image: str | None = Field(default=None, nullable=True) profile_image: str | None = Field(default=None, nullable=True)

View file

@ -67,6 +67,8 @@ class LocalStorageService(StorageService):
:return: A list of file names. :return: A list of file names.
:raises FileNotFoundError: If the flow directory does not exist. :raises FileNotFoundError: If the flow directory does not exist.
""" """
if not isinstance(flow_id, str):
flow_id = str(flow_id)
folder_path = self.data_dir / flow_id folder_path = self.data_dir / flow_id
if not await folder_path.exists() or not await folder_path.is_dir(): if not await folder_path.exists() or not await folder_path.is_dir():
logger.warning(f"Flow {flow_id} directory does not exist.") logger.warning(f"Flow {flow_id} directory does not exist.")

View file

@ -1,4 +1,4 @@
from sqlalchemy.engine.reflection import Inspector import sqlalchemy as sa
def table_exists(name, conn): def table_exists(name, conn):
@ -11,7 +11,7 @@ def table_exists(name, conn):
Returns: Returns:
bool: True if the table exists, False otherwise. bool: True if the table exists, False otherwise.
""" """
inspector = Inspector.from_engine(conn) inspector = sa.inspect(conn)
return name in inspector.get_table_names() return name in inspector.get_table_names()
@ -26,7 +26,7 @@ def column_exists(table_name, column_name, conn):
Returns: Returns:
bool: True if the column exists, False otherwise. bool: True if the column exists, False otherwise.
""" """
inspector = Inspector.from_engine(conn) inspector = sa.inspect(conn)
return column_name in [column["name"] for column in inspector.get_columns(table_name)] return column_name in [column["name"] for column in inspector.get_columns(table_name)]
@ -41,7 +41,7 @@ def foreign_key_exists(table_name, fk_name, conn):
Returns: Returns:
bool: True if the foreign key exists, False otherwise. bool: True if the foreign key exists, False otherwise.
""" """
inspector = Inspector.from_engine(conn) inspector = sa.inspect(conn)
return fk_name in [fk["name"] for fk in inspector.get_foreign_keys(table_name)] return fk_name in [fk["name"] for fk in inspector.get_foreign_keys(table_name)]
@ -56,6 +56,6 @@ def constraint_exists(table_name, constraint_name, conn):
Returns: Returns:
bool: True if the constraint exists, False otherwise. bool: True if the constraint exists, False otherwise.
""" """
inspector = Inspector.from_engine(conn) inspector = sa.inspect(conn)
constraints = inspector.get_unique_constraints(table_name) constraints = inspector.get_unique_constraints(table_name)
return constraint_name in [constraint["name"] for constraint in constraints] return constraint_name in [constraint["name"] for constraint in constraints]

View file

@ -114,10 +114,10 @@ dependencies = [
"langchain~=0.3.3", "langchain~=0.3.3",
"langchain-core~=0.3.15", "langchain-core~=0.3.15",
"langchainhub~=0.1.15", "langchainhub~=0.1.15",
"sqlmodel==0.0.18",
"loguru>=0.7.1,<1.0.0", "loguru>=0.7.1,<1.0.0",
"rich>=13.7.0,<14.0.0", "rich>=13.7.0,<14.0.0",
"langchain-experimental>=0.0.61,<1.0.0", "langchain-experimental>=0.0.61,<1.0.0",
"sqlmodel==0.0.22",
"pydantic~=2.7.0", "pydantic~=2.7.0",
"pydantic-settings>=2.2.0,<3.0.0", "pydantic-settings>=2.2.0,<3.0.0",
"typer>=0.13.0,<1.0.0", "typer>=0.13.0,<1.0.0",

File diff suppressed because it is too large Load diff

View file

@ -8,17 +8,9 @@ from langflow.components.outputs import ChatOutput
from langflow.components.tools.calculator import CalculatorToolComponent from langflow.components.tools.calculator import CalculatorToolComponent
from langflow.graph import Graph from langflow.graph import Graph
from langflow.schema.data import Data from langflow.schema.data import Data
from langflow.services.settings.feature_flags import FEATURE_FLAGS
from pydantic import BaseModel from pydantic import BaseModel
@pytest.fixture
def _add_toolkit_output():
FEATURE_FLAGS.add_toolkit_output = True
yield
FEATURE_FLAGS.add_toolkit_output = False
async def test_component_tool(): async def test_component_tool():
calculator_component = CalculatorToolComponent() calculator_component = CalculatorToolComponent()
component_toolkit = ComponentToolkit(component=calculator_component) component_toolkit = ComponentToolkit(component=calculator_component)
@ -43,7 +35,6 @@ async def test_component_tool():
@pytest.mark.api_key_required @pytest.mark.api_key_required
@pytest.mark.usefixtures("_add_toolkit_output")
def test_component_tool_with_api_key(): def test_component_tool_with_api_key():
chat_output = ChatOutput() chat_output = ChatOutput()
openai_llm = OpenAIModelComponent() openai_llm = OpenAIModelComponent()

View file

@ -2,6 +2,7 @@ import asyncio
import time import time
from typing import Any from typing import Any
from unittest.mock import MagicMock from unittest.mock import MagicMock
from uuid import uuid4
import pytest import pytest
from langflow.custom.custom_component.component import Component from langflow.custom.custom_component.component import Component
@ -9,7 +10,7 @@ from langflow.events.event_manager import EventManager
from langflow.schema.content_block import ContentBlock from langflow.schema.content_block import ContentBlock
from langflow.schema.content_types import TextContent, ToolContent from langflow.schema.content_types import TextContent, ToolContent
from langflow.schema.message import Message from langflow.schema.message import Message
from langflow.schema.properties import Source from langflow.schema.properties import Properties, Source
from langflow.template.field.base import Output from langflow.template.field.base import Output
@ -52,11 +53,13 @@ async def test_component_message_sending():
component.set_event_manager(event_manager) component.set_event_manager(event_manager)
# Create a message # Create a message
properties = Properties()
message = Message( message = Message(
sender="test_sender", sender="test_sender",
session_id="test_session", session_id="test_session",
sender_name="test_sender_name", sender_name="test_sender_name",
content_blocks=[ContentBlock(title="Test Block", contents=[TextContent(type="text", text="Test message")])], content_blocks=[ContentBlock(title="Test Block", contents=[TextContent(type="text", text="Test message")])],
properties=properties,
) )
# Send the message # Send the message
@ -80,6 +83,7 @@ async def test_component_tool_output():
component.set_event_manager(event_manager) component.set_event_manager(event_manager)
# Create a message with tool content # Create a message with tool content
properties = Properties()
message = Message( message = Message(
sender="test_sender", sender="test_sender",
session_id="test_session", session_id="test_session",
@ -90,6 +94,7 @@ async def test_component_tool_output():
contents=[ToolContent(type="tool_use", name="test_tool", tool_input={"query": "test input"})], contents=[ToolContent(type="tool_use", name="test_tool", tool_input={"query": "test input"})],
) )
], ],
properties=properties,
) )
# Send the message # Send the message
@ -210,7 +215,7 @@ async def test_component_streaming_message():
# Create a proper mock vertex with graph and flow_id # Create a proper mock vertex with graph and flow_id
vertex = MagicMock() vertex = MagicMock()
mock_graph = MagicMock() mock_graph = MagicMock()
mock_graph.flow_id = "12345678-1234-5678-1234-567812345678" # Valid UUID string mock_graph.flow_id = str(uuid4())
vertex.graph = mock_graph vertex.graph = mock_graph
component = ComponentForTesting(_vertex=vertex) component = ComponentForTesting(_vertex=vertex)
@ -227,11 +232,13 @@ async def test_component_streaming_message():
yield StreamChunk(chunk) yield StreamChunk(chunk)
# Create a streaming message # Create a streaming message
properties = Properties()
message = Message( message = Message(
sender="test_sender", sender="test_sender",
session_id="test_session", session_id="test_session",
sender_name="test_sender_name", sender_name="test_sender_name",
text=text_generator(), text=text_generator(),
properties=properties,
) )
# Send the streaming message # Send the streaming message

View file

@ -6,6 +6,7 @@ from langchain_core.messages import AIMessage, HumanMessage
from langchain_core.prompts.chat import ChatPromptTemplate from langchain_core.prompts.chat import ChatPromptTemplate
from langflow.schema.message import Message from langflow.schema.message import Message
from langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_USER from langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_USER
from loguru import logger
from platformdirs import user_cache_dir from platformdirs import user_cache_dir
@ -176,4 +177,7 @@ def cleanup():
# Clean up the real cache directory after tests # Clean up the real cache directory after tests
cache_dir = Path(user_cache_dir("langflow")) cache_dir = Path(user_cache_dir("langflow"))
if cache_dir.exists(): if cache_dir.exists():
shutil.rmtree(str(cache_dir)) try:
shutil.rmtree(str(cache_dir))
except OSError as exc:
logger.error(f"Error cleaning up cache directory: {exc}")

8
uv.lock generated
View file

@ -4048,7 +4048,7 @@ requires-dist = [
{ name = "sentry-sdk", extras = ["fastapi", "loguru"], specifier = ">=2.5.1,<3.0.0" }, { name = "sentry-sdk", extras = ["fastapi", "loguru"], specifier = ">=2.5.1,<3.0.0" },
{ name = "setuptools", specifier = ">=70,<76.0.0" }, { name = "setuptools", specifier = ">=70,<76.0.0" },
{ name = "spider-client", specifier = ">=0.0.27,<1.0.0" }, { name = "spider-client", specifier = ">=0.0.27,<1.0.0" },
{ name = "sqlmodel", specifier = "==0.0.18" }, { name = "sqlmodel", specifier = "==0.0.22" },
{ name = "typer", specifier = ">=0.13.0,<1.0.0" }, { name = "typer", specifier = ">=0.13.0,<1.0.0" },
{ name = "types-google-cloud-ndb", marker = "extra == 'dev'", specifier = ">=2.2.0.0" }, { name = "types-google-cloud-ndb", marker = "extra == 'dev'", specifier = ">=2.2.0.0" },
{ name = "types-markdown", marker = "extra == 'dev'", specifier = ">=3.7.0.20240822" }, { name = "types-markdown", marker = "extra == 'dev'", specifier = ">=3.7.0.20240822" },
@ -7421,15 +7421,15 @@ postgresql-psycopgbinary = [
[[package]] [[package]]
name = "sqlmodel" name = "sqlmodel"
version = "0.0.18" version = "0.0.22"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "pydantic" }, { name = "pydantic" },
{ name = "sqlalchemy" }, { name = "sqlalchemy" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/32/19/d0b363befa90c168941f4f7826f6a9d7211f4aa2b99660ac0410bf5803f8/sqlmodel-0.0.18.tar.gz", hash = "sha256:2e520efe03810ef2c268a1004cfc5ef8f8a936312232f38d6c8e62c11af2cac3", size = 109419 } sdist = { url = "https://files.pythonhosted.org/packages/b5/39/8641040ab0d5e1d8a1c2325ae89a01ae659fc96c61a43d158fb71c9a0bf0/sqlmodel-0.0.22.tar.gz", hash = "sha256:7d37c882a30c43464d143e35e9ecaf945d88035e20117bf5ec2834a23cbe505e", size = 116392 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/cc/5f/8838e6b1b6673709e93386d6d42d28030883079b5ebcbdc7a37f2953e993/sqlmodel-0.0.18-py3-none-any.whl", hash = "sha256:d70fdf8fe595e30a918660cf4537b9c5fc2fffdbfcba851a0135de73c3ebcbb7", size = 26507 }, { url = "https://files.pythonhosted.org/packages/dd/b1/3af5104b716c420e40a6ea1b09886cae3a1b9f4538343875f637755cae5b/sqlmodel-0.0.22-py3-none-any.whl", hash = "sha256:a1ed13e28a1f4057cbf4ff6cdb4fc09e85702621d3259ba17b3c230bfb2f941b", size = 28276 },
] ]
[[package]] [[package]]