Skip to main content

chainsaw/lang/python/
mod.rs

1//! Python support: tree-sitter parser with source-root and virtualenv resolution.
2
3mod parser;
4mod resolver;
5
6#[cfg(test)]
7mod conformance;
8
9use std::path::{Path, PathBuf};
10use std::sync::Arc;
11
12use crate::lang::{LanguageSupport, ParseError, ParseResult};
13use crate::vfs::{OsVfs, Vfs};
14
15use self::resolver::{PythonResolver, package_name_from_path};
16
17pub struct PythonSupport {
18    resolver: PythonResolver,
19}
20
21impl std::fmt::Debug for PythonSupport {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        f.debug_struct("PythonSupport").finish_non_exhaustive()
24    }
25}
26
27impl PythonSupport {
28    pub fn new(root: &Path) -> Self {
29        Self::with_vfs(root, Arc::new(OsVfs))
30    }
31
32    pub fn with_vfs(root: &Path, vfs: Arc<dyn Vfs>) -> Self {
33        Self {
34            resolver: PythonResolver::with_vfs(root, vfs),
35        }
36    }
37
38    pub fn source_roots(&self) -> &[PathBuf] {
39        self.resolver.source_roots()
40    }
41}
42
43impl LanguageSupport for PythonSupport {
44    fn extensions(&self) -> &'static [&'static str] {
45        &["py"]
46    }
47
48    fn parse(&self, path: &Path, source: &str) -> Result<ParseResult, ParseError> {
49        parser::parse_file(path, source)
50    }
51
52    fn resolve(&self, from_dir: &Path, specifier: &str) -> Option<PathBuf> {
53        self.resolver.resolve(from_dir, specifier)
54    }
55
56    fn package_name(&self, resolved_path: &Path) -> Option<String> {
57        package_name_from_path(resolved_path, self.resolver.site_packages())
58    }
59
60    fn workspace_package_name(&self, _file_path: &Path, _project_root: &Path) -> Option<String> {
61        None
62    }
63}