mtcli 3.7.0.dev2__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 CHANGED
@@ -1,17 +1,27 @@
1
1
  """
2
2
  Sistema de carregamento de plugins do mtcli.
3
3
 
4
- Responsável por descobrir e registrar plugins externos
5
- instalados via entry points.
4
+ Este módulo descobre e registra plugins de duas fontes:
6
5
 
7
- Plugins devem declarar entry points no grupo:
6
+ 1. Plugins internos localizados em ``mtcli.plugins``
7
+ 2. Plugins externos registrados via entry points ``mtcli.plugins``
8
8
 
9
- mtcli.plugins
9
+ Plugins podem expor:
10
+
11
+ • função ``register(cli)``
12
+ • objeto ``click.Command``
13
+
14
+ Entry point exemplo:
15
+
16
+ [project.entry-points."mtcli.plugins"]
17
+ renko = "mtcli_renko.plugin:register"
10
18
  """
11
19
 
12
20
  from __future__ import annotations
13
21
 
22
+ import importlib
14
23
  import logging
24
+ import pkgutil
15
25
  from typing import Iterable, List
16
26
 
17
27
  import click
@@ -21,15 +31,22 @@ try:
21
31
  except ImportError: # pragma: no cover
22
32
  from importlib_metadata import EntryPoint, entry_points
23
33
 
34
+ import mtcli.plugins
35
+
24
36
 
25
37
  logger = logging.getLogger(__name__)
26
38
 
27
39
  PLUGIN_GROUP = "mtcli.plugins"
28
40
 
29
41
 
30
- def discover_plugins() -> Iterable[EntryPoint]:
42
+ # ---------------------------------------------------------
43
+ # Descoberta de plugins externos
44
+ # ---------------------------------------------------------
45
+
46
+
47
+ def discover_external_plugins() -> Iterable[EntryPoint]:
31
48
  """
32
- Descobre plugins registrados via entry points.
49
+ Descobre plugins externos via entry points.
33
50
 
34
51
  Returns
35
52
  -------
@@ -38,110 +55,172 @@ def discover_plugins() -> Iterable[EntryPoint]:
38
55
  """
39
56
 
40
57
  try:
58
+ eps = entry_points()
41
59
 
42
- # Python moderno
43
- try:
44
- return entry_points(group=PLUGIN_GROUP)
45
- except TypeError:
46
- # Compatibilidade Python antigo
47
- eps = entry_points()
48
-
49
- if hasattr(eps, "select"):
50
- return eps.select(group=PLUGIN_GROUP)
60
+ if hasattr(eps, "select"):
61
+ return eps.select(group=PLUGIN_GROUP)
51
62
 
52
- return eps.get(PLUGIN_GROUP, [])
63
+ return eps.get(PLUGIN_GROUP, [])
53
64
 
54
65
  except Exception as exc: # pragma: no cover
55
- logger.error("Erro ao descobrir plugins: %s", exc)
66
+ logger.error("Erro ao descobrir plugins externos: %s", exc)
56
67
  return []
57
68
 
58
69
 
59
- def register_plugin(cli: click.Group, ep: EntryPoint) -> None:
70
+ # ---------------------------------------------------------
71
+ # Registro de plugin
72
+ # ---------------------------------------------------------
73
+
74
+
75
+ def register_plugin(cli: click.Group, plugin, name: str) -> None:
60
76
  """
61
- Carrega e registra um plugin individual.
77
+ Registra um plugin no CLI.
62
78
 
63
- O plugin pode expor:
79
+ O plugin pode ser:
64
80
 
65
- - função ``register(cli)``
66
- - objeto ``click.Command``
81
+ função ``register(cli)``
82
+ objeto ``click.Command``
67
83
 
68
84
  Parameters
69
85
  ----------
70
86
  cli : click.Group
71
87
  CLI principal.
72
- ep : EntryPoint
73
- Entry point do plugin.
88
+ plugin : Any
89
+ Objeto do plugin carregado.
90
+ name : str
91
+ Nome do plugin.
74
92
  """
75
93
 
76
- plugin = ep.load()
77
-
78
94
  if callable(plugin) and not isinstance(plugin, click.Command):
79
-
80
95
  plugin(cli)
81
-
82
- logger.debug(
83
- "Plugin '%s' registrado via função register() (%s)",
84
- ep.name,
85
- ep.value,
86
- )
96
+ logger.debug("Plugin '%s' registrado via register()", name)
87
97
 
88
98
  elif isinstance(plugin, click.Command):
89
-
90
99
  cli.add_command(plugin)
91
-
92
- logger.debug(
93
- "Plugin '%s' registrado como comando Click (%s)",
94
- ep.name,
95
- ep.value,
96
- )
100
+ logger.debug("Plugin '%s' registrado como comando", name)
97
101
 
98
102
  else:
99
-
100
103
  raise TypeError(
101
- f"Plugin '{ep.name}' inválido: "
102
- "não é click.Command nem função register(cli)"
104
+ f"Plugin '{name}' inválido: não é click.Command nem register(cli)"
103
105
  )
104
106
 
105
107
 
106
- def load_plugins(cli: click.Group) -> List[str]:
108
+ # ---------------------------------------------------------
109
+ # Plugins internos
110
+ # ---------------------------------------------------------
111
+
112
+
113
+ def load_internal_plugins(cli: click.Group) -> List[str]:
107
114
  """
108
- Descobre e carrega todos os plugins instalados.
115
+ Carrega plugins internos do pacote ``mtcli.plugins``.
109
116
 
110
- Parameters
111
- ----------
112
- cli : click.Group
113
- CLI principal do mtcli.
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.
114
160
 
115
161
  Returns
116
162
  -------
117
163
  list[str]
118
- Lista de plugins carregados com sucesso.
164
+ Lista de plugins carregados.
119
165
  """
120
166
 
121
- loaded: List[str] = []
167
+ loaded = []
122
168
  seen = set()
123
169
 
124
- for ep in discover_plugins():
170
+ for ep in discover_external_plugins():
125
171
 
126
172
  if ep.name in seen:
127
173
  logger.warning("Plugin duplicado ignorado: %s", ep.name)
128
174
  continue
129
175
 
130
176
  try:
177
+ plugin = ep.load()
131
178
 
132
- register_plugin(cli, ep)
179
+ register_plugin(cli, plugin, ep.name)
133
180
 
134
- seen.add(ep.name)
135
181
  loaded.append(ep.name)
182
+ seen.add(ep.name)
136
183
 
137
184
  except Exception as exc:
138
-
139
185
  logger.error(
140
186
  "Falha ao carregar plugin '%s': %s",
141
187
  ep.name,
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mtcli
3
- Version: 3.7.0.dev2
3
+ Version: 3.7.0.dev3
4
4
  Summary: Aplicativo CLI para exibir gráficos do MetaTrader 5 screen reader friendly
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -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=vj3vUf_kfl6w4l7enUoTAbJlmdvPmUX1aBaC8P3H-Gk,3218
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.dev2.dist-info/entry_points.txt,sha256=sFL07BcOh-MKaij-M26bNlRbmlw9Xx0CTYTPtHegfI8,99
69
- mtcli-3.7.0.dev2.dist-info/licenses/LICENSE,sha256=Z-2ANeRgM9IjXnHeg9mA2gillM6eTQj8sIExAGNe2-8,1092
70
- mtcli-3.7.0.dev2.dist-info/METADATA,sha256=_eWz6YOhk378zYlsV--M4yD-l0kNDy1PcaoPSqZrBxU,3650
71
- mtcli-3.7.0.dev2.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
72
- mtcli-3.7.0.dev2.dist-info/RECORD,,
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,,