python_ast/ast/tree/
attribute.rs1use proc_macro2::TokenStream;
2use pyo3::{Bound, PyAny, FromPyObject, PyResult, prelude::PyAnyMethods, types::PyTypeMethods};
3use quote::{format_ident, quote};
4
5use crate::{dump, CodeGen, CodeGenContext, ExprType, Node, PythonOptions, SymbolTableScopes};
6
7use serde::{Deserialize, Serialize};
8
9#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
10pub struct Attribute {
12 value: Box<ExprType>,
13 attr: String,
14 ctx: String,
15}
16
17impl<'a> FromPyObject<'a> for Attribute {
18 fn extract_bound(ob: &Bound<'a, PyAny>) -> PyResult<Self> {
19 let value = ob.getattr("value").expect("Attribute.value");
20 let attr = ob.getattr("attr").expect("Attribute.attr");
21 let ctx = ob
22 .getattr("ctx")
23 .expect("getting attribute context")
24 .get_type()
25 .name()
26 .expect(
27 ob.error_message(
28 "<unknown>",
29 format!("extracting type name {:?} in attribute", dump(ob, None)),
30 )
31 .as_str(),
32 );
33 Ok(Attribute {
34 value: Box::new(value.extract().expect("Attribute.value")),
35 attr: attr.extract().expect("Attribute.attr"),
36 ctx: ctx.to_string(),
37 })
38 }
39}
40
41impl<'a> CodeGen for Attribute {
42 type Context = CodeGenContext;
43 type Options = PythonOptions;
44 type SymbolTable = SymbolTableScopes;
45
46 fn to_rust(
47 self,
48 ctx: Self::Context,
49 options: Self::Options,
50 symbols: Self::SymbolTable,
51 ) -> Result<TokenStream, Box<dyn std::error::Error>> {
52 let value_tokens = self.value.to_rust(ctx, options, symbols)?;
53 let value_str = value_tokens.to_string();
54 let attr = format_ident!("{}", self.attr);
55
56 let is_module_access = matches!(value_str.as_str(),
59 "sys" | "os" | "subprocess" | "json" | "urllib" | "xml" | "asyncio" |
60 "os :: path" | "os::path" );
62
63 if is_module_access {
64 let needs_deref = matches!((value_str.as_str(), self.attr.as_str()),
67 ("sys", "executable") | ("sys", "argv") | ("os", "environ")
68 );
69
70 if needs_deref {
71 Ok(quote!((*#value_tokens::#attr)))
74 } else {
75 Ok(quote!(#value_tokens::#attr))
76 }
77 } else {
78 Ok(quote!(#value_tokens.#attr))
80 }
81 }
82}