diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index ae068cd0680e0..2d24e7868720a 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -38,6 +38,7 @@ env: MLFLOW_HOME: ${{ github.workspace }} MLFLOW_CONDA_HOME: /usr/share/miniconda PIP_EXTRA_INDEX_URL: https://download.pytorch.org/whl/cpu + PIP_CONSTRAINT: ${{ github.workspace }}/requirements/constraints.txt PYTHONFAULTHANDLER: "1" jobs: @@ -123,9 +124,9 @@ jobs: run: | REPO="${{ github.repository }}" PR_NUMBER="${{ github.event.pull_request.number }}" - CHANGED_FILES=$(python dev/list_changed_files.py --repository $REPO --pr-num $PR_NUMBER | grep "Dockerfile\|\.dockerignore" || true); - DOCKER_CHANGED=$([[ ! -z "$CHANGED_FILES" ]] && echo "true" || echo "false") - echo -e "CHANGED_FILES:\nCHANGED_FILES" + CHANGED_FILES=$(python dev/list_changed_files.py --repository $REPO --pr-num $PR_NUMBER | grep -E '^(Dockerfile|\.dockerignore)$' || true) + DOCKER_CHANGED=$([[ -n "$CHANGED_FILES" ]] && echo "true" || echo "false") + echo -e "CHANGED_FILES:\n$CHANGED_FILES" echo "DOCKER_CHANGED: $DOCKER_CHANGED" echo "docker_changed=$DOCKER_CHANGED" >> $GITHUB_OUTPUT diff --git a/examples/mlflow_artifacts/docker-compose.yml b/examples/mlflow_artifacts/docker-compose.yml index a8976b60eb1d9..2a09d4f566c08 100644 --- a/examples/mlflow_artifacts/docker-compose.yml +++ b/examples/mlflow_artifacts/docker-compose.yml @@ -1,7 +1,7 @@ version: "3" services: minio: - image: minio/minio + image: quay.io/minio/minio:RELEASE.2024-12-18T13-15-44Z expose: - "9000" ports: @@ -20,7 +20,7 @@ services: command: server /data --console-address ":9001" minio-create-bucket: - image: minio/mc + image: quay.io/minio/mc:RELEASE.2024-11-21T17-21-54Z depends_on: minio: condition: service_healthy diff --git a/mlflow/R/mlflow/Dockerfile.dev b/mlflow/R/mlflow/Dockerfile.dev index d673f73f4741f..7d7de1a6408c0 100644 --- a/mlflow/R/mlflow/Dockerfile.dev +++ b/mlflow/R/mlflow/Dockerfile.dev @@ -1,9 +1,8 @@ -# Our internal Jenkins job can't build an image from rocker/r-ver:>=4.2.2 (which is based on Ubuntu 22.04). -FROM rocker/r-ver:4.2.1 +FROM rocker/r-ver:4.4.2 WORKDIR /mlflow/mlflow/R/mlflow RUN apt-get update -y -RUN apt-get install lsb-release git wget libxml2-dev libgit2-dev -y +RUN apt-get install lsb-release git wget libxml2-dev libgit2-dev libcurl4-openssl-dev libuv1 -y # Install miniforge RUN wget https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh -O ~/miniforge.sh diff --git a/mlflow/sentence_transformers/__init__.py b/mlflow/sentence_transformers/__init__.py index 099fdbacdb61b..82ac5b8c4c866 100644 --- a/mlflow/sentence_transformers/__init__.py +++ b/mlflow/sentence_transformers/__init__.py @@ -524,9 +524,13 @@ def predict(self, sentences, params: dict[str, Any] | None = None): # Wrap the output to OpenAI format only when the input is dict `{"input": ... }` if self.task and list(sentences.columns)[0] == _LLM_V1_EMBEDDING_INPUT_KEY: convert_output_to_llm_v1_format = True - sentences = sentences.iloc[:, 0] - if type(sentences[0]) == list: + # `model.encode` rejects `pd.Series`/`DataFrame` since sentence-transformers v5.4 + # (https://github.com/huggingface/sentence-transformers/pull/3554) + sentences = sentences.iloc[:, 0].tolist() + if sentences and type(sentences[0]) == list: sentences = sentences[0] + elif type(sentences) == pd.Series: + sentences = sentences.tolist() # The encode API has additional parameters that we can add as kwargs. # See https://www.sbert.net/docs/package_reference/SentenceTransformer.html#sentence_transformers.SentenceTransformer.encode diff --git a/requirements/extra-ml-requirements.txt b/requirements/extra-ml-requirements.txt index 362d28931ed98..6143bfc0d294b 100644 --- a/requirements/extra-ml-requirements.txt +++ b/requirements/extra-ml-requirements.txt @@ -6,6 +6,7 @@ spacy>=3.3.0,<3.8 # Required by mlflow.tensorflow tensorflow>=2.10.0; platform_system!="Darwin" or platform_machine!="arm64" tensorflow-macos>=2.10.0; platform_system=="Darwin" and platform_machine=="arm64" +tensorboard # Required by mlflow.pytorch torch>=1.11.0 torchvision>=0.12.0 diff --git a/tests/server/auth/test_auth.py b/tests/server/auth/test_auth.py index 618dd828433e0..f894c84a5e00f 100644 --- a/tests/server/auth/test_auth.py +++ b/tests/server/auth/test_auth.py @@ -363,15 +363,15 @@ def test_create_and_delete_registered_model(client, monkeypatch): assert rm.name == "test_model" -def _wait(url: str): +def _wait(url: str, timeout: int = 10) -> None: t = time.time() - while time.time() - t < 5: + while time.time() - t < timeout: try: if requests.get(f"{url}/health").ok: - yield + return except requests.exceptions.ConnectionError: pass - time.sleep(1) + time.sleep(0.5) pytest.fail("Server did not start") @@ -412,8 +412,7 @@ def test_proxy_log_artifacts(monkeypatch, tmp_path): ) as prc: try: url = f"http://{host}:{port}" - for _ in _wait(url): - break + _wait(url) mlflow.set_tracking_uri(url) client = MlflowClient(url) diff --git a/tests/tracking/test_mlflow_artifacts.py b/tests/tracking/test_mlflow_artifacts.py index 99fcf54ccc446..09adbffdc29dc 100644 --- a/tests/tracking/test_mlflow_artifacts.py +++ b/tests/tracking/test_mlflow_artifacts.py @@ -17,6 +17,7 @@ MLFLOW_WORKSPACE, MLFLOW_WORKSPACE_STORE_URI, ) +from mlflow.store.tracking.sqlalchemy_store import SqlAlchemyStore from mlflow.utils.os import is_windows from tests.helper_functions import LOCALHOST, get_safe_port @@ -68,6 +69,9 @@ def artifacts_server(): artifacts_destination = os.path.join(tmpdir, "mlartifacts") url = f"http://{LOCALHOST}:{port}" default_artifact_root = f"{url}/api/2.0/mlflow-artifacts/artifacts" + # Initialize the database before launching the server process + s = SqlAlchemyStore(backend_store_uri, default_artifact_root) + s.engine.dispose() process = _launch_server( LOCALHOST, port,