Skip to main content

sniff/
roles_python_names.rs

1pub fn is_python_identifier_like(text: &str) -> bool {
2    let mut chars = text.chars();
3    match chars.next() {
4        Some(first) if first == '_' || first.is_ascii_alphabetic() => {}
5        _ => return false,
6    }
7    chars.all(|ch| ch == '_' || ch.is_ascii_alphanumeric())
8}
9
10pub fn is_python_alias_export_assignment(trimmed: &str) -> bool {
11    let Some((lhs, rhs)) = trimmed.split_once('=') else {
12        return false;
13    };
14    if trimmed.contains("==") || trimmed.contains("!=") {
15        return false;
16    }
17    let lhs = lhs.trim();
18    let rhs = rhs.trim().trim_end_matches(',').trim();
19    let target = lhs
20        .split_once(':')
21        .map(|(name, _)| name)
22        .unwrap_or(lhs)
23        .trim();
24    if !is_python_identifier_like(target) || rhs.is_empty() {
25        return false;
26    }
27    if rhs.contains('(')
28        || rhs.contains(')')
29        || rhs.contains('[')
30        || rhs.contains(']')
31        || rhs.contains('{')
32        || rhs.contains('}')
33    {
34        return false;
35    }
36    let mut saw_dot = false;
37    for part in rhs.split('.') {
38        if part.is_empty() || !is_python_identifier_like(part) {
39            return false;
40        }
41        saw_dot = saw_dot || rhs.contains('.');
42    }
43    saw_dot || is_python_identifier_like(rhs)
44}