Skip to content

Commit d50bc03

Browse files
committed
[IMP] server: hooks for werkzeug monkeypatches
1 parent b708931 commit d50bc03

File tree

5 files changed

+239
-72
lines changed

5 files changed

+239
-72
lines changed

server/src/core/import_resolver.rs

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
use glob::glob;
22
use lsp_types::{Diagnostic, DiagnosticTag, Position, Range};
3+
use ruff_python_ast::name::Name;
34
use tracing::error;
45
use std::collections::{HashMap, HashSet};
56
use std::rc::Rc;
67
use std::cell::RefCell;
78
use std::path::{Path, PathBuf};
89

9-
use ruff_text_size::TextRange;
10+
use ruff_text_size::{TextRange, TextSize};
1011
use ruff_python_ast::{Alias, Identifier};
1112
use crate::{constants::*, oyarn, Sy, S};
1213
use crate::core::diagnostics::{create_diagnostic, DiagnosticCode};
@@ -51,15 +52,32 @@ fn resolve_import_stmt_hook(alias: &Alias, from_symbol: &Option<Rc<RefCell<Symbo
5152
}
5253
}
5354

55+
/**
56+
* Helper to manually import a symbol. Do not forget to use level instead of '.' in the from_stmt parameter.
57+
*/
58+
pub fn manual_import(session: &mut SessionInfo, source_file_symbol: &Rc<RefCell<Symbol>>, from_stmt:Option<String>, name: &str, asname: Option<String>, level: Option<u32>, diagnostics: &mut Option<&mut Vec<Diagnostic>>) -> Vec<ImportResult> {
59+
let name_aliases = vec![Alias {
60+
name: Identifier { id: Name::new(name), range: TextRange::new(TextSize::new(0), TextSize::new(0)) },
61+
asname: match asname {
62+
Some(asname_inner) => Some(Identifier { id: Name::new(asname_inner), range: TextRange::new(TextSize::new(0), TextSize::new(0)) }),
63+
None => None,
64+
},
65+
range: TextRange::new(TextSize::new(0), TextSize::new(0)),
66+
}];
67+
let from_stmt = match from_stmt {
68+
Some(from_stmt_inner) => Some(Identifier { id: Name::new(from_stmt_inner), range: TextRange::new(TextSize::new(0), TextSize::new(0)) }),
69+
None => None,
70+
};
71+
resolve_import_stmt(session, source_file_symbol, from_stmt.as_ref(), &name_aliases, level, diagnostics)
72+
}
73+
5474
pub fn resolve_import_stmt(session: &mut SessionInfo, source_file_symbol: &Rc<RefCell<Symbol>>, from_stmt: Option<&Identifier>, name_aliases: &[Alias], level: Option<u32>, diagnostics: &mut Option<&mut Vec<Diagnostic>>) -> Vec<ImportResult> {
5575
//A: search base of different imports
5676
let source_root = source_file_symbol.borrow().get_root().as_ref().unwrap().upgrade().unwrap();
5777
let entry = source_root.borrow().get_entry().unwrap();
5878
let _source_file_symbol_lock = source_file_symbol.borrow_mut();
5979
let file_tree = _resolve_packages(
60-
&_source_file_symbol_lock.paths()[0].clone(),
61-
&_source_file_symbol_lock.get_tree(),
62-
&_source_file_symbol_lock.typ(),
80+
&_source_file_symbol_lock,
6381
level,
6482
from_stmt);
6583
drop(_source_file_symbol_lock);
@@ -206,20 +224,20 @@ pub fn find_module(session: &mut SessionInfo, odoo_addons: Rc<RefCell<Symbol>>,
206224
None
207225
}
208226

209-
fn _resolve_packages(file_path: &String, file_tree: &Tree, file_sym_type: &SymType, level: Option<u32>, from_stmt: Option<&Identifier>) -> Vec<OYarn> {
227+
fn _resolve_packages(from_file: &Symbol, level: Option<u32>, from_stmt: Option<&Identifier>) -> Vec<OYarn> {
210228
let mut first_part_tree: Vec<OYarn> = vec![];
211229
if level.is_some() && level.unwrap() > 0 {
212230
let mut lvl = level.unwrap();
213-
if lvl > Path::new(file_path).components().count() as u32 {
231+
if lvl > Path::new(&from_file.paths()[0]).components().count() as u32 {
214232
panic!("Level is too high!")
215233
}
216-
if matches!(*file_sym_type, SymType::PACKAGE(_)) {
234+
if matches!(from_file.typ(), SymType::PACKAGE(_)) {
217235
lvl -= 1;
218236
}
219237
if lvl == 0 {
220-
first_part_tree = file_tree.0.clone();
238+
first_part_tree = from_file.get_tree().0.clone();
221239
} else {
222-
let tree = file_tree;
240+
let tree = from_file.get_tree();
223241
if lvl > tree.0.len() as u32 {
224242
error!("Level is too high and going out of scope");
225243
first_part_tree = vec![];
@@ -417,9 +435,7 @@ pub fn get_all_valid_names(session: &mut SessionInfo, source_file_symbol: &Rc<Re
417435
let entry = source_root.borrow().get_entry().unwrap();
418436
let _source_file_symbol_lock = source_file_symbol.borrow_mut();
419437
let file_tree = _resolve_packages(
420-
&_source_file_symbol_lock.paths()[0].clone(),
421-
&_source_file_symbol_lock.get_tree(),
422-
&_source_file_symbol_lock.typ(),
438+
&_source_file_symbol_lock,
423439
level,
424440
from_stmt);
425441
drop(_source_file_symbol_lock);

server/src/core/odoo.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ impl SyncOdoo {
235235
.map(|v| v as u32)
236236
.take(3)
237237
.collect();
238+
info!("Detected python version: {}.{}.{}", session.sync_odoo.python_version[0], session.sync_odoo.python_version[1], session.sync_odoo.python_version[2]);
238239
} else {
239240
let stderr = String::from_utf8_lossy(&output.stderr);
240241
error!("{}", stderr);

server/src/core/python_arch_builder_hooks.rs

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ use std::rc::Rc;
44
use std::cell::RefCell;
55
use once_cell::sync::Lazy;
66
use ruff_text_size::{TextRange, TextSize};
7-
use tracing::warn;
7+
use tracing::{info, warn};
88
use crate::core::entry_point::EntryPoint;
9+
use crate::core::import_resolver::manual_import;
910
use crate::core::symbols::symbol::Symbol;
1011
use crate::threads::SessionInfo;
11-
use crate::utils::compare_semver;
12+
use crate::utils::{compare_semver, is_file_cs, PathSanitizer};
1213
use crate::{Sy, S};
1314
use crate::constants::OYarn;
1415

@@ -195,6 +196,45 @@ impl PythonArchBuilderHooks {
195196
}
196197
}
197198
}
199+
} else if name == "werkzeug" {
200+
if symbol.borrow().get_main_entry_tree(session) == (vec![Sy!("odoo"), Sy!("_monkeypatches"), Sy!("werkzeug")], vec![]) {
201+
//doing this patch like this imply that an odoo project will make these functions available for all entrypoints, but heh
202+
let werkzeug_url = session.sync_odoo.get_symbol(symbol.borrow().paths()[0].as_str(), &(vec![Sy!("werkzeug"), Sy!("urls")], vec![]), u32::MAX);
203+
if let Some(werkzeug_url) = werkzeug_url.first() {
204+
//fake variable, as ext_symbols are not seen through get_symbol, etc...
205+
werkzeug_url.borrow_mut().add_new_variable(session, Sy!("url_decode"), &TextRange::new(TextSize::new(0), TextSize::new(0)));
206+
werkzeug_url.borrow_mut().add_new_variable(session, Sy!("url_encode"), &TextRange::new(TextSize::new(0), TextSize::new(0)));
207+
werkzeug_url.borrow_mut().add_new_variable(session, Sy!("url_join"), &TextRange::new(TextSize::new(0), TextSize::new(0)));
208+
werkzeug_url.borrow_mut().add_new_variable(session, Sy!("url_parse"), &TextRange::new(TextSize::new(0), TextSize::new(0)));
209+
werkzeug_url.borrow_mut().add_new_variable(session, Sy!("url_quote"), &TextRange::new(TextSize::new(0), TextSize::new(0)));
210+
werkzeug_url.borrow_mut().add_new_variable(session, Sy!("url_unquote"), &TextRange::new(TextSize::new(0), TextSize::new(0)));
211+
werkzeug_url.borrow_mut().add_new_variable(session, Sy!("url_quote_plus"), &TextRange::new(TextSize::new(0), TextSize::new(0)));
212+
werkzeug_url.borrow_mut().add_new_variable(session, Sy!("url_unquote_plus"), &TextRange::new(TextSize::new(0), TextSize::new(0)));
213+
werkzeug_url.borrow_mut().add_new_variable(session, Sy!("url_unparse"), &TextRange::new(TextSize::new(0), TextSize::new(0)));
214+
werkzeug_url.borrow_mut().add_new_variable(session, Sy!("URL"), &TextRange::new(TextSize::new(0), TextSize::new(0)));
215+
} else {
216+
warn!("Unable to find werkzeug.urls to monkeypatch it");
217+
}
218+
}
219+
} else if name == "urls" {
220+
if symbol.borrow().get_local_tree() == (vec![Sy!("werkzeug"), Sy!("urls")], vec![]) {
221+
//manually load patch, as a manual dependency
222+
let full_path_monkeypatches = S!("odoo._monkeypatches");
223+
let mut main_odoo_symbol = None;
224+
if let Some(main_ep) = session.sync_odoo.entry_point_mgr.borrow().main_entry_point.as_ref() {
225+
//To import from main entry point, we have to import 'from' a symbol coming from main entry point.
226+
//We then use the main symbol of the main entry point to achieve that, instead of the werkzeug symbol
227+
main_odoo_symbol = Some(main_ep.borrow().get_symbol().unwrap());
228+
}
229+
if let Some(main_odoo_symbol) = main_odoo_symbol {
230+
let werkzeug_patch = manual_import(session, &main_odoo_symbol, Some(full_path_monkeypatches), "werkzeug", None, None, &mut None);
231+
for werkzeug_patch in werkzeug_patch {
232+
if werkzeug_patch.found {
233+
info!("monkeypatch manually found");
234+
}
235+
}
236+
}
237+
}
198238
}
199239
}
200240
}

0 commit comments

Comments
 (0)