mtcli 3.7.0.dev1__py3-none-any.whl → 3.7.0.dev3__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.
- mtcli/plugin_loader.py +127 -48
- {mtcli-3.7.0.dev1.dist-info → mtcli-3.7.0.dev3.dist-info}/METADATA +1 -1
- {mtcli-3.7.0.dev1.dist-info → mtcli-3.7.0.dev3.dist-info}/RECORD +6 -6
- {mtcli-3.7.0.dev1.dist-info → mtcli-3.7.0.dev3.dist-info}/WHEEL +0 -0
- {mtcli-3.7.0.dev1.dist-info → mtcli-3.7.0.dev3.dist-info}/entry_points.txt +0 -0
- {mtcli-3.7.0.dev1.dist-info → mtcli-3.7.0.dev3.dist-info}/licenses/LICENSE +0 -0
mtcli/plugin_loader.py
CHANGED
|
@@ -1,38 +1,27 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Sistema de carregamento de plugins do mtcli.
|
|
3
3
|
|
|
4
|
-
Este módulo
|
|
5
|
-
instalados via entry points do Python.
|
|
4
|
+
Este módulo descobre e registra plugins de duas fontes:
|
|
6
5
|
|
|
7
|
-
Plugins
|
|
6
|
+
1. Plugins internos localizados em ``mtcli.plugins``
|
|
7
|
+
2. Plugins externos registrados via entry points ``mtcli.plugins``
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Plugins podem expor:
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
• função ``register(cli)``
|
|
12
|
+
• objeto ``click.Command``
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
2. Um objeto ``click.Command``
|
|
15
|
-
|
|
16
|
-
Exemplo de entry point no pyproject.toml:
|
|
14
|
+
Entry point exemplo:
|
|
17
15
|
|
|
18
16
|
[project.entry-points."mtcli.plugins"]
|
|
19
17
|
renko = "mtcli_renko.plugin:register"
|
|
20
|
-
|
|
21
|
-
Ou diretamente um comando:
|
|
22
|
-
|
|
23
|
-
renko = "mtcli_renko.cli:renko"
|
|
24
|
-
|
|
25
|
-
Este loader garante:
|
|
26
|
-
|
|
27
|
-
- compatibilidade com Python 3.8+
|
|
28
|
-
- proteção contra plugins duplicados
|
|
29
|
-
- logging estruturado
|
|
30
|
-
- isolamento de falhas de plugins
|
|
31
18
|
"""
|
|
32
19
|
|
|
33
20
|
from __future__ import annotations
|
|
34
21
|
|
|
22
|
+
import importlib
|
|
35
23
|
import logging
|
|
24
|
+
import pkgutil
|
|
36
25
|
from typing import Iterable, List
|
|
37
26
|
|
|
38
27
|
import click
|
|
@@ -42,20 +31,27 @@ try:
|
|
|
42
31
|
except ImportError: # pragma: no cover
|
|
43
32
|
from importlib_metadata import EntryPoint, entry_points
|
|
44
33
|
|
|
34
|
+
import mtcli.plugins
|
|
35
|
+
|
|
45
36
|
|
|
46
37
|
logger = logging.getLogger(__name__)
|
|
47
38
|
|
|
48
39
|
PLUGIN_GROUP = "mtcli.plugins"
|
|
49
40
|
|
|
50
41
|
|
|
51
|
-
|
|
42
|
+
# ---------------------------------------------------------
|
|
43
|
+
# Descoberta de plugins externos
|
|
44
|
+
# ---------------------------------------------------------
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def discover_external_plugins() -> Iterable[EntryPoint]:
|
|
52
48
|
"""
|
|
53
|
-
Descobre plugins
|
|
49
|
+
Descobre plugins externos via entry points.
|
|
54
50
|
|
|
55
51
|
Returns
|
|
56
52
|
-------
|
|
57
53
|
Iterable[EntryPoint]
|
|
58
|
-
|
|
54
|
+
Entry points encontrados no grupo ``mtcli.plugins``.
|
|
59
55
|
"""
|
|
60
56
|
|
|
61
57
|
try:
|
|
@@ -67,73 +63,123 @@ def discover_plugins() -> Iterable[EntryPoint]:
|
|
|
67
63
|
return eps.get(PLUGIN_GROUP, [])
|
|
68
64
|
|
|
69
65
|
except Exception as exc: # pragma: no cover
|
|
70
|
-
logger.error("Erro ao descobrir plugins: %s", exc)
|
|
66
|
+
logger.error("Erro ao descobrir plugins externos: %s", exc)
|
|
71
67
|
return []
|
|
72
68
|
|
|
73
69
|
|
|
74
|
-
|
|
70
|
+
# ---------------------------------------------------------
|
|
71
|
+
# Registro de plugin
|
|
72
|
+
# ---------------------------------------------------------
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def register_plugin(cli: click.Group, plugin, name: str) -> None:
|
|
75
76
|
"""
|
|
76
|
-
|
|
77
|
+
Registra um plugin no CLI.
|
|
77
78
|
|
|
78
79
|
O plugin pode ser:
|
|
79
80
|
|
|
80
|
-
|
|
81
|
-
|
|
81
|
+
• função ``register(cli)``
|
|
82
|
+
• objeto ``click.Command``
|
|
82
83
|
|
|
83
84
|
Parameters
|
|
84
85
|
----------
|
|
85
86
|
cli : click.Group
|
|
86
|
-
CLI principal
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
CLI principal.
|
|
88
|
+
plugin : Any
|
|
89
|
+
Objeto do plugin carregado.
|
|
90
|
+
name : str
|
|
91
|
+
Nome do plugin.
|
|
89
92
|
"""
|
|
90
93
|
|
|
91
|
-
plugin = ep.load()
|
|
92
|
-
|
|
93
94
|
if callable(plugin) and not isinstance(plugin, click.Command):
|
|
94
95
|
plugin(cli)
|
|
95
|
-
logger.debug("Plugin '%s' registrado via register()",
|
|
96
|
+
logger.debug("Plugin '%s' registrado via register()", name)
|
|
96
97
|
|
|
97
98
|
elif isinstance(plugin, click.Command):
|
|
98
99
|
cli.add_command(plugin)
|
|
99
|
-
logger.debug("Plugin '%s' registrado como comando",
|
|
100
|
+
logger.debug("Plugin '%s' registrado como comando", name)
|
|
100
101
|
|
|
101
102
|
else:
|
|
102
103
|
raise TypeError(
|
|
103
|
-
f"Plugin '{
|
|
104
|
-
"não é click.Command nem função register(cli)"
|
|
104
|
+
f"Plugin '{name}' inválido: não é click.Command nem register(cli)"
|
|
105
105
|
)
|
|
106
106
|
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
# ---------------------------------------------------------
|
|
109
|
+
# Plugins internos
|
|
110
|
+
# ---------------------------------------------------------
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def load_internal_plugins(cli: click.Group) -> List[str]:
|
|
109
114
|
"""
|
|
110
|
-
|
|
115
|
+
Carrega plugins internos do pacote ``mtcli.plugins``.
|
|
111
116
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
117
|
+
Cada módulo deve expor a função:
|
|
118
|
+
|
|
119
|
+
register(cli)
|
|
120
|
+
|
|
121
|
+
Returns
|
|
122
|
+
-------
|
|
123
|
+
list[str]
|
|
124
|
+
Lista de plugins carregados.
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
loaded = []
|
|
128
|
+
|
|
129
|
+
for module_info in pkgutil.iter_modules(mtcli.plugins.__path__):
|
|
130
|
+
|
|
131
|
+
module_name = f"mtcli.plugins.{module_info.name}"
|
|
132
|
+
|
|
133
|
+
try:
|
|
134
|
+
module = importlib.import_module(module_name)
|
|
135
|
+
|
|
136
|
+
if hasattr(module, "register"):
|
|
137
|
+
module.register(cli)
|
|
138
|
+
loaded.append(module_info.name)
|
|
139
|
+
|
|
140
|
+
logger.debug("Plugin interno carregado: %s", module_info.name)
|
|
141
|
+
|
|
142
|
+
except Exception as exc:
|
|
143
|
+
logger.error(
|
|
144
|
+
"Falha ao carregar plugin interno '%s': %s",
|
|
145
|
+
module_info.name,
|
|
146
|
+
exc,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
return loaded
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
# ---------------------------------------------------------
|
|
153
|
+
# Plugins externos
|
|
154
|
+
# ---------------------------------------------------------
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def load_external_plugins(cli: click.Group) -> List[str]:
|
|
158
|
+
"""
|
|
159
|
+
Carrega plugins externos instalados via entry points.
|
|
116
160
|
|
|
117
161
|
Returns
|
|
118
162
|
-------
|
|
119
163
|
list[str]
|
|
120
|
-
Lista
|
|
164
|
+
Lista de plugins carregados.
|
|
121
165
|
"""
|
|
122
166
|
|
|
123
|
-
loaded
|
|
167
|
+
loaded = []
|
|
124
168
|
seen = set()
|
|
125
169
|
|
|
126
|
-
for ep in
|
|
170
|
+
for ep in discover_external_plugins():
|
|
127
171
|
|
|
128
172
|
if ep.name in seen:
|
|
129
173
|
logger.warning("Plugin duplicado ignorado: %s", ep.name)
|
|
130
174
|
continue
|
|
131
175
|
|
|
132
176
|
try:
|
|
133
|
-
|
|
177
|
+
plugin = ep.load()
|
|
178
|
+
|
|
179
|
+
register_plugin(cli, plugin, ep.name)
|
|
134
180
|
|
|
135
|
-
seen.add(ep.name)
|
|
136
181
|
loaded.append(ep.name)
|
|
182
|
+
seen.add(ep.name)
|
|
137
183
|
|
|
138
184
|
except Exception as exc:
|
|
139
185
|
logger.error(
|
|
@@ -142,6 +188,39 @@ def load_plugins(cli: click.Group) -> List[str]:
|
|
|
142
188
|
exc,
|
|
143
189
|
)
|
|
144
190
|
|
|
191
|
+
return loaded
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
# ---------------------------------------------------------
|
|
195
|
+
# Loader principal
|
|
196
|
+
# ---------------------------------------------------------
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def load_plugins(cli: click.Group) -> List[str]:
|
|
200
|
+
"""
|
|
201
|
+
Carrega todos os plugins do mtcli.
|
|
202
|
+
|
|
203
|
+
Isso inclui:
|
|
204
|
+
|
|
205
|
+
• plugins internos
|
|
206
|
+
• plugins externos
|
|
207
|
+
|
|
208
|
+
Parameters
|
|
209
|
+
----------
|
|
210
|
+
cli : click.Group
|
|
211
|
+
CLI principal.
|
|
212
|
+
|
|
213
|
+
Returns
|
|
214
|
+
-------
|
|
215
|
+
list[str]
|
|
216
|
+
Lista com todos os plugins carregados.
|
|
217
|
+
"""
|
|
218
|
+
|
|
219
|
+
loaded = []
|
|
220
|
+
|
|
221
|
+
loaded.extend(load_internal_plugins(cli))
|
|
222
|
+
loaded.extend(load_external_plugins(cli))
|
|
223
|
+
|
|
145
224
|
logger.info("Plugins carregados: %d", len(loaded))
|
|
146
225
|
|
|
147
226
|
return loaded
|
|
@@ -28,7 +28,7 @@ mtcli/models/signals_model.py,sha256=XhyCErgyuHF0o85vnjIVJlgsCF7XFsWQltSbLZ3Aals
|
|
|
28
28
|
mtcli/models/unconsecutive_bar_model.py,sha256=AiClcoyYnk3K6D1YkC0E2PRUhbGwsjdSnh1vIHZsIe8,2079
|
|
29
29
|
mtcli/mt5_context.py,sha256=oLevCe4nYeZ6VtGoaO-j7U4xzACE09wGmX38P0oRg5A,2147
|
|
30
30
|
mtcli/plugin.py,sha256=Wabbr22BVi32D-XNM7XS45bRdgKob7EKO6TuWtq9_ZM,414
|
|
31
|
-
mtcli/plugin_loader.py,sha256=
|
|
31
|
+
mtcli/plugin_loader.py,sha256=tuL2dVYvyJpat5qagG1j3lJhEJRgAhKcn6lspNZr67w,5295
|
|
32
32
|
mtcli/plugin_manager.py,sha256=JTK6rmhjLa9MdyUiGgufAAnaaBhUI1Bm4g4t6p18WdU,555
|
|
33
33
|
mtcli/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
34
34
|
mtcli/plugins/exemplo.py-dist,sha256=q8H_sBpI-IZej9RvkCl2o_br9q2z_WXXn_qA1MRRbBo,538
|
|
@@ -65,8 +65,8 @@ mtcli/views/ranges_view.py,sha256=5gA2bAJuco-Xj964nsjs87tZ-079O7xKvaeif1UJ-PQ,12
|
|
|
65
65
|
mtcli/views/rates_view.py,sha256=Jkdbg-Q_OVJuID-Q9HFUVICCF1jE82d-qfZWNm1JJ_4,1214
|
|
66
66
|
mtcli/views/vars_view.py,sha256=Vpcej41qnZSvvSyvXYyW8W7CEFdqTxBd8NczV84XPJY,1635
|
|
67
67
|
mtcli/views/volumes_view.py,sha256=d_6YxM0vA1revwoPwnwUjV19KcqnddVgdpBHTt5Vqms,1575
|
|
68
|
-
mtcli-3.7.0.
|
|
69
|
-
mtcli-3.7.0.
|
|
70
|
-
mtcli-3.7.0.
|
|
71
|
-
mtcli-3.7.0.
|
|
72
|
-
mtcli-3.7.0.
|
|
68
|
+
mtcli-3.7.0.dev3.dist-info/entry_points.txt,sha256=sFL07BcOh-MKaij-M26bNlRbmlw9Xx0CTYTPtHegfI8,99
|
|
69
|
+
mtcli-3.7.0.dev3.dist-info/licenses/LICENSE,sha256=Z-2ANeRgM9IjXnHeg9mA2gillM6eTQj8sIExAGNe2-8,1092
|
|
70
|
+
mtcli-3.7.0.dev3.dist-info/METADATA,sha256=GFkl2N34O4Pj9I0P-ikGqTtkuDi48PW8L-K-jYQhG9M,3650
|
|
71
|
+
mtcli-3.7.0.dev3.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
72
|
+
mtcli-3.7.0.dev3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|