panelbox 0.2.0__py3-none-any.whl

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 (90) hide show
  1. panelbox/__init__.py +67 -0
  2. panelbox/__version__.py +14 -0
  3. panelbox/cli/__init__.py +0 -0
  4. panelbox/cli/{commands}/__init__.py +0 -0
  5. panelbox/core/__init__.py +0 -0
  6. panelbox/core/base_model.py +164 -0
  7. panelbox/core/formula_parser.py +318 -0
  8. panelbox/core/panel_data.py +387 -0
  9. panelbox/core/results.py +366 -0
  10. panelbox/datasets/__init__.py +0 -0
  11. panelbox/datasets/{data}/__init__.py +0 -0
  12. panelbox/gmm/__init__.py +65 -0
  13. panelbox/gmm/difference_gmm.py +645 -0
  14. panelbox/gmm/estimator.py +562 -0
  15. panelbox/gmm/instruments.py +580 -0
  16. panelbox/gmm/results.py +550 -0
  17. panelbox/gmm/system_gmm.py +621 -0
  18. panelbox/gmm/tests.py +535 -0
  19. panelbox/models/__init__.py +11 -0
  20. panelbox/models/dynamic/__init__.py +0 -0
  21. panelbox/models/iv/__init__.py +0 -0
  22. panelbox/models/static/__init__.py +13 -0
  23. panelbox/models/static/fixed_effects.py +516 -0
  24. panelbox/models/static/pooled_ols.py +298 -0
  25. panelbox/models/static/random_effects.py +512 -0
  26. panelbox/report/__init__.py +61 -0
  27. panelbox/report/asset_manager.py +410 -0
  28. panelbox/report/css_manager.py +472 -0
  29. panelbox/report/exporters/__init__.py +15 -0
  30. panelbox/report/exporters/html_exporter.py +440 -0
  31. panelbox/report/exporters/latex_exporter.py +510 -0
  32. panelbox/report/exporters/markdown_exporter.py +446 -0
  33. panelbox/report/renderers/__init__.py +11 -0
  34. panelbox/report/renderers/static/__init__.py +0 -0
  35. panelbox/report/renderers/static_validation_renderer.py +341 -0
  36. panelbox/report/report_manager.py +502 -0
  37. panelbox/report/template_manager.py +337 -0
  38. panelbox/report/transformers/__init__.py +0 -0
  39. panelbox/report/transformers/static/__init__.py +0 -0
  40. panelbox/report/validation_transformer.py +449 -0
  41. panelbox/standard_errors/__init__.py +0 -0
  42. panelbox/templates/__init__.py +0 -0
  43. panelbox/templates/assets/css/base_styles.css +382 -0
  44. panelbox/templates/assets/css/report_components.css +747 -0
  45. panelbox/templates/assets/js/tab-navigation.js +161 -0
  46. panelbox/templates/assets/js/utils.js +276 -0
  47. panelbox/templates/common/footer.html +24 -0
  48. panelbox/templates/common/header.html +44 -0
  49. panelbox/templates/common/meta.html +5 -0
  50. panelbox/templates/validation/interactive/index.html +272 -0
  51. panelbox/templates/validation/interactive/partials/charts.html +58 -0
  52. panelbox/templates/validation/interactive/partials/methodology.html +201 -0
  53. panelbox/templates/validation/interactive/partials/overview.html +146 -0
  54. panelbox/templates/validation/interactive/partials/recommendations.html +101 -0
  55. panelbox/templates/validation/interactive/partials/test_results.html +231 -0
  56. panelbox/utils/__init__.py +0 -0
  57. panelbox/utils/formatting.py +172 -0
  58. panelbox/utils/matrix_ops.py +233 -0
  59. panelbox/utils/statistical.py +173 -0
  60. panelbox/validation/__init__.py +58 -0
  61. panelbox/validation/base.py +175 -0
  62. panelbox/validation/cointegration/__init__.py +0 -0
  63. panelbox/validation/cross_sectional_dependence/__init__.py +13 -0
  64. panelbox/validation/cross_sectional_dependence/breusch_pagan_lm.py +222 -0
  65. panelbox/validation/cross_sectional_dependence/frees.py +297 -0
  66. panelbox/validation/cross_sectional_dependence/pesaran_cd.py +188 -0
  67. panelbox/validation/heteroskedasticity/__init__.py +13 -0
  68. panelbox/validation/heteroskedasticity/breusch_pagan.py +222 -0
  69. panelbox/validation/heteroskedasticity/modified_wald.py +172 -0
  70. panelbox/validation/heteroskedasticity/white.py +208 -0
  71. panelbox/validation/instruments/__init__.py +0 -0
  72. panelbox/validation/robustness/__init__.py +0 -0
  73. panelbox/validation/serial_correlation/__init__.py +13 -0
  74. panelbox/validation/serial_correlation/baltagi_wu.py +220 -0
  75. panelbox/validation/serial_correlation/breusch_godfrey.py +260 -0
  76. panelbox/validation/serial_correlation/wooldridge_ar.py +200 -0
  77. panelbox/validation/specification/__init__.py +16 -0
  78. panelbox/validation/specification/chow.py +273 -0
  79. panelbox/validation/specification/hausman.py +264 -0
  80. panelbox/validation/specification/mundlak.py +331 -0
  81. panelbox/validation/specification/reset.py +273 -0
  82. panelbox/validation/unit_root/__init__.py +0 -0
  83. panelbox/validation/validation_report.py +257 -0
  84. panelbox/validation/validation_suite.py +401 -0
  85. panelbox-0.2.0.dist-info/METADATA +337 -0
  86. panelbox-0.2.0.dist-info/RECORD +90 -0
  87. panelbox-0.2.0.dist-info/WHEEL +5 -0
  88. panelbox-0.2.0.dist-info/entry_points.txt +2 -0
  89. panelbox-0.2.0.dist-info/licenses/LICENSE +21 -0
  90. panelbox-0.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,502 @@
1
+ """
2
+ Report Manager for PanelBox.
3
+
4
+ Main orchestrator for report generation across all report types.
5
+ """
6
+
7
+ import sys
8
+ import datetime
9
+ from pathlib import Path
10
+ from typing import Dict, Any, Optional, List, Union
11
+
12
+ from .template_manager import TemplateManager
13
+ from .asset_manager import AssetManager
14
+ from .css_manager import CSSManager
15
+
16
+
17
+ # Version info
18
+ try:
19
+ from .. import __version__ as PANELBOX_VERSION
20
+ except ImportError:
21
+ PANELBOX_VERSION = "0.1.0-dev"
22
+
23
+
24
+ class ReportManager:
25
+ """
26
+ Main orchestrator for PanelBox report generation.
27
+
28
+ Coordinates TemplateManager, AssetManager, and CSSManager to generate
29
+ complete, self-contained HTML reports.
30
+
31
+ Parameters
32
+ ----------
33
+ template_dir : str or Path, optional
34
+ Directory containing templates
35
+ asset_dir : str or Path, optional
36
+ Directory containing assets
37
+ enable_cache : bool, default=True
38
+ Enable template and asset caching
39
+ minify : bool, default=False
40
+ Enable CSS/JS minification
41
+
42
+ Attributes
43
+ ----------
44
+ template_manager : TemplateManager
45
+ Template manager instance
46
+ asset_manager : AssetManager
47
+ Asset manager instance
48
+ css_manager : CSSManager
49
+ CSS manager instance
50
+
51
+ Examples
52
+ --------
53
+ >>> report_mgr = ReportManager()
54
+ >>> html = report_mgr.generate_report(
55
+ ... report_type='validation',
56
+ ... template='validation/interactive/index.html',
57
+ ... context={'title': 'My Report', ...}
58
+ ... )
59
+ >>> report_mgr.save_report(html, 'report.html')
60
+ """
61
+
62
+ def __init__(
63
+ self,
64
+ template_dir: Optional[Path] = None,
65
+ asset_dir: Optional[Path] = None,
66
+ enable_cache: bool = True,
67
+ minify: bool = False
68
+ ):
69
+ """Initialize Report Manager."""
70
+ # Initialize managers
71
+ self.template_manager = TemplateManager(
72
+ template_dir=template_dir,
73
+ enable_cache=enable_cache
74
+ )
75
+
76
+ self.asset_manager = AssetManager(
77
+ asset_dir=asset_dir,
78
+ minify=minify
79
+ )
80
+
81
+ self.css_manager = CSSManager(
82
+ asset_manager=self.asset_manager,
83
+ minify=minify
84
+ )
85
+
86
+ self.minify = minify
87
+ self.enable_cache = enable_cache
88
+
89
+ def generate_report(
90
+ self,
91
+ report_type: str,
92
+ template: str,
93
+ context: Dict[str, Any],
94
+ embed_assets: bool = True,
95
+ include_plotly: bool = True,
96
+ custom_css: Optional[List[str]] = None,
97
+ custom_js: Optional[List[str]] = None
98
+ ) -> str:
99
+ """
100
+ Generate a complete HTML report.
101
+
102
+ Parameters
103
+ ----------
104
+ report_type : str
105
+ Type of report (e.g., 'validation', 'regression', 'gmm')
106
+ template : str
107
+ Template path relative to template directory
108
+ context : dict
109
+ Template context variables
110
+ embed_assets : bool, default=True
111
+ Embed all assets inline for self-contained HTML
112
+ include_plotly : bool, default=True
113
+ Include Plotly.js library
114
+ custom_css : list of str, optional
115
+ Additional custom CSS files to include
116
+ custom_js : list of str, optional
117
+ Additional custom JS files to include
118
+
119
+ Returns
120
+ -------
121
+ str
122
+ Complete HTML report
123
+
124
+ Examples
125
+ --------
126
+ >>> html = report_mgr.generate_report(
127
+ ... report_type='validation',
128
+ ... template='validation/interactive/index.html',
129
+ ... context={'title': 'Panel Validation', 'data': {...}}
130
+ ... )
131
+ """
132
+ # Prepare base context
133
+ full_context = self._prepare_context(report_type, context)
134
+
135
+ # Add custom CSS to manager
136
+ if custom_css:
137
+ for css_file in custom_css:
138
+ self.css_manager.add_custom_css(css_file)
139
+
140
+ # Compile CSS
141
+ if embed_assets:
142
+ compiled_css = self.css_manager.compile_for_report_type(report_type)
143
+ full_context['css_inline'] = compiled_css
144
+ else:
145
+ full_context['css_files'] = self._get_css_files()
146
+
147
+ # Collect JavaScript
148
+ if embed_assets:
149
+ js_files = ['utils.js', 'tab-navigation.js']
150
+ if custom_js:
151
+ js_files.extend(custom_js)
152
+
153
+ compiled_js = self.asset_manager.collect_js(js_files)
154
+ full_context['js_inline'] = compiled_js
155
+ else:
156
+ full_context['js_files'] = self._get_js_files(custom_js)
157
+
158
+ # Plotly
159
+ if include_plotly:
160
+ full_context['plotly_js'] = self.asset_manager.embed_plotly(
161
+ include_plotly=True
162
+ )
163
+ else:
164
+ full_context['plotly_js'] = ""
165
+
166
+ # Render template
167
+ html = self.template_manager.render_template(template, full_context)
168
+
169
+ return html
170
+
171
+ def generate_validation_report(
172
+ self,
173
+ validation_data: Dict[str, Any],
174
+ interactive: bool = True,
175
+ title: Optional[str] = None,
176
+ subtitle: Optional[str] = None
177
+ ) -> str:
178
+ """
179
+ Generate a validation report.
180
+
181
+ Convenience method for validation reports.
182
+
183
+ Parameters
184
+ ----------
185
+ validation_data : dict
186
+ Validation data (from ValidationTransformer)
187
+ interactive : bool, default=True
188
+ Generate interactive report with Plotly charts
189
+ title : str, optional
190
+ Report title
191
+ subtitle : str, optional
192
+ Report subtitle
193
+
194
+ Returns
195
+ -------
196
+ str
197
+ Complete HTML validation report
198
+
199
+ Examples
200
+ --------
201
+ >>> html = report_mgr.generate_validation_report(
202
+ ... validation_data={'tests': [...], 'model_info': {...}},
203
+ ... title='Panel Data Validation'
204
+ ... )
205
+ """
206
+ # Determine template
207
+ if interactive:
208
+ template = 'validation/interactive/index.html'
209
+ else:
210
+ template = 'validation/static/index.html'
211
+
212
+ # Build context
213
+ # Spread model_info to top level for easy access in templates
214
+ model_info = validation_data.get('model_info', {})
215
+
216
+ context = {
217
+ 'report_title': title or 'Panel Data Validation Report',
218
+ 'report_subtitle': subtitle,
219
+ **validation_data,
220
+ # Spread model_info for template convenience
221
+ **model_info
222
+ }
223
+
224
+ # Generate
225
+ return self.generate_report(
226
+ report_type='validation',
227
+ template=template,
228
+ context=context,
229
+ include_plotly=interactive
230
+ )
231
+
232
+ def generate_regression_report(
233
+ self,
234
+ regression_data: Dict[str, Any],
235
+ title: Optional[str] = None,
236
+ subtitle: Optional[str] = None
237
+ ) -> str:
238
+ """
239
+ Generate a regression results report.
240
+
241
+ Convenience method for regression reports.
242
+
243
+ Parameters
244
+ ----------
245
+ regression_data : dict
246
+ Regression data (from RegressionTransformer)
247
+ title : str, optional
248
+ Report title
249
+ subtitle : str, optional
250
+ Report subtitle
251
+
252
+ Returns
253
+ -------
254
+ str
255
+ Complete HTML regression report
256
+
257
+ Examples
258
+ --------
259
+ >>> html = report_mgr.generate_regression_report(
260
+ ... regression_data={'coefficients': [...], 'diagnostics': {...}},
261
+ ... title='Fixed Effects Results'
262
+ ... )
263
+ """
264
+ template = 'regression/index.html'
265
+
266
+ context = {
267
+ 'report_title': title or 'Regression Results',
268
+ 'report_subtitle': subtitle,
269
+ **regression_data
270
+ }
271
+
272
+ return self.generate_report(
273
+ report_type='regression',
274
+ template=template,
275
+ context=context,
276
+ include_plotly=True
277
+ )
278
+
279
+ def generate_gmm_report(
280
+ self,
281
+ gmm_data: Dict[str, Any],
282
+ title: Optional[str] = None,
283
+ subtitle: Optional[str] = None
284
+ ) -> str:
285
+ """
286
+ Generate a GMM results report.
287
+
288
+ Convenience method for GMM reports.
289
+
290
+ Parameters
291
+ ----------
292
+ gmm_data : dict
293
+ GMM data (from GMMTransformer)
294
+ title : str, optional
295
+ Report title
296
+ subtitle : str, optional
297
+ Report subtitle
298
+
299
+ Returns
300
+ -------
301
+ str
302
+ Complete HTML GMM report
303
+
304
+ Examples
305
+ --------
306
+ >>> html = report_mgr.generate_gmm_report(
307
+ ... gmm_data={'coefficients': [...], 'hansen_test': {...}},
308
+ ... title='System GMM Results'
309
+ ... )
310
+ """
311
+ template = 'gmm/index.html'
312
+
313
+ context = {
314
+ 'report_title': title or 'GMM Results',
315
+ 'report_subtitle': subtitle,
316
+ **gmm_data
317
+ }
318
+
319
+ return self.generate_report(
320
+ report_type='gmm',
321
+ template=template,
322
+ context=context,
323
+ include_plotly=True
324
+ )
325
+
326
+ def save_report(
327
+ self,
328
+ html: str,
329
+ output_path: Union[str, Path],
330
+ overwrite: bool = False
331
+ ) -> Path:
332
+ """
333
+ Save HTML report to file.
334
+
335
+ Parameters
336
+ ----------
337
+ html : str
338
+ HTML content
339
+ output_path : str or Path
340
+ Output file path
341
+ overwrite : bool, default=False
342
+ Overwrite existing file
343
+
344
+ Returns
345
+ -------
346
+ Path
347
+ Path to saved file
348
+
349
+ Examples
350
+ --------
351
+ >>> html = report_mgr.generate_report(...)
352
+ >>> path = report_mgr.save_report(html, 'report.html')
353
+ >>> print(f"Report saved to {path}")
354
+ """
355
+ output_path = Path(output_path)
356
+
357
+ # Check if file exists
358
+ if output_path.exists() and not overwrite:
359
+ raise FileExistsError(
360
+ f"File already exists: {output_path}. "
361
+ "Use overwrite=True to replace."
362
+ )
363
+
364
+ # Create parent directories
365
+ output_path.parent.mkdir(parents=True, exist_ok=True)
366
+
367
+ # Write file
368
+ output_path.write_text(html, encoding='utf-8')
369
+
370
+ return output_path
371
+
372
+ def _prepare_context(
373
+ self,
374
+ report_type: str,
375
+ context: Dict[str, Any]
376
+ ) -> Dict[str, Any]:
377
+ """
378
+ Prepare base context with metadata.
379
+
380
+ Parameters
381
+ ----------
382
+ report_type : str
383
+ Report type
384
+ context : dict
385
+ User-provided context
386
+
387
+ Returns
388
+ -------
389
+ dict
390
+ Complete context with metadata
391
+ """
392
+ # Get current timestamp
393
+ now = datetime.datetime.now()
394
+
395
+ # Base context
396
+ base_context = {
397
+ # Metadata
398
+ 'panelbox_version': PANELBOX_VERSION,
399
+ 'python_version': f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
400
+ 'report_type': report_type,
401
+ 'generation_date': now.strftime('%Y-%m-%d %H:%M:%S'),
402
+ 'generation_timestamp': now.isoformat(),
403
+
404
+ # Report display options
405
+ 'show_export_buttons': True,
406
+ 'show_navigation': True,
407
+
408
+ # Defaults (can be overridden)
409
+ 'report_title': f"PanelBox {report_type.title()} Report",
410
+ 'report_subtitle': None,
411
+ }
412
+
413
+ # Merge with user context (user context takes precedence)
414
+ base_context.update(context)
415
+
416
+ return base_context
417
+
418
+ def _get_css_files(self) -> List[str]:
419
+ """
420
+ Get list of CSS files (for non-embedded mode).
421
+
422
+ Returns
423
+ -------
424
+ list of str
425
+ CSS file paths
426
+ """
427
+ css_files = []
428
+
429
+ for layer in sorted(
430
+ self.css_manager.layers.values(),
431
+ key=lambda l: l.priority
432
+ ):
433
+ css_files.extend(layer.files)
434
+
435
+ return css_files
436
+
437
+ def _get_js_files(self, custom_js: Optional[List[str]] = None) -> List[str]:
438
+ """
439
+ Get list of JS files (for non-embedded mode).
440
+
441
+ Parameters
442
+ ----------
443
+ custom_js : list of str, optional
444
+ Additional JS files
445
+
446
+ Returns
447
+ -------
448
+ list of str
449
+ JS file paths
450
+ """
451
+ js_files = ['utils.js', 'tab-navigation.js']
452
+
453
+ if custom_js:
454
+ js_files.extend(custom_js)
455
+
456
+ return js_files
457
+
458
+ def clear_cache(self) -> None:
459
+ """
460
+ Clear all caches.
461
+
462
+ Examples
463
+ --------
464
+ >>> report_mgr.clear_cache()
465
+ """
466
+ self.template_manager.clear_cache()
467
+ self.asset_manager.clear_cache()
468
+ self.css_manager.clear_cache()
469
+
470
+ def get_info(self) -> Dict[str, Any]:
471
+ """
472
+ Get information about report manager state.
473
+
474
+ Returns
475
+ -------
476
+ dict
477
+ Manager information
478
+
479
+ Examples
480
+ --------
481
+ >>> info = report_mgr.get_info()
482
+ >>> print(f"Templates cached: {info['templates_cached']}")
483
+ """
484
+ return {
485
+ 'panelbox_version': PANELBOX_VERSION,
486
+ 'template_dir': str(self.template_manager.template_dir),
487
+ 'asset_dir': str(self.asset_manager.asset_dir),
488
+ 'templates_cached': len(self.template_manager.template_cache),
489
+ 'assets_cached': len(self.asset_manager.asset_cache),
490
+ 'css_layers': len(self.css_manager.layers),
491
+ 'minify_enabled': self.minify,
492
+ 'cache_enabled': self.enable_cache
493
+ }
494
+
495
+ def __repr__(self) -> str:
496
+ """String representation."""
497
+ return (
498
+ f"ReportManager("
499
+ f"version={PANELBOX_VERSION}, "
500
+ f"cache={self.enable_cache}, "
501
+ f"minify={self.minify})"
502
+ )