fix: project name auto-detect, module docstrings, dataclass critical threshold #2

Merged
Arkasha merged 2 commits from feature/improvements-v2 into main 2026-02-15 11:37:24 +03:00
Showing only changes of commit 136697caf0 - Show all commits

View File

@@ -658,9 +658,9 @@ impl PythonAnalyzer {
let doc_summary = if is_init {
parsed_module.file_docstring.clone()
} else {
// For non-init files, check if there's an __init__.py docstring for this module's parent
init_docstrings.get(&module_id).cloned()
.or_else(|| parsed_module.file_docstring.clone())
// For non-init files, use file docstring first, then check __init__.py
parsed_module.file_docstring.clone()
.or_else(|| init_docstrings.get(&module_id).cloned())
};
let module = Module {
@@ -799,6 +799,25 @@ impl PythonAnalyzer {
Ok(())
}
/// Check if a class symbol is a simple data container (dataclass-like).
/// A class is considered a dataclass if it has ≤2 methods (typically __init__ and __repr__/__str__).
fn is_dataclass_like(symbol_id: &str, project_model: &ProjectModel) -> bool {
let symbol = match project_model.symbols.get(symbol_id) {
Some(s) => s,
None => return false,
};
if symbol.kind != crate::model::SymbolKind::Class {
return false;
}
// Count methods belonging to this class
let class_name = &symbol.qualname;
let method_prefix = format!("{}::{}.", symbol.module_id, class_name);
let method_count = project_model.symbols.values()
.filter(|s| s.kind == crate::model::SymbolKind::Method && s.id.starts_with(&method_prefix))
.count();
method_count <= 2
}
fn compute_metrics(&self, project_model: &mut ProjectModel) -> Result<(), ArchDocError> {
// Collect fan-in/fan-out first to avoid borrow issues
let mut metrics: std::collections::HashMap<String, (usize, usize)> = std::collections::HashMap::new();
@@ -815,12 +834,20 @@ impl PythonAnalyzer {
metrics.insert(symbol_id.clone(), (fan_in, fan_out));
}
// Pre-compute which symbols are dataclass-like (need immutable borrow)
let dataclass_ids: std::collections::HashSet<String> = metrics.keys()
.filter(|id| Self::is_dataclass_like(id, project_model))
.cloned()
.collect();
for (symbol_id, (fan_in, fan_out)) in &metrics {
if let Some(symbol) = project_model.symbols.get_mut(symbol_id) {
symbol.metrics.fan_in = *fan_in;
symbol.metrics.fan_out = *fan_out;
symbol.metrics.is_critical = *fan_in > self.config.thresholds.critical_fan_in
// Don't mark dataclass-like classes as critical — they're just data containers
let exceeds_threshold = *fan_in > self.config.thresholds.critical_fan_in
|| *fan_out > self.config.thresholds.critical_fan_out;
symbol.metrics.is_critical = exceeds_threshold && !dataclass_ids.contains(symbol_id);
}
}