Repository: astral-sh/ruff
File: crates/ruff_linter/src/rules/airflow/rules/function_signature_change_in_3.rs (Rust)

Code before:
///
/// ## Why is this bad?
/// Airflow 3.0 might introduce changes to function signatures. Code that
/// worked in Airflow 2.x may raise a runtime error if not updated in Airflow
/// 3.0.
///
/// ## Example
/// ```python
/// from airflow.lineage.hook import HookLineageCollector
///
/// collector = HookLineageCollector()
/// # Passing positional arguments will raise a runtime error in Airflow 3.0
/// collector.create_asset("s3://bucket/key")
/// ```
///
/// Use instead:
/// ```python
/// from airflow.lineage.hook import HookLineageCollector
///
/// collector = HookLineageCollector()
/// # Passing arguments as keyword arguments instead of positional arguments
/// collector.create_asset(uri="s3://bucket/key")
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "0.14.11")]
pub(crate) struct Airflow3FunctionSignatureChange {
    function_name: String,
    change_type: FunctionSignatureChangeType,
}

impl Violation for Airflow3FunctionSignatureChange {
    const FIX_AVAILABILITY: FixAvailability = FixAvailability::None;

    #[derive_message_formats]
    fn message(&self) -> String {
        let Airflow3FunctionSignatureChange {
            function_name,
            change_type,
        } = self;
        match change_type {
            FunctionSignatureChangeType::KeywordOnly { .. } => {
                format!("`{function_name}` only accepts keyword arguments in Airflow 3.0")
            }
        }
    }

    fn fix_title(&self) -> Option<String> {
        let Airflow3FunctionSignatureChange { change_type, .. } = self;
        match change_type {
            FunctionSignatureChangeType::KeywordOnly { message } => Some(message.to_string()),
        }

Review comment (suggestion):
I don't think this name quite aligns with our [naming conventions](https://docs.astral.sh/ruff/contributing/#rule-naming-convention), specifically

> Ruff's rule names should make grammatical and logical sense when read as "allow ${rule}" or "allow ${rule} items", as in the context of suppression comments

but I'm not coming up with a great alternative either. Maybe something like `Airflow3IncompatibleFunctionSignature` or `Airflow3IncompatibleCall`?

I'm okay with what you have now if it sounds better to you, though.

Code after:
///
/// ## Why is this bad?
/// Airflow 3.0 introduces changes to function signatures. Code that
/// worked in Airflow 2.x will raise a runtime error if not updated in Airflow
/// 3.0.
///
/// ## Example
/// ```python
/// from airflow.lineage.hook import HookLineageCollector
///
/// collector = HookLineageCollector()
/// # Passing positional arguments will raise a runtime error in Airflow 3.0
/// collector.create_asset("s3://bucket/key")
/// ```
///
/// Use instead:
/// ```python
/// from airflow.lineage.hook import HookLineageCollector
///
/// collector = HookLineageCollector()
/// # Passing arguments as keyword arguments instead of positional arguments
/// collector.create_asset(uri="s3://bucket/key")
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(preview_since = "0.14.11")]
pub(crate) struct Airflow3IncompatibleFunctionSignature {
    function_name: String,
    change_type: FunctionSignatureChangeType,
}

impl Violation for Airflow3IncompatibleFunctionSignature {
    const FIX_AVAILABILITY: FixAvailability = FixAvailability::None;

    #[derive_message_formats]
    fn message(&self) -> String {
        let Airflow3IncompatibleFunctionSignature {
            function_name,
            change_type,
        } = self;
        match change_type {
            FunctionSignatureChangeType::KeywordOnly { .. } => {
                format!("`{function_name}` signature is changed in Airflow 3.0")
            }
        }
    }

    fn fix_title(&self) -> Option<String> {
        let Airflow3IncompatibleFunctionSignature { change_type, .. } = self;
        match change_type {
            FunctionSignatureChangeType::KeywordOnly { message } => Some(message.to_string()),
        }