firehot 0.3.4__tar.gz → 0.4.1.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 (80) hide show
  1. {firehot-0.3.4 → firehot-0.4.1.dev1}/.github/workflows/ci-build.yml +14 -6
  2. {firehot-0.3.4 → firehot-0.4.1.dev1}/Cargo.lock +1 -1
  3. {firehot-0.3.4 → firehot-0.4.1.dev1}/Cargo.toml +1 -1
  4. {firehot-0.3.4 → firehot-0.4.1.dev1}/PKG-INFO +1 -1
  5. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp310-cp310-macosx_10_12_x86_64.whl +0 -0
  6. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp310-cp310-macosx_11_0_arm64.whl +0 -0
  7. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl +0 -0
  8. 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
  9. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp311-cp311-macosx_10_12_x86_64.whl +0 -0
  10. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp311-cp311-macosx_11_0_arm64.whl +0 -0
  11. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl +0 -0
  12. 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
  13. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp312-cp312-macosx_10_12_x86_64.whl +0 -0
  14. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp312-cp312-macosx_11_0_arm64.whl +0 -0
  15. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl +0 -0
  16. 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
  17. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp313-cp313-macosx_10_12_x86_64.whl +0 -0
  18. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp313-cp313-macosx_11_0_arm64.whl +0 -0
  19. firehot-0.4.1.dev1/dist_clean/firehot-0.4.1.dev1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl +0 -0
  20. 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
  21. {firehot-0.3.4 → firehot-0.4.1.dev1}/firehot/__tests__/test_context.py +17 -1
  22. {firehot-0.3.4 → firehot-0.4.1.dev1}/firehot/context.py +5 -2
  23. {firehot-0.3.4 → firehot-0.4.1.dev1}/pyproject.toml +1 -1
  24. {firehot-0.3.4 → firehot-0.4.1.dev1}/src/ast.rs +114 -7
  25. {firehot-0.3.4 → firehot-0.4.1.dev1}/src/environment.rs +19 -11
  26. {firehot-0.3.4 → firehot-0.4.1.dev1}/src/layer.rs +2 -2
  27. {firehot-0.3.4 → firehot-0.4.1.dev1}/src/lib.rs +12 -2
  28. {firehot-0.3.4 → firehot-0.4.1.dev1}/src/test_utils/harness.rs +1 -1
  29. firehot-0.3.4/dist_clean/firehot-0.3.4-cp310-cp310-macosx_11_0_arm64.whl +0 -0
  30. firehot-0.3.4/dist_clean/firehot-0.3.4-cp310-cp310-manylinux_2_39_x86_64.whl +0 -0
  31. firehot-0.3.4/dist_clean/firehot-0.3.4-cp311-cp311-macosx_11_0_arm64.whl +0 -0
  32. firehot-0.3.4/dist_clean/firehot-0.3.4-cp311-cp311-manylinux_2_39_x86_64.whl +0 -0
  33. firehot-0.3.4/dist_clean/firehot-0.3.4-cp312-cp312-macosx_11_0_arm64.whl +0 -0
  34. firehot-0.3.4/dist_clean/firehot-0.3.4-cp312-cp312-manylinux_2_39_x86_64.whl +0 -0
  35. firehot-0.3.4/dist_clean/firehot-0.3.4-cp313-cp313-macosx_11_0_arm64.whl +0 -0
  36. firehot-0.3.4/dist_clean/firehot-0.3.4-cp313-cp313-manylinux_2_39_x86_64.whl +0 -0
  37. {firehot-0.3.4 → firehot-0.4.1.dev1}/.DS_Store +0 -0
  38. {firehot-0.3.4 → firehot-0.4.1.dev1}/.github/scripts/update_version.py +0 -0
  39. {firehot-0.3.4 → firehot-0.4.1.dev1}/.github/workflows/ci-test.yml +0 -0
  40. {firehot-0.3.4 → firehot-0.4.1.dev1}/.gitignore +0 -0
  41. {firehot-0.3.4 → firehot-0.4.1.dev1}/Makefile +0 -0
  42. {firehot-0.3.4 → firehot-0.4.1.dev1}/README.md +0 -0
  43. {firehot-0.3.4 → firehot-0.4.1.dev1}/demopackage/.python-version +0 -0
  44. {firehot-0.3.4 → firehot-0.4.1.dev1}/demopackage/README.md +0 -0
  45. {firehot-0.3.4 → firehot-0.4.1.dev1}/demopackage/demopackage/__init__.py +0 -0
  46. {firehot-0.3.4 → firehot-0.4.1.dev1}/demopackage/demopackage/app.py +0 -0
  47. {firehot-0.3.4 → firehot-0.4.1.dev1}/demopackage/demopackage/dep.py +0 -0
  48. {firehot-0.3.4 → firehot-0.4.1.dev1}/demopackage/demopackage/test_hotreload.py +0 -0
  49. {firehot-0.3.4 → firehot-0.4.1.dev1}/demopackage/external-package/.python-version +0 -0
  50. {firehot-0.3.4 → firehot-0.4.1.dev1}/demopackage/external-package/README.md +0 -0
  51. {firehot-0.3.4 → firehot-0.4.1.dev1}/demopackage/external-package/external_package/__init__.py +0 -0
  52. {firehot-0.3.4 → firehot-0.4.1.dev1}/demopackage/external-package/external_package/mock_imports.py +0 -0
  53. {firehot-0.3.4 → firehot-0.4.1.dev1}/demopackage/external-package/pyproject.toml +0 -0
  54. {firehot-0.3.4 → firehot-0.4.1.dev1}/demopackage/external-package/uv.lock +0 -0
  55. {firehot-0.3.4 → firehot-0.4.1.dev1}/demopackage/pyproject.toml +0 -0
  56. {firehot-0.3.4 → firehot-0.4.1.dev1}/demopackage/uv.lock +0 -0
  57. {firehot-0.3.4 → firehot-0.4.1.dev1}/firehot/__init__.py +0 -0
  58. {firehot-0.3.4 → firehot-0.4.1.dev1}/firehot/__tests__/__init__.py +0 -0
  59. {firehot-0.3.4 → firehot-0.4.1.dev1}/firehot/__tests__/conftest.py +0 -0
  60. {firehot-0.3.4 → firehot-0.4.1.dev1}/firehot/__tests__/embedded/__init__.py +0 -0
  61. {firehot-0.3.4 → firehot-0.4.1.dev1}/firehot/__tests__/embedded/test_call_serializer.py +0 -0
  62. {firehot-0.3.4 → firehot-0.4.1.dev1}/firehot/__tests__/embedded/test_child_entrypoint.py +0 -0
  63. {firehot-0.3.4 → firehot-0.4.1.dev1}/firehot/__tests__/embedded/test_parent_entrypoint.py +0 -0
  64. {firehot-0.3.4 → firehot-0.4.1.dev1}/firehot/__tests__/test_environment.py +0 -0
  65. {firehot-0.3.4 → firehot-0.4.1.dev1}/firehot/__tests__/test_naming.py +0 -0
  66. {firehot-0.3.4 → firehot-0.4.1.dev1}/firehot/embedded/call_serializer.py +0 -0
  67. {firehot-0.3.4 → firehot-0.4.1.dev1}/firehot/embedded/child_entrypoint.py +0 -0
  68. {firehot-0.3.4 → firehot-0.4.1.dev1}/firehot/embedded/parent_entrypoint.py +0 -0
  69. {firehot-0.3.4 → firehot-0.4.1.dev1}/firehot/embedded/types.py +0 -0
  70. {firehot-0.3.4 → firehot-0.4.1.dev1}/firehot/environment.py +0 -0
  71. {firehot-0.3.4 → firehot-0.4.1.dev1}/firehot/naming.py +0 -0
  72. {firehot-0.3.4 → firehot-0.4.1.dev1}/firehot/py.typed +0 -0
  73. {firehot-0.3.4 → firehot-0.4.1.dev1}/media/header.png +0 -0
  74. {firehot-0.3.4 → firehot-0.4.1.dev1}/src/async_resolve.rs +0 -0
  75. {firehot-0.3.4 → firehot-0.4.1.dev1}/src/messages.rs +0 -0
  76. {firehot-0.3.4 → firehot-0.4.1.dev1}/src/multiplex_logs.rs +0 -0
  77. {firehot-0.3.4 → firehot-0.4.1.dev1}/src/process.rs +0 -0
  78. {firehot-0.3.4 → firehot-0.4.1.dev1}/src/scripts.rs +0 -0
  79. {firehot-0.3.4 → firehot-0.4.1.dev1}/src/test_utils/mod.rs +0 -0
  80. {firehot-0.3.4 → firehot-0.4.1.dev1}/uv.lock +0 -0
@@ -87,6 +87,7 @@ jobs:
87
87
  matrix:
88
88
  os: [ubuntu-latest, macos-latest]
89
89
  python-version: ['3.10', '3.11', '3.12', '3.13']
90
+ target: [aarch64, x86_64]
90
91
 
91
92
  steps:
92
93
  - uses: actions/checkout@v3
@@ -103,9 +104,6 @@ jobs:
103
104
  toolchain: stable
104
105
  override: true
105
106
 
106
- - name: Install maturin
107
- run: pip install maturin
108
-
109
107
  - name: Update version
110
108
  if: startsWith(github.ref, 'refs/tags/v')
111
109
  shell: bash
@@ -113,13 +111,23 @@ jobs:
113
111
  pip install packaging toml
114
112
  python .github/scripts/update_version.py ${{ github.ref_name }}
115
113
 
116
- - name: Build wheels
117
- run: maturin build --release --strip --out dist
114
+ - name: build wheels
115
+ uses: PyO3/maturin-action@v1
116
+ with:
117
+ target: ${{ matrix.target }}
118
+ manylinux: auto
119
+ args: -vv --release --out dist --interpreter ${{ matrix.python-version }}
120
+ rust-toolchain: stable
121
+ docker-options: -e CI -e CI_TARGET=${{ matrix.target }}
122
+ # Already defaults to build, but we make explicit here. Any arguments should
123
+ # be added to args above and not here - otherwise we will affect the switch()
124
+ # condition handling of maturin-action.
125
+ command: build
118
126
 
119
127
  - name: Upload wheels
120
128
  uses: actions/upload-artifact@v4
121
129
  with:
122
- name: wheels-${{ matrix.os }}-py${{ matrix.python-version }}
130
+ name: wheels-${{ matrix.os }}-py${{ matrix.python-version }}-${{ matrix.target }}
123
131
  path: dist/*.whl
124
132
 
125
133
  # Collate all wheels for PyPI upload
@@ -217,7 +217,7 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
217
217
 
218
218
  [[package]]
219
219
  name = "firehot"
220
- version = "0.3.4"
220
+ version = "0.4.1-dev1"
221
221
  dependencies = [
222
222
  "anstream",
223
223
  "anyhow",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "firehot"
3
- version = "0.3.4"
3
+ version = "0.4.1-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.3.4
3
+ Version: 0.4.1.dev1
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Rust
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -1,7 +1,7 @@
1
1
  import importlib
2
2
  from pathlib import Path
3
3
 
4
- from firehot.context import resolve_package_metadata
4
+ from firehot.context import isolate_imports, resolve_package_metadata
5
5
 
6
6
 
7
7
  def test_resolve_package_metadata(sample_package):
@@ -29,3 +29,19 @@ def test_resolve_package_metadata(sample_package):
29
29
 
30
30
  # Check that the directory name matches the package name
31
31
  assert resolved_path.name == sample_package
32
+
33
+
34
+ def test_isolate_imports(sample_package):
35
+ """
36
+ Test that isolate_imports correctly creates an isolated environment and accepts ignored_modules.
37
+ """
38
+ # Test basic functionality without ignored modules
39
+ with isolate_imports(sample_package) as env:
40
+ assert env.runner_id is not None, "Expected runner_id to be set"
41
+
42
+ # Test with ignored modules
43
+ ignored = ["numpy", "pandas"]
44
+ with isolate_imports(sample_package, ignored_modules=ignored) as env:
45
+ assert env.runner_id is not None, "Expected runner_id to be set"
46
+ # The runner_id should be different from the previous one
47
+ assert isinstance(env.runner_id, str), "Expected runner_id to be a string"
@@ -42,18 +42,21 @@ def resolve_package_metadata(package: str) -> tuple[str, str]:
42
42
 
43
43
 
44
44
  @contextmanager
45
- def isolate_imports(package: str):
45
+ def isolate_imports(package: str, *, ignored_modules: list[str] | None = None):
46
46
  """
47
47
  Context manager that isolates imports for the given package path.
48
48
 
49
49
  :param package: Package to isolate imports. This must be importable from the current
50
50
  virtual environment
51
+ :param ignored_modules: Optional list of module names to ignore during hot reloading.
52
+ Changes to these modules will not trigger reloads.
51
53
  :yields: An Environment object that can be used to execute code in the isolated environment
54
+
52
55
  """
53
56
  package_path, package_name = resolve_package_metadata(package)
54
57
  runner_id: str | None = None
55
58
  try:
56
- runner_id = start_import_runner_rs(package_name, package_path)
59
+ runner_id = start_import_runner_rs(package_name, package_path, ignored_modules)
57
60
  yield Environment(runner_id)
58
61
  finally:
59
62
  if runner_id:
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "firehot"
7
- version = "0.3.4"
7
+ version = "0.4.1.dev1"
8
8
  description = "Wicked fast hot reloading"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -44,11 +44,17 @@ pub struct ProjectAstManager {
44
44
  package_name: String,
45
45
  /// The root path of the project
46
46
  project_path: String,
47
+ /// Set of modules to ignore when determining third-party imports
48
+ ignored_modules: HashSet<String>,
47
49
  }
48
50
 
49
51
  impl ProjectAstManager {
50
52
  /// Create a new ProjectAstManager for the given project path
51
- pub fn new(project_name: &str, project_path: &str) -> Self {
53
+ pub fn new(
54
+ project_name: &str,
55
+ project_path: &str,
56
+ ignored_modules: Option<HashSet<String>>,
57
+ ) -> Self {
52
58
  debug!(
53
59
  "Creating new ProjectAstManager for {} at {}",
54
60
  project_name, project_path
@@ -58,6 +64,7 @@ impl ProjectAstManager {
58
64
  file_imports: HashMap::new(),
59
65
  package_name: project_name.to_string(),
60
66
  project_path: project_path.to_string(),
67
+ ignored_modules: ignored_modules.unwrap_or_default(),
61
68
  }
62
69
  }
63
70
 
@@ -226,6 +233,11 @@ impl ProjectAstManager {
226
233
  trace!("Checking if import is third party: {:?}", imp);
227
234
  trace!("Package name: {}", self.package_name);
228
235
 
236
+ // If the module is in the ignored list, it's not considered third-party
237
+ if self.ignored_modules.contains(&imp.module) {
238
+ return false;
239
+ }
240
+
229
241
  let is_third_party = !imp.is_relative && !imp.module.starts_with(&self.package_name);
230
242
 
231
243
  trace!("Is third party: {}", is_third_party);
@@ -350,7 +362,7 @@ mod tests {
350
362
 
351
363
  #[test]
352
364
  fn test_project_ast_manager_initialization() {
353
- let manager = ProjectAstManager::new("test_package", "/test/path");
365
+ let manager = ProjectAstManager::new("test_package", "/test/path", None);
354
366
  assert_eq!(manager.get_project_path(), "/test/path");
355
367
  assert_eq!(manager.get_package_name(), "test_package");
356
368
  }
@@ -360,7 +372,8 @@ mod tests {
360
372
  let temp_dir = TempDir::new().unwrap();
361
373
  let file_path = create_temp_py_file(&temp_dir, "test.py", "print('hello')");
362
374
 
363
- let manager = ProjectAstManager::new("test_package", temp_dir.path().to_str().unwrap());
375
+ let manager =
376
+ ProjectAstManager::new("test_package", temp_dir.path().to_str().unwrap(), None);
364
377
  let hash_result = manager.calculate_file_hash(file_path.to_str().unwrap());
365
378
 
366
379
  assert!(hash_result.is_ok());
@@ -573,7 +586,7 @@ def function():
573
586
 
574
587
  #[test]
575
588
  fn test_is_third_party_import() {
576
- let manager = ProjectAstManager::new("my_package", "/test/path");
589
+ let manager = ProjectAstManager::new("my_package", "/test/path", None);
577
590
 
578
591
  // First-party absolute import (starts with package name)
579
592
  let first_party = ImportInfo {
@@ -612,7 +625,8 @@ def function():
612
625
  let python_code = "import os\nimport sys";
613
626
  let file_path = create_temp_py_file(&temp_dir, "test_file.py", python_code);
614
627
 
615
- let mut manager = ProjectAstManager::new("test_package", temp_dir.path().to_str().unwrap());
628
+ let mut manager =
629
+ ProjectAstManager::new("test_package", temp_dir.path().to_str().unwrap(), None);
616
630
  let imports_result = manager.process_py_file(file_path.to_str().unwrap());
617
631
 
618
632
  assert!(imports_result.is_ok());
@@ -630,7 +644,8 @@ def function():
630
644
  let file_path = create_temp_py_file(&temp_dir, "test_cache.py", python_code);
631
645
  let path_str = file_path.to_str().unwrap();
632
646
 
633
- let mut manager = ProjectAstManager::new("test_package", temp_dir.path().to_str().unwrap());
647
+ let mut manager =
648
+ ProjectAstManager::new("test_package", temp_dir.path().to_str().unwrap(), None);
634
649
 
635
650
  // First call should parse the file
636
651
  let _ = manager.process_py_file(path_str).unwrap();
@@ -669,7 +684,8 @@ def function():
669
684
  let file1_path = create_temp_py_file(&temp_dir, "file1.py", "import os\nimport requests");
670
685
  let _file2_path = create_temp_py_file(&temp_dir, "file2.py", "import sys\nimport flask");
671
686
 
672
- let mut manager = ProjectAstManager::new("testpkg", temp_dir.path().to_str().unwrap());
687
+ let mut manager =
688
+ ProjectAstManager::new("testpkg", temp_dir.path().to_str().unwrap(), None);
673
689
 
674
690
  // Initial processing
675
691
  let initial_imports = manager.process_all_py_files().unwrap();
@@ -700,4 +716,95 @@ def function():
700
716
  assert!(!removed.is_empty());
701
717
  assert!(removed.contains("requests"));
702
718
  }
719
+
720
+ #[test]
721
+ fn test_ignored_modules() {
722
+ let temp_dir = TempDir::new().unwrap();
723
+
724
+ // Create a Python file with various imports
725
+ let python_code = r#"
726
+ import os
727
+ import sys
728
+ import requests
729
+ from pandas import DataFrame
730
+ from my_package.utils import helper
731
+ from . import local_module
732
+ "#;
733
+ create_temp_py_file(&temp_dir, "test_imports.py", python_code);
734
+
735
+ // Create a manager with ignored modules
736
+ let mut ignored_modules = HashSet::new();
737
+ ignored_modules.insert("pandas".to_string());
738
+ ignored_modules.insert("requests".to_string());
739
+
740
+ let mut manager = ProjectAstManager::new(
741
+ "my_package",
742
+ temp_dir.path().to_str().unwrap(),
743
+ Some(ignored_modules),
744
+ );
745
+
746
+ // Process all files and get third-party imports
747
+ let third_party_imports = manager.process_all_py_files().unwrap();
748
+
749
+ // Verify that ignored modules are not included in third-party imports
750
+ assert!(
751
+ !third_party_imports.contains("pandas"),
752
+ "pandas should be ignored"
753
+ );
754
+ assert!(
755
+ !third_party_imports.contains("requests"),
756
+ "requests should be ignored"
757
+ );
758
+
759
+ // But other third-party modules should be included
760
+ assert!(third_party_imports.contains("os"), "os should be included");
761
+ assert!(
762
+ third_party_imports.contains("sys"),
763
+ "sys should be included"
764
+ );
765
+
766
+ // First-party imports should still be excluded
767
+ assert!(
768
+ !third_party_imports.contains("my_package.utils"),
769
+ "my_package.utils should not be included"
770
+ );
771
+ assert!(
772
+ !third_party_imports.contains("local_module"),
773
+ "local_module should not be included"
774
+ );
775
+
776
+ // Now test with no ignored modules
777
+ let mut manager_no_ignore =
778
+ ProjectAstManager::new("my_package", temp_dir.path().to_str().unwrap(), None);
779
+
780
+ let all_third_party_imports = manager_no_ignore.process_all_py_files().unwrap();
781
+
782
+ // Without ignore list, all third-party modules should be included
783
+ assert!(
784
+ all_third_party_imports.contains("pandas"),
785
+ "pandas should be included when not ignored"
786
+ );
787
+ assert!(
788
+ all_third_party_imports.contains("requests"),
789
+ "requests should be included when not ignored"
790
+ );
791
+ assert!(
792
+ all_third_party_imports.contains("os"),
793
+ "os should be included"
794
+ );
795
+ assert!(
796
+ all_third_party_imports.contains("sys"),
797
+ "sys should be included"
798
+ );
799
+
800
+ // First-party imports should still be excluded
801
+ assert!(
802
+ !all_third_party_imports.contains("my_package.utils"),
803
+ "my_package.utils should not be included"
804
+ );
805
+ assert!(
806
+ !all_third_party_imports.contains("local_module"),
807
+ "local_module should not be included"
808
+ );
809
+ }
703
810
  }
@@ -30,9 +30,13 @@ pub struct Environment {
30
30
  }
31
31
 
32
32
  impl Environment {
33
- pub fn new(project_name: &str, project_path: &str) -> Self {
33
+ pub fn new(
34
+ project_name: &str,
35
+ project_path: &str,
36
+ ignored_modules: Option<HashSet<String>>,
37
+ ) -> Self {
34
38
  // Create a new AST manager for this project
35
- let ast_manager = ProjectAstManager::new(project_name, project_path);
39
+ let ast_manager = ProjectAstManager::new(project_name, project_path, ignored_modules);
36
40
  info!("Created AST manager for project: {}", project_name);
37
41
 
38
42
  Self {
@@ -45,9 +49,13 @@ impl Environment {
45
49
  }
46
50
 
47
51
  /// Create a new Environment in test mode (buffers output instead of printing)
48
- pub fn new_for_test(project_name: &str, project_path: &str) -> Self {
52
+ pub fn new_for_test(
53
+ project_name: &str,
54
+ project_path: &str,
55
+ ignored_modules: Option<HashSet<String>>,
56
+ ) -> Self {
49
57
  // Create a new AST manager for this project
50
- let ast_manager = ProjectAstManager::new(project_name, project_path);
58
+ let ast_manager = ProjectAstManager::new(project_name, project_path, ignored_modules);
51
59
  info!("Created AST manager for project: {}", project_name);
52
60
 
53
61
  Self {
@@ -647,7 +655,7 @@ mod tests {
647
655
  // Create a simple Python project
648
656
  create_temp_py_file(&temp_dir, "main.py", "print('Hello, world!')");
649
657
 
650
- let mut runner = Environment::new("test_package", dir_path);
658
+ let mut runner = Environment::new("test_package", dir_path, None);
651
659
  assert_eq!(runner.ast_manager.get_project_path(), dir_path);
652
660
 
653
661
  // Boot the environment before checking it
@@ -668,7 +676,7 @@ mod tests {
668
676
  // Create a simple Python project with initial imports
669
677
  create_temp_py_file(&temp_dir, "main.py", "import os\nimport sys");
670
678
 
671
- let mut runner = Environment::new("test_package", dir_path);
679
+ let mut runner = Environment::new("test_package", dir_path, None);
672
680
 
673
681
  // Boot the environment before accessing it
674
682
  runner.boot_main().expect("Failed to boot main environment");
@@ -750,7 +758,7 @@ def main():
750
758
  crate::test_utils::harness::prepare_script_for_isolation(python_script, "main")
751
759
  .expect("Failed to prepare script for isolation");
752
760
 
753
- let mut runner = Environment::new("test_package", &python_env.container_path);
761
+ let mut runner = Environment::new("test_package", &python_env.container_path, None);
754
762
 
755
763
  // Boot the environment before accessing it
756
764
  runner.boot_main().expect("Failed to boot main environment");
@@ -800,7 +808,7 @@ def main():
800
808
  let temp_dir = TempDir::new().unwrap();
801
809
  let dir_path = temp_dir.path().to_str().unwrap();
802
810
 
803
- let mut runner = Environment::new("test_package", dir_path);
811
+ let mut runner = Environment::new("test_package", dir_path, None);
804
812
 
805
813
  // Boot the environment before accessing it
806
814
  runner.boot_main().expect("Failed to boot main environment");
@@ -885,7 +893,7 @@ def main():
885
893
  let temp_dir = TempDir::new().unwrap();
886
894
  let dir_path = temp_dir.path().to_str().unwrap();
887
895
 
888
- let mut runner = Environment::new("test_package", dir_path);
896
+ let mut runner = Environment::new("test_package", dir_path, None);
889
897
 
890
898
  // Boot the environment before stopping it
891
899
  runner.boot_main().expect("Failed to boot main environment");
@@ -921,7 +929,7 @@ def main():
921
929
  crate::test_utils::harness::prepare_script_for_isolation(python_script, "main")?;
922
930
 
923
931
  // Create and boot the Environment
924
- let mut runner = Environment::new("test_package", dir_path);
932
+ let mut runner = Environment::new("test_package", dir_path, None);
925
933
  runner.boot_main()?;
926
934
 
927
935
  // Execute the script in isolation - this should not fail at this point
@@ -980,7 +988,7 @@ def main():
980
988
  .expect("Failed to prepare long-running script for isolation");
981
989
 
982
990
  // Create and boot environment
983
- let mut runner = Environment::new("test_package", &python_env.container_path);
991
+ let mut runner = Environment::new("test_package", &python_env.container_path, None);
984
992
  runner.boot_main().expect("Failed to boot main environment");
985
993
 
986
994
  // Execute the long-running function
@@ -648,7 +648,7 @@ def main():
648
648
  crate::test_utils::harness::prepare_script_for_isolation(python_script, "main")?;
649
649
 
650
650
  // Create and boot the Environment
651
- let mut runner = Environment::new_for_test("test_package", dir_path);
651
+ let mut runner = Environment::new_for_test("test_package", dir_path, None);
652
652
  runner.boot_main()?;
653
653
 
654
654
  // Execute the script in isolation
@@ -725,7 +725,7 @@ def main():
725
725
  crate::test_utils::harness::prepare_script_for_isolation(python_script, "main")?;
726
726
 
727
727
  // Create and boot the Environment
728
- let mut runner = Environment::new_for_test("test_package", dir_path);
728
+ let mut runner = Environment::new_for_test("test_package", dir_path, None);
729
729
  runner.boot_main()?;
730
730
 
731
731
  // Execute the script in isolation
@@ -7,6 +7,7 @@ use std::{collections::HashMap, time::Instant};
7
7
  use pyo3::exceptions::PyRuntimeError;
8
8
  use pyo3::prelude::*;
9
9
  use pyo3::types::PyDict;
10
+ use std::collections::HashSet;
10
11
  use std::sync::Mutex;
11
12
  use uuid::Uuid;
12
13
 
@@ -86,7 +87,12 @@ fn firehot(_py: Python, m: &PyModule) -> PyResult<()> {
86
87
 
87
88
  /// Initialize and start the import runner, returning a unique identifier
88
89
  #[pyfunction]
89
- fn start_import_runner(_py: Python, project_name: &str, package_path: &str) -> PyResult<String> {
90
+ fn start_import_runner(
91
+ _py: Python,
92
+ project_name: &str,
93
+ package_path: &str,
94
+ ignored_modules: Option<Vec<String>>,
95
+ ) -> PyResult<String> {
90
96
  // Generate a unique ID for this runner
91
97
  let env_id = Uuid::new_v4().to_string();
92
98
 
@@ -98,9 +104,13 @@ fn start_import_runner(_py: Python, project_name: &str, package_path: &str) -> P
98
104
  project_name.cyan().bold()
99
105
  );
100
106
 
107
+ // Convert ignored_modules from Vec to HashSet if provided
108
+ let ignored_modules_set =
109
+ ignored_modules.map(|modules| modules.into_iter().collect::<HashSet<String>>());
110
+
101
111
  // Create the runner object
102
112
  info!("Creating environment with ID: {}", env_id);
103
- let mut runner = environment::Environment::new(project_name, package_path);
113
+ let mut runner = environment::Environment::new(project_name, package_path, ignored_modules_set);
104
114
 
105
115
  runner.boot_main().map_err(|e| {
106
116
  error!("Failed to boot main: {}", e);
@@ -253,7 +253,7 @@ def main():
253
253
  let (pickled_data, python_env) = prepare_script_for_isolation(python_script, "main")?;
254
254
 
255
255
  // Create a mock Environment
256
- let mut runner = Environment::new("test_package", &python_env.container_path);
256
+ let mut runner = Environment::new("test_package", &python_env.container_path, None);
257
257
 
258
258
  // Boot the environment
259
259
  runner.boot_main()?;
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes