analyze-ci
Analyze failed GitHub Action jobs. Takes one or more GitHub URLs (job, workflow-run, or PR)…
Python coding and testing conventions for MLflow. Use when writing, modifying, or reviewing Python source files and tests in this repository.
$ npx -y skills add mlflow/mlflow --skill python-style --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/python-styleContext preview
The summary Claude sees to decide when to auto-load this skill.
Python coding and testing conventions for MLflow. Use when writing, modifying, or reviewing Python source files and tests in this repository.
name: python-style description: Python coding and testing conventions for MLflow. Use when writing, modifying, or reviewing Python source files and tests in this repository.
This guide documents Python coding conventions that go beyond what [ruff](https://docs.astral.sh/ruff/) and [clint](../../../dev/clint/) can enforce. The practices below require human judgment to implement correctly and improve code readability, maintainability, and testability across the MLflow codebase.
Omit docstrings that merely repeat the function name or provide no additional value. Function names should be self-documenting.
# Bad
def calculate_sum(a: int, b: int) -> int:
"""Calculate sum"""
return a + b
# Good
def calculate_sum(a: int, b: int) -> int:
return a + bWhen a parameter only accepts a fixed set of string values, use `typing.Literal` instead of a plain `str` type hint. This improves type-checking, enables IDE autocompletion, and documents allowed values at the type level.
# Bad
def f(app: str) -> None:
"""
Args:
app: Application type. Either "fastapi" or "flask".
"""
...
# Good
from typing import Literal
def f(app: Literal["fastapi", "flask"]) -> None:
"""
Args:
app: Application type. Either "fastapi" or "flask".
"""
...Wrap only the specific operations that can raise exceptions. Keep safe operations outside the try block to improve debugging and avoid masking unexpected errors.
# Bad
try:
never_fails()
can_fail()
except ...:
handle_error()
# Good
never_fails()
try:
can_fail()
except ...:
handle_error()Replace tuples with 3+ elements with named dataclasses. This improves code clarity, prevents positional argument errors, and enables type checking on individual fields.
# Bad
def get_user() -> tuple[str, int, str]:
return "Alice", 30, "Engineer"
# Good
from dataclasses import dataclass
@dataclass
class User:
name: str
age: int
occupation: str
def get_user() -> User:
return User(name="Alice", age=30, occupation="Engineer")When you have a `pathlib.Path` object, use its built-in methods instead of `os` module functions. This is more readable, type-safe, and follows object-oriented principles.
from pathlib import Path
path = Path("some/file.txt")
# Bad
import os
os.path.exists(path)
os.remove(path)
# Good
path.exists()
path.unlink()Avoid converting `pathlib.Path` objects to strings when passing them to `subprocess` functions. Modern Python (3.8+) accepts Path objects directly, making the code cleaner and more type-safe.
import subprocess
from pathlib import Path
path = Path("some/script.py")
# Bad
subprocess.check_call(["foo", "bar", str(path)])
# Good
subprocess.check_call(["foo", "bar", path])Use the `next()` builtin function with a generator expression to find the first item that matches a condition. This is more concise and functional than manually looping with break statements.
# Bad
result = None
for item in items:
if item.name == "target":
result = item
break
# Good
result = next((item for item in items if item.name == "target"), None)Pattern matching is preferred for string splitting (replaces unsafe unpacking), nested dict access (replaces chained `.get()` calls), and list length dispatch (replaces verbose length checks).
# Bad
a, b = some_str.split(".")
# Good
match some_str.split("."):
case [a, b]:
...
case _:
raise ValueError(f"Invalid format: {some_str!r}")# Bad
def f(data):
return data.get("data", {}).get("repository", {}).get("pullRequest", {}).get("nodes", [])
# Good
def f(data):
match data:
case {"data": {"repository": {"pullRequest": {"nodes": nodes}}}}:
return nodes
case _:
return []# Bad
def f(items):
if len(items) == 0:
raise ValueError("No results found")
elif len(items) == 1:
return items[0].id
else:
raise ValueError("Multiple results found")
# Good
def f(items):
match items:
case []:
raise ValueError("No results found")
case [item]:
return item.id
case _:
raise ValueError("Multiple results found")Every mocked function must have an assertion (`assert_called`, `assert_called_once`, etc.) to verify it was invoked correctly. Without assertions, tests may pass even when the mocked code isn't executed.
from unittest import mock
# Bad
def test_foo():
with mock.patch("foo.bar"):
calls_bar()
# Good
def test_bar():
with mock.patch("foo.bar") as mock_bar:
calls_bar()
mock_bar.assert_called_once()Define `return_value` and `side_effect` directly in the `patch()` call rather than assigning them afterward. This keeps mock configuration explicit and reduces setup code.
from unittest import mock
# Bad
def test_foo():
with mock.patch("foo.bar") as mock_bar:
mock_bar.return_value = 42
calls_bar()
with mock.patch("foo.bar") as mock_bar:
mock_bar.side_effect = Exception("Error")
calls_bar()
# Good
def test_foo():
with mock.patch("foo.bar", return_value=42) as mock_bar:
calls_bar()
with mock.patch("foo.bar", side_efThe open source AI engineering platform for agents, LLMs, and ML models. MLflow enables teams of all sizes to debug, evaluate, monitor, and optimize production-quality AI applications while controlling costs and managing access to models and data.
Repo: mlflow/mlflow
Analyze failed GitHub Action jobs. Takes one or more GitHub URLs (job, workflow-run, or PR)…
GitHub Actions workflow and composite action conventions for MLflow. Use when writing,…
Review a pull request and emit a validated review payload.
Review a GitHub PR's UI/UX changes by launching the MLflow web app, driving a headless…
Upload one or more local images or videos to GitHub and get back a `user-attachments` URL for…
Configure MLflow tracing for Claude Code.