firehot 0.4.1__tar.gz → 0.4.2.dev1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {firehot-0.4.1 → firehot-0.4.2.dev1}/Cargo.lock +1 -1
- {firehot-0.4.1 → firehot-0.4.2.dev1}/Cargo.toml +1 -1
- {firehot-0.4.1 → firehot-0.4.2.dev1}/PKG-INFO +1 -1
- firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp310-cp310-macosx_10_12_x86_64.whl +0 -0
- firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp310-cp310-macosx_11_0_arm64.whl +0 -0
- firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl +0 -0
- firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl +0 -0
- firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp311-cp311-macosx_10_12_x86_64.whl +0 -0
- firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp311-cp311-macosx_11_0_arm64.whl +0 -0
- firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl +0 -0
- firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl +0 -0
- firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp312-cp312-macosx_10_12_x86_64.whl +0 -0
- firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp312-cp312-macosx_11_0_arm64.whl +0 -0
- firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl +0 -0
- firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl +0 -0
- firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp313-cp313-macosx_10_12_x86_64.whl +0 -0
- firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp313-cp313-macosx_11_0_arm64.whl +0 -0
- firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl +0 -0
- firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/pyproject.toml +1 -1
- {firehot-0.4.1 → firehot-0.4.2.dev1}/src/ast.rs +23 -23
- {firehot-0.4.1 → firehot-0.4.2.dev1}/src/async_resolve.rs +4 -4
- {firehot-0.4.1 → firehot-0.4.2.dev1}/src/environment.rs +62 -109
- {firehot-0.4.1 → firehot-0.4.2.dev1}/src/layer.rs +198 -13
- {firehot-0.4.1 → firehot-0.4.2.dev1}/src/lib.rs +11 -11
- {firehot-0.4.1 → firehot-0.4.2.dev1}/src/messages.rs +3 -3
- {firehot-0.4.1 → firehot-0.4.2.dev1}/src/multiplex_logs.rs +4 -5
- {firehot-0.4.1 → firehot-0.4.2.dev1}/src/test_utils/harness.rs +9 -9
- firehot-0.4.1/dist_clean/firehot-0.4.1-cp310-cp310-macosx_10_12_x86_64.whl +0 -0
- firehot-0.4.1/dist_clean/firehot-0.4.1-cp310-cp310-macosx_11_0_arm64.whl +0 -0
- firehot-0.4.1/dist_clean/firehot-0.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl +0 -0
- firehot-0.4.1/dist_clean/firehot-0.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl +0 -0
- firehot-0.4.1/dist_clean/firehot-0.4.1-cp311-cp311-macosx_10_12_x86_64.whl +0 -0
- firehot-0.4.1/dist_clean/firehot-0.4.1-cp311-cp311-macosx_11_0_arm64.whl +0 -0
- firehot-0.4.1/dist_clean/firehot-0.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl +0 -0
- firehot-0.4.1/dist_clean/firehot-0.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl +0 -0
- firehot-0.4.1/dist_clean/firehot-0.4.1-cp312-cp312-macosx_10_12_x86_64.whl +0 -0
- firehot-0.4.1/dist_clean/firehot-0.4.1-cp312-cp312-macosx_11_0_arm64.whl +0 -0
- firehot-0.4.1/dist_clean/firehot-0.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl +0 -0
- firehot-0.4.1/dist_clean/firehot-0.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl +0 -0
- firehot-0.4.1/dist_clean/firehot-0.4.1-cp313-cp313-macosx_10_12_x86_64.whl +0 -0
- firehot-0.4.1/dist_clean/firehot-0.4.1-cp313-cp313-macosx_11_0_arm64.whl +0 -0
- firehot-0.4.1/dist_clean/firehot-0.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl +0 -0
- firehot-0.4.1/dist_clean/firehot-0.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/.DS_Store +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/.github/scripts/update_version.py +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/.github/workflows/ci-build.yml +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/.github/workflows/ci-test.yml +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/.gitignore +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/Makefile +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/README.md +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/demopackage/.python-version +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/demopackage/README.md +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/demopackage/demopackage/__init__.py +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/demopackage/demopackage/app.py +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/demopackage/demopackage/dep.py +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/demopackage/demopackage/test_hotreload.py +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/demopackage/external-package/.python-version +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/demopackage/external-package/README.md +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/demopackage/external-package/external_package/__init__.py +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/demopackage/external-package/external_package/mock_imports.py +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/demopackage/external-package/pyproject.toml +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/demopackage/external-package/uv.lock +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/demopackage/pyproject.toml +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/demopackage/uv.lock +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/firehot/__init__.py +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/firehot/__tests__/__init__.py +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/firehot/__tests__/conftest.py +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/firehot/__tests__/embedded/__init__.py +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/firehot/__tests__/embedded/test_call_serializer.py +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/firehot/__tests__/embedded/test_child_entrypoint.py +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/firehot/__tests__/embedded/test_parent_entrypoint.py +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/firehot/__tests__/test_context.py +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/firehot/__tests__/test_environment.py +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/firehot/__tests__/test_naming.py +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/firehot/context.py +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/firehot/embedded/call_serializer.py +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/firehot/embedded/child_entrypoint.py +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/firehot/embedded/parent_entrypoint.py +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/firehot/embedded/types.py +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/firehot/environment.py +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/firehot/naming.py +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/firehot/py.typed +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/media/header.png +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/src/process.rs +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/src/scripts.rs +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/src/test_utils/mod.rs +0 -0
- {firehot-0.4.1 → firehot-0.4.2.dev1}/uv.lock +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -223,7 +223,7 @@ impl ProjectAstManager {
|
|
|
223
223
|
let mut hasher = Sha256::new();
|
|
224
224
|
hasher.update(&content);
|
|
225
225
|
let hash = hasher.finalize();
|
|
226
|
-
let hash_str = format!("{:x}"
|
|
226
|
+
let hash_str = format!("{hash:x}");
|
|
227
227
|
trace!("Calculated hash for {}: {}", file_path, hash_str);
|
|
228
228
|
Ok(hash_str)
|
|
229
229
|
}
|
|
@@ -404,13 +404,13 @@ mod tests {
|
|
|
404
404
|
assert_eq!(imports.len(), 2);
|
|
405
405
|
assert_eq!(imports[0].module, "os");
|
|
406
406
|
assert_eq!(imports[0].names, vec!["os"]);
|
|
407
|
-
|
|
408
|
-
|
|
407
|
+
assert!(!imports[0].is_relative);
|
|
408
|
+
assert!(!imports[0].is_from_import);
|
|
409
409
|
|
|
410
410
|
assert_eq!(imports[1].module, "sys");
|
|
411
411
|
assert_eq!(imports[1].names, vec!["sys"]);
|
|
412
|
-
|
|
413
|
-
|
|
412
|
+
assert!(!imports[1].is_relative);
|
|
413
|
+
assert!(!imports[1].is_from_import);
|
|
414
414
|
}
|
|
415
415
|
|
|
416
416
|
#[test]
|
|
@@ -432,13 +432,13 @@ mod tests {
|
|
|
432
432
|
assert_eq!(imports.len(), 2);
|
|
433
433
|
assert_eq!(imports[0].module, "os");
|
|
434
434
|
assert_eq!(imports[0].names, vec!["path"]);
|
|
435
|
-
|
|
436
|
-
|
|
435
|
+
assert!(!imports[0].is_relative);
|
|
436
|
+
assert!(imports[0].is_from_import);
|
|
437
437
|
|
|
438
438
|
assert_eq!(imports[1].module, "sys");
|
|
439
439
|
assert_eq!(imports[1].names, vec!["argv", "version"]);
|
|
440
|
-
|
|
441
|
-
|
|
440
|
+
assert!(!imports[1].is_relative);
|
|
441
|
+
assert!(imports[1].is_from_import);
|
|
442
442
|
}
|
|
443
443
|
|
|
444
444
|
#[test]
|
|
@@ -460,13 +460,13 @@ mod tests {
|
|
|
460
460
|
assert_eq!(imports.len(), 2);
|
|
461
461
|
assert_eq!(imports[0].module, "os");
|
|
462
462
|
assert_eq!(imports[0].names, vec!["os"]);
|
|
463
|
-
|
|
464
|
-
|
|
463
|
+
assert!(!imports[0].is_relative);
|
|
464
|
+
assert!(!imports[0].is_from_import);
|
|
465
465
|
|
|
466
466
|
assert_eq!(imports[1].module, "sys");
|
|
467
467
|
assert_eq!(imports[1].names, vec!["argv"]);
|
|
468
|
-
|
|
469
|
-
|
|
468
|
+
assert!(!imports[1].is_relative);
|
|
469
|
+
assert!(imports[1].is_from_import);
|
|
470
470
|
}
|
|
471
471
|
|
|
472
472
|
#[test]
|
|
@@ -486,7 +486,7 @@ mod tests {
|
|
|
486
486
|
let imports = collect_imports(stmts);
|
|
487
487
|
|
|
488
488
|
// Debugging to understand the actual structure
|
|
489
|
-
println!("Relative imports found: {:#?}"
|
|
489
|
+
println!("Relative imports found: {imports:#?}");
|
|
490
490
|
|
|
491
491
|
// For now, just check that we find something, we'll refine this test
|
|
492
492
|
// after seeing the actual output structure
|
|
@@ -494,8 +494,8 @@ mod tests {
|
|
|
494
494
|
|
|
495
495
|
// All these should be relative from imports
|
|
496
496
|
for import in &imports {
|
|
497
|
-
|
|
498
|
-
|
|
497
|
+
assert!(import.is_from_import);
|
|
498
|
+
assert!(import.is_relative);
|
|
499
499
|
}
|
|
500
500
|
}
|
|
501
501
|
|
|
@@ -574,14 +574,14 @@ def function():
|
|
|
574
574
|
// First import: "import time"
|
|
575
575
|
assert_eq!(imports[0].module, "time");
|
|
576
576
|
assert_eq!(imports[0].names, vec!["time"]);
|
|
577
|
-
|
|
578
|
-
|
|
577
|
+
assert!(!imports[0].is_relative);
|
|
578
|
+
assert!(!imports[0].is_from_import); // This is a simple import
|
|
579
579
|
|
|
580
580
|
// Second import: "from time import time as time_func"
|
|
581
581
|
assert_eq!(imports[1].module, "time");
|
|
582
582
|
assert_eq!(imports[1].names, vec!["time"]); // Should contain the original name, not the alias
|
|
583
|
-
|
|
584
|
-
|
|
583
|
+
assert!(!imports[1].is_relative);
|
|
584
|
+
assert!(imports[1].is_from_import); // This is a from import
|
|
585
585
|
}
|
|
586
586
|
|
|
587
587
|
#[test]
|
|
@@ -689,7 +689,7 @@ def function():
|
|
|
689
689
|
|
|
690
690
|
// Initial processing
|
|
691
691
|
let initial_imports = manager.process_all_py_files().unwrap();
|
|
692
|
-
println!("Initial imports found: {:#?}"
|
|
692
|
+
println!("Initial imports found: {initial_imports:#?}");
|
|
693
693
|
|
|
694
694
|
// Verify we have the expected number of third-party imports
|
|
695
695
|
// os, requests, sys, flask should all be considered third-party
|
|
@@ -707,8 +707,8 @@ def function():
|
|
|
707
707
|
|
|
708
708
|
// Compute delta - should detect the changes
|
|
709
709
|
let (added, removed) = manager.compute_import_delta().unwrap();
|
|
710
|
-
println!("Added imports: {:#?}"
|
|
711
|
-
println!("Removed imports: {:#?}"
|
|
710
|
+
println!("Added imports: {added:#?}");
|
|
711
|
+
println!("Removed imports: {removed:#?}");
|
|
712
712
|
|
|
713
713
|
assert!(!added.is_empty());
|
|
714
714
|
assert!(added.contains("pandas"));
|
|
@@ -76,7 +76,7 @@ impl<T: Clone> AsyncResolve<T> {
|
|
|
76
76
|
let value_lock_result = self.value.lock();
|
|
77
77
|
|
|
78
78
|
if let Err(e) = &value_lock_result {
|
|
79
|
-
let err_msg = format!("Failed to lock value mutex: {:?}"
|
|
79
|
+
let err_msg = format!("Failed to lock value mutex: {e:?}");
|
|
80
80
|
warn!("{}", err_msg);
|
|
81
81
|
return Err(err_msg);
|
|
82
82
|
}
|
|
@@ -98,7 +98,7 @@ impl<T: Clone> AsyncResolve<T> {
|
|
|
98
98
|
let completion_lock_result = mutex.lock();
|
|
99
99
|
|
|
100
100
|
if let Err(e) = &completion_lock_result {
|
|
101
|
-
let err_msg = format!("Failed to lock completion mutex: {:?}"
|
|
101
|
+
let err_msg = format!("Failed to lock completion mutex: {e:?}");
|
|
102
102
|
warn!("{}", err_msg);
|
|
103
103
|
return Err(err_msg);
|
|
104
104
|
}
|
|
@@ -112,7 +112,7 @@ impl<T: Clone> AsyncResolve<T> {
|
|
|
112
112
|
let wait_result = condvar.wait(completed);
|
|
113
113
|
|
|
114
114
|
if let Err(e) = &wait_result {
|
|
115
|
-
let err_msg = format!("Failed to wait on condvar: {:?}"
|
|
115
|
+
let err_msg = format!("Failed to wait on condvar: {e:?}");
|
|
116
116
|
warn!("{}", err_msg);
|
|
117
117
|
return Err(err_msg);
|
|
118
118
|
}
|
|
@@ -133,7 +133,7 @@ impl<T: Clone> AsyncResolve<T> {
|
|
|
133
133
|
let value_lock_result = self.value.lock();
|
|
134
134
|
|
|
135
135
|
if let Err(e) = &value_lock_result {
|
|
136
|
-
let err_msg = format!("Failed to lock value mutex after wait: {:?}"
|
|
136
|
+
let err_msg = format!("Failed to lock value mutex after wait: {e:?}");
|
|
137
137
|
warn!("{}", err_msg);
|
|
138
138
|
return Err(err_msg);
|
|
139
139
|
}
|
|
@@ -10,7 +10,6 @@ use std::sync::{Arc, Mutex};
|
|
|
10
10
|
use std::time::Instant;
|
|
11
11
|
|
|
12
12
|
use libc;
|
|
13
|
-
use std::io::BufRead;
|
|
14
13
|
use uuid::Uuid;
|
|
15
14
|
|
|
16
15
|
use crate::ast::ProjectAstManager;
|
|
@@ -98,7 +97,7 @@ impl Environment {
|
|
|
98
97
|
let third_party_modules = self
|
|
99
98
|
.ast_manager
|
|
100
99
|
.process_all_py_files()
|
|
101
|
-
.map_err(|e| format!("Failed to process Python files: {}"
|
|
100
|
+
.map_err(|e| format!("Failed to process Python files: {e}"))?;
|
|
102
101
|
|
|
103
102
|
let start_time = Instant::now();
|
|
104
103
|
|
|
@@ -108,7 +107,7 @@ impl Environment {
|
|
|
108
107
|
third_party_modules.len()
|
|
109
108
|
);
|
|
110
109
|
let mut child = spawn_python_loader(&third_party_modules)
|
|
111
|
-
.map_err(|e| format!("Failed to spawn Python loader: {}"
|
|
110
|
+
.map_err(|e| format!("Failed to spawn Python loader: {e}"))?;
|
|
112
111
|
|
|
113
112
|
let stdin = child
|
|
114
113
|
.stdin
|
|
@@ -126,54 +125,26 @@ impl Environment {
|
|
|
126
125
|
.take()
|
|
127
126
|
.ok_or_else(|| "Failed to capture stderr for python process".to_string())?;
|
|
128
127
|
|
|
129
|
-
|
|
130
|
-
let
|
|
131
|
-
|
|
132
|
-
// Create a stderr reader
|
|
128
|
+
// Create BufReaders for the Layer constructor
|
|
129
|
+
let stdout_reader = BufReader::new(stdout);
|
|
133
130
|
let stderr_reader = BufReader::new(stderr);
|
|
134
|
-
let stderr_lines_iter = stderr_reader.lines();
|
|
135
|
-
|
|
136
|
-
// Wait for the ImportComplete message
|
|
137
|
-
info!("Waiting for import completion...");
|
|
138
|
-
let mut imports_loaded = false;
|
|
139
|
-
for line in &mut lines_iter {
|
|
140
|
-
let line = line.map_err(|e| format!("Failed to read line: {}", e))?;
|
|
141
|
-
|
|
142
|
-
// Parse the line as a message
|
|
143
|
-
if let Ok(message) = serde_json::from_str::<Message>(&line) {
|
|
144
|
-
match message {
|
|
145
|
-
Message::ImportComplete(_) => {
|
|
146
|
-
info!("Imports loaded successfully");
|
|
147
|
-
imports_loaded = true;
|
|
148
|
-
break;
|
|
149
|
-
}
|
|
150
|
-
Message::ImportError(error) => {
|
|
151
|
-
error!(
|
|
152
|
-
"Import error: {}: {}",
|
|
153
|
-
error.error,
|
|
154
|
-
error.traceback.clone().unwrap_or_default()
|
|
155
|
-
);
|
|
156
|
-
return Err(format!(
|
|
157
|
-
"Import error: {}: {}",
|
|
158
|
-
error.error,
|
|
159
|
-
error.traceback.unwrap_or_default()
|
|
160
|
-
));
|
|
161
|
-
}
|
|
162
|
-
_ => {
|
|
163
|
-
// Log other message types for debugging
|
|
164
|
-
debug!("Received message: {}", line);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
} else {
|
|
168
|
-
// If we can't parse it as a message, log it
|
|
169
|
-
debug!("Non-message output: {}", line);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
131
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
132
|
+
// Create the Layer with UTF-8 lossy readers
|
|
133
|
+
let mut layer = if self.test_mode {
|
|
134
|
+
// Use the test mode constructor
|
|
135
|
+
Layer::new_for_test(child, stdin, stdout_reader, stderr_reader)
|
|
136
|
+
} else {
|
|
137
|
+
// Use the standard constructor
|
|
138
|
+
Layer::new(child, stdin, stdout_reader, stderr_reader)
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// Start the monitor thread immediately
|
|
142
|
+
layer.start_monitor_thread();
|
|
143
|
+
|
|
144
|
+
// For now, we'll assume imports are loaded successfully
|
|
145
|
+
// The Layer will handle any import errors through its normal monitoring
|
|
146
|
+
info!("Layer created and monitor thread started");
|
|
147
|
+
let _imports_loaded = true;
|
|
177
148
|
|
|
178
149
|
// Calculate total setup time and log completion
|
|
179
150
|
let elapsed = start_time.elapsed();
|
|
@@ -198,16 +169,7 @@ impl Environment {
|
|
|
198
169
|
format!("with ID: {}", self.id).white().bold()
|
|
199
170
|
);
|
|
200
171
|
|
|
201
|
-
|
|
202
|
-
// Use the test mode constructor
|
|
203
|
-
Layer::new_for_test(child, stdin, lines_iter, stderr_lines_iter)
|
|
204
|
-
} else {
|
|
205
|
-
// Use the standard constructor
|
|
206
|
-
Layer::new(child, stdin, lines_iter, stderr_lines_iter)
|
|
207
|
-
};
|
|
208
|
-
|
|
209
|
-
// Start the monitor thread
|
|
210
|
-
layer.start_monitor_thread();
|
|
172
|
+
// Layer creation and monitoring setup moved earlier
|
|
211
173
|
|
|
212
174
|
// Store the layer in the environment
|
|
213
175
|
self.layer = Some(Arc::new(Mutex::new(layer)));
|
|
@@ -229,7 +191,7 @@ impl Environment {
|
|
|
229
191
|
|
|
230
192
|
let env_guard = layer
|
|
231
193
|
.lock()
|
|
232
|
-
.map_err(|e| format!("Failed to lock environment mutex: {}"
|
|
194
|
+
.map_err(|e| format!("Failed to lock environment mutex: {e}"))?;
|
|
233
195
|
|
|
234
196
|
// First, stop all child processes
|
|
235
197
|
info!("Stopping all child processes before terminating main process");
|
|
@@ -237,7 +199,7 @@ impl Environment {
|
|
|
237
199
|
let forked_processes = env_guard
|
|
238
200
|
.forked_processes
|
|
239
201
|
.lock()
|
|
240
|
-
.map_err(|e| format!("Failed to lock forked processes: {}"
|
|
202
|
+
.map_err(|e| format!("Failed to lock forked processes: {e}"))?;
|
|
241
203
|
|
|
242
204
|
// Create a clone of all keys to avoid borrowing issues
|
|
243
205
|
forked_processes.keys().cloned().collect::<Vec<String>>()
|
|
@@ -257,16 +219,16 @@ impl Environment {
|
|
|
257
219
|
// Re-acquire the env_guard
|
|
258
220
|
let mut env_guard = layer
|
|
259
221
|
.lock()
|
|
260
|
-
.map_err(|e| format!("Failed to lock environment mutex: {}"
|
|
222
|
+
.map_err(|e| format!("Failed to lock environment mutex: {e}"))?;
|
|
261
223
|
|
|
262
224
|
// Now send ExitRequest to the parent process to allow it to clean up gracefully
|
|
263
225
|
info!("Sending ExitRequest to parent process");
|
|
264
226
|
let exit_request = ExitRequest::new();
|
|
265
227
|
let exit_json = serde_json::to_string(&Message::ExitRequest(exit_request))
|
|
266
|
-
.map_err(|e| format!("Failed to serialize exit request: {}"
|
|
228
|
+
.map_err(|e| format!("Failed to serialize exit request: {e}"))?;
|
|
267
229
|
|
|
268
230
|
// Send the message to the parent process
|
|
269
|
-
if let Err(e) = writeln!(env_guard.stdin, "{}"
|
|
231
|
+
if let Err(e) = writeln!(env_guard.stdin, "{exit_json}") {
|
|
270
232
|
warn!("Failed to write exit request to parent stdin: {}", e);
|
|
271
233
|
} else if let Err(e) = env_guard.stdin.flush() {
|
|
272
234
|
warn!("Failed to flush parent stdin: {}", e);
|
|
@@ -298,21 +260,21 @@ impl Environment {
|
|
|
298
260
|
let mut forked_processes = env_guard
|
|
299
261
|
.forked_processes
|
|
300
262
|
.lock()
|
|
301
|
-
.map_err(|e| format!("Failed to lock forked processes: {}"
|
|
263
|
+
.map_err(|e| format!("Failed to lock forked processes: {e}"))?;
|
|
302
264
|
forked_processes.clear();
|
|
303
265
|
drop(forked_processes);
|
|
304
266
|
|
|
305
267
|
let mut fork_resolvers = env_guard
|
|
306
268
|
.fork_resolvers
|
|
307
269
|
.lock()
|
|
308
|
-
.map_err(|e| format!("Failed to lock fork resolvers: {}"
|
|
270
|
+
.map_err(|e| format!("Failed to lock fork resolvers: {e}"))?;
|
|
309
271
|
fork_resolvers.clear();
|
|
310
272
|
drop(fork_resolvers);
|
|
311
273
|
|
|
312
274
|
let mut completion_resolvers = env_guard
|
|
313
275
|
.completion_resolvers
|
|
314
276
|
.lock()
|
|
315
|
-
.map_err(|e| format!("Failed to lock completion resolvers: {}"
|
|
277
|
+
.map_err(|e| format!("Failed to lock completion resolvers: {e}"))?;
|
|
316
278
|
completion_resolvers.clear();
|
|
317
279
|
drop(completion_resolvers);
|
|
318
280
|
|
|
@@ -332,7 +294,7 @@ impl Environment {
|
|
|
332
294
|
let (added, removed) = self
|
|
333
295
|
.ast_manager
|
|
334
296
|
.compute_import_delta()
|
|
335
|
-
.map_err(|e| format!("Failed to compute import delta: {}"
|
|
297
|
+
.map_err(|e| format!("Failed to compute import delta: {e}"))?;
|
|
336
298
|
|
|
337
299
|
// Check if imports have changed
|
|
338
300
|
if added.is_empty() && removed.is_empty() {
|
|
@@ -350,13 +312,13 @@ impl Environment {
|
|
|
350
312
|
let forked_processes = {
|
|
351
313
|
let env_guard = env
|
|
352
314
|
.lock()
|
|
353
|
-
.map_err(|e| format!("Failed to lock layer mutex: {}"
|
|
315
|
+
.map_err(|e| format!("Failed to lock layer mutex: {e}"))?;
|
|
354
316
|
|
|
355
317
|
// Get the forked processes mutex
|
|
356
318
|
let forked_processes_guard = env_guard
|
|
357
319
|
.forked_processes
|
|
358
320
|
.lock()
|
|
359
|
-
.map_err(|e| format!("Failed to lock forked processes: {}"
|
|
321
|
+
.map_err(|e| format!("Failed to lock forked processes: {e}"))?;
|
|
360
322
|
|
|
361
323
|
// Create a copy of the process UUIDs
|
|
362
324
|
forked_processes_guard
|
|
@@ -402,14 +364,14 @@ impl Environment {
|
|
|
402
364
|
// Send the code to the forked process
|
|
403
365
|
let mut env_guard = environment
|
|
404
366
|
.lock()
|
|
405
|
-
.map_err(|e| format!("Failed to lock environment mutex: {}"
|
|
367
|
+
.map_err(|e| format!("Failed to lock environment mutex: {e}"))?;
|
|
406
368
|
|
|
407
369
|
// Create async resolvers for both fork status and completion
|
|
408
370
|
let fork_resolver = AsyncResolve::new();
|
|
409
371
|
let mut fork_resolvers = env_guard
|
|
410
372
|
.fork_resolvers
|
|
411
373
|
.lock()
|
|
412
|
-
.map_err(|e| format!("Failed to lock fork resolvers: {}"
|
|
374
|
+
.map_err(|e| format!("Failed to lock fork resolvers: {e}"))?;
|
|
413
375
|
fork_resolvers.insert(process_uuid.clone(), fork_resolver.clone());
|
|
414
376
|
drop(fork_resolvers);
|
|
415
377
|
|
|
@@ -417,16 +379,15 @@ impl Environment {
|
|
|
417
379
|
let mut completion_resolvers = env_guard
|
|
418
380
|
.completion_resolvers
|
|
419
381
|
.lock()
|
|
420
|
-
.map_err(|e| format!("Failed to lock completion resolvers: {}"
|
|
382
|
+
.map_err(|e| format!("Failed to lock completion resolvers: {e}"))?;
|
|
421
383
|
completion_resolvers.insert(process_uuid.clone(), completion_resolver.clone());
|
|
422
384
|
drop(completion_resolvers);
|
|
423
385
|
|
|
424
386
|
let exec_code = format!(
|
|
425
387
|
r#"
|
|
426
|
-
pickled_str = "{}"
|
|
427
|
-
{}
|
|
388
|
+
pickled_str = "{pickled_data}"
|
|
389
|
+
{PYTHON_CHILD_SCRIPT}
|
|
428
390
|
"#,
|
|
429
|
-
pickled_data, PYTHON_CHILD_SCRIPT,
|
|
430
391
|
);
|
|
431
392
|
|
|
432
393
|
// Create a ForkRequest message
|
|
@@ -437,15 +398,15 @@ pickled_str = "{}"
|
|
|
437
398
|
};
|
|
438
399
|
|
|
439
400
|
let fork_json = serde_json::to_string(&Message::ForkRequest(fork_request))
|
|
440
|
-
.map_err(|e| format!("Failed to serialize fork request: {}"
|
|
401
|
+
.map_err(|e| format!("Failed to serialize fork request: {e}"))?;
|
|
441
402
|
|
|
442
403
|
// Send the message to the child process
|
|
443
|
-
writeln!(env_guard.stdin, "{}"
|
|
444
|
-
.map_err(|e| format!("Failed to write to child stdin: {}"
|
|
404
|
+
writeln!(env_guard.stdin, "{fork_json}")
|
|
405
|
+
.map_err(|e| format!("Failed to write to child stdin: {e}"))?;
|
|
445
406
|
env_guard
|
|
446
407
|
.stdin
|
|
447
408
|
.flush()
|
|
448
|
-
.map_err(|e| format!("Failed to flush child stdin: {}"
|
|
409
|
+
.map_err(|e| format!("Failed to flush child stdin: {e}"))?;
|
|
449
410
|
|
|
450
411
|
// Release the lock so we don't block other operations
|
|
451
412
|
drop(env_guard);
|
|
@@ -479,13 +440,13 @@ pickled_str = "{}"
|
|
|
479
440
|
info!("Stopping isolated process: {}", process_uuid);
|
|
480
441
|
let env_guard = environment
|
|
481
442
|
.lock()
|
|
482
|
-
.map_err(|e| format!("Failed to lock environment mutex: {}"
|
|
443
|
+
.map_err(|e| format!("Failed to lock environment mutex: {e}"))?;
|
|
483
444
|
|
|
484
445
|
// Check if the process UUID exists
|
|
485
446
|
let forked_processes = env_guard
|
|
486
447
|
.forked_processes
|
|
487
448
|
.lock()
|
|
488
|
-
.map_err(|e| format!("Failed to lock forked processes: {}"
|
|
449
|
+
.map_err(|e| format!("Failed to lock forked processes: {e}"))?;
|
|
489
450
|
|
|
490
451
|
if !forked_processes.contains_key(process_uuid) {
|
|
491
452
|
warn!("No forked process found with UUID: {}", process_uuid);
|
|
@@ -518,21 +479,21 @@ pickled_str = "{}"
|
|
|
518
479
|
let mut forked_processes = env_guard
|
|
519
480
|
.forked_processes
|
|
520
481
|
.lock()
|
|
521
|
-
.map_err(|e| format!("Failed to lock forked processes: {}"
|
|
482
|
+
.map_err(|e| format!("Failed to lock forked processes: {e}"))?;
|
|
522
483
|
forked_processes.remove(process_uuid);
|
|
523
484
|
drop(forked_processes);
|
|
524
485
|
|
|
525
486
|
let mut fork_resolvers = env_guard
|
|
526
487
|
.fork_resolvers
|
|
527
488
|
.lock()
|
|
528
|
-
.map_err(|e| format!("Failed to lock fork resolvers: {}"
|
|
489
|
+
.map_err(|e| format!("Failed to lock fork resolvers: {e}"))?;
|
|
529
490
|
fork_resolvers.remove(process_uuid);
|
|
530
491
|
drop(fork_resolvers);
|
|
531
492
|
|
|
532
493
|
let mut completion_resolvers = env_guard
|
|
533
494
|
.completion_resolvers
|
|
534
495
|
.lock()
|
|
535
|
-
.map_err(|e| format!("Failed to lock completion resolvers: {}"
|
|
496
|
+
.map_err(|e| format!("Failed to lock completion resolvers: {e}"))?;
|
|
536
497
|
completion_resolvers.remove(process_uuid);
|
|
537
498
|
drop(completion_resolvers);
|
|
538
499
|
|
|
@@ -551,19 +512,16 @@ pickled_str = "{}"
|
|
|
551
512
|
|
|
552
513
|
let env_guard = environment
|
|
553
514
|
.lock()
|
|
554
|
-
.map_err(|e| format!("Failed to lock environment mutex: {}"
|
|
515
|
+
.map_err(|e| format!("Failed to lock environment mutex: {e}"))?;
|
|
555
516
|
|
|
556
517
|
// Check if the process exists
|
|
557
518
|
let forked_processes = env_guard
|
|
558
519
|
.forked_processes
|
|
559
520
|
.lock()
|
|
560
|
-
.map_err(|e| format!("Failed to lock forked processes: {}"
|
|
521
|
+
.map_err(|e| format!("Failed to lock forked processes: {e}"))?;
|
|
561
522
|
|
|
562
523
|
if !forked_processes.contains_key(process_uuid) {
|
|
563
|
-
return Err(format!(
|
|
564
|
-
"No forked process found with UUID: {}",
|
|
565
|
-
process_uuid
|
|
566
|
-
));
|
|
524
|
+
return Err(format!("No forked process found with UUID: {process_uuid}"));
|
|
567
525
|
}
|
|
568
526
|
drop(forked_processes);
|
|
569
527
|
|
|
@@ -571,14 +529,13 @@ pickled_str = "{}"
|
|
|
571
529
|
let completion_resolvers = env_guard
|
|
572
530
|
.completion_resolvers
|
|
573
531
|
.lock()
|
|
574
|
-
.map_err(|e| format!("Failed to lock completion resolvers: {}"
|
|
532
|
+
.map_err(|e| format!("Failed to lock completion resolvers: {e}"))?;
|
|
575
533
|
|
|
576
534
|
let completion_resolver = match completion_resolvers.get(process_uuid) {
|
|
577
535
|
Some(resolver) => resolver.clone(),
|
|
578
536
|
None => {
|
|
579
537
|
return Err(format!(
|
|
580
|
-
"No completion resolver found for UUID: {}"
|
|
581
|
-
process_uuid
|
|
538
|
+
"No completion resolver found for UUID: {process_uuid}"
|
|
582
539
|
))
|
|
583
540
|
}
|
|
584
541
|
};
|
|
@@ -686,7 +643,7 @@ mod tests {
|
|
|
686
643
|
|
|
687
644
|
// Get the PID of the initial Python process
|
|
688
645
|
let initial_pid = runner.layer.as_ref().unwrap().lock().unwrap().child.id();
|
|
689
|
-
println!("Initial process PID: {:?}"
|
|
646
|
+
println!("Initial process PID: {initial_pid:?}");
|
|
690
647
|
|
|
691
648
|
// First, prime the system by calling process_all_py_files to establish a baseline
|
|
692
649
|
let _ = runner.ast_manager.process_all_py_files().unwrap();
|
|
@@ -700,15 +657,14 @@ mod tests {
|
|
|
700
657
|
);
|
|
701
658
|
|
|
702
659
|
// The environment should NOT have been updated (return false)
|
|
703
|
-
|
|
704
|
-
no_change_result.unwrap(),
|
|
705
|
-
false,
|
|
660
|
+
assert!(
|
|
661
|
+
!no_change_result.unwrap(),
|
|
706
662
|
"Environment should not have been updated when imports didn't change"
|
|
707
663
|
);
|
|
708
664
|
|
|
709
665
|
// Get the PID after update with no changes
|
|
710
666
|
let unchanged_pid = runner.layer.as_ref().unwrap().lock().unwrap().child.id();
|
|
711
|
-
println!("PID after no changes: {:?}"
|
|
667
|
+
println!("PID after no changes: {unchanged_pid:?}");
|
|
712
668
|
|
|
713
669
|
// Verify that the process was NOT restarted (PIDs should be the same)
|
|
714
670
|
assert_eq!(
|
|
@@ -739,7 +695,7 @@ mod tests {
|
|
|
739
695
|
|
|
740
696
|
// Get the PID of the new Python process
|
|
741
697
|
let new_pid = runner.layer.as_ref().unwrap().lock().unwrap().child.id();
|
|
742
|
-
println!("New process PID after import changes: {:?}"
|
|
698
|
+
println!("New process PID after import changes: {new_pid:?}");
|
|
743
699
|
}
|
|
744
700
|
|
|
745
701
|
#[test]
|
|
@@ -787,14 +743,13 @@ def main():
|
|
|
787
743
|
|
|
788
744
|
// The result should be our timestamp string
|
|
789
745
|
let result_str = result_option.unwrap();
|
|
790
|
-
println!("Result from time.time(): {}"
|
|
746
|
+
println!("Result from time.time(): {result_str}");
|
|
791
747
|
|
|
792
748
|
// Try to parse the result as a float to verify it's a valid timestamp
|
|
793
749
|
let parsed_result = result_str.parse::<f64>();
|
|
794
750
|
assert!(
|
|
795
751
|
parsed_result.is_ok(),
|
|
796
|
-
"Failed to parse result as a float: {}"
|
|
797
|
-
result_str
|
|
752
|
+
"Failed to parse result as a float: {result_str}"
|
|
798
753
|
);
|
|
799
754
|
|
|
800
755
|
// Clean up by stopping the isolated process
|
|
@@ -851,7 +806,7 @@ def main():
|
|
|
851
806
|
);
|
|
852
807
|
|
|
853
808
|
let pid = *forked_processes.get(&test_uuid).unwrap();
|
|
854
|
-
println!("Process PID: {}"
|
|
809
|
+
println!("Process PID: {pid}");
|
|
855
810
|
drop(forked_processes);
|
|
856
811
|
}
|
|
857
812
|
|
|
@@ -943,7 +898,7 @@ def main():
|
|
|
943
898
|
let result = runner.communicate_isolated(&process_uuid);
|
|
944
899
|
|
|
945
900
|
// Verify that we got an error
|
|
946
|
-
assert!(result.is_err(), "Expected an error but got: {:?}"
|
|
901
|
+
assert!(result.is_err(), "Expected an error but got: {result:?}");
|
|
947
902
|
|
|
948
903
|
// Get the error message
|
|
949
904
|
let error_message = result.err().unwrap();
|
|
@@ -951,16 +906,14 @@ def main():
|
|
|
951
906
|
// The error should contain the specific error message
|
|
952
907
|
assert!(
|
|
953
908
|
error_message.contains("This is a custom error message"),
|
|
954
|
-
"Error should contain the custom error message but got: {}"
|
|
955
|
-
error_message
|
|
909
|
+
"Error should contain the custom error message but got: {error_message}"
|
|
956
910
|
);
|
|
957
911
|
|
|
958
912
|
// The error should contain traceback information
|
|
959
913
|
assert!(
|
|
960
914
|
error_message.contains("Traceback")
|
|
961
915
|
|| error_message.contains("function_that_raises_error"),
|
|
962
|
-
"Error should contain traceback information but got: {}"
|
|
963
|
-
error_message
|
|
916
|
+
"Error should contain traceback information but got: {error_message}"
|
|
964
917
|
);
|
|
965
918
|
|
|
966
919
|
// Clean up
|