firehot 0.4.1.dev1__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.
Files changed (88) hide show
  1. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/Cargo.lock +1 -1
  2. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/Cargo.toml +1 -1
  3. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/PKG-INFO +1 -1
  4. firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp310-cp310-macosx_10_12_x86_64.whl +0 -0
  5. firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp310-cp310-macosx_11_0_arm64.whl +0 -0
  6. firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl +0 -0
  7. 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
  8. firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp311-cp311-macosx_10_12_x86_64.whl +0 -0
  9. firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp311-cp311-macosx_11_0_arm64.whl +0 -0
  10. firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl +0 -0
  11. 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
  12. firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp312-cp312-macosx_10_12_x86_64.whl +0 -0
  13. firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp312-cp312-macosx_11_0_arm64.whl +0 -0
  14. firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl +0 -0
  15. 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
  16. firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp313-cp313-macosx_10_12_x86_64.whl +0 -0
  17. firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp313-cp313-macosx_11_0_arm64.whl +0 -0
  18. firehot-0.4.2.dev1/dist_clean/firehot-0.4.2.dev1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl +0 -0
  19. 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
  20. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/pyproject.toml +1 -1
  21. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/src/ast.rs +23 -23
  22. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/src/async_resolve.rs +4 -4
  23. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/src/environment.rs +62 -109
  24. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/src/layer.rs +198 -13
  25. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/src/lib.rs +11 -11
  26. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/src/messages.rs +3 -3
  27. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/src/multiplex_logs.rs +4 -5
  28. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/src/test_utils/harness.rs +9 -9
  29. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp310-cp310-macosx_10_12_x86_64.whl +0 -0
  30. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp310-cp310-macosx_11_0_arm64.whl +0 -0
  31. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl +0 -0
  32. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl +0 -0
  33. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp311-cp311-macosx_10_12_x86_64.whl +0 -0
  34. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp311-cp311-macosx_11_0_arm64.whl +0 -0
  35. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl +0 -0
  36. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl +0 -0
  37. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp312-cp312-macosx_10_12_x86_64.whl +0 -0
  38. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp312-cp312-macosx_11_0_arm64.whl +0 -0
  39. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl +0 -0
  40. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl +0 -0
  41. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp313-cp313-macosx_10_12_x86_64.whl +0 -0
  42. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp313-cp313-macosx_11_0_arm64.whl +0 -0
  43. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl +0 -0
  44. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl +0 -0
  45. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/.DS_Store +0 -0
  46. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/.github/scripts/update_version.py +0 -0
  47. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/.github/workflows/ci-build.yml +0 -0
  48. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/.github/workflows/ci-test.yml +0 -0
  49. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/.gitignore +0 -0
  50. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/Makefile +0 -0
  51. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/README.md +0 -0
  52. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/demopackage/.python-version +0 -0
  53. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/demopackage/README.md +0 -0
  54. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/demopackage/demopackage/__init__.py +0 -0
  55. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/demopackage/demopackage/app.py +0 -0
  56. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/demopackage/demopackage/dep.py +0 -0
  57. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/demopackage/demopackage/test_hotreload.py +0 -0
  58. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/demopackage/external-package/.python-version +0 -0
  59. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/demopackage/external-package/README.md +0 -0
  60. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/demopackage/external-package/external_package/__init__.py +0 -0
  61. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/demopackage/external-package/external_package/mock_imports.py +0 -0
  62. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/demopackage/external-package/pyproject.toml +0 -0
  63. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/demopackage/external-package/uv.lock +0 -0
  64. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/demopackage/pyproject.toml +0 -0
  65. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/demopackage/uv.lock +0 -0
  66. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/firehot/__init__.py +0 -0
  67. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/firehot/__tests__/__init__.py +0 -0
  68. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/firehot/__tests__/conftest.py +0 -0
  69. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/firehot/__tests__/embedded/__init__.py +0 -0
  70. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/firehot/__tests__/embedded/test_call_serializer.py +0 -0
  71. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/firehot/__tests__/embedded/test_child_entrypoint.py +0 -0
  72. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/firehot/__tests__/embedded/test_parent_entrypoint.py +0 -0
  73. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/firehot/__tests__/test_context.py +0 -0
  74. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/firehot/__tests__/test_environment.py +0 -0
  75. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/firehot/__tests__/test_naming.py +0 -0
  76. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/firehot/context.py +0 -0
  77. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/firehot/embedded/call_serializer.py +0 -0
  78. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/firehot/embedded/child_entrypoint.py +0 -0
  79. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/firehot/embedded/parent_entrypoint.py +0 -0
  80. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/firehot/embedded/types.py +0 -0
  81. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/firehot/environment.py +0 -0
  82. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/firehot/naming.py +0 -0
  83. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/firehot/py.typed +0 -0
  84. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/media/header.png +0 -0
  85. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/src/process.rs +0 -0
  86. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/src/scripts.rs +0 -0
  87. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/src/test_utils/mod.rs +0 -0
  88. {firehot-0.4.1.dev1 → firehot-0.4.2.dev1}/uv.lock +0 -0
@@ -217,7 +217,7 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
217
217
 
218
218
  [[package]]
219
219
  name = "firehot"
220
- version = "0.4.1-dev1"
220
+ version = "0.4.2-dev1"
221
221
  dependencies = [
222
222
  "anstream",
223
223
  "anyhow",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "firehot"
3
- version = "0.4.1-dev1"
3
+ version = "0.4.2-dev1"
4
4
  edition = "2021"
5
5
 
6
6
  [lib]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: firehot
3
- Version: 0.4.1.dev1
3
+ Version: 0.4.2.dev1
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Rust
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "firehot"
7
- version = "0.4.1.dev1"
7
+ version = "0.4.2.dev1"
8
8
  description = "Wicked fast hot reloading"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -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}", hash);
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
- assert_eq!(imports[0].is_relative, false);
408
- assert_eq!(imports[0].is_from_import, false);
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
- assert_eq!(imports[1].is_relative, false);
413
- assert_eq!(imports[1].is_from_import, false);
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
- assert_eq!(imports[0].is_relative, false);
436
- assert_eq!(imports[0].is_from_import, true);
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
- assert_eq!(imports[1].is_relative, false);
441
- assert_eq!(imports[1].is_from_import, true);
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
- assert_eq!(imports[0].is_relative, false);
464
- assert_eq!(imports[0].is_from_import, false);
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
- assert_eq!(imports[1].is_relative, false);
469
- assert_eq!(imports[1].is_from_import, true);
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: {:#?}", imports);
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
- assert_eq!(import.is_from_import, true);
498
- assert_eq!(import.is_relative, true);
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
- assert_eq!(imports[0].is_relative, false);
578
- assert_eq!(imports[0].is_from_import, false); // This is a simple import
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
- assert_eq!(imports[1].is_relative, false);
584
- assert_eq!(imports[1].is_from_import, true); // This is a from import
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: {:#?}", initial_imports);
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: {:#?}", added);
711
- println!("Removed imports: {:#?}", removed);
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: {:?}", e);
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: {:?}", e);
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: {:?}", e);
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: {:?}", e);
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: {}", e))?;
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: {}", e))?;
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
- let reader = BufReader::new(stdout);
130
- let mut lines_iter = reader.lines();
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
- if !imports_loaded {
174
- error!("Python loader did not report successful imports");
175
- return Err("Python loader did not report successful imports".to_string());
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
- let mut layer = if self.test_mode {
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: {}", e))?;
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: {}", e))?;
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: {}", e))?;
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: {}", e))?;
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, "{}", exit_json) {
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: {}", e))?;
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: {}", e))?;
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: {}", e))?;
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: {}", e))?;
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: {}", e))?;
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: {}", e))?;
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: {}", e))?;
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: {}", e))?;
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: {}", e))?;
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: {}", e))?;
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, "{}", fork_json)
444
- .map_err(|e| format!("Failed to write to child stdin: {}", e))?;
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: {}", e))?;
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: {}", e))?;
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: {}", e))?;
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: {}", e))?;
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: {}", e))?;
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: {}", e))?;
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: {}", e))?;
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: {}", e))?;
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: {}", e))?;
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: {:?}", initial_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
- assert_eq!(
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: {:?}", unchanged_pid);
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: {:?}", new_pid);
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(): {}", result_str);
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: {}", 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: {:?}", result);
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