mtcli 3.7.0.dev4__py3-none-any.whl → 3.7.0.dev6__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,98 +1,123 @@
1
1
  """
2
2
  Sistema de carregamento de plugins do mtcli.
3
3
 
4
- Este módulo carrega automaticamente:
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 devem expor uma função:
8
+ [project.entry-points."mtcli.plugins"]
9
+ nome = "pacote.plugin:register"
10
10
 
11
- register(cli)
11
+ O plugin pode fornecer:
12
12
 
13
- onde `cli` é o grupo principal do Click.
13
+ 1. register(cli)
14
+ 2. um objeto click.Command
14
15
  """
15
16
 
16
- import importlib
17
- import pkgutil
17
+ from __future__ import annotations
18
+
19
+ from typing import Iterable, List
18
20
 
19
21
  import click
20
22
 
21
23
  try:
22
- from importlib.metadata import entry_points
23
- except ImportError: # Python < 3.10
24
- from importlib_metadata import entry_points
24
+ from importlib.metadata import EntryPoint, entry_points
25
+ except ImportError: # pragma: no cover
26
+ from importlib_metadata import EntryPoint, entry_points
25
27
 
26
- import mtcli.plugins
28
+ from mtcli.logger import setup_logger
27
29
 
28
30
 
29
- def load_internal_plugins(cli: click.Group) -> None:
30
- """
31
- Carrega plugins internos do pacote `mtcli.plugins`.
31
+ logger = setup_logger(__name__)
32
32
 
33
- Cada módulo encontrado deve expor a função:
33
+ PLUGIN_GROUP = "mtcli.plugins"
34
34
 
35
- register(cli)
36
35
 
37
- Args:
38
- cli: grupo principal do Click.
36
+ def discover_plugins() -> Iterable[EntryPoint]:
39
37
  """
38
+ Descobre plugins registrados via entry points.
39
+
40
+ Returns
41
+ -------
42
+ Iterable[EntryPoint]
43
+ Entry points encontrados.
44
+ """
45
+
46
+ try:
47
+ eps = entry_points()
40
48
 
41
- for module_info in pkgutil.iter_modules(mtcli.plugins.__path__):
49
+ if hasattr(eps, "select"):
50
+ plugins = eps.select(group=PLUGIN_GROUP)
51
+ else:
52
+ plugins = eps.get(PLUGIN_GROUP, [])
42
53
 
43
- module_name = f"mtcli.plugins.{module_info.name}"
54
+ logger.debug("Plugins descobertos: %s", [ep.name for ep in plugins])
44
55
 
45
- module = importlib.import_module(module_name)
56
+ return plugins
46
57
 
47
- if hasattr(module, "register"):
48
- module.register(cli)
58
+ except Exception as exc:
59
+ logger.exception("Erro ao descobrir plugins: %s", exc)
60
+ return []
49
61
 
50
62
 
51
- def load_external_plugins(cli: click.Group) -> None:
63
+ def register_plugin(cli: click.Group, ep: EntryPoint) -> None:
64
+ """
65
+ Carrega e registra um plugin individual.
52
66
  """
53
- Carrega plugins externos instalados via entry points.
54
67
 
55
- Os plugins devem declarar no pyproject.toml:
68
+ logger.debug("Carregando plugin: %s -> %s", ep.name, ep.value)
56
69
 
57
- [project.entry-points."mtcli.plugins"]
58
- nome = "pacote.plugin:register"
70
+ plugin = ep.load()
59
71
 
60
- Args:
61
- cli: grupo principal do Click.
62
- """
72
+ if callable(plugin) and not isinstance(plugin, click.Command):
63
73
 
64
- eps = entry_points()
74
+ plugin(cli)
65
75
 
66
- plugins = (
67
- eps.select(group="mtcli.plugins")
68
- if hasattr(eps, "select")
69
- else eps.get("mtcli.plugins", [])
70
- )
76
+ logger.info("Plugin registrado via register(): %s", ep.name)
71
77
 
72
- for ep in plugins:
78
+ elif isinstance(plugin, click.Command):
73
79
 
74
- plugin = ep.load()
80
+ cli.add_command(plugin)
75
81
 
76
- if callable(plugin) and not isinstance(plugin, click.Command):
77
- plugin(cli)
82
+ logger.info("Plugin registrado como comando: %s", ep.name)
78
83
 
79
- elif isinstance(plugin, click.Command):
80
- cli.add_command(plugin)
84
+ else:
81
85
 
82
- else:
83
- raise TypeError(
84
- f"Plugin {ep.name} inválido: deve ser um comando Click ou função register."
85
- )
86
+ raise TypeError(
87
+ f"Plugin '{ep.name}' inválido: "
88
+ "não é click.Command nem função register(cli)"
89
+ )
86
90
 
87
91
 
88
- def load_plugins(cli: click.Group) -> None:
92
+ def load_plugins(cli: click.Group) -> List[str]:
89
93
  """
90
- Carrega todos os plugins (internos e externos).
91
-
92
- Args:
93
- cli: grupo principal do Click.
94
+ Descobre e carrega todos os plugins instalados.
94
95
  """
95
96
 
96
- load_internal_plugins(cli)
97
- load_external_plugins(cli)
97
+ loaded: List[str] = []
98
+ seen = set()
99
+
100
+ for ep in discover_plugins():
101
+
102
+ if ep.name in seen:
103
+ logger.warning("Plugin duplicado ignorado: %s", ep.name)
104
+ continue
105
+
106
+ try:
107
+
108
+ register_plugin(cli, ep)
109
+
110
+ seen.add(ep.name)
111
+ loaded.append(ep.name)
112
+
113
+ except Exception as exc:
114
+
115
+ logger.exception(
116
+ "Falha ao carregar plugin '%s': %s",
117
+ ep.name,
118
+ exc,
119
+ )
120
+
121
+ logger.info("Total de plugins carregados: %d", len(loaded))
98
122
 
123
+ return loaded
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mtcli
3
- Version: 3.7.0.dev4
3
+ Version: 3.7.0.dev6
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=8c0PPsKuOfacV2UgZkH6MmaipV7lXH4_GHrhmggP12g,2220
31
+ mtcli/plugin_loader.py,sha256=5709Az6SEYLdyDEblzfeLWH_R7HXpZpW6pY6fgJ9btM,2746
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.dev4.dist-info/entry_points.txt,sha256=sFL07BcOh-MKaij-M26bNlRbmlw9Xx0CTYTPtHegfI8,99
69
- mtcli-3.7.0.dev4.dist-info/licenses/LICENSE,sha256=Z-2ANeRgM9IjXnHeg9mA2gillM6eTQj8sIExAGNe2-8,1092
70
- mtcli-3.7.0.dev4.dist-info/METADATA,sha256=J7uFBfK13ud9uvjTbNzxuti2NbvQKmZc0AMWTh9DkKs,3650
71
- mtcli-3.7.0.dev4.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
72
- mtcli-3.7.0.dev4.dist-info/RECORD,,
68
+ mtcli-3.7.0.dev6.dist-info/entry_points.txt,sha256=sFL07BcOh-MKaij-M26bNlRbmlw9Xx0CTYTPtHegfI8,99
69
+ mtcli-3.7.0.dev6.dist-info/licenses/LICENSE,sha256=Z-2ANeRgM9IjXnHeg9mA2gillM6eTQj8sIExAGNe2-8,1092
70
+ mtcli-3.7.0.dev6.dist-info/METADATA,sha256=Qtl2W-YL3ZpTx5-O7K7oNrpAXANkfgqiBVHgj1xijMk,3650
71
+ mtcli-3.7.0.dev6.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
72
+ mtcli-3.7.0.dev6.dist-info/RECORD,,