Coverage for src / marimushka / dependencies.py: 100%
31 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-28 17:41 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-28 17:41 +0000
1"""Dependency injection container for marimushka.
3This module provides a dependency container pattern that encapsulates all
4injectable dependencies used throughout the application. This makes it easier
5to manage dependencies, test components in isolation, and customize behavior.
7Example::
9 from marimushka.dependencies import Dependencies, create_dependencies
11 # Use default dependencies
12 deps = create_dependencies()
14 # Or customize for testing/special cases
15 from marimushka.audit import AuditLogger
16 from marimushka.config import MarimushkaConfig
18 custom_audit = AuditLogger(log_file=Path("custom_audit.log"))
19 custom_config = MarimushkaConfig(max_workers=8, timeout=600)
21 deps = Dependencies(
22 audit_logger=custom_audit,
23 config=custom_config
24 )
26 # Use in application
27 from marimushka.export import main_with_deps
28 html = main_with_deps(deps, notebooks="notebooks", apps="apps")
30"""
32from dataclasses import dataclass, field
33from pathlib import Path
35from .audit import AuditLogger, get_audit_logger
36from .config import MarimushkaConfig
39@dataclass
40class Dependencies:
41 """Container for all injectable dependencies.
43 This class holds all dependencies that can be injected throughout the
44 application, providing a single point of configuration and making it
45 easy to customize behavior for testing or special use cases.
47 Attributes:
48 audit_logger: Logger for security-relevant audit events.
49 config: Configuration settings for export behavior.
51 Example::
53 from marimushka.dependencies import Dependencies
54 from marimushka.audit import AuditLogger
55 from marimushka.config import MarimushkaConfig
57 # Create custom dependencies
58 deps = Dependencies(
59 audit_logger=AuditLogger(log_file=Path("my_audit.log")),
60 config=MarimushkaConfig(max_workers=8)
61 )
63 # Use with export functions
64 from marimushka.orchestrator import generate_index
65 html = generate_index(
66 output=Path("_site"),
67 template_file=Path("template.html.j2"),
68 notebooks=[],
69 audit_logger=deps.audit_logger
70 )
72 """
74 audit_logger: AuditLogger = field(default_factory=get_audit_logger)
75 config: MarimushkaConfig = field(default_factory=MarimushkaConfig)
77 def with_audit_logger(self, audit_logger: AuditLogger) -> "Dependencies":
78 """Create a new Dependencies instance with a different audit logger.
80 Args:
81 audit_logger: The new audit logger to use.
83 Returns:
84 A new Dependencies instance with the specified audit logger.
86 Example::
88 from marimushka.dependencies import create_dependencies
89 from marimushka.audit import AuditLogger
90 from pathlib import Path
92 deps = create_dependencies()
93 test_deps = deps.with_audit_logger(
94 AuditLogger(log_file=Path("test_audit.log"))
95 )
97 """
98 return Dependencies(
99 audit_logger=audit_logger,
100 config=self.config,
101 )
103 def with_config(self, config: MarimushkaConfig) -> "Dependencies":
104 """Create a new Dependencies instance with a different configuration.
106 Args:
107 config: The new configuration to use.
109 Returns:
110 A new Dependencies instance with the specified configuration.
112 Example::
114 from marimushka.dependencies import create_dependencies
115 from marimushka.config import MarimushkaConfig
117 deps = create_dependencies()
118 prod_deps = deps.with_config(
119 MarimushkaConfig(max_workers=16, timeout=900)
120 )
122 """
123 return Dependencies(
124 audit_logger=self.audit_logger,
125 config=config,
126 )
129def create_dependencies(
130 audit_log: Path | None = None,
131 config: MarimushkaConfig | None = None,
132) -> Dependencies:
133 """Create a Dependencies container with optional customization.
135 This factory function provides a convenient way to create Dependencies
136 with common customizations while falling back to sensible defaults.
138 Args:
139 audit_log: Optional path to audit log file. If provided, creates
140 an AuditLogger that writes to this file.
141 config: Optional custom configuration. If None, uses default config.
143 Returns:
144 A Dependencies instance with the specified settings.
146 Example::
148 from pathlib import Path
149 from marimushka.dependencies import create_dependencies
150 from marimushka.config import MarimushkaConfig
152 # Simple usage with audit log
153 deps = create_dependencies(audit_log=Path("audit.log"))
155 # With custom config
156 config = MarimushkaConfig(max_workers=8, parallel=True)
157 deps = create_dependencies(config=config)
159 # With both
160 deps = create_dependencies(
161 audit_log=Path("audit.log"),
162 config=MarimushkaConfig(timeout=600)
163 )
165 """
166 audit_logger = AuditLogger(log_file=audit_log) if audit_log is not None else get_audit_logger()
168 if config is None:
169 config = MarimushkaConfig()
171 return Dependencies(
172 audit_logger=audit_logger,
173 config=config,
174 )
177def create_dependencies_from_config_file(
178 config_path: Path,
179 audit_log: Path | None = None,
180) -> Dependencies:
181 """Create Dependencies by loading configuration from a TOML file.
183 This function loads configuration from a file and creates a Dependencies
184 container with it, optionally overriding the audit log path.
186 Args:
187 config_path: Path to the TOML configuration file.
188 audit_log: Optional override for audit log path. If None, uses
189 the audit log path from the config file (if specified).
191 Returns:
192 A Dependencies instance with settings from the config file.
194 Raises:
195 FileNotFoundError: If config_path doesn't exist.
196 ValueError: If the config file is invalid.
198 Example::
200 from pathlib import Path
201 from marimushka.dependencies import create_dependencies_from_config_file
203 # Load from config file
204 deps = create_dependencies_from_config_file(
205 Path(".marimushka.toml")
206 )
208 # Override audit log
209 deps = create_dependencies_from_config_file(
210 config_path=Path(".marimushka.toml"),
211 audit_log=Path("custom_audit.log")
212 )
214 """
215 config = MarimushkaConfig.from_file(config_path)
217 # Determine audit log path
218 if audit_log is not None:
219 # Use explicit override
220 audit_log_path = audit_log
221 elif config.audit_log is not None:
222 # Use path from config
223 audit_log_path = Path(config.audit_log)
224 else:
225 # No audit log file
226 audit_log_path = None
228 # Create audit logger
229 if audit_log_path is not None:
230 audit_logger = AuditLogger(
231 enabled=config.audit_enabled,
232 log_file=audit_log_path,
233 )
234 else:
235 audit_logger = AuditLogger(enabled=config.audit_enabled)
237 return Dependencies(
238 audit_logger=audit_logger,
239 config=config,
240 )
243def create_test_dependencies(tmp_dir: Path) -> Dependencies:
244 """Create Dependencies suitable for testing.
246 This function creates a Dependencies container configured for testing,
247 with audit logging to a temporary file and default configuration.
249 Args:
250 tmp_dir: Temporary directory for test artifacts.
252 Returns:
253 A Dependencies instance configured for testing.
255 Example::
257 from pathlib import Path
258 from marimushka.dependencies import create_test_dependencies
260 def test_something(tmp_path):
261 deps = create_test_dependencies(tmp_path)
262 # Use deps in your test...
264 """
265 audit_log = tmp_dir / "test_audit.log"
266 return Dependencies(
267 audit_logger=AuditLogger(enabled=True, log_file=audit_log),
268 config=MarimushkaConfig(),
269 )