opera-eco 0.4.5__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 (58) hide show
  1. opera_eco-0.4.5/LICENSE +21 -0
  2. opera_eco-0.4.5/PKG-INFO +140 -0
  3. opera_eco-0.4.5/README.md +88 -0
  4. opera_eco-0.4.5/pyproject.toml +103 -0
  5. opera_eco-0.4.5/setup.cfg +4 -0
  6. opera_eco-0.4.5/src/opera/__init__.py +8 -0
  7. opera_eco-0.4.5/src/opera/cli.py +174 -0
  8. opera_eco-0.4.5/src/opera/sample_realtime_data.py +160 -0
  9. opera_eco-0.4.5/src/opera/skill_api.py +315 -0
  10. opera_eco-0.4.5/src/opera/skills/__init__.py +1 -0
  11. opera_eco-0.4.5/src/opera/skills/bvar.md +251 -0
  12. opera_eco-0.4.5/src/opera/skills/forecast_combo.md +284 -0
  13. opera_eco-0.4.5/src/opera/skills/forecast_evaluation.md +574 -0
  14. opera_eco-0.4.5/src/opera/skills/forecast_realtime.md +420 -0
  15. opera_eco-0.4.5/src/opera/skills/news_decomp.md +185 -0
  16. opera_eco-0.4.5/src/opera/skills/nowcast_midas.md +674 -0
  17. opera_eco-0.4.5/src/opera/skills/opera.md +374 -0
  18. opera_eco-0.4.5/src/opera/skills_manager.py +169 -0
  19. opera_eco-0.4.5/src/opera/tests/__init__.py +0 -0
  20. opera_eco-0.4.5/src/opera/tests/conftest.py +0 -0
  21. opera_eco-0.4.5/src/opera/tests/contracts/__init__.py +0 -0
  22. opera_eco-0.4.5/src/opera/tests/contracts/schema.py +4 -0
  23. opera_eco-0.4.5/src/opera/tests/contracts/test_forecast_evaluation_contract.py +133 -0
  24. opera_eco-0.4.5/src/opera/tests/contracts/test_forecast_model_contract.py +49 -0
  25. opera_eco-0.4.5/src/opera/tests/contracts/test_interoperability_contract.py +76 -0
  26. opera_eco-0.4.5/src/opera/tests/contracts/test_news_decomposition_contract.py +65 -0
  27. opera_eco-0.4.5/src/opera/tests/contracts/test_schema.py +20 -0
  28. opera_eco-0.4.5/src/opera/tests/pipelines/__init__.py +0 -0
  29. opera_eco-0.4.5/src/opera/tests/pipelines/bvar/__init__.py +0 -0
  30. opera_eco-0.4.5/src/opera/tests/pipelines/bvar/__snapshots__/test_bvar_snapshot.ambr +415 -0
  31. opera_eco-0.4.5/src/opera/tests/pipelines/bvar/test_bvar_snapshot.py +144 -0
  32. opera_eco-0.4.5/src/opera/tests/pipelines/ecosystem/__init__.py +0 -0
  33. opera_eco-0.4.5/src/opera/tests/pipelines/ecosystem/__snapshots__/test_ecosystem_pipeline.ambr +5242 -0
  34. opera_eco-0.4.5/src/opera/tests/pipelines/ecosystem/test_ecosystem_pipeline.py +132 -0
  35. opera_eco-0.4.5/src/opera/tests/pipelines/midas/__init__.py +0 -0
  36. opera_eco-0.4.5/src/opera/tests/pipelines/midas/__snapshots__/test_midas_snapshot.ambr +1125 -0
  37. opera_eco-0.4.5/src/opera/tests/pipelines/midas/__snapshots__/test_multimidas_snapshot.ambr +1629 -0
  38. opera_eco-0.4.5/src/opera/tests/pipelines/midas/__snapshots__/test_scmidas_snapshot.ambr +145 -0
  39. opera_eco-0.4.5/src/opera/tests/pipelines/midas/sample_data.py +18 -0
  40. opera_eco-0.4.5/src/opera/tests/pipelines/midas/test_midas_snapshot.py +113 -0
  41. opera_eco-0.4.5/src/opera/tests/pipelines/midas/test_multimidas_snapshot.py +120 -0
  42. opera_eco-0.4.5/src/opera/tests/pipelines/midas/test_scmidas_snapshot.py +155 -0
  43. opera_eco-0.4.5/src/opera/tests/pipelines/mixed_freq/__init__.py +0 -0
  44. opera_eco-0.4.5/src/opera/tests/pipelines/mixed_freq/__snapshots__/test_mixed_freq_snapshot.ambr +5183 -0
  45. opera_eco-0.4.5/src/opera/tests/pipelines/mixed_freq/test_mixed_freq_snapshot.py +132 -0
  46. opera_eco-0.4.5/src/opera/tests/pipelines/news/__init__.py +0 -0
  47. opera_eco-0.4.5/src/opera/tests/pipelines/news/sample_news.py +933 -0
  48. opera_eco-0.4.5/src/opera/tests/pipelines/news/test_news.py +594 -0
  49. opera_eco-0.4.5/src/opera/tests/pipelines/sample_data.py +29 -0
  50. opera_eco-0.4.5/src/opera/tests/skills_tests/test_skill_api.py +197 -0
  51. opera_eco-0.4.5/src/opera/tests/skills_tests/test_skill_snippets.py +175 -0
  52. opera_eco-0.4.5/src/opera/tests/skills_tests/test_skills.py +123 -0
  53. opera_eco-0.4.5/src/opera_eco.egg-info/PKG-INFO +140 -0
  54. opera_eco-0.4.5/src/opera_eco.egg-info/SOURCES.txt +56 -0
  55. opera_eco-0.4.5/src/opera_eco.egg-info/dependency_links.txt +1 -0
  56. opera_eco-0.4.5/src/opera_eco.egg-info/entry_points.txt +2 -0
  57. opera_eco-0.4.5/src/opera_eco.egg-info/requires.txt +33 -0
  58. opera_eco-0.4.5/src/opera_eco.egg-info/top_level.txt +1 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Bank of England
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,140 @@
1
+ Metadata-Version: 2.4
2
+ Name: opera-eco
3
+ Version: 0.4.5
4
+ Summary: Dependency and skill manager for the OPERA ecosystem
5
+ Author-email: Paul Labonne <Paul.Labonne@bankofengland.co.uk>, Diego Lopez <Diego.Lopez@bankofengland.co.uk>
6
+ Maintainer-email: Paul Labonne <Paul.Labonne@bankofengland.co.uk>
7
+ License-Expression: MIT
8
+ Project-URL: Documentation, https://bank-of-england.github.io/opera-eco/
9
+ Project-URL: Repository, https://github.com/bank-of-england/opera-eco
10
+ Project-URL: Issues, https://github.com/bank-of-england/opera-eco/issues
11
+ Keywords: time-series,forecasting,evaluation,backtesting,economics
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Scientific/Engineering
20
+ Requires-Python: >=3.11
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: numpy
24
+ Requires-Dist: pandas
25
+ Provides-Extra: modules
26
+ Requires-Dist: forecast_evaluation==0.1.13; extra == "modules"
27
+ Requires-Dist: forecast_realtime[models]==0.5.4; extra == "modules"
28
+ Requires-Dist: forecast_combo==0.1.1; extra == "modules"
29
+ Requires-Dist: bvar==0.3.1; extra == "modules"
30
+ Requires-Dist: nowcast-midas==0.0.1; extra == "modules"
31
+ Requires-Dist: news_decomp==0.0.7; extra == "modules"
32
+ Provides-Extra: test
33
+ Requires-Dist: opera-eco[modules]; extra == "test"
34
+ Requires-Dist: pytest; extra == "test"
35
+ Requires-Dist: pytest-xdist; extra == "test"
36
+ Requires-Dist: pytest-timeout; extra == "test"
37
+ Requires-Dist: pandera; extra == "test"
38
+ Requires-Dist: syrupy; extra == "test"
39
+ Provides-Extra: notebooks
40
+ Requires-Dist: marimo==0.24.0; extra == "notebooks"
41
+ Provides-Extra: dev
42
+ Requires-Dist: build; extra == "dev"
43
+ Requires-Dist: packaging; extra == "dev"
44
+ Requires-Dist: pre-commit; extra == "dev"
45
+ Requires-Dist: pydoclint; extra == "dev"
46
+ Requires-Dist: ruff; extra == "dev"
47
+ Requires-Dist: twine; extra == "dev"
48
+ Provides-Extra: docs
49
+ Requires-Dist: mkdocstrings[python]; extra == "docs"
50
+ Requires-Dist: zensical; extra == "docs"
51
+ Dynamic: license-file
52
+
53
+ # OPERA: Open-Source Prediction Evaluation and Real-Time Analysis
54
+
55
+ **[Documentation](https://bank-of-england.github.io/opera-eco/)**
56
+
57
+ OPERA is a modular ecosystem aimed at streamlining forecasting tasks for economists and fostering open collaboration. Model logic - estimation, forecasting, forecast decomposition - is separated from the real-time workflow, making it easier to compare models in replicable environments and leverage open source contributions. The ecosystem is currently composed of seven blocks which cover the full pipeline from raw data to evaluation. Its architecture, interfaces and design principles reflect the specific constraints of macro analysis: data revision, ragged edge, mixed-frequency, conditional projections, uncertainty quantification, narrative accounting and nested models. By making these modules open-source, OPERA provides a platform for central bankers, academics and other forecasters to share infrastructure and collaborate.
58
+
59
+
60
+ ---
61
+
62
+ ## Architecture
63
+
64
+ ![Forecasting Ecosystem Architecture](docs/diagram.svg)
65
+
66
+ ---
67
+
68
+ ## Modules
69
+
70
+ | Module | Package | Role |
71
+ |---|---|---|
72
+ | Model Libraries | `bvar`, `nowcast-midas` | Bayesian VARs; mixed-data sampling and SC-MIDAS combinations |
73
+ | Forecast Evaluation | `forecast_evaluation` | Validate data, evaluate accuracy, run statistical tests, visualise |
74
+ | Real-time Forecasting | `forecast_realtime` | Fit and forecast wrappers, backtesting, simulation, stress-testing, R/MATLAB/Julia adapters |
75
+ | Forecast Combination | `forecast_combo` | Inverse-error, regression and hierarchical combination |
76
+ | News Decomposition | `news_decomp` | Nowcast decomposition into level and revision; news/reestimation/interaction |
77
+
78
+ Install all ecosystem packages with `pip install "opera-eco[modules]"`.
79
+
80
+ ## Authors
81
+
82
+ The package authors listed in each repository's `pyproject.toml` are:
83
+
84
+ | Package | Authors |
85
+ |---|---|
86
+ | `opera-eco` | Paul Labonne; Diego Lopez |
87
+ | `forecast_evaluation` | James Hurley; Paul Labonne; Harry Li |
88
+ | `forecast_realtime` | Paul Labonne; Sumer Singh; Harry Li; Nades Raviraj |
89
+ | `bvar` | Paul Labonne; Andrea Renzetti; Joseph Oyegoke |
90
+ | `nowcast-midas` | James Kensett; Paul Labonne; Andre Moreira |
91
+ | `forecast_combo` | Filippo Busetto; Paul Labonne; James McConachie; Roshni Tara |
92
+ | `news_decomp` | Guido Bonatti; Kensley Blaise; Paul Labonne; Nades Raviraj |
93
+
94
+ ---
95
+
96
+ ## Quick Start
97
+
98
+ ```bash
99
+ pip install opera-eco # Install the CLI and skills only.
100
+ pip install "opera-eco[modules]" # Install the CLI and all ecosystem packages.
101
+ pip install "opera-eco[notebooks]" # Install Marimo notebook tooling.
102
+ opera install skills # Install AI skills in .claude/skills/.
103
+ ```
104
+
105
+ Then ask Copilot or Claude to use an installed skill:
106
+
107
+ ```text
108
+ Tell me about @opera and how I can use it with my model.
109
+ ```
110
+
111
+ ## OPERA Skills for Claude and Copilot
112
+
113
+ The package includes seven skills for AI coding assistants:
114
+
115
+ | Skill | Description |
116
+ |---|---|
117
+ | **opera** | Meta-skill covering the full ecosystem: architecture, modules, data flows, conventions, integration patterns |
118
+ | **forecast-evaluation** | Data validation, accuracy metrics, statistical tests, visualisations, dashboards |
119
+ | **forecast-realtime** | Real-time forecasting, backtesting, model wrapping, external language models (R, MATLAB, Julia) |
120
+ | **bvar** | Bayesian VARs, conditional forecasting with hard/soft/skewed constraints, GIRFs |
121
+ | **nowcast-midas** | MIDAS regressions, MultiMIDAS, SC-MIDAS combinations, monthly-to-quarterly nowcasting |
122
+ | **forecast-combo** | Forecast combination methods, hierarchical pooling, weight analysis |
123
+ | **forecast-decomp** | Nowcast decomposition: levels and revisions, news, reestimation, interaction, and New York Fed-style analysis |
124
+
125
+ ## Project Layout
126
+
127
+ ```
128
+ docs/ # Documentation site.
129
+ examples/illustration.py # Runnable end-to-end example.
130
+ examples/illustration_marimo.py # Native Marimo version of the example.
131
+ src/opera/ # Package source, bundled skills, and tests.
132
+ cli.py # Command-line interface.
133
+ skills_manager.py # Skill discovery and installation.
134
+ skills/ # Bundled Markdown skill files.
135
+ pyproject.toml # Python package configuration.
136
+ zensical.toml # Documentation site configuration.
137
+ ```
138
+
139
+ ## Data Classification
140
+ Bank of England Data Classification: OFFICIAL BLUE
@@ -0,0 +1,88 @@
1
+ # OPERA: Open-Source Prediction Evaluation and Real-Time Analysis
2
+
3
+ **[Documentation](https://bank-of-england.github.io/opera-eco/)**
4
+
5
+ OPERA is a modular ecosystem aimed at streamlining forecasting tasks for economists and fostering open collaboration. Model logic - estimation, forecasting, forecast decomposition - is separated from the real-time workflow, making it easier to compare models in replicable environments and leverage open source contributions. The ecosystem is currently composed of seven blocks which cover the full pipeline from raw data to evaluation. Its architecture, interfaces and design principles reflect the specific constraints of macro analysis: data revision, ragged edge, mixed-frequency, conditional projections, uncertainty quantification, narrative accounting and nested models. By making these modules open-source, OPERA provides a platform for central bankers, academics and other forecasters to share infrastructure and collaborate.
6
+
7
+
8
+ ---
9
+
10
+ ## Architecture
11
+
12
+ ![Forecasting Ecosystem Architecture](docs/diagram.svg)
13
+
14
+ ---
15
+
16
+ ## Modules
17
+
18
+ | Module | Package | Role |
19
+ |---|---|---|
20
+ | Model Libraries | `bvar`, `nowcast-midas` | Bayesian VARs; mixed-data sampling and SC-MIDAS combinations |
21
+ | Forecast Evaluation | `forecast_evaluation` | Validate data, evaluate accuracy, run statistical tests, visualise |
22
+ | Real-time Forecasting | `forecast_realtime` | Fit and forecast wrappers, backtesting, simulation, stress-testing, R/MATLAB/Julia adapters |
23
+ | Forecast Combination | `forecast_combo` | Inverse-error, regression and hierarchical combination |
24
+ | News Decomposition | `news_decomp` | Nowcast decomposition into level and revision; news/reestimation/interaction |
25
+
26
+ Install all ecosystem packages with `pip install "opera-eco[modules]"`.
27
+
28
+ ## Authors
29
+
30
+ The package authors listed in each repository's `pyproject.toml` are:
31
+
32
+ | Package | Authors |
33
+ |---|---|
34
+ | `opera-eco` | Paul Labonne; Diego Lopez |
35
+ | `forecast_evaluation` | James Hurley; Paul Labonne; Harry Li |
36
+ | `forecast_realtime` | Paul Labonne; Sumer Singh; Harry Li; Nades Raviraj |
37
+ | `bvar` | Paul Labonne; Andrea Renzetti; Joseph Oyegoke |
38
+ | `nowcast-midas` | James Kensett; Paul Labonne; Andre Moreira |
39
+ | `forecast_combo` | Filippo Busetto; Paul Labonne; James McConachie; Roshni Tara |
40
+ | `news_decomp` | Guido Bonatti; Kensley Blaise; Paul Labonne; Nades Raviraj |
41
+
42
+ ---
43
+
44
+ ## Quick Start
45
+
46
+ ```bash
47
+ pip install opera-eco # Install the CLI and skills only.
48
+ pip install "opera-eco[modules]" # Install the CLI and all ecosystem packages.
49
+ pip install "opera-eco[notebooks]" # Install Marimo notebook tooling.
50
+ opera install skills # Install AI skills in .claude/skills/.
51
+ ```
52
+
53
+ Then ask Copilot or Claude to use an installed skill:
54
+
55
+ ```text
56
+ Tell me about @opera and how I can use it with my model.
57
+ ```
58
+
59
+ ## OPERA Skills for Claude and Copilot
60
+
61
+ The package includes seven skills for AI coding assistants:
62
+
63
+ | Skill | Description |
64
+ |---|---|
65
+ | **opera** | Meta-skill covering the full ecosystem: architecture, modules, data flows, conventions, integration patterns |
66
+ | **forecast-evaluation** | Data validation, accuracy metrics, statistical tests, visualisations, dashboards |
67
+ | **forecast-realtime** | Real-time forecasting, backtesting, model wrapping, external language models (R, MATLAB, Julia) |
68
+ | **bvar** | Bayesian VARs, conditional forecasting with hard/soft/skewed constraints, GIRFs |
69
+ | **nowcast-midas** | MIDAS regressions, MultiMIDAS, SC-MIDAS combinations, monthly-to-quarterly nowcasting |
70
+ | **forecast-combo** | Forecast combination methods, hierarchical pooling, weight analysis |
71
+ | **forecast-decomp** | Nowcast decomposition: levels and revisions, news, reestimation, interaction, and New York Fed-style analysis |
72
+
73
+ ## Project Layout
74
+
75
+ ```
76
+ docs/ # Documentation site.
77
+ examples/illustration.py # Runnable end-to-end example.
78
+ examples/illustration_marimo.py # Native Marimo version of the example.
79
+ src/opera/ # Package source, bundled skills, and tests.
80
+ cli.py # Command-line interface.
81
+ skills_manager.py # Skill discovery and installation.
82
+ skills/ # Bundled Markdown skill files.
83
+ pyproject.toml # Python package configuration.
84
+ zensical.toml # Documentation site configuration.
85
+ ```
86
+
87
+ ## Data Classification
88
+ Bank of England Data Classification: OFFICIAL BLUE
@@ -0,0 +1,103 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "opera-eco"
7
+ version = "0.4.5"
8
+ description = "Dependency and skill manager for the OPERA ecosystem"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ authors = [
12
+ {name="Paul Labonne", email="Paul.Labonne@bankofengland.co.uk"},
13
+ {name="Diego Lopez", email="Diego.Lopez@bankofengland.co.uk"},
14
+ ]
15
+
16
+ maintainers = [
17
+ {name="Paul Labonne", email="Paul.Labonne@bankofengland.co.uk"},
18
+ ]
19
+
20
+ license = "MIT"
21
+ keywords = ["time-series", "forecasting", "evaluation", "backtesting", "economics"]
22
+ classifiers = [
23
+ "Development Status :: 4 - Beta",
24
+ "Operating System :: OS Independent",
25
+ "Programming Language :: Python :: 3",
26
+ "Programming Language :: Python :: 3.11",
27
+ "Programming Language :: Python :: 3.12",
28
+ "Programming Language :: Python :: 3.13",
29
+ "Programming Language :: Python :: 3.14",
30
+ "Topic :: Scientific/Engineering",
31
+ ]
32
+
33
+ dependencies = [
34
+ "numpy",
35
+ "pandas",
36
+ ]
37
+
38
+ [project.urls]
39
+ Documentation = "https://bank-of-england.github.io/opera-eco/"
40
+ Repository = "https://github.com/bank-of-england/opera-eco"
41
+ Issues = "https://github.com/bank-of-england/opera-eco/issues"
42
+
43
+ # Integration manifest containing the pinned ecosystem versions.
44
+ # Update these pins only after the contract and pipeline suites pass.
45
+ [project.optional-dependencies]
46
+ modules = [
47
+ "forecast_evaluation == 0.1.13",
48
+ "forecast_realtime[models]==0.5.4",
49
+ "forecast_combo==0.1.1",
50
+ "bvar==0.3.1",
51
+ "nowcast-midas==0.0.1",
52
+ "news_decomp==0.0.7",
53
+ ]
54
+
55
+ test = [
56
+ "opera-eco[modules]",
57
+ "pytest",
58
+ "pytest-xdist",
59
+ "pytest-timeout",
60
+ "pandera",
61
+ "syrupy",
62
+ ]
63
+
64
+ notebooks = [
65
+ "marimo==0.24.0",
66
+ ]
67
+
68
+ dev = [
69
+ "build",
70
+ "packaging",
71
+ "pre-commit",
72
+ "pydoclint",
73
+ "ruff",
74
+ "twine",
75
+ ]
76
+
77
+ docs = [
78
+ "mkdocstrings[python]",
79
+ "zensical",
80
+ ]
81
+
82
+ [project.scripts]
83
+ opera = "opera.cli:main"
84
+
85
+ [tool.setuptools.packages.find]
86
+ where = ["src"]
87
+
88
+ [tool.setuptools.package-data]
89
+ "opera.skills" = ["*.md"]
90
+ "opera.tests" = ["**/*.py", "**/__snapshots__/*.ambr"]
91
+
92
+ [tool.pytest.ini_options]
93
+ testpaths = ["src/opera/tests"]
94
+ markers = [
95
+ "contract: shared-schema and interface contract tests (fast)",
96
+ "skill_snippet: isolated executable skill documentation snippets",
97
+ "pipeline: cross-module end-to-end tests (slow)",
98
+ "bvar: pipeline tests exercising the BVAR model",
99
+ "midas: pipeline tests exercising the MIDAS-family models (MIDAS, MultiMIDAS, SC-MIDAS)",
100
+ "news: pipeline tests exercising the news/decomposition pipeline",
101
+ "mixed_freq: pipeline tests exercising the real-time mixed-frequency pipeline",
102
+ "ecosystem: pipeline tests exercising the full OPERA ecosystem illustration",
103
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,8 @@
1
+ """OPERA — Open-source Prediction, Evaluation and Real-time Analysis.
2
+
3
+ Ecosystem CLI and skill manager for the Bank of England forecasting platform.
4
+ """
5
+
6
+ __version__ = "0.4.4"
7
+
8
+ __all__ = ["__version__"]
@@ -0,0 +1,174 @@
1
+ """Manage OPERA skills from the command line.
2
+
3
+ Usage
4
+ -----
5
+ ::
6
+
7
+ opera install skills [--target DIR] [--only name1,name2]
8
+ opera list skills
9
+ opera show skill <name>
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import argparse
15
+ import sys
16
+ import textwrap
17
+
18
+ from opera import __version__
19
+
20
+ # Subcommands
21
+
22
+
23
+ def _cmd_install_skills(args: argparse.Namespace) -> None:
24
+ """Install the selected bundled skills into the requested directory.
25
+
26
+ The parsed arguments provide the destination and an optional comma-separated
27
+ list of skill names. The command reports each skill after installation.
28
+ """
29
+ from opera.skills_manager import SKILL_FILES, install_skills
30
+
31
+ skills = None
32
+ if args.only:
33
+ skills = [s.strip() for s in args.only.split(",")]
34
+
35
+ target = install_skills(target=args.target, skills=skills)
36
+
37
+ installed = skills or list(SKILL_FILES)
38
+ print(f"Installed {len(installed)} skill(s) to {target}")
39
+ for name in installed:
40
+ print(f" - {name}")
41
+
42
+
43
+ def _cmd_list_skills(_args: argparse.Namespace) -> None:
44
+ """Print a table of bundled skills, files, and descriptions."""
45
+ from opera.skills_manager import list_skills
46
+
47
+ skills = list_skills()
48
+ header = f"{'Name':<25} {'File':<30} Description"
49
+ sep = f"{'-' * 25} {'-' * 30} {'-' * 50}"
50
+ print(header)
51
+ print(sep)
52
+ for s in skills:
53
+ desc = textwrap.shorten(s["description"], width=50, placeholder="…")
54
+ print(f"{s['name']:<25} {s['filename']:<30} {desc}")
55
+
56
+
57
+ def _cmd_show_skill(args: argparse.Namespace) -> None:
58
+ """Write the named bundled skill to standard output as UTF-8 text.
59
+
60
+ An unknown skill name is reported on standard output and causes the command
61
+ to exit with status 1.
62
+ """
63
+ from opera.skills_manager import show_skill
64
+
65
+ try:
66
+ text = show_skill(args.name)
67
+ sys.stdout.buffer.write(text.encode("utf-8", errors="replace"))
68
+ sys.stdout.buffer.write(b"\n")
69
+ except KeyError as exc:
70
+ print(str(exc))
71
+ sys.exit(1)
72
+
73
+
74
+ def _cmd_sync_api(_args: argparse.Namespace) -> None:
75
+ """Synchronise generated API sections in the bundled skill files.
76
+
77
+ The command reports changed files, or confirms that the generated sections
78
+ are current. Synchronisation errors are written to standard error and cause
79
+ the command to exit with status 1.
80
+ """
81
+ from opera.skill_api import sync_api_sections
82
+
83
+ try:
84
+ changed = sync_api_sections()
85
+ except Exception as exc:
86
+ print(f"opera skills sync-api: {exc}", file=sys.stderr)
87
+ raise SystemExit(1) from exc
88
+ for path in changed:
89
+ print(f"Updated {path}")
90
+ if not changed:
91
+ print("Skill API sections are current.")
92
+
93
+
94
+ # Argument parser
95
+
96
+
97
+ def build_parser() -> argparse.ArgumentParser:
98
+ """Build and return the parser for all OPERA CLI commands.
99
+
100
+ The parser registers skill installation, listing, display, and API
101
+ synchronisation commands and attaches each command's handler.
102
+ """
103
+ parser = argparse.ArgumentParser(
104
+ prog="opera",
105
+ description="OPERA ecosystem CLI — manage skills and dependencies.",
106
+ )
107
+ parser.add_argument(
108
+ "-V", "--version", action="version", version=f"%(prog)s {__version__}"
109
+ )
110
+
111
+ sub = parser.add_subparsers(dest="command", required=True)
112
+
113
+ # Install skills or dependencies.
114
+ install_parser = sub.add_parser("install", help="Install skills or dependencies")
115
+ install_sub = install_parser.add_subparsers(dest="install_target", required=True)
116
+
117
+ # Install skills.
118
+ install_skills_parser = install_sub.add_parser(
119
+ "skills", help="Copy OPERA skill files to a target directory"
120
+ )
121
+ install_skills_parser.add_argument(
122
+ "--target",
123
+ default=None,
124
+ help="Destination directory (default: .claude/skills or .github/skills)",
125
+ )
126
+ install_skills_parser.add_argument(
127
+ "--only",
128
+ default=None,
129
+ help="Comma-separated list of skill names to install (default: all)",
130
+ )
131
+ install_skills_parser.set_defaults(func=_cmd_install_skills)
132
+
133
+ # Synchronise generated API sections in the repository checkout.
134
+ skills_command_parser = sub.add_parser(
135
+ "skills", help="Maintain bundled skill resources"
136
+ )
137
+ skills_sub = skills_command_parser.add_subparsers(
138
+ dest="skills_command", required=True
139
+ )
140
+ sync_api_parser = skills_sub.add_parser(
141
+ "sync-api", help="Update generated skill API sections"
142
+ )
143
+ sync_api_parser.set_defaults(func=_cmd_sync_api)
144
+
145
+ # List available resources.
146
+ list_parser = sub.add_parser("list", help="List available resources")
147
+ list_sub = list_parser.add_subparsers(dest="list_target", required=True)
148
+
149
+ list_skills_parser = list_sub.add_parser("skills", help="List bundled skills")
150
+ list_skills_parser.set_defaults(func=_cmd_list_skills)
151
+
152
+ # Show a resource.
153
+ show_parser = sub.add_parser("show", help="Show a resource")
154
+ show_sub = show_parser.add_subparsers(dest="show_target", required=True)
155
+
156
+ show_skill_parser = show_sub.add_parser("skill", help="Print a skill file")
157
+ show_skill_parser.add_argument("name", help="Skill short-name (e.g. opera, bvar)")
158
+ show_skill_parser.set_defaults(func=_cmd_show_skill)
159
+
160
+ return parser
161
+
162
+
163
+ def main(argv: list[str] | None = None) -> None:
164
+ """Parse arguments and dispatch to the selected OPERA CLI command.
165
+
166
+ When ``argv`` is omitted, arguments are read from the process command line.
167
+ """
168
+ parser = build_parser()
169
+ args = parser.parse_args(argv)
170
+ args.func(args)
171
+
172
+
173
+ if __name__ == "__main__":
174
+ main()