scythe_codegen/backends/
python_common.rs1use scythe_core::errors::{ErrorCode, ScytheError};
2
3#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
5pub enum PythonRowType {
6 #[default]
7 Dataclass,
8 Pydantic,
9 Msgspec,
10}
11
12impl PythonRowType {
13 pub fn from_option(value: &str) -> Result<Self, ScytheError> {
15 match value {
16 "dataclass" => Ok(Self::Dataclass),
17 "pydantic" => Ok(Self::Pydantic),
18 "msgspec" => Ok(Self::Msgspec),
19 _ => Err(ScytheError::new(
20 ErrorCode::InternalError,
21 format!(
22 "invalid row_type '{}': expected 'dataclass', 'pydantic', or 'msgspec'",
23 value
24 ),
25 )),
26 }
27 }
28
29 pub fn import_line(self) -> &'static str {
31 match self {
32 Self::Dataclass => "from dataclasses import dataclass",
33 Self::Pydantic => "from pydantic import BaseModel",
34 Self::Msgspec => "import msgspec",
35 }
36 }
37
38 pub fn is_stdlib_import(self) -> bool {
40 matches!(self, Self::Dataclass)
41 }
42
43 pub fn sorted_third_party_imports(self, library_import: &str) -> String {
49 let row_import = self.import_line();
50 let row_is_bare = row_import.starts_with("import ");
51 let lib_is_bare = library_import.starts_with("import ");
52
53 match (row_is_bare, lib_is_bare) {
54 (true, true) | (false, false) => {
56 if row_import < library_import {
57 format!("{row_import}\n{library_import}")
58 } else {
59 format!("{library_import}\n{row_import}")
60 }
61 }
62 (true, false) => format!("{row_import}\n{library_import}"),
64 (false, true) => format!("{library_import}\n{row_import}"),
66 }
67 }
68
69 pub fn decorator(self) -> &'static str {
71 match self {
72 Self::Dataclass => "@dataclass\n",
73 Self::Pydantic | Self::Msgspec => "",
74 }
75 }
76
77 pub fn class_def(self, class_name: &str) -> String {
79 match self {
80 Self::Dataclass => format!("class {}:", class_name),
81 Self::Pydantic => format!("class {}(BaseModel):", class_name),
82 Self::Msgspec => format!("class {}(msgspec.Struct):", class_name),
83 }
84 }
85}