Skip to main content

ruff_python_ast/
lib.rs

1use std::ffi::OsStr;
2use std::path::Path;
3
4pub use expression::*;
5pub use generated::*;
6pub use int::*;
7pub use node_index::*;
8pub use nodes::*;
9pub use operator_precedence::*;
10pub use python_version::*;
11
12pub mod comparable;
13pub mod docstrings;
14mod expression;
15pub mod find_node;
16mod generated;
17pub mod helpers;
18pub mod identifier;
19mod int;
20pub mod name;
21mod node;
22mod node_index;
23mod nodes;
24pub mod operator_precedence;
25pub mod parenthesize;
26mod python_version;
27pub mod relocate;
28pub mod script;
29pub mod statement_visitor;
30pub mod stmt_if;
31pub mod str;
32pub mod str_prefix;
33pub mod token;
34pub mod traversal;
35pub mod types;
36pub mod visitor;
37pub mod whitespace;
38
39/// The type of a source file.
40#[derive(Clone, Copy, Debug, PartialEq, is_macro::Is)]
41pub enum SourceType {
42    /// The file contains Python source code.
43    Python(PySourceType),
44    /// The file contains TOML.
45    Toml(TomlSourceType),
46    /// The file contains Markdown.
47    Markdown,
48}
49
50impl SourceType {
51    pub fn from_extension(ext: &str) -> Self {
52        match ext {
53            "toml" => Self::Toml(TomlSourceType::Unrecognized),
54            "md" => Self::Markdown,
55            _ => Self::Python(PySourceType::from_extension(ext)),
56        }
57    }
58}
59
60impl Default for SourceType {
61    fn default() -> Self {
62        Self::Python(PySourceType::Python)
63    }
64}
65
66impl<P: AsRef<Path>> From<P> for SourceType {
67    fn from(path: P) -> Self {
68        match path.as_ref().file_name() {
69            Some(filename) if filename == "pyproject.toml" => Self::Toml(TomlSourceType::Pyproject),
70            Some(filename) if filename == "Pipfile" => Self::Toml(TomlSourceType::Pipfile),
71            Some(filename) if filename == "poetry.lock" => Self::Toml(TomlSourceType::Poetry),
72            Some(filename) if filename == "ruff.toml" || filename == ".ruff.toml" => {
73                Self::Toml(TomlSourceType::Ruff)
74            }
75            _ => Self::from_extension(
76                path.as_ref()
77                    .extension()
78                    .and_then(OsStr::to_str)
79                    .unwrap_or(""),
80            ),
81        }
82    }
83}
84
85#[derive(Clone, Copy, Debug, PartialEq, is_macro::Is)]
86pub enum TomlSourceType {
87    /// The source is a `pyproject.toml`.
88    Pyproject,
89    /// The source is a `ruff.toml` or `.ruff.toml`.
90    Ruff,
91    /// The source is a `Pipfile`.
92    Pipfile,
93    /// The source is a `poetry.lock`.
94    Poetry,
95    /// The source is an unrecognized TOML file.
96    Unrecognized,
97}
98
99#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
100#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
101pub enum PySourceType {
102    /// The source is a Python file (`.py`, `.pyw`).
103    /// Note: `.pyw` files contain Python code, but do not represent importable namespaces.
104    /// Consider adding a separate source type later if combining the two causes issues.
105    #[default]
106    Python,
107    /// The source is a Python stub file (`.pyi`).
108    Stub,
109    /// The source is a Jupyter notebook (`.ipynb`).
110    Ipynb,
111}
112
113impl PySourceType {
114    /// Infers the source type from the file extension.
115    ///
116    /// Falls back to `Python` if the extension is not recognized.
117    pub fn from_extension(extension: &str) -> Self {
118        Self::try_from_extension(extension).unwrap_or_default()
119    }
120
121    /// Infers the source type from the file extension.
122    pub fn try_from_extension(extension: &str) -> Option<Self> {
123        let ty = match extension {
124            "py" => Self::Python,
125            "pyi" => Self::Stub,
126            "pyw" => Self::Python,
127            "ipynb" => Self::Ipynb,
128            _ => return None,
129        };
130
131        Some(ty)
132    }
133
134    pub fn try_from_path(path: impl AsRef<Path>) -> Option<Self> {
135        path.as_ref()
136            .extension()
137            .and_then(OsStr::to_str)
138            .and_then(Self::try_from_extension)
139    }
140
141    pub const fn is_py_file(self) -> bool {
142        matches!(self, Self::Python)
143    }
144
145    pub const fn is_stub(self) -> bool {
146        matches!(self, Self::Stub)
147    }
148
149    pub const fn is_py_file_or_stub(self) -> bool {
150        matches!(self, Self::Python | Self::Stub)
151    }
152
153    pub const fn is_ipynb(self) -> bool {
154        matches!(self, Self::Ipynb)
155    }
156}
157
158impl<P: AsRef<Path>> From<P> for PySourceType {
159    fn from(path: P) -> Self {
160        Self::try_from_path(path).unwrap_or_default()
161    }
162}