ref: Add ALL ruff rules for tests (#4183)

Add ALL ruff rules for tests
This commit is contained in:
Christophe Bornet 2024-10-19 22:41:37 +02:00 • committed by GitHub
commit f96f2eaf8a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
67 changed files with 424 additions and 364 deletions

View file

@ -216,6 +216,43 @@ directory = "coverage"
exclude = ["src/backend/langflow/alembic/*"]
line-length = 120
[tool.ruff.lint]
pydocstyle.convention = "google"
select = ["ALL"]
ignore = [
"C90", # McCabe complexity
"CPY", # Missing copyright
"COM812", # Messes with the formatter
"ERA", # Eradicate commented-out code
"FIX002", # Line contains TODO
"ISC001", # Messes with the formatter
"PERF203", # Rarely useful
"PLR09", # Too many something (arg, statements, etc)
"RUF012", # Pydantic models are currently not well detected. See https://github.com/astral-sh/ruff/issues/13630
"TD002", # Missing author in TODO
"TD003", # Missing issue link in TODO
"TRY301", # A bit too harsh (Abstract `raise` to an inner function)
# Rules that are TODOs
"ANN",
]
# Preview rules that are not yet activated
external = ["RUF027"]
[tool.ruff.lint.per-file-ignores]
"scripts/*" = [
"D1",
"INP",
"T201",
]
"src/backend/tests/*" = [
"D1",
"PLR2004",
"S101",
"SLF001",
]
[tool.mypy]
plugins = ["pydantic.mypy"]
follow_imports = "skip"

View file

@ -12,8 +12,10 @@ PYPI_LANGFLOW_NIGHTLY_URL = "https://pypi.org/pypi/langflow-nightly/json"
PYPI_LANGFLOW_BASE_URL = "https://pypi.org/pypi/langflow-base/json"
PYPI_LANGFLOW_BASE_NIGHTLY_URL = "https://pypi.org/pypi/langflow-base-nightly/json"
ARGUMENT_NUMBER = 2
def get_latest_published_version(build_type: str, is_nightly: bool) -> Version:
def get_latest_published_version(build_type: str, *, is_nightly: bool) -> Version:
import requests
url = ""
@ -25,12 +27,12 @@ def get_latest_published_version(build_type: str, is_nightly: bool) -> Version:
msg = f"Invalid build type: {build_type}"
raise ValueError(msg)
res = requests.get(url)
res = requests.get(url, timeout=10)
try:
version_str = res.json()["info"]["version"]
except Exception as e:
msg = "Got unexpected response from PyPI"
raise RuntimeError(msg, e)
raise RuntimeError(msg) from e
return Version(version_str)
@ -74,9 +76,9 @@ def create_tag(build_type: str):
if __name__ == "__main__":
if len(sys.argv) != 2:
if len(sys.argv) != ARGUMENT_NUMBER:
msg = "Specify base or main"
raise Exception(msg)
raise ValueError(msg)
build_type = sys.argv[1]
tag = create_tag(build_type)

View file

@ -1,3 +1,5 @@
#!/usr/bin/env python
import re
import sys
from pathlib import Path
@ -5,6 +7,7 @@ from pathlib import Path
import packaging.version
BASE_DIR = Path(__file__).parent.parent.parent
ARGUMENT_NUMBER = 2
def update_base_dep(pyproject_path: str, new_version: str) -> None:
@ -18,7 +21,7 @@ def update_base_dep(pyproject_path: str, new_version: str) -> None:
pattern = re.compile(r'langflow-base = \{ path = "\./src/backend/base", develop = true \}')
if not pattern.search(content):
msg = f'langflow-base poetry dependency not found in "{filepath}"'
raise Exception(msg)
raise ValueError(msg)
content = pattern.sub(replacement, content)
filepath.write_text(content, encoding="utf-8")
@ -28,16 +31,13 @@ def verify_pep440(version):
https://github.com/pypa/packaging/blob/16.7/packaging/version.py#L191
"""
try:
return packaging.version.Version(version)
except packaging.version.InvalidVersion:
raise
return packaging.version.Version(version)
def main() -> None:
if len(sys.argv) != 2:
if len(sys.argv) != ARGUMENT_NUMBER:
msg = "New version not specified"
raise Exception(msg)
raise ValueError(msg)
base_version = sys.argv[1]
# Strip "v" prefix from version if present

View file

@ -1,8 +1,11 @@
#!/usr/bin/env python
import re
import sys
from pathlib import Path
BASE_DIR = Path(__file__).parent.parent.parent
ARGUMENT_NUMBER = 3
def update_pyproject_name(pyproject_path: str, new_project_name: str) -> None:
@ -15,7 +18,7 @@ def update_pyproject_name(pyproject_path: str, new_project_name: str) -> None:
if not pattern.search(content):
msg = f'Project name not found in "{filepath}"'
raise Exception(msg)
raise ValueError(msg)
content = pattern.sub(new_project_name, content)
filepath.write_text(content, encoding="utf-8")
@ -39,15 +42,15 @@ def update_uv_dep(pyproject_path: str, new_project_name: str) -> None:
# Updates the dependency name for uv
if not pattern.search(content):
msg = f"{replacement} uv dependency not found in {filepath}"
raise Exception(msg)
raise ValueError(msg)
content = pattern.sub(replacement, content)
filepath.write_text(content, encoding="utf-8")
def main() -> None:
if len(sys.argv) != 3:
if len(sys.argv) != ARGUMENT_NUMBER:
msg = "Must specify project name and build type, e.g. langflow-nightly base"
raise Exception(msg)
raise ValueError(msg)
new_project_name = sys.argv[1]
build_type = sys.argv[2]

View file

@ -1,3 +1,5 @@
#!/usr/bin/env python
import re
import sys
from pathlib import Path
@ -5,6 +7,7 @@ from pathlib import Path
import packaging.version
BASE_DIR = Path(__file__).parent.parent.parent
ARGUMENT_NUMBER = 3
def update_pyproject_version(pyproject_path: str, new_version: str) -> None:
@ -17,7 +20,7 @@ def update_pyproject_version(pyproject_path: str, new_version: str) -> None:
if not pattern.search(content):
msg = f'Project version not found in "{filepath}"'
raise Exception(msg)
raise ValueError(msg)
content = pattern.sub(new_version, content)
@ -29,16 +32,13 @@ def verify_pep440(version):
https://github.com/pypa/packaging/blob/16.7/packaging/version.py#L191
"""
try:
return packaging.version.Version(version)
except packaging.version.InvalidVersion:
raise
return packaging.version.Version(version)
def main() -> None:
if len(sys.argv) != 3:
if len(sys.argv) != ARGUMENT_NUMBER:
msg = "New version not specified"
raise Exception(msg)
raise ValueError(msg)
new_version = sys.argv[1]
# Strip "v" prefix from version if present

View file

@ -1,8 +1,11 @@
#!/usr/bin/env python
import re
import sys
from pathlib import Path
BASE_DIR = Path(__file__).parent.parent.parent
ARGUMENT_NUMBER = 2
def update_uv_dep(base_version: str) -> None:
@ -19,7 +22,7 @@ def update_uv_dep(base_version: str) -> None:
# Check if the pattern is found
if not pattern.search(content):
msg = f"{pattern} UV dependency not found in {pyproject_path}"
raise Exception(msg)
raise ValueError(msg)
# Replace the matched pattern with the new one
content = pattern.sub(replacement, content)
@ -29,9 +32,9 @@ def update_uv_dep(base_version: str) -> None:
def main() -> None:
if len(sys.argv) != 2:
if len(sys.argv) != ARGUMENT_NUMBER:
msg = "specify base version"
raise Exception(msg)
raise ValueError(msg)
base_version = sys.argv[1]
base_version = base_version.lstrip("v")
update_uv_dep(base_version)

View file

@ -12,7 +12,7 @@ from pydantic import BaseModel
from langflow.base.tools.constants import TOOL_OUTPUT_NAME
from langflow.custom.tree_visitor import RequiredInputsVisitor
from langflow.field_typing import Tool # noqa: TCH001 Needed by add_toolkit_output
from langflow.field_typing import Tool # noqa: TCH001 Needed by _add_toolkit_output
from langflow.graph.state.model import create_state_model
from langflow.helpers.custom import format_type
from langflow.schema.artifact import get_artifact_type, post_process_raw

View file

@ -0,0 +1 @@
"""Version package."""

View file

@ -1,8 +1,11 @@
"""Module for package versioning."""
import contextlib
def get_version() -> str:
"""Retrieves the version of the package from a possible list of package names.
This accounts for after package names are updated for -nightly builds.
Returns:
@ -32,7 +35,9 @@ def get_version() -> str:
def is_pre_release(v: str) -> bool:
"""Returns a boolean indicating whether the version is a pre-release version,
"""Returns a boolean indicating whether the version is a pre-release version.
Returns a boolean indicating whether the version is a pre-release version,
as per the definition of a pre-release segment from PEP 440.
"""
return any(label in v for label in ["a", "b", "rc"])

View file

@ -28,7 +28,6 @@ from langflow.services.database.models.vertex_builds.crud import delete_vertex_b
from langflow.services.database.utils import session_getter
from langflow.services.deps import get_db_service
from loguru import logger
from pytest import LogCaptureFixture
from sqlmodel import Session, SQLModel, create_engine, select
from sqlmodel.pool import StaticPool
from typer.testing import CliRunner
@ -102,7 +101,7 @@ def _delete_transactions_and_vertex_builds(session, user: User):
@pytest.fixture
def caplog(caplog: LogCaptureFixture):
def caplog(caplog: pytest.LogCaptureFixture):
handler_id = logger.add(
caplog.handler,
format="{message}",
@ -144,7 +143,7 @@ def load_flows_dir():
@pytest.fixture(name="distributed_env")
def setup_env(monkeypatch):
def _setup_env(monkeypatch):
monkeypatch.setenv("LANGFLOW_CACHE_TYPE", "redis")
monkeypatch.setenv("LANGFLOW_REDIS_HOST", "result_backend")
monkeypatch.setenv("LANGFLOW_REDIS_PORT", "6379")
@ -158,7 +157,11 @@ def setup_env(monkeypatch):
@pytest.fixture(name="distributed_client")
def distributed_client_fixture(session: Session, monkeypatch, distributed_env):
def distributed_client_fixture(
session: Session, # noqa: ARG001
monkeypatch,
distributed_env, # noqa: ARG001
):
# Here we load the .env from ../deploy/.env
from langflow.core import celery_app
@ -273,7 +276,12 @@ def json_memory_chatbot_no_llm():
@pytest.fixture(name="client")
async def client_fixture(session: Session, monkeypatch, request, load_flows_dir):
async def client_fixture(
session: Session, # noqa: ARG001
monkeypatch,
request,
load_flows_dir,
):
# Set the database url to a test database
if "noclient" in request.keywords:
yield
@ -296,9 +304,11 @@ async def client_fixture(session: Session, monkeypatch, request, load_flows_dir)
db_service.database_url = f"sqlite:///{db_path}"
db_service.reload_engine()
# app.dependency_overrides[get_session] = get_session_override
async with LifespanManager(app, startup_timeout=None, shutdown_timeout=None) as manager:
async with AsyncClient(transport=ASGITransport(app=manager.app), base_url="http://testserver/") as client:
yield client
async with (
LifespanManager(app, startup_timeout=None, shutdown_timeout=None) as manager,
AsyncClient(transport=ASGITransport(app=manager.app), base_url="http://testserver/") as client,
):
yield client
# app.dependency_overrides.clear()
monkeypatch.undo()
# clear the temp db
@ -308,7 +318,7 @@ async def client_fixture(session: Session, monkeypatch, request, load_flows_dir)
# create a fixture for session_getter above
@pytest.fixture(name="session_getter")
def session_getter_fixture(client):
def session_getter_fixture(client): # noqa: ARG001
@contextmanager
def blank_session_getter(db_service: "DatabaseService"):
with Session(db_service.engine) as session:
@ -326,7 +336,7 @@ def runner():
async def test_user(client):
user_data = UserCreate(
username="testuser",
password="testpassword",
password="testpassword", # noqa: S106
)
response = await client.post("api/v1/users/", json=user_data.model_dump())
assert response.status_code == 201
@ -337,7 +347,7 @@ async def test_user(client):
@pytest.fixture
def active_user(client):
def active_user(client): # noqa: ARG001
db_manager = get_db_service()
with db_manager.with_session() as session:
user = User(
@ -375,7 +385,11 @@ async def logged_in_headers(client, active_user):
@pytest.fixture
def flow(client, json_flow: str, active_user):
def flow(
client, # noqa: ARG001
json_flow: str,
active_user,
):
from langflow.services.database.models.flow.model import FlowCreate
loaded_json = json.loads(json_flow)

View file

@ -7,7 +7,7 @@ class TestComponent(CustomComponent):
def refresh_values(self):
# This is a function that will be called every time the component is updated
# and should return a list of random strings
return [f"Random {random.randint(1, 100)}" for _ in range(5)]
return [f"Random {random.randint(1, 100)}" for _ in range(5)] # noqa: S311
def build_config(self):
return {"param": {"display_name": "Param", "options": self.refresh_values}}

View file

@ -16,7 +16,7 @@ class MultipleOutputsComponent(Component):
]
def certain_output(self) -> int:
return randint(0, self.number)
return randint(0, self.number) # noqa: S311
def other_output(self) -> int:
return self.certain_output()

View file

@ -8,7 +8,7 @@ class TestComponent(CustomComponent):
def refresh_values(self):
# This is a function that will be called every time the component is updated
# and should return a list of random strings
return [f"Random {random.randint(1, 100)}" for _ in range(5)]
return [f"Random {random.randint(1, 100)}" for _ in range(5)] # noqa: S311
def build_config(self):
return {"param": Input(display_name="Param", options=self.refresh_values)}

View file

@ -1,5 +1,6 @@
import pytest
from langflow.schema.message import Message
from tests.api_keys import get_openai_api_key
from tests.integration.utils import download_flow_from_github, run_json_flow

View file

@ -1,4 +1,5 @@
import pytest
from tests.integration.utils import run_single_component

View file

@ -6,6 +6,7 @@ from langchain_core.documents import Document
from langflow.components.embeddings import OpenAIEmbeddingsComponent
from langflow.components.vectorstores import AstraVectorStoreComponent
from langflow.schema.data import Data
from tests.api_keys import get_astradb_api_endpoint, get_astradb_application_token, get_openai_api_key
from tests.integration.components.mock_components import TextToData
from tests.integration.utils import ComponentInputHandle, run_single_component
@ -27,7 +28,7 @@ ALL_COLLECTIONS = [
@pytest.fixture
def astradb_client(request):
def astradb_client():
client = AstraDB(api_endpoint=get_astradb_api_endpoint(), token=get_astradb_application_token())
yield client
for collection in ALL_COLLECTIONS:

View file

@ -2,6 +2,7 @@ import pytest
from langflow.components.helpers.ParseJSONData import ParseJSONDataComponent
from langflow.components.inputs import ChatInput
from langflow.schema import Data
from tests.integration.components.mock_components import TextToData
from tests.integration.utils import ComponentInputHandle, run_single_component

View file

@ -2,6 +2,7 @@ import pytest
from langflow.components.inputs import ChatInput
from langflow.memory import get_messages
from langflow.schema.message import Message
from tests.integration.utils import run_single_component

View file

@ -1,6 +1,7 @@
import pytest
from langflow.components.inputs import TextInputComponent
from langflow.schema.message import Message
from tests.integration.utils import run_single_component

View file

@ -4,6 +4,7 @@ import pytest
from langflow.components.models.OpenAIModel import OpenAIModelComponent
from langflow.components.output_parsers.OutputParser import OutputParserComponent
from langflow.components.prompts.Prompt import PromptComponent
from tests.integration.utils import ComponentInputHandle, run_single_component

Some files were not shown because too many files have changed in this diff Show more