Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
22fda8c
Cleanup the traditional ML landing page (#18799)
BenWilson2 Nov 13, 2025
aa67507
Clean up SparkML docs (#18811)
BenWilson2 Nov 13, 2025
93dab38
Update support URL to use UI bug report template (#18828)
harupy Nov 14, 2025
66be5b6
Remove deprecated diviner flavor (#18808)
Copilot Nov 14, 2025
0fecdbe
Remove log file (#18837)
daniellok-db Nov 14, 2025
4ae8654
Infer Python version from repository pyproject.toml for dev versions …
harupy Nov 14, 2025
08eb07d
Fix misleading error message for `mlflow.start_run` (#18798)
WeichenXu123 Nov 14, 2025
e3fc54a
Conditionally collapse changed-pages section in preview comments when…
Copilot Nov 14, 2025
ada5c06
Remove cache-pip from flavors job using uv (#18846)
Copilot Nov 14, 2025
10a7c79
Handle CrewAI v1 in CI (#18786)
B-Step62 Nov 14, 2025
da4a411
Fix Semantic Kernel tracing cross version test (#18787)
B-Step62 Nov 14, 2025
abd8bd6
Cleanup Prophet docs (#18814)
BenWilson2 Nov 14, 2025
1b00127
Fix langchain js doc (#18845)
B-Step62 Nov 14, 2025
5cdb505
Fix Bedrock Anthropic adapter by adding required `anthropic_version` …
harupy Nov 15, 2025
98dd373
Fix Click 8.3.0 `Sentinel.UNSET` handling in MCP server (#18858)
harupy Nov 17, 2025
c52bd16
Fix race condition in `test_prompt_webhook_with_mixed_events` (#18859)
harupy Nov 17, 2025
98b7dd6
Use `sys.executable` in `test_mcp.py` instead of hardcoded `"python"`…
Copilot Nov 17, 2025
c915029
Support attribute translation for Vercel spans (#18782)
B-Step62 Nov 17, 2025
fd7e5f8
Add lint rule to flag `subprocess.run` with only `check=True` (#18861)
Copilot Nov 17, 2025
abfc2f1
Update Python versions in setup-python action to match GitHub-hosted …
Copilot Nov 17, 2025
9983c5c
Update `uv.lock` (#18866)
mlflow-app[bot] Nov 17, 2025
c8adda9
Add auth support for scorers (#18699)
BenWilson2 Nov 17, 2025
5157267
Cleanup torch docs (#18816)
BenWilson2 Nov 17, 2025
c3b06bc
Fix evaluate_traces MCP tool error: use result_df instead of tables (…
alkispoly-db Nov 17, 2025
8d21be3
Replace deprecated with_mock with with_mocked_bindings in R tests (#1…
harupy Nov 18, 2025
5e0e5e4
Record usage event when traces logged to MLflow server (#18822)
dbczumar Nov 18, 2025
dc1c148
Speed up R tests by using uv as env-manager instead of virtualenv (#1…
Copilot Nov 18, 2025
aae3db2
Use SQLite as default unless existing mlruns data is detected (#18497)
harupy Nov 18, 2025
46f1d49
Fix llama-index cross version test (#18885)
daniellok-db Nov 18, 2025
08f8f35
Fix CLI link missing api_reference prefix in documentation sidebars (…
Copilot Nov 18, 2025
c48fb20
Pin database Docker images and show digests in CI (#18903)
harupy Nov 19, 2025
2197e41
Add @joelrobin18 to core members list (#18904)
daniellok-db Nov 19, 2025
b42e3c8
[ML-59303] Support multiturn judge creation with make_judge api and d…
xsh310 Nov 19, 2025
36649f4
get_trace support for stores (#18556)
serena-ruan Nov 19, 2025
2694e73
Fix attributes encoding issue (#18780)
serena-ruan Nov 19, 2025
edddb7a
Refactor get_trace_artifact_handler for better readability (#18914)
harupy Nov 19, 2025
dc8d4ef
Fix: correctly associate SqlLoggedModelMetric with experiment_id (#18…
mcompen Nov 19, 2025
788321f
update basic auth docs: default admin password: passwrod -> password1…
UnfixedMold Nov 19, 2025
2218466
Unify batch_get_traces signatures to make location parameter optional…
Copilot Nov 19, 2025
046e211
Add back `tables` property back to the evaluation result (#18879)
B-Step62 Nov 19, 2025
1f0b624
Add workspace database schema
mprahl Nov 18, 2025
23c8fd8
Add workspace CRUD support
mprahl Nov 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/actions/setup-python/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ runs:
fi
if [[ "$python_version" == "3.10" ]]; then
if [ ${{ runner.os }} == "Linux" ]; then
python_version="3.10.16"
python_version="3.10.19"
else
python_version="3.10.11"
fi
elif [[ "$python_version" == "3.11" ]]; then
if [ ${{ runner.os }} == "Windows" ]; then
python_version="3.11.8"
python_version="3.11.9"
else
python_version="3.11.8"
python_version="3.11.14"
fi
else
echo "Invalid python version: '$python_version'. Must be '3.10', or '3.11'."
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/master.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ jobs:
- name: Build
run: |
./tests/db/compose.sh pull -q postgresql mysql mssql
docker images
docker images --digests
./tests/db/compose.sh build --build-arg DEPENDENCIES="$(python dev/extract_deps.py)"
- name: Run tests
run: |
Expand Down Expand Up @@ -199,7 +199,6 @@ jobs:
- uses: ./.github/actions/setup-python
- uses: ./.github/actions/setup-pyenv
- uses: ./.github/actions/setup-java
- uses: ./.github/actions/cache-pip
- name: Install dependencies
run: |
uv sync --extra extras
Expand Down
13 changes: 12 additions & 1 deletion .github/workflows/preview-comment.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,10 @@ function getCommentTemplate({

if (changedPages && changedPages.length > 0) {
const pageLinks = changedPages.map(({ link, status }) => `- ${link} (${status})`).join("\n");
changedPagesSection = `

// Only collapse if there are more than 5 changed pages
if (changedPages.length > 5) {
changedPagesSection = `

<details>
<summary>Changed Pages (${changedPages.length})</summary>
Expand All @@ -138,6 +141,14 @@ ${pageLinks}

</details>
`;
} else {
changedPagesSection = `

**Changed Pages (${changedPages.length})**

${pageLinks}
`;
}
}

return `
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ MLflow is currently maintained by the following core members with significant co
- [Daniel Lok](https://github.com/daniellok-db)
- [Gabriel Fu](https://github.com/gabrielfu)
- [Harutaka Kawamura](https://github.com/harupy)
- [Joel Robin P](https://github.com/joelrobin18)
- [Serena Ruan](https://github.com/serena-ruan)
- [Tomu Hirata](https://github.com/TomeHirata)
- [Weichen Xu](https://github.com/WeichenXu123)
Expand Down
3 changes: 3 additions & 0 deletions dev/clint/src/clint/linter.py
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,9 @@ def visit_Call(self, node: ast.Call) -> None:
if rules.IsinstanceUnionSyntax.check(node):
self._check(Range.from_node(node), rules.IsinstanceUnionSyntax())

if rules.SubprocessCheckCall.check(node, self.resolver):
self._check(Range.from_node(node), rules.SubprocessCheckCall())

if self._is_in_test() and rules.OsChdirInTest.check(node, self.resolver):
self._check(Range.from_node(node), rules.OsChdirInTest())

Expand Down
2 changes: 2 additions & 0 deletions dev/clint/src/clint/rules/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from clint.rules.os_environ_set_in_test import OsEnvironSetInTest
from clint.rules.pytest_mark_repeat import PytestMarkRepeat
from clint.rules.redundant_test_docstring import RedundantTestDocstring
from clint.rules.subprocess_check_call import SubprocessCheckCall
from clint.rules.temp_dir_in_test import TempDirInTest
from clint.rules.test_name_typo import TestNameTypo
from clint.rules.thread_pool_executor_without_thread_name_prefix import (
Expand Down Expand Up @@ -85,6 +86,7 @@
"OsEnvironSetInTest",
"PytestMarkRepeat",
"RedundantTestDocstring",
"SubprocessCheckCall",
"TempDirInTest",
"TestNameTypo",
"ThreadPoolExecutorWithoutThreadNamePrefix",
Expand Down
43 changes: 43 additions & 0 deletions dev/clint/src/clint/rules/subprocess_check_call.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import ast

from clint.resolver import Resolver
from clint.rules.base import Rule


class SubprocessCheckCall(Rule):
def _message(self) -> str:
return (
"Use `subprocess.check_call(...)` instead of `subprocess.run(..., check=True)` "
"for better readability. Only applies when check=True is the only keyword argument."
)

@staticmethod
def check(node: ast.Call, resolver: Resolver) -> bool:
"""
Returns True if `node` is `subprocess.run(..., check=True)` with no other keyword arguments.
"""
resolved = resolver.resolve(node)

# Check if this is subprocess.run
if resolved != ["subprocess", "run"]:
return False

# Check if there are any keyword arguments
if not node.keywords:
return False

# Check if the only keyword argument is check=True
if len(node.keywords) != 1:
return False

keyword = node.keywords[0]

# Check if the keyword is 'check' (not **kwargs)
if keyword.arg != "check":
return False

# Check if the value is True
if not isinstance(keyword.value, ast.Constant):
return False

return keyword.value.value is True
28 changes: 28 additions & 0 deletions dev/clint/tests/rules/test_subprocess_check_call.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from pathlib import Path

from clint.config import Config
from clint.linter import Position, Range, lint_file
from clint.rules import SubprocessCheckCall


def test_subprocess_check_call(index_path: Path) -> None:
code = """
import subprocess

# Bad
subprocess.run(["echo", "hello"], check=True)

# Good - has other kwargs
subprocess.run(["echo", "hello"], check=True, text=True)

# Good - check_call
subprocess.check_call(["echo", "hello"])

# Good - no check
subprocess.run(["echo", "hello"])
"""
config = Config(select={SubprocessCheckCall.name})
results = lint_file(Path("test.py"), code, config, index_path)
assert len(results) == 1
assert isinstance(results[0].rule, SubprocessCheckCall)
assert results[0].range == Range(Position(4, 0))
6 changes: 2 additions & 4 deletions dev/create_release_tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,8 @@

def main(new_version: str, remote: str, dry_run: bool = False):
release_tag = f"v{new_version}"
subprocess.run(["git", "tag", release_tag], check=True)
subprocess.run(
["git", "push", remote, release_tag, *(["--dry-run"] if dry_run else [])], check=True
)
subprocess.check_call(["git", "tag", release_tag])
subprocess.check_call(["git", "push", remote, release_tag, *(["--dry-run"] if dry_run else [])])


if __name__ == "__main__":
Expand Down
55 changes: 50 additions & 5 deletions dev/set_matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ class PackageInfo(BaseModel):
install_dev: str | None = None
module_name: str | None = None
genai: bool = False
repo: str | None = None


class TestConfig(BaseModel):
Expand Down Expand Up @@ -340,11 +341,49 @@ def _requires_python(package: str, version: str) -> str | None:
return None


def infer_python_version(package: str, version: str) -> str:
def _requires_python_from_repo(repo_url: str) -> str | None:
"""
Fetch requires-python from repository's pyproject.toml for dev version inference.
"""
match = re.match(r"https://github\.com/([^/]+/[^/]+)/tree/HEAD(?:/(.+))?", repo_url)
if not match:
raise ValueError(f"Invalid GitHub repository URL format: {repo_url}")

owner_repo = match.group(1)
subpath = match.group(2) or ""
pyproject_path = f"{subpath}/pyproject.toml" if subpath else "pyproject.toml"
raw_url = f"https://raw.githubusercontent.com/{owner_repo}/HEAD/{pyproject_path}"

print(f"Fetching pyproject.toml from {owner_repo} (path: {pyproject_path})", file=sys.stderr)

try:
resp = requests.get(raw_url, timeout=10)
resp.raise_for_status()
except requests.HTTPError as e:
if e.response.status_code == 404:
print(f" pyproject.toml not found at {raw_url}", file=sys.stderr)
return None
raise

if match := re.search(r'requires-python\s*=\s*["\']([^"\']+)["\']', resp.text):
print(f" Found requires-python: {match.group(1)}", file=sys.stderr)
return match.group(1)

print(" requires-python field not found in pyproject.toml", file=sys.stderr)
return None


def infer_python_version(package: str, version: str, repo_url: str | None = None) -> str:
"""
Infer the minimum Python version required by the package.
"""
candidates = ("3.10", "3.11")

if version == DEV_VERSION and repo_url:
if rp := _requires_python_from_repo(repo_url):
spec = SpecifierSet(rp)
return next(filter(spec.contains, candidates), candidates[0])

if rp := _requires_python(package, version):
spec = SpecifierSet(rp)
return next(filter(spec.contains, candidates), candidates[0])
Expand All @@ -368,11 +407,13 @@ def _find_matches(spec: dict[str, T], version: str) -> Iterator[T]:
yield val


def get_python_version(python: dict[str, str] | None, package: str, version: str) -> str:
def get_python_version(
python: dict[str, str] | None, package: str, version: str, repo_url: str | None = None
) -> str:
if python and (match := next(_find_matches(python, version), None)):
return match

return infer_python_version(package, version)
return infer_python_version(package, version, repo_url)


def get_runs_on(runs_on: dict[str, str] | None, version: str) -> str:
Expand Down Expand Up @@ -621,7 +662,9 @@ def expand_config(config: dict[str, Any], *, is_ref: bool = False) -> set[Matrix
requirements.extend(get_matched_requirements(cfg.requirements or {}, str(ver)))
install = make_pip_install_command(requirements)
run = remove_comments(cfg.run)
python = get_python_version(cfg.python, package_info.pip_release, str(ver))
python = get_python_version(
cfg.python, package_info.pip_release, str(ver), package_info.repo
)
runs_on = get_runs_on(cfg.runs_on, ver)
java = get_java_version(cfg.java, str(ver))

Expand Down Expand Up @@ -674,7 +717,9 @@ def expand_config(config: dict[str, Any], *, is_ref: bool = False) -> set[Matrix
install = make_pip_install_command(requirements) + "\n" + install_dev
else:
install = install_dev
python = get_python_version(cfg.python, package_info.pip_release, DEV_VERSION)
python = get_python_version(
cfg.python, package_info.pip_release, DEV_VERSION, package_info.repo
)
runs_on = get_runs_on(cfg.runs_on, DEV_VERSION)
java = get_java_version(cfg.java, DEV_VERSION)

Expand Down
19 changes: 14 additions & 5 deletions docs/api_reference/api_inventory.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ mlflow.client.MlflowClient.delete_tag
mlflow.client.MlflowClient.delete_trace_tag
mlflow.client.MlflowClient.delete_traces
mlflow.client.MlflowClient.delete_webhook
mlflow.client.MlflowClient.delete_workspace
mlflow.client.MlflowClient.detach_prompt_from_run
mlflow.client.MlflowClient.download_artifacts
mlflow.client.MlflowClient.end_span
Expand All @@ -84,6 +85,8 @@ mlflow.client.MlflowClient.get_registered_model
mlflow.client.MlflowClient.get_run
mlflow.client.MlflowClient.get_trace
mlflow.client.MlflowClient.get_webhook
mlflow.client.MlflowClient.get_workspace
mlflow.client.MlflowClient.get_workspace_uri
mlflow.client.MlflowClient.link_prompt_version_to_model
mlflow.client.MlflowClient.link_prompt_version_to_run
mlflow.client.MlflowClient.link_prompt_versions_to_trace
Expand All @@ -92,6 +95,7 @@ mlflow.client.MlflowClient.list_artifacts
mlflow.client.MlflowClient.list_logged_model_artifacts
mlflow.client.MlflowClient.list_logged_prompts
mlflow.client.MlflowClient.list_webhooks
mlflow.client.MlflowClient.list_workspaces
mlflow.client.MlflowClient.load_prompt
mlflow.client.MlflowClient.load_table
mlflow.client.MlflowClient.log_artifact
Expand Down Expand Up @@ -146,6 +150,7 @@ mlflow.client.MlflowClient.update_model_version
mlflow.client.MlflowClient.update_registered_model
mlflow.client.MlflowClient.update_run
mlflow.client.MlflowClient.update_webhook
mlflow.client.MlflowClient.update_workspace
mlflow.config.disable_system_metrics_logging
mlflow.config.enable_async_logging
mlflow.config.enable_system_metrics_logging
Expand Down Expand Up @@ -290,11 +295,6 @@ mlflow.deployments.openai.OpenAIDeploymentClient
mlflow.deployments.run_local
mlflow.deployments.set_deployments_target
mlflow.disable_system_metrics_logging
mlflow.diviner.get_default_conda_env
mlflow.diviner.get_default_pip_requirements
mlflow.diviner.load_model
mlflow.diviner.log_model
mlflow.diviner.save_model
mlflow.doctor
mlflow.dspy.autolog
mlflow.dspy.load_model
Expand Down Expand Up @@ -533,6 +533,7 @@ mlflow.entities.WebhookStatus.to_proto
mlflow.entities.WebhookTestResult
mlflow.entities.WebhookTestResult.from_proto
mlflow.entities.WebhookTestResult.to_proto
mlflow.entities.Workspace
mlflow.entities.assessment.Assessment
mlflow.entities.assessment.Expectation
mlflow.entities.assessment.Feedback
Expand Down Expand Up @@ -632,6 +633,7 @@ mlflow.entities.webhook.Webhook
mlflow.entities.webhook.WebhookEvent
mlflow.entities.webhook.WebhookStatus
mlflow.entities.webhook.WebhookTestResult
mlflow.entities.workspace.Workspace
mlflow.evaluate
mlflow.exceptions.get_error_code
mlflow.finalize_logged_model
Expand Down Expand Up @@ -1185,15 +1187,19 @@ mlflow.sentence_transformers.save_model
mlflow.server.auth.client.AuthServiceClient
mlflow.server.auth.client.AuthServiceClient.create_experiment_permission
mlflow.server.auth.client.AuthServiceClient.create_registered_model_permission
mlflow.server.auth.client.AuthServiceClient.create_scorer_permission
mlflow.server.auth.client.AuthServiceClient.create_user
mlflow.server.auth.client.AuthServiceClient.delete_experiment_permission
mlflow.server.auth.client.AuthServiceClient.delete_registered_model_permission
mlflow.server.auth.client.AuthServiceClient.delete_scorer_permission
mlflow.server.auth.client.AuthServiceClient.delete_user
mlflow.server.auth.client.AuthServiceClient.get_experiment_permission
mlflow.server.auth.client.AuthServiceClient.get_registered_model_permission
mlflow.server.auth.client.AuthServiceClient.get_scorer_permission
mlflow.server.auth.client.AuthServiceClient.get_user
mlflow.server.auth.client.AuthServiceClient.update_experiment_permission
mlflow.server.auth.client.AuthServiceClient.update_registered_model_permission
mlflow.server.auth.client.AuthServiceClient.update_scorer_permission
mlflow.server.auth.client.AuthServiceClient.update_user_admin
mlflow.server.auth.client.AuthServiceClient.update_user_password
mlflow.server.auth.entities.ExperimentPermission
Expand All @@ -1202,6 +1208,9 @@ mlflow.server.auth.entities.ExperimentPermission.to_json
mlflow.server.auth.entities.RegisteredModelPermission
mlflow.server.auth.entities.RegisteredModelPermission.from_json
mlflow.server.auth.entities.RegisteredModelPermission.to_json
mlflow.server.auth.entities.ScorerPermission
mlflow.server.auth.entities.ScorerPermission.from_json
mlflow.server.auth.entities.ScorerPermission.to_json
mlflow.server.auth.entities.User
mlflow.server.auth.entities.User.from_json
mlflow.server.auth.entities.User.to_json
Expand Down
7 changes: 0 additions & 7 deletions docs/api_reference/source/python_api/mlflow.diviner.rst

This file was deleted.

Loading
Loading