media-engine 0.1.0__tar.gz → 0.1.1__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.
- {media_engine-0.1.0 → media_engine-0.1.1}/PKG-INFO +3 -2
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/_version.py +2 -2
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/routers/models.py +27 -11
- {media_engine-0.1.0 → media_engine-0.1.1}/pyproject.toml +2 -1
- media_engine-0.1.1/tests/test_dependencies.py +176 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/.github/workflows/ci.yml +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/.github/workflows/release.yml +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/.gitignore +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/API.md +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/CLAUDE.md +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/Dockerfile +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/Dockerfile.cuda +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/Dockerfile.mlx +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/LICENSE +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/MANIFEST.in +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/README.md +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/cli/clip.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/cli/faces.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/cli/metadata.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/cli/motion.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/cli/objects.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/cli/ocr.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/cli/scenes.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/cli/telemetry.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/cli/transcript.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/demo/index.html +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/demo/run.sh +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/demo/server.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/docker-compose.yml +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/__init__.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/app.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/batch/__init__.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/batch/models.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/batch/processor.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/batch/queue.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/batch/state.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/batch/timing.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/cli.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/config.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/__init__.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/clip.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/faces.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/frame_buffer.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/frames.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/metadata/__init__.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/metadata/apple.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/metadata/arri.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/metadata/avchd.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/metadata/avchd_gps.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/metadata/base.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/metadata/blackmagic.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/metadata/camera_360.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/metadata/canon.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/metadata/dji.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/metadata/dv.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/metadata/ffmpeg.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/metadata/generic.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/metadata/gopro.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/metadata/red.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/metadata/registry.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/metadata/sony.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/metadata/tesla.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/motion.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/objects.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/objects_qwen.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/ocr.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/scenes.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/shot_type.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/telemetry.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/transcribe.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/translate.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/extractors/vad.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/main.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/py.typed +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/routers/__init__.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/routers/batch.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/routers/health.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/routers/settings.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/routers/utils.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/schemas.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/utils/__init__.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/utils/logging.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/media_engine/utils/memory.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/tests/__init__.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/tests/conftest.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/tests/stress_test.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/tests/test_api.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/tests/test_batch_api.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/tests/test_clip.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/tests/test_faces.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/tests/test_memory.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/tests/test_metadata.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/tests/test_model_lifecycle.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/tests/test_objects.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/tests/test_ocr.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/tests/test_scenes.py +0 -0
- {media_engine-0.1.0 → media_engine-0.1.1}/tests/test_transcribe.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: media-engine
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: AI-powered video extraction API for metadata, transcripts, faces, scenes, objects, and more
|
|
5
5
|
Project-URL: Repository, https://github.com/thetrainroom/media-engine
|
|
6
6
|
Project-URL: Issues, https://github.com/thetrainroom/media-engine/issues
|
|
@@ -28,6 +28,8 @@ Requires-Dist: psutil>=5.9.0
|
|
|
28
28
|
Requires-Dist: pydantic-settings>=2.0.0
|
|
29
29
|
Requires-Dist: pydantic>=2.0.0
|
|
30
30
|
Requires-Dist: scenedetect[opencv]>=0.6.0
|
|
31
|
+
Requires-Dist: tf-keras>=2.16.0
|
|
32
|
+
Requires-Dist: transformers>=4.40.0
|
|
31
33
|
Requires-Dist: uvicorn>=0.27.0
|
|
32
34
|
Requires-Dist: webrtcvad>=2.0.10
|
|
33
35
|
Provides-Extra: cpu
|
|
@@ -58,7 +60,6 @@ Provides-Extra: qwen
|
|
|
58
60
|
Requires-Dist: accelerate>=0.30.0; extra == 'qwen'
|
|
59
61
|
Requires-Dist: qwen-vl-utils>=0.0.8; extra == 'qwen'
|
|
60
62
|
Requires-Dist: torch>=2.0.0; extra == 'qwen'
|
|
61
|
-
Requires-Dist: transformers>=4.40.0; extra == 'qwen'
|
|
62
63
|
Description-Content-Type: text/markdown
|
|
63
64
|
|
|
64
65
|
# Media Engine
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.1.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 1,
|
|
31
|
+
__version__ = version = '0.1.1'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 1, 1)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -33,22 +33,38 @@ def _run_model_checks(check_id: str) -> None:
|
|
|
33
33
|
_model_check_status[check_id] = "running"
|
|
34
34
|
|
|
35
35
|
try:
|
|
36
|
-
# Test Qwen 2B
|
|
37
|
-
logger.info("Testing Qwen 2B model...")
|
|
38
|
-
start = time.time()
|
|
36
|
+
# Test Qwen 2B (requires qwen extras: pip install media-engine[qwen])
|
|
39
37
|
try:
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
38
|
+
import importlib.util
|
|
39
|
+
|
|
40
|
+
if importlib.util.find_spec("transformers") is None:
|
|
41
|
+
results["qwen_2b"] = {
|
|
42
|
+
"canLoad": False,
|
|
43
|
+
"error": "transformers not installed. Install with: pip install media-engine[qwen]",
|
|
44
|
+
"loadTimeSeconds": 0,
|
|
45
|
+
}
|
|
46
|
+
else:
|
|
47
|
+
logger.info("Testing Qwen 2B model...")
|
|
48
|
+
start = time.time()
|
|
49
|
+
try:
|
|
50
|
+
_get_qwen_model("Qwen/Qwen2-VL-2B-Instruct")
|
|
51
|
+
results["qwen_2b"] = {
|
|
52
|
+
"canLoad": True,
|
|
53
|
+
"error": None,
|
|
54
|
+
"loadTimeSeconds": round(time.time() - start, 1),
|
|
55
|
+
}
|
|
56
|
+
unload_qwen_model()
|
|
57
|
+
except Exception as e:
|
|
58
|
+
results["qwen_2b"] = {
|
|
59
|
+
"canLoad": False,
|
|
60
|
+
"error": str(e),
|
|
61
|
+
"loadTimeSeconds": round(time.time() - start, 1),
|
|
62
|
+
}
|
|
47
63
|
except Exception as e:
|
|
48
64
|
results["qwen_2b"] = {
|
|
49
65
|
"canLoad": False,
|
|
50
66
|
"error": str(e),
|
|
51
|
-
"loadTimeSeconds":
|
|
67
|
+
"loadTimeSeconds": 0,
|
|
52
68
|
}
|
|
53
69
|
|
|
54
70
|
# Test Whisper large-v3
|
|
@@ -25,6 +25,8 @@ dependencies = [
|
|
|
25
25
|
"ffmpeg-python>=0.2.0",
|
|
26
26
|
"scenedetect[opencv]>=0.6.0",
|
|
27
27
|
"deepface>=0.0.79",
|
|
28
|
+
"tf-keras>=2.16.0", # Required by deepface with TensorFlow 2.16+
|
|
29
|
+
"transformers>=4.40.0", # Required for Qwen VLM
|
|
28
30
|
"paddleocr>=2.7.0",
|
|
29
31
|
"paddlepaddle>=2.5.0",
|
|
30
32
|
"webrtcvad>=2.0.10",
|
|
@@ -70,7 +72,6 @@ cpu = [
|
|
|
70
72
|
"ultralytics>=8.0.0",
|
|
71
73
|
]
|
|
72
74
|
qwen = [
|
|
73
|
-
"transformers>=4.40.0",
|
|
74
75
|
"accelerate>=0.30.0",
|
|
75
76
|
"qwen-vl-utils>=0.0.8",
|
|
76
77
|
"torch>=2.0.0",
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"""Test that all required dependencies are importable."""
|
|
2
|
+
|
|
3
|
+
import importlib
|
|
4
|
+
import importlib.util
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
# Modules that crash on import (e.g., paddle on macOS) - check with find_spec only
|
|
9
|
+
SPEC_CHECK_ONLY = {"paddle"}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TestBaseDependencies:
|
|
13
|
+
"""Test base dependencies that are always required."""
|
|
14
|
+
|
|
15
|
+
@pytest.mark.parametrize(
|
|
16
|
+
"module",
|
|
17
|
+
[
|
|
18
|
+
"fastapi",
|
|
19
|
+
"uvicorn",
|
|
20
|
+
"pydantic",
|
|
21
|
+
"pydantic_settings",
|
|
22
|
+
"ffmpeg",
|
|
23
|
+
"scenedetect",
|
|
24
|
+
"deepface",
|
|
25
|
+
"tf_keras",
|
|
26
|
+
"transformers",
|
|
27
|
+
"paddleocr",
|
|
28
|
+
"paddle",
|
|
29
|
+
"webrtcvad",
|
|
30
|
+
"psutil",
|
|
31
|
+
"langdetect",
|
|
32
|
+
"httpx",
|
|
33
|
+
],
|
|
34
|
+
)
|
|
35
|
+
def test_base_dependency_importable(self, module: str):
|
|
36
|
+
"""Verify base dependency can be imported."""
|
|
37
|
+
if module in SPEC_CHECK_ONLY:
|
|
38
|
+
# Some modules crash on import but are installed - just check spec
|
|
39
|
+
if importlib.util.find_spec(module) is None:
|
|
40
|
+
pytest.fail(f"Base dependency '{module}' not installed")
|
|
41
|
+
return
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
importlib.import_module(module)
|
|
45
|
+
except ImportError as e:
|
|
46
|
+
pytest.fail(f"Base dependency '{module}' not importable: {e}")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class TestMLXDependencies:
|
|
50
|
+
"""Test MLX dependencies (Apple Silicon)."""
|
|
51
|
+
|
|
52
|
+
@pytest.mark.parametrize(
|
|
53
|
+
"module",
|
|
54
|
+
[
|
|
55
|
+
"mlx",
|
|
56
|
+
"mlx_whisper",
|
|
57
|
+
"open_clip",
|
|
58
|
+
"torch",
|
|
59
|
+
"ultralytics",
|
|
60
|
+
],
|
|
61
|
+
)
|
|
62
|
+
def test_mlx_dependency_importable(self, module: str):
|
|
63
|
+
"""Verify MLX dependency can be imported if MLX extras installed."""
|
|
64
|
+
if importlib.util.find_spec("mlx") is None:
|
|
65
|
+
pytest.skip("MLX extras not installed")
|
|
66
|
+
try:
|
|
67
|
+
importlib.import_module(module)
|
|
68
|
+
except ImportError as e:
|
|
69
|
+
pytest.fail(f"MLX dependency '{module}' not importable: {e}")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class TestCUDADependencies:
|
|
73
|
+
"""Test CUDA dependencies (NVIDIA GPU)."""
|
|
74
|
+
|
|
75
|
+
@pytest.mark.parametrize(
|
|
76
|
+
"module",
|
|
77
|
+
[
|
|
78
|
+
"faster_whisper",
|
|
79
|
+
"open_clip",
|
|
80
|
+
"torch",
|
|
81
|
+
"ultralytics",
|
|
82
|
+
],
|
|
83
|
+
)
|
|
84
|
+
def test_cuda_dependency_importable(self, module: str):
|
|
85
|
+
"""Verify CUDA dependency can be imported if CUDA extras installed."""
|
|
86
|
+
if importlib.util.find_spec("faster_whisper") is None:
|
|
87
|
+
pytest.skip("CUDA extras not installed")
|
|
88
|
+
try:
|
|
89
|
+
importlib.import_module(module)
|
|
90
|
+
except ImportError as e:
|
|
91
|
+
pytest.fail(f"CUDA dependency '{module}' not importable: {e}")
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class TestCPUDependencies:
|
|
95
|
+
"""Test CPU dependencies (fallback)."""
|
|
96
|
+
|
|
97
|
+
@pytest.mark.parametrize(
|
|
98
|
+
"module",
|
|
99
|
+
[
|
|
100
|
+
"whisper",
|
|
101
|
+
"open_clip",
|
|
102
|
+
"torch",
|
|
103
|
+
"ultralytics",
|
|
104
|
+
],
|
|
105
|
+
)
|
|
106
|
+
def test_cpu_dependency_importable(self, module: str):
|
|
107
|
+
"""Verify CPU dependency can be imported if CPU extras installed."""
|
|
108
|
+
if importlib.util.find_spec("whisper") is None:
|
|
109
|
+
pytest.skip("CPU extras not installed")
|
|
110
|
+
try:
|
|
111
|
+
importlib.import_module(module)
|
|
112
|
+
except ImportError as e:
|
|
113
|
+
pytest.fail(f"CPU dependency '{module}' not importable: {e}")
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class TestQwenDependencies:
|
|
117
|
+
"""Test Qwen dependencies (VLM)."""
|
|
118
|
+
|
|
119
|
+
@pytest.mark.parametrize(
|
|
120
|
+
"module",
|
|
121
|
+
[
|
|
122
|
+
"accelerate",
|
|
123
|
+
"qwen_vl_utils",
|
|
124
|
+
],
|
|
125
|
+
)
|
|
126
|
+
def test_qwen_dependency_importable(self, module: str):
|
|
127
|
+
"""Verify Qwen dependency can be imported if Qwen extras installed."""
|
|
128
|
+
if importlib.util.find_spec("qwen_vl_utils") is None:
|
|
129
|
+
pytest.skip("Qwen extras not installed")
|
|
130
|
+
try:
|
|
131
|
+
importlib.import_module(module)
|
|
132
|
+
except ImportError as e:
|
|
133
|
+
pytest.fail(f"Qwen dependency '{module}' not importable: {e}")
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class TestMediaEngineImports:
|
|
137
|
+
"""Test that media_engine modules are importable."""
|
|
138
|
+
|
|
139
|
+
@pytest.mark.parametrize(
|
|
140
|
+
"module",
|
|
141
|
+
[
|
|
142
|
+
"media_engine",
|
|
143
|
+
"media_engine.main",
|
|
144
|
+
"media_engine.config",
|
|
145
|
+
"media_engine.schemas",
|
|
146
|
+
"media_engine.extractors",
|
|
147
|
+
"media_engine.extractors.metadata",
|
|
148
|
+
"media_engine.extractors.scenes",
|
|
149
|
+
"media_engine.extractors.ocr",
|
|
150
|
+
"media_engine.extractors.telemetry",
|
|
151
|
+
],
|
|
152
|
+
)
|
|
153
|
+
def test_media_engine_module_importable(self, module: str):
|
|
154
|
+
"""Verify media_engine module can be imported."""
|
|
155
|
+
try:
|
|
156
|
+
importlib.import_module(module)
|
|
157
|
+
except ImportError as e:
|
|
158
|
+
pytest.fail(f"Module '{module}' not importable: {e}")
|
|
159
|
+
|
|
160
|
+
def test_extractors_with_torch(self):
|
|
161
|
+
"""Verify extractors requiring torch are importable when torch is available."""
|
|
162
|
+
if importlib.util.find_spec("torch") is None:
|
|
163
|
+
pytest.skip("torch not installed")
|
|
164
|
+
|
|
165
|
+
modules = [
|
|
166
|
+
"media_engine.extractors.faces",
|
|
167
|
+
"media_engine.extractors.objects",
|
|
168
|
+
"media_engine.extractors.objects_qwen",
|
|
169
|
+
"media_engine.extractors.clip",
|
|
170
|
+
"media_engine.extractors.transcribe",
|
|
171
|
+
]
|
|
172
|
+
for module in modules:
|
|
173
|
+
try:
|
|
174
|
+
importlib.import_module(module)
|
|
175
|
+
except ImportError as e:
|
|
176
|
+
pytest.fail(f"Module '{module}' not importable: {e}")
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|