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#[derive(Clone, Copy, Debug, PartialEq, is_macro::Is)]
41pub enum SourceType {
42 Python(PySourceType),
44 Toml(TomlSourceType),
46 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 Pyproject,
89 Ruff,
91 Pipfile,
93 Poetry,
95 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 #[default]
106 Python,
107 Stub,
109 Ipynb,
111}
112
113impl PySourceType {
114 pub fn from_extension(extension: &str) -> Self {
118 Self::try_from_extension(extension).unwrap_or_default()
119 }
120
121 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}