opencode-pyneruntime 6.6.4__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.
- opencode_pyneruntime-6.6.4.dist-info/METADATA +281 -0
- opencode_pyneruntime-6.6.4.dist-info/RECORD +261 -0
- opencode_pyneruntime-6.6.4.dist-info/WHEEL +5 -0
- opencode_pyneruntime-6.6.4.dist-info/entry_points.txt +6 -0
- opencode_pyneruntime-6.6.4.dist-info/licenses/LICENSE +201 -0
- opencode_pyneruntime-6.6.4.dist-info/licenses/NOTICE +21 -0
- opencode_pyneruntime-6.6.4.dist-info/top_level.txt +1 -0
- pynecore/__init__.py +6 -0
- pynecore/cli/__init__.py +2 -0
- pynecore/cli/app.py +238 -0
- pynecore/cli/commands/__init__.py +343 -0
- pynecore/cli/commands/benchmark.py +186 -0
- pynecore/cli/commands/compile.py +198 -0
- pynecore/cli/commands/data.py +857 -0
- pynecore/cli/commands/debug.py +63 -0
- pynecore/cli/commands/optimize.py +956 -0
- pynecore/cli/commands/plugin.py +242 -0
- pynecore/cli/commands/run.py +2006 -0
- pynecore/cli/pluggable.py +132 -0
- pynecore/cli/utils/__init__.py +0 -0
- pynecore/cli/utils/api_error_handler.py +168 -0
- pynecore/cli/utils/broker_picker.py +330 -0
- pynecore/cli/utils/error_hook.py +28 -0
- pynecore/cli/utils/keyreader.py +178 -0
- pynecore/cli/utils/provider_picker.py +19 -0
- pynecore/cli/utils/symbol_browser.py +1149 -0
- pynecore/core/__init__.py +0 -0
- pynecore/core/aggregator.py +257 -0
- pynecore/core/bar_magnifier.py +168 -0
- pynecore/core/broker/__init__.py +64 -0
- pynecore/core/broker/defaults.py +113 -0
- pynecore/core/broker/disappearance.py +927 -0
- pynecore/core/broker/emulator.py +345 -0
- pynecore/core/broker/exceptions.py +346 -0
- pynecore/core/broker/idempotency.py +401 -0
- pynecore/core/broker/intent_builder.py +334 -0
- pynecore/core/broker/journal.py +1785 -0
- pynecore/core/broker/models.py +1600 -0
- pynecore/core/broker/native_failsafe_manager.py +1436 -0
- pynecore/core/broker/one_way_emulator.py +1128 -0
- pynecore/core/broker/position.py +787 -0
- pynecore/core/broker/run_identity.py +126 -0
- pynecore/core/broker/software_entry_stop_engine.py +351 -0
- pynecore/core/broker/software_partial_bracket_engine.py +1379 -0
- pynecore/core/broker/spot_inventory.py +1327 -0
- pynecore/core/broker/storage.py +2655 -0
- pynecore/core/broker/store_helpers.py +2161 -0
- pynecore/core/broker/sync_engine.py +16070 -0
- pynecore/core/broker/validation.py +382 -0
- pynecore/core/class_property.py +7 -0
- pynecore/core/config.py +392 -0
- pynecore/core/csv_file.py +547 -0
- pynecore/core/currency.py +262 -0
- pynecore/core/data_converter.py +1002 -0
- pynecore/core/datetime.py +296 -0
- pynecore/core/download_info.py +71 -0
- pynecore/core/download_runner.py +274 -0
- pynecore/core/htf_aggregator.py +181 -0
- pynecore/core/import_hook.py +358 -0
- pynecore/core/instance_state.py +494 -0
- pynecore/core/live_ltf_collector.py +442 -0
- pynecore/core/live_ltf_window.py +189 -0
- pynecore/core/live_runner.py +1347 -0
- pynecore/core/module_property.py +26 -0
- pynecore/core/ohlcv_file.py +1888 -0
- pynecore/core/overload.py +371 -0
- pynecore/core/pine_cast.py +113 -0
- pynecore/core/pine_export.py +95 -0
- pynecore/core/pine_method.py +244 -0
- pynecore/core/pine_range.py +86 -0
- pynecore/core/pine_udt.py +69 -0
- pynecore/core/plugin/__init__.py +394 -0
- pynecore/core/plugin/broker.py +781 -0
- pynecore/core/plugin/cli.py +96 -0
- pynecore/core/plugin/live_provider.py +208 -0
- pynecore/core/plugin/provider.py +331 -0
- pynecore/core/provider_string.py +148 -0
- pynecore/core/random.py +40 -0
- pynecore/core/resampler.py +686 -0
- pynecore/core/safe_convert.py +64 -0
- pynecore/core/script.py +1011 -0
- pynecore/core/script_runner.py +3202 -0
- pynecore/core/security.py +1749 -0
- pynecore/core/security_process.py +1253 -0
- pynecore/core/security_shm.py +456 -0
- pynecore/core/series.py +417 -0
- pynecore/core/strategy_stats.py +669 -0
- pynecore/core/symbol_map.py +134 -0
- pynecore/core/syminfo.py +505 -0
- pynecore/core/viz.py +591 -0
- pynecore/lib/__init__.py +1771 -0
- pynecore/lib/_fixnan.py +32 -0
- pynecore/lib/_math_stateful.py +202 -0
- pynecore/lib/_timeframe_change.py +101 -0
- pynecore/lib/adjustment.py +6 -0
- pynecore/lib/alert.py +39 -0
- pynecore/lib/alert.pyi +14 -0
- pynecore/lib/array.py +1051 -0
- pynecore/lib/barmerge.py +60 -0
- pynecore/lib/barstate.py +30 -0
- pynecore/lib/box.py +415 -0
- pynecore/lib/chart.py +128 -0
- pynecore/lib/color.py +152 -0
- pynecore/lib/color.pyi +50 -0
- pynecore/lib/currency.py +62 -0
- pynecore/lib/dayofweek.py +36 -0
- pynecore/lib/dayofweek.pyi +18 -0
- pynecore/lib/display.py +8 -0
- pynecore/lib/dividends.py +9 -0
- pynecore/lib/earnings.py +11 -0
- pynecore/lib/extend.py +6 -0
- pynecore/lib/font.py +5 -0
- pynecore/lib/footprint.py +79 -0
- pynecore/lib/format.py +11 -0
- pynecore/lib/hline.py +67 -0
- pynecore/lib/hline.pyi +24 -0
- pynecore/lib/label.py +409 -0
- pynecore/lib/line.py +433 -0
- pynecore/lib/linefill.py +93 -0
- pynecore/lib/location.py +11 -0
- pynecore/lib/log.py +362 -0
- pynecore/lib/map.py +150 -0
- pynecore/lib/math.py +385 -0
- pynecore/lib/matrix.py +708 -0
- pynecore/lib/order.py +8 -0
- pynecore/lib/pivotpointtype.py +8 -0
- pynecore/lib/plot.py +95 -0
- pynecore/lib/plot.pyi +33 -0
- pynecore/lib/polyline.py +91 -0
- pynecore/lib/position.py +15 -0
- pynecore/lib/request.py +281 -0
- pynecore/lib/runtime.py +5 -0
- pynecore/lib/scale.py +9 -0
- pynecore/lib/session.py +267 -0
- pynecore/lib/session.pyi +12 -0
- pynecore/lib/shape.py +18 -0
- pynecore/lib/size.py +12 -0
- pynecore/lib/splits.py +4 -0
- pynecore/lib/strategy/__init__.py +4778 -0
- pynecore/lib/strategy/closedtrades.py +347 -0
- pynecore/lib/strategy/closedtrades.pyi +53 -0
- pynecore/lib/strategy/commission.py +9 -0
- pynecore/lib/strategy/direction.py +9 -0
- pynecore/lib/strategy/oca.py +13 -0
- pynecore/lib/strategy/opentrades.py +281 -0
- pynecore/lib/strategy/opentrades.pyi +49 -0
- pynecore/lib/strategy/risk.py +109 -0
- pynecore/lib/string.py +649 -0
- pynecore/lib/syminfo.py +84 -0
- pynecore/lib/ta.py +2230 -0
- pynecore/lib/table.py +290 -0
- pynecore/lib/text.py +17 -0
- pynecore/lib/ticker.py +207 -0
- pynecore/lib/timeframe.py +293 -0
- pynecore/lib/volume_row.py +67 -0
- pynecore/lib/xloc.py +4 -0
- pynecore/lib/yloc.py +5 -0
- pynecore/providers/__init__.py +0 -0
- pynecore/providers/ccxt.py +664 -0
- pynecore/providers/replay.py +187 -0
- pynecore/pynesys/__init__.py +0 -0
- pynecore/pynesys/api.py +498 -0
- pynecore/pynesys/compiler.py +112 -0
- pynecore/standalone.py +99 -0
- pynecore/testing/__init__.py +1 -0
- pynecore/testing/broker_lab/__init__.py +41 -0
- pynecore/testing/broker_lab/__main__.py +5 -0
- pynecore/testing/broker_lab/cli.py +87 -0
- pynecore/testing/broker_lab/generate.py +47 -0
- pynecore/testing/broker_lab/model.py +84 -0
- pynecore/testing/broker_lab/reference.py +645 -0
- pynecore/testing/broker_lab/runner.py +372 -0
- pynecore/testing/broker_lab/scheduler.py +50 -0
- pynecore/testing/broker_lab/subprocess.py +73 -0
- pynecore/transformers/__init__.py +0 -0
- pynecore/transformers/builtin_shadow.py +136 -0
- pynecore/transformers/closure_arguments_transformer.py +428 -0
- pynecore/transformers/display_rewrite.py +140 -0
- pynecore/transformers/dynamic_default.py +147 -0
- pynecore/transformers/function_isolation.py +757 -0
- pynecore/transformers/import_lifter.py +61 -0
- pynecore/transformers/import_normalizer.py +328 -0
- pynecore/transformers/inline_series_hoist.py +178 -0
- pynecore/transformers/input_transformer.py +175 -0
- pynecore/transformers/lib_series.py +201 -0
- pynecore/transformers/locations.py +70 -0
- pynecore/transformers/module_properties.json +3387 -0
- pynecore/transformers/module_property.py +221 -0
- pynecore/transformers/ne_guard.py +70 -0
- pynecore/transformers/persistent.py +320 -0
- pynecore/transformers/persistent_series.py +76 -0
- pynecore/transformers/safe_convert_transformer.py +97 -0
- pynecore/transformers/safe_division_transformer.py +95 -0
- pynecore/transformers/script_requirements.py +308 -0
- pynecore/transformers/security.py +752 -0
- pynecore/transformers/security_instantiation.py +274 -0
- pynecore/transformers/series.py +275 -0
- pynecore/transformers/slot_layout.py +381 -0
- pynecore/transformers/type_checking_stripper.py +25 -0
- pynecore/transformers/unused_series_detector.py +267 -0
- pynecore/types/__init__.py +21 -0
- pynecore/types/alert.py +5 -0
- pynecore/types/barmerge.py +5 -0
- pynecore/types/base.py +39 -0
- pynecore/types/box.py +37 -0
- pynecore/types/chart.py +17 -0
- pynecore/types/color.py +107 -0
- pynecore/types/currency.py +5 -0
- pynecore/types/datetime.py +6 -0
- pynecore/types/display.py +5 -0
- pynecore/types/dividends.py +5 -0
- pynecore/types/earnings.py +5 -0
- pynecore/types/extend.py +5 -0
- pynecore/types/font.py +5 -0
- pynecore/types/footprint.py +41 -0
- pynecore/types/format.py +5 -0
- pynecore/types/hline.py +24 -0
- pynecore/types/ib_persistent.py +8 -0
- pynecore/types/ib_persistent.pyi +10 -0
- pynecore/types/label.py +35 -0
- pynecore/types/line.py +32 -0
- pynecore/types/linefill.py +13 -0
- pynecore/types/location.py +5 -0
- pynecore/types/matrix.py +999 -0
- pynecore/types/na.py +237 -0
- pynecore/types/na.pyi +83 -0
- pynecore/types/ohlcv.py +12 -0
- pynecore/types/order.py +5 -0
- pynecore/types/persistent.py +8 -0
- pynecore/types/persistent.pyi +13 -0
- pynecore/types/pine_types.py +11 -0
- pynecore/types/pine_types.pyi +15 -0
- pynecore/types/pivotpointtype.py +5 -0
- pynecore/types/plot.py +12 -0
- pynecore/types/plot_meta.py +60 -0
- pynecore/types/polyline.py +40 -0
- pynecore/types/position.py +5 -0
- pynecore/types/scale.py +5 -0
- pynecore/types/script_type.py +15 -0
- pynecore/types/series.py +23 -0
- pynecore/types/series.pyi +19 -0
- pynecore/types/session.py +35 -0
- pynecore/types/shape.py +5 -0
- pynecore/types/size.py +5 -0
- pynecore/types/source.py +33 -0
- pynecore/types/splits.py +5 -0
- pynecore/types/strategy.py +45 -0
- pynecore/types/table.py +87 -0
- pynecore/types/text.py +13 -0
- pynecore/types/type_checker.py +7 -0
- pynecore/types/type_checker.pyi +48 -0
- pynecore/types/volume_row.py +36 -0
- pynecore/types/weekdays.py +11 -0
- pynecore/types/xloc.py +5 -0
- pynecore/types/yloc.py +5 -0
- pynecore/utils/__init__.py +0 -0
- pynecore/utils/file_utils.py +50 -0
- pynecore/utils/rich/__init__.py +0 -0
- pynecore/utils/rich/date_column.py +25 -0
- pynecore/utils/sequence_view.py +92 -0
- pynecore/utils/stdlib_checker.py +17 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
from typer import Typer, Option, Argument, Exit, secho, colors
|
|
2
|
+
|
|
3
|
+
from ..app import app
|
|
4
|
+
|
|
5
|
+
__all__ = []
|
|
6
|
+
|
|
7
|
+
app_plugin = Typer(help="Plugin management commands")
|
|
8
|
+
app.add_typer(app_plugin, name="plugin")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _get_capabilities(cls: type) -> list[str]:
|
|
12
|
+
"""Determine plugin capabilities from its class hierarchy."""
|
|
13
|
+
from ...core.plugin import ProviderPlugin, CLIPlugin
|
|
14
|
+
from ...core.plugin.broker import BrokerPlugin
|
|
15
|
+
|
|
16
|
+
caps = []
|
|
17
|
+
if isinstance(cls, type) and issubclass(cls, ProviderPlugin):
|
|
18
|
+
caps.append('provider')
|
|
19
|
+
if isinstance(cls, type) and issubclass(cls, BrokerPlugin):
|
|
20
|
+
caps.append('broker')
|
|
21
|
+
if isinstance(cls, type) and issubclass(cls, CLIPlugin):
|
|
22
|
+
caps.append('cli')
|
|
23
|
+
return caps
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@app_plugin.command("list")
|
|
27
|
+
def list_plugins(
|
|
28
|
+
plugin_type: str = Option(
|
|
29
|
+
None, '--type', '-t',
|
|
30
|
+
help="Filter by capability (e.g. 'provider', 'cli')",
|
|
31
|
+
),
|
|
32
|
+
as_json: bool = Option(
|
|
33
|
+
False, '--json',
|
|
34
|
+
help="Machine readable output for tooling",
|
|
35
|
+
),
|
|
36
|
+
):
|
|
37
|
+
"""
|
|
38
|
+
List all installed PyneCore plugins.
|
|
39
|
+
"""
|
|
40
|
+
from ...core.plugin import (
|
|
41
|
+
discover_plugin_entry_points, get_plugin_metadata, get_plugin_package, get_plugin_summary
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
plugins = discover_plugin_entry_points()
|
|
45
|
+
if not plugins and not as_json:
|
|
46
|
+
secho("No plugins installed.", fg=colors.YELLOW)
|
|
47
|
+
secho("")
|
|
48
|
+
return
|
|
49
|
+
|
|
50
|
+
# Collect data first to calculate column widths. A plugin name may be
|
|
51
|
+
# declared by several packages — list every one of them, flagged.
|
|
52
|
+
rows = []
|
|
53
|
+
errors = []
|
|
54
|
+
for name, eps in sorted(plugins.items()):
|
|
55
|
+
conflict = len(eps) > 1
|
|
56
|
+
for ep in eps:
|
|
57
|
+
try:
|
|
58
|
+
cls = ep.load()
|
|
59
|
+
meta = get_plugin_metadata(ep)
|
|
60
|
+
caps = _get_capabilities(cls)
|
|
61
|
+
|
|
62
|
+
if plugin_type and plugin_type not in caps:
|
|
63
|
+
continue
|
|
64
|
+
|
|
65
|
+
display_name = getattr(cls, 'plugin_name', '') or name
|
|
66
|
+
version = f"v{meta['version']}" if meta['version'] else ''
|
|
67
|
+
caps_str = ', '.join(caps) if caps else 'library'
|
|
68
|
+
summary = get_plugin_summary(cls) or meta['description']
|
|
69
|
+
rows.append((name, display_name, version, caps_str, summary,
|
|
70
|
+
meta['package'], conflict))
|
|
71
|
+
except Exception as e:
|
|
72
|
+
errors.append((f"{name} ({get_plugin_package(ep)})" if conflict else name, str(e)))
|
|
73
|
+
|
|
74
|
+
if as_json:
|
|
75
|
+
import json
|
|
76
|
+
secho(json.dumps({
|
|
77
|
+
'plugins': [
|
|
78
|
+
{
|
|
79
|
+
'name': name,
|
|
80
|
+
'display_name': display_name,
|
|
81
|
+
'version': version.lstrip('v'),
|
|
82
|
+
'capabilities': caps_str.split(', '),
|
|
83
|
+
'summary': summary,
|
|
84
|
+
'package': package,
|
|
85
|
+
'conflict': conflict,
|
|
86
|
+
}
|
|
87
|
+
for name, display_name, version, caps_str, summary, package, conflict in rows
|
|
88
|
+
],
|
|
89
|
+
'errors': [{'name': name, 'error': error} for name, error in errors],
|
|
90
|
+
}))
|
|
91
|
+
return
|
|
92
|
+
|
|
93
|
+
if not rows and not errors:
|
|
94
|
+
secho("No plugins found for the given filter.", fg=colors.YELLOW)
|
|
95
|
+
secho("")
|
|
96
|
+
return
|
|
97
|
+
|
|
98
|
+
# Calculate column widths
|
|
99
|
+
w_name = max((len(r[0]) for r in rows), default=0)
|
|
100
|
+
w_disp = max((len(r[1]) for r in rows), default=0)
|
|
101
|
+
w_ver = max((len(r[2]) for r in rows), default=0)
|
|
102
|
+
|
|
103
|
+
secho(f"\n Installed plugins:\n", fg=colors.BRIGHT_WHITE, bold=True)
|
|
104
|
+
|
|
105
|
+
indent = 4 + w_name + 3
|
|
106
|
+
conflicting: dict[str, list[str]] = {}
|
|
107
|
+
for name, display_name, version, caps_str, summary, package, conflict in rows:
|
|
108
|
+
prefix = " ! " if conflict else " "
|
|
109
|
+
secho(f"{prefix}{name:<{w_name}} {display_name:<{w_disp}} {version:<{w_ver}} [{caps_str}]",
|
|
110
|
+
fg=colors.YELLOW if conflict else None)
|
|
111
|
+
if summary:
|
|
112
|
+
secho(f"{' ' * indent}└─ {summary}", dim=True)
|
|
113
|
+
if conflict:
|
|
114
|
+
conflicting.setdefault(name, []).append(package)
|
|
115
|
+
|
|
116
|
+
for name, error in errors:
|
|
117
|
+
secho(f" {name:<{w_name}} (failed to load: {error})", fg=colors.RED)
|
|
118
|
+
|
|
119
|
+
if conflicting:
|
|
120
|
+
secho("")
|
|
121
|
+
secho(" ! Name conflicts:", fg=colors.YELLOW, bold=True)
|
|
122
|
+
for name, packages in sorted(conflicting.items()):
|
|
123
|
+
secho(f" '{name}' is declared by: {', '.join(packages)}", fg=colors.YELLOW)
|
|
124
|
+
secho(" Loading such a plugin fails until all but one package is uninstalled.", dim=True)
|
|
125
|
+
|
|
126
|
+
secho("")
|
|
127
|
+
secho(" Use 'pyne plugin info <name>' for details.", dim=True)
|
|
128
|
+
secho("")
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@app_plugin.command("info")
|
|
132
|
+
def plugin_info(
|
|
133
|
+
name: str = Argument(..., help="Plugin name (e.g. 'ccxt', 'capitalcom')"),
|
|
134
|
+
):
|
|
135
|
+
"""
|
|
136
|
+
Show detailed information about an installed plugin.
|
|
137
|
+
"""
|
|
138
|
+
from ...core.plugin import (
|
|
139
|
+
discover_plugin_entry_points, get_plugin_metadata, get_plugin_description, get_plugin_package
|
|
140
|
+
)
|
|
141
|
+
from rich.console import Console
|
|
142
|
+
from rich.markdown import Markdown
|
|
143
|
+
from rich.padding import Padding
|
|
144
|
+
import dataclasses
|
|
145
|
+
|
|
146
|
+
plugins = discover_plugin_entry_points()
|
|
147
|
+
candidates = plugins.get(name)
|
|
148
|
+
if not candidates:
|
|
149
|
+
secho(f"Plugin '{name}' is not installed.", fg=colors.RED, err=True)
|
|
150
|
+
secho(f"Available plugins: {', '.join(sorted(plugins)) or '(none)'}", fg=colors.YELLOW, err=True)
|
|
151
|
+
raise Exit(1)
|
|
152
|
+
|
|
153
|
+
if len(candidates) > 1:
|
|
154
|
+
secho(f"Plugin name '{name}' is ambiguous — declared by {len(candidates)} installed packages:",
|
|
155
|
+
fg=colors.RED, err=True)
|
|
156
|
+
for candidate in candidates:
|
|
157
|
+
secho(f" {get_plugin_package(candidate)} ({candidate.value})", fg=colors.YELLOW, err=True)
|
|
158
|
+
secho("Uninstall all but the one you want to use.", fg=colors.YELLOW, err=True)
|
|
159
|
+
raise Exit(1)
|
|
160
|
+
|
|
161
|
+
ep = candidates[0]
|
|
162
|
+
try:
|
|
163
|
+
cls = ep.load()
|
|
164
|
+
except Exception as e:
|
|
165
|
+
secho(f"Failed to load plugin '{name}': {e}", fg=colors.RED, err=True)
|
|
166
|
+
raise Exit(1)
|
|
167
|
+
|
|
168
|
+
meta = get_plugin_metadata(ep)
|
|
169
|
+
caps = _get_capabilities(cls)
|
|
170
|
+
|
|
171
|
+
secho(f"\n Plugin: {name}", fg=colors.BRIGHT_WHITE, bold=True)
|
|
172
|
+
secho(f" Package: {meta['package']}")
|
|
173
|
+
secho(f" Version: {meta['version'] or 'unknown'}")
|
|
174
|
+
secho(f" Description: {meta['description'] or '-'}")
|
|
175
|
+
secho(f" Needs PyneCore: {meta['requires_pynecore'] or 'any'}")
|
|
176
|
+
secho(f" Capabilities: {', '.join(caps) if caps else 'library'}")
|
|
177
|
+
secho(f" Entry point: {ep.value}")
|
|
178
|
+
|
|
179
|
+
description = get_plugin_description(cls)
|
|
180
|
+
if description:
|
|
181
|
+
secho("\n Details:", fg=colors.BRIGHT_WHITE, bold=True)
|
|
182
|
+
Console().print(Padding(Markdown(description), (0, 0, 0, 2)))
|
|
183
|
+
|
|
184
|
+
if 'broker' in caps:
|
|
185
|
+
from rich.table import Table
|
|
186
|
+
from rich import box
|
|
187
|
+
from ...core.broker.models import CapabilityLevel
|
|
188
|
+
|
|
189
|
+
# ``get_capabilities`` is an instance method but well-behaved broker
|
|
190
|
+
# plugins return a static dataclass with no I/O. Try a default
|
|
191
|
+
# construction first; if the plugin requires its Config dataclass
|
|
192
|
+
# (e.g. Capital.com asserts on it), retry with a default-constructed
|
|
193
|
+
# Config. Fall back to a warning if even that fails — long-term fix
|
|
194
|
+
# is to make ``get_capabilities`` a classmethod.
|
|
195
|
+
ex_caps = None
|
|
196
|
+
intro_error: Exception | None = None
|
|
197
|
+
try:
|
|
198
|
+
ex_caps = cls().get_capabilities() # type: ignore[call-arg]
|
|
199
|
+
except Exception as e1:
|
|
200
|
+
intro_error = e1
|
|
201
|
+
cfg_cls = getattr(cls, 'Config', None)
|
|
202
|
+
if cfg_cls is not None and dataclasses.is_dataclass(cfg_cls):
|
|
203
|
+
try:
|
|
204
|
+
ex_caps = cls(config=cfg_cls()).get_capabilities() # type: ignore[call-arg]
|
|
205
|
+
intro_error = None
|
|
206
|
+
except Exception as e2:
|
|
207
|
+
intro_error = e2
|
|
208
|
+
if intro_error is not None:
|
|
209
|
+
secho(
|
|
210
|
+
f"\n Exchange Capabilities: (cannot introspect: {intro_error})",
|
|
211
|
+
fg=colors.YELLOW,
|
|
212
|
+
)
|
|
213
|
+
else:
|
|
214
|
+
assert ex_caps is not None
|
|
215
|
+
secho("\n Exchange Capabilities:", fg=colors.BRIGHT_WHITE, bold=True)
|
|
216
|
+
level_color = {
|
|
217
|
+
CapabilityLevel.NATIVE: "green",
|
|
218
|
+
CapabilityLevel.PARTIAL_NATIVE: "yellow",
|
|
219
|
+
CapabilityLevel.SOFTWARE: "cyan",
|
|
220
|
+
CapabilityLevel.UNSUPPORTED: "dim white",
|
|
221
|
+
}
|
|
222
|
+
table = Table(box=box.SIMPLE, show_header=False, padding=(0, 2, 0, 2))
|
|
223
|
+
table.add_column("Capability", style="white")
|
|
224
|
+
table.add_column("Level")
|
|
225
|
+
# noinspection PyDataclass
|
|
226
|
+
for f in dataclasses.fields(ex_caps):
|
|
227
|
+
value = getattr(ex_caps, f.name)
|
|
228
|
+
colour = level_color.get(value, "cyan")
|
|
229
|
+
table.add_row(f.name, f"[{colour}]{value.value}[/{colour}]")
|
|
230
|
+
Console().print(Padding(table, (0, 0, 0, 2)))
|
|
231
|
+
|
|
232
|
+
config_cls: type | None = getattr(cls, 'Config', None)
|
|
233
|
+
if config_cls is not None and dataclasses.is_dataclass(config_cls):
|
|
234
|
+
# noinspection PyDataclass
|
|
235
|
+
fields = dataclasses.fields(config_cls)
|
|
236
|
+
if fields:
|
|
237
|
+
secho(f"\n Config fields (defaults):")
|
|
238
|
+
for f in fields:
|
|
239
|
+
default = f"= {f.default!r}" if f.default is not dataclasses.MISSING else "(required)"
|
|
240
|
+
secho(f" {f.name:20s} {default}")
|
|
241
|
+
|
|
242
|
+
secho("")
|