mtcli 3.7.0.dev5__py3-none-any.whl → 3.7.0.dev7__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/cli.py CHANGED
@@ -1,34 +1,72 @@
1
- """
2
- CLI principal do mtcli.
3
-
4
- Este módulo define o grupo principal `mt`
5
- e inicializa o carregamento de plugins.
6
- """
7
-
8
- import click
9
-
10
- from mtcli.plugin_loader import load_plugins
11
- from .commands.bars import bars
12
-
13
-
14
- @click.group(context_settings={"max_content_width": 120})
15
- @click.version_option(package_name="mtcli")
16
- def mt():
17
- """
18
- CLI principal do mtcli.
19
-
20
- Exibe gráficos e informações de mercado
21
- em formato textual compatível com leitores de tela.
22
- """
23
- pass
24
-
25
-
26
- mt.add_command(bars, name="bars")
27
-
28
-
29
- # Carrega plugins automaticamente
30
- load_plugins(mt)
31
-
32
-
33
- if __name__ == "__main__":
34
- mt()
1
+ """
2
+ CLI principal do mtcli.
3
+
4
+ Este módulo define o grupo principal `mt`
5
+ e inicializa o carregamento de plugins.
6
+ """
7
+
8
+ import click
9
+
10
+ from mtcli.plugin_loader import load_plugins
11
+ from mtcli.logger import setup_logger
12
+
13
+ from .commands.bars import bars
14
+
15
+
16
+ logger = setup_logger(__name__)
17
+
18
+
19
+ @click.group(context_settings={"max_content_width": 120})
20
+ @click.version_option(package_name="mtcli")
21
+ def mt():
22
+ """
23
+ CLI principal do mtcli.
24
+
25
+ Exibe gráficos e informações de mercado
26
+ em formato textual compatível com leitores de tela.
27
+ """
28
+ pass
29
+
30
+
31
+ # ---------------------------------------------------------
32
+ # Comandos internos
33
+ # ---------------------------------------------------------
34
+
35
+ mt.add_command(bars, name="bars")
36
+
37
+
38
+ # ---------------------------------------------------------
39
+ # Carregamento de plugins
40
+ # ---------------------------------------------------------
41
+
42
+ loaded_plugins = load_plugins(mt)
43
+
44
+ logger.info("Plugins carregados: %s", loaded_plugins)
45
+
46
+
47
+ # ---------------------------------------------------------
48
+ # Comando utilitário: listar plugins
49
+ # ---------------------------------------------------------
50
+
51
+ @mt.command(name="plugins")
52
+ def list_plugins():
53
+ """
54
+ Lista os plugins atualmente carregados no mtcli.
55
+ """
56
+
57
+ if not loaded_plugins:
58
+ click.echo("Nenhum plugin carregado.")
59
+ return
60
+
61
+ click.echo("Plugins carregados:\n")
62
+
63
+ for name in loaded_plugins:
64
+ click.echo(f" {name}")
65
+
66
+
67
+ # ---------------------------------------------------------
68
+ # Entry point
69
+ # ---------------------------------------------------------
70
+
71
+ if __name__ == "__main__":
72
+ mt()
mtcli/plugin_loader.py CHANGED
@@ -1,27 +1,21 @@
1
1
  """
2
2
  Sistema de carregamento de plugins do mtcli.
3
3
 
4
- Este módulo descobre e registra plugins de duas fontes:
4
+ Descobre e registra plugins instalados via entry points.
5
5
 
6
- 1. Plugins internos localizados em ``mtcli.plugins``
7
- 2. Plugins externos registrados via entry points ``mtcli.plugins``
6
+ Plugins devem declarar:
8
7
 
9
- Plugins podem expor:
10
-
11
- função ``register(cli)``
12
- objeto ``click.Command``
8
+ [project.entry-points."mtcli.plugins"]
9
+ nome = "pacote.plugin:register"
13
10
 
14
- Entry point exemplo:
11
+ O plugin pode fornecer:
15
12
 
16
- [project.entry-points."mtcli.plugins"]
17
- renko = "mtcli_renko.plugin:register"
13
+ 1. register(cli)
14
+ 2. um objeto click.Command
18
15
  """
19
16
 
20
17
  from __future__ import annotations
21
18
 
22
- import importlib
23
- import logging
24
- import pkgutil
25
19
  from typing import Iterable, List
26
20
 
27
21
  import click
@@ -31,196 +25,99 @@ try:
31
25
  except ImportError: # pragma: no cover
32
26
  from importlib_metadata import EntryPoint, entry_points
33
27
 
34
- import mtcli.plugins
28
+ from mtcli.logger import setup_logger
35
29
 
36
30
 
37
- logger = logging.getLogger(__name__)
31
+ logger = setup_logger(__name__)
38
32
 
39
33
  PLUGIN_GROUP = "mtcli.plugins"
40
34
 
41
35
 
42
- # ---------------------------------------------------------
43
- # Descoberta de plugins externos
44
- # ---------------------------------------------------------
45
-
46
-
47
- def discover_external_plugins() -> Iterable[EntryPoint]:
36
+ def discover_plugins() -> Iterable[EntryPoint]:
48
37
  """
49
- Descobre plugins externos via entry points.
38
+ Descobre plugins registrados via entry points.
50
39
 
51
40
  Returns
52
41
  -------
53
42
  Iterable[EntryPoint]
54
- Entry points encontrados no grupo ``mtcli.plugins``.
43
+ Entry points encontrados.
55
44
  """
56
45
 
57
46
  try:
58
47
  eps = entry_points()
59
48
 
60
49
  if hasattr(eps, "select"):
61
- return eps.select(group=PLUGIN_GROUP)
50
+ plugins = eps.select(group=PLUGIN_GROUP)
51
+ else:
52
+ plugins = eps.get(PLUGIN_GROUP, [])
62
53
 
63
- return eps.get(PLUGIN_GROUP, [])
64
-
65
- except Exception as exc: # pragma: no cover
66
- logger.error("Erro ao descobrir plugins externos: %s", exc)
67
- return []
54
+ logger.debug("Plugins descobertos: %s", [ep.name for ep in plugins])
68
55
 
56
+ return plugins
69
57
 
70
- # ---------------------------------------------------------
71
- # Registro de plugin
72
- # ---------------------------------------------------------
58
+ except Exception as exc:
59
+ logger.exception("Erro ao descobrir plugins: %s", exc)
60
+ return []
73
61
 
74
62
 
75
- def register_plugin(cli: click.Group, plugin, name: str) -> None:
63
+ def register_plugin(cli: click.Group, ep: EntryPoint) -> None:
64
+ """
65
+ Carrega e registra um plugin individual.
76
66
  """
77
- Registra um plugin no CLI.
78
-
79
- O plugin pode ser:
80
67
 
81
- função ``register(cli)``
82
- objeto ``click.Command``
68
+ logger.debug("Carregando plugin: %s -> %s", ep.name, ep.value)
83
69
 
84
- Parameters
85
- ----------
86
- cli : click.Group
87
- CLI principal.
88
- plugin : Any
89
- Objeto do plugin carregado.
90
- name : str
91
- Nome do plugin.
92
- """
70
+ plugin = ep.load()
93
71
 
94
72
  if callable(plugin) and not isinstance(plugin, click.Command):
73
+
95
74
  plugin(cli)
96
- logger.debug("Plugin '%s' registrado via register()", name)
75
+
76
+ logger.info("Plugin registrado via register(): %s", ep.name)
97
77
 
98
78
  elif isinstance(plugin, click.Command):
79
+
99
80
  cli.add_command(plugin)
100
- logger.debug("Plugin '%s' registrado como comando", name)
81
+
82
+ logger.info("Plugin registrado como comando: %s", ep.name)
101
83
 
102
84
  else:
85
+
103
86
  raise TypeError(
104
- f"Plugin '{name}' inválido: não é click.Command nem register(cli)"
87
+ f"Plugin '{ep.name}' inválido: "
88
+ "não é click.Command nem função register(cli)"
105
89
  )
106
90
 
107
91
 
108
- # ---------------------------------------------------------
109
- # Plugins internos
110
- # ---------------------------------------------------------
111
-
112
-
113
- def load_internal_plugins(cli: click.Group) -> List[str]:
114
- """
115
- Carrega plugins internos do pacote ``mtcli.plugins``.
116
-
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]:
92
+ def load_plugins(cli: click.Group) -> List[str]:
158
93
  """
159
- Carrega plugins externos instalados via entry points.
160
-
161
- Returns
162
- -------
163
- list[str]
164
- Lista de plugins carregados.
94
+ Descobre e carrega todos os plugins instalados.
165
95
  """
166
96
 
167
- loaded = []
97
+ loaded: List[str] = []
168
98
  seen = set()
169
99
 
170
- for ep in discover_external_plugins():
100
+ for ep in discover_plugins():
171
101
 
172
102
  if ep.name in seen:
173
103
  logger.warning("Plugin duplicado ignorado: %s", ep.name)
174
104
  continue
175
105
 
176
106
  try:
177
- plugin = ep.load()
178
107
 
179
- register_plugin(cli, plugin, ep.name)
108
+ register_plugin(cli, ep)
180
109
 
181
- loaded.append(ep.name)
182
110
  seen.add(ep.name)
111
+ loaded.append(ep.name)
183
112
 
184
113
  except Exception as exc:
185
- logger.error(
114
+
115
+ logger.exception(
186
116
  "Falha ao carregar plugin '%s': %s",
187
117
  ep.name,
188
118
  exc,
189
119
  )
190
120
 
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
-
224
- logger.info("Plugins carregados: %d", len(loaded))
121
+ logger.info("Total de plugins carregados: %d", len(loaded))
225
122
 
226
123
  return loaded
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mtcli
3
- Version: 3.7.0.dev5
3
+ Version: 3.7.0.dev7
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
@@ -1,5 +1,5 @@
1
1
  mtcli/__init__.py,sha256=guFO5EmCfuH8MNujJH8hw_oPg8Ee__QlQgVd-4A3N6o,84
2
- mtcli/cli.py,sha256=VOPMvrRQE8hiQ4qhoRikncl-slOYddMAaV3IVX1eJMA,607
2
+ mtcli/cli.py,sha256=3ujncFjY1DFQBCo3rj4FnmU7mdSVOsUVTVIIZcFYZNE,1687
3
3
  mtcli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  mtcli/commands/bars.py,sha256=JXXq9HIeFU-VKf8e2rOKTMXx_h5SRcuvKER-mlOjxjM,4205
5
5
  mtcli/commands/conf.py,sha256=UshpB9-uq1FdKwnDg2zFbdtzeEzZhiJjqFY4Ra1LeLY,910
@@ -28,8 +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 - Copia.py,sha256=8c0PPsKuOfacV2UgZkH6MmaipV7lXH4_GHrhmggP12g,2220
32
- mtcli/plugin_loader.py,sha256=tjLDxxGEU_29WMWjmRwYKF1kaAvHsqd8NbueVtTnAdU,5283
31
+ mtcli/plugin_loader.py,sha256=5709Az6SEYLdyDEblzfeLWH_R7HXpZpW6pY6fgJ9btM,2746
33
32
  mtcli/plugin_manager.py,sha256=JTK6rmhjLa9MdyUiGgufAAnaaBhUI1Bm4g4t6p18WdU,555
34
33
  mtcli/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
34
  mtcli/plugins/exemplo.py-dist,sha256=q8H_sBpI-IZej9RvkCl2o_br9q2z_WXXn_qA1MRRbBo,538
@@ -66,8 +65,8 @@ mtcli/views/ranges_view.py,sha256=5gA2bAJuco-Xj964nsjs87tZ-079O7xKvaeif1UJ-PQ,12
66
65
  mtcli/views/rates_view.py,sha256=Jkdbg-Q_OVJuID-Q9HFUVICCF1jE82d-qfZWNm1JJ_4,1214
67
66
  mtcli/views/vars_view.py,sha256=Vpcej41qnZSvvSyvXYyW8W7CEFdqTxBd8NczV84XPJY,1635
68
67
  mtcli/views/volumes_view.py,sha256=d_6YxM0vA1revwoPwnwUjV19KcqnddVgdpBHTt5Vqms,1575
69
- mtcli-3.7.0.dev5.dist-info/entry_points.txt,sha256=sFL07BcOh-MKaij-M26bNlRbmlw9Xx0CTYTPtHegfI8,99
70
- mtcli-3.7.0.dev5.dist-info/licenses/LICENSE,sha256=Z-2ANeRgM9IjXnHeg9mA2gillM6eTQj8sIExAGNe2-8,1092
71
- mtcli-3.7.0.dev5.dist-info/METADATA,sha256=80GUTSdwxGX2vaql6enilI3MnUh_eJj81KbnpEg9FZQ,3650
72
- mtcli-3.7.0.dev5.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
73
- mtcli-3.7.0.dev5.dist-info/RECORD,,
68
+ mtcli-3.7.0.dev7.dist-info/entry_points.txt,sha256=sFL07BcOh-MKaij-M26bNlRbmlw9Xx0CTYTPtHegfI8,99
69
+ mtcli-3.7.0.dev7.dist-info/licenses/LICENSE,sha256=Z-2ANeRgM9IjXnHeg9mA2gillM6eTQj8sIExAGNe2-8,1092
70
+ mtcli-3.7.0.dev7.dist-info/METADATA,sha256=rNVn3lA9qhZc1oz59j-3pRP6TSTsSuYS_CWCfrqFgF4,3650
71
+ mtcli-3.7.0.dev7.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
72
+ mtcli-3.7.0.dev7.dist-info/RECORD,,
@@ -1,98 +0,0 @@
1
- """
2
- Sistema de carregamento de plugins do mtcli.
3
-
4
- Este módulo carrega automaticamente:
5
-
6
- 1. Plugins internos localizados em `mtcli.plugins`
7
- 2. Plugins externos registrados via entry points `mtcli.plugins`
8
-
9
- Plugins devem expor uma função:
10
-
11
- register(cli)
12
-
13
- onde `cli` é o grupo principal do Click.
14
- """
15
-
16
- import importlib
17
- import pkgutil
18
-
19
- import click
20
-
21
- try:
22
- from importlib.metadata import entry_points
23
- except ImportError: # Python < 3.10
24
- from importlib_metadata import entry_points
25
-
26
- import mtcli.plugins
27
-
28
-
29
- def load_internal_plugins(cli: click.Group) -> None:
30
- """
31
- Carrega plugins internos do pacote `mtcli.plugins`.
32
-
33
- Cada módulo encontrado deve expor a função:
34
-
35
- register(cli)
36
-
37
- Args:
38
- cli: grupo principal do Click.
39
- """
40
-
41
- for module_info in pkgutil.iter_modules(mtcli.plugins.__path__):
42
-
43
- module_name = f"mtcli.plugins.{module_info.name}"
44
-
45
- module = importlib.import_module(module_name)
46
-
47
- if hasattr(module, "register"):
48
- module.register(cli)
49
-
50
-
51
- def load_external_plugins(cli: click.Group) -> None:
52
- """
53
- Carrega plugins externos instalados via entry points.
54
-
55
- Os plugins devem declarar no pyproject.toml:
56
-
57
- [project.entry-points."mtcli.plugins"]
58
- nome = "pacote.plugin:register"
59
-
60
- Args:
61
- cli: grupo principal do Click.
62
- """
63
-
64
- eps = entry_points()
65
-
66
- plugins = (
67
- eps.select(group="mtcli.plugins")
68
- if hasattr(eps, "select")
69
- else eps.get("mtcli.plugins", [])
70
- )
71
-
72
- for ep in plugins:
73
-
74
- plugin = ep.load()
75
-
76
- if callable(plugin) and not isinstance(plugin, click.Command):
77
- plugin(cli)
78
-
79
- elif isinstance(plugin, click.Command):
80
- cli.add_command(plugin)
81
-
82
- else:
83
- raise TypeError(
84
- f"Plugin {ep.name} inválido: deve ser um comando Click ou função register."
85
- )
86
-
87
-
88
- def load_plugins(cli: click.Group) -> None:
89
- """
90
- Carrega todos os plugins (internos e externos).
91
-
92
- Args:
93
- cli: grupo principal do Click.
94
- """
95
-
96
- load_internal_plugins(cli)
97
- load_external_plugins(cli)
98
-