pac0-cli 0.6.0__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.
pac0/cli/__init__.py ADDED
File without changes
@@ -0,0 +1,51 @@
1
+ import textual
2
+ from textual.app import App, ComposeResult
3
+ from textual.widgets import Header, Footer, Placeholder
4
+ from textual.containers import Container
5
+ from .screens.services import ServicesScreen
6
+ from .screens.stats import StatsScreen
7
+ from .screens.tests import TestsScreen
8
+
9
+
10
+ class ConsoleApp(App):
11
+ """Application console principale"""
12
+
13
+ TITLE = "PAC Console"
14
+ SUB_TITLE = "Plateforme Agréée Communautaire"
15
+
16
+ BINDINGS = [
17
+ ("d", "toggle_dark", "Mode sombre"),
18
+ ("s", "switch_screen('services')", "Services"),
19
+ ("t", "switch_screen('stats')", "Statistiques"),
20
+ ("e", "switch_screen('tests')", "Tests"),
21
+ ("q", "quit", "Quitter"),
22
+ ]
23
+
24
+ SCREENS = {
25
+ "services": ServicesScreen,
26
+ "stats": StatsScreen,
27
+ "tests": TestsScreen,
28
+ }
29
+
30
+ # def on_mount(self) -> None:
31
+ # """Initialisation de l'application"""
32
+ # self.switch_screen("services")
33
+
34
+ def compose(self) -> ComposeResult:
35
+ """Création de l'interface"""
36
+ yield Header()
37
+ # yield Container()
38
+ yield Footer()
39
+
40
+ def action_toggle_dark(self) -> None:
41
+ """Basculer entre le mode clair et sombre"""
42
+ self.dark = not self.dark
43
+
44
+ def action_switch_screen(self, screen_name: str) -> None:
45
+ """Changer d'écran"""
46
+ self.switch_screen(screen_name)
47
+
48
+
49
+ if __name__ == "__main__":
50
+ app = ConsoleApp()
51
+ app.run()
@@ -0,0 +1,37 @@
1
+ from textual.screen import Screen
2
+ from textual.widgets import DataTable, Label, Footer
3
+ from textual.containers import Container
4
+
5
+
6
+ class ServicesScreen(Screen):
7
+ """Écran d'affichage des services"""
8
+
9
+ BINDINGS = [
10
+ ("escape", "app.pop_screen", "Retour"),
11
+ ]
12
+
13
+ def compose(self):
14
+ """
15
+ yield Container(
16
+ Label("Services PAC", id="title"),
17
+ DataTable(id="services-table"),
18
+ id="services-container",
19
+ )
20
+ """
21
+ yield Footer()
22
+
23
+ def on_mount(self) -> None:
24
+ """Initialisation de l'écran"""
25
+
26
+ table = self.query_one(DataTable)
27
+ table.add_columns("Nom", "Statut", "Port", "Démarré le")
28
+
29
+ # Données de démonstration
30
+ services_data = [
31
+ ("api-gateway", "En cours", "8000", "2026-01-16 10:30"),
32
+ ("auth-service", "En cours", "8001", "2026-01-16 10:31"),
33
+ ("db-service", "Arrêté", "-", "-"),
34
+ ]
35
+
36
+ for service in services_data:
37
+ table.add_row(*service)
@@ -0,0 +1,21 @@
1
+ from textual.screen import Screen
2
+ from textual.widgets import Label, Footer
3
+ from textual.containers import Container
4
+
5
+
6
+ class StatsScreen(Screen):
7
+ """Écran d'affichage des statistiques"""
8
+
9
+ BINDINGS = [
10
+ ("escape", "app.pop_screen", "Retour"),
11
+ ]
12
+
13
+ def compose(self):
14
+ yield Container(
15
+ Label("Statistiques PAC", id="title"),
16
+ Label("Factures reçues: 1250", id="invoices-received"),
17
+ Label("Factures traitées: 1120", id="invoices-processed"),
18
+ Label("Erreurs: 5", id="errors"),
19
+ id="stats-container",
20
+ )
21
+ yield Footer()
@@ -0,0 +1,34 @@
1
+ from textual.screen import Screen
2
+ from textual.widgets import DataTable, Label, Footer
3
+ from textual.containers import Container
4
+
5
+
6
+ class TestsScreen(Screen):
7
+ """Écran d'affichage des résultats de tests"""
8
+
9
+ BINDINGS = [
10
+ ("escape", "app.pop_screen", "Retour"),
11
+ ]
12
+
13
+ def compose(self):
14
+ yield Container(
15
+ Label("Résultats des tests", id="title"),
16
+ DataTable(id="tests-table"),
17
+ id="tests-container",
18
+ )
19
+ yield Footer()
20
+
21
+ def on_mount(self) -> None:
22
+ """Initialisation de l'écran"""
23
+ table = self.query_one(DataTable)
24
+ table.add_columns("Test", "Statut", "Durée", "Message")
25
+
26
+ # Données de démonstration
27
+ tests_data = [
28
+ ("test_api_gateway", "PASS", "0.2s", "Tous les endpoints fonctionnent"),
29
+ ("test_auth_service", "FAIL", "0.1s", "Échec d'authentification"),
30
+ ("test_database", "PASS", "0.5s", "Connexion réussie"),
31
+ ]
32
+
33
+ for test in tests_data:
34
+ table.add_row(*test)
File without changes
File without changes
@@ -0,0 +1,94 @@
1
+ import typer
2
+ import subprocess
3
+ import subprocess
4
+ from . import setup
5
+ from .. import utils
6
+
7
+
8
+ app = typer.Typer()
9
+
10
+
11
+ services = [
12
+ "01-api-gateway",
13
+ "02-esb-central",
14
+ "03-controle-formats",
15
+ "04-validation-metier",
16
+ "05-conversion-formats",
17
+ "06-annuaire-local",
18
+ "07-routage",
19
+ "08-transmission-fiscale",
20
+ "09-gestion-cycle-vie",
21
+ ]
22
+
23
+
24
+ def _run_service(
25
+ service: str,
26
+ ):
27
+ # TODO: check/install tools
28
+ setup.tool(install=True)
29
+ # TODO: get app folder
30
+ setup.source()
31
+ # TODO: clone if necessary
32
+ _call(service)
33
+
34
+
35
+ def _call(
36
+ service: str,
37
+ run: bool = True,
38
+ check: bool = False,
39
+ ):
40
+ # service folder: "05-conversion-formats" -> "conversion_formats"
41
+ service_folder = "_".join(service.split("-")[1:])
42
+ base_folder = utils.get_app_base_folder()
43
+ print(f"{base_folder=}")
44
+ if service == "01-api-gateway":
45
+ full_path = f"src/pac0/service/{service_folder}/main.py"
46
+ cmd = ["uv", "run", "fastapi", "dev", str(full_path)]
47
+ elif service == "02-esb-central":
48
+ cmd = ["nats-server", "-V", "-js"]
49
+ else:
50
+ full_path = f"src/pac0/service/{service_folder}/main:app"
51
+ cmd = ["uv", "run", "faststream", "run", str(full_path)]
52
+
53
+ if service != "02-esb-central":
54
+ if check and not full_path.exists():
55
+ typer.echo(f"Erreur: Le service {service} n'existe pas ({full_path})")
56
+ raise typer.Exit(code=1)
57
+
58
+ pac0_package_base_folder = base_folder / "packages" / "pac0"
59
+ typer.echo(f"Lancement du service {service}...")
60
+ typer.echo(f"Commande: {' '.join(cmd)}")
61
+ typer.echo(f"pac0_package_base_folder: {pac0_package_base_folder}")
62
+
63
+ if run:
64
+ subprocess.call(cmd, cwd=pac0_package_base_folder)
65
+
66
+
67
+ @app.command(name="1", help="lance le service 01-api-gateway ...")
68
+ def _(): _run_service("01-api-gateway")
69
+
70
+ @app.command(name='2', help='lance le service 02-esb-central ...')
71
+ def _(): _run_service("02-esb-central")
72
+
73
+ @app.command(name='3', help='lance le service 03-controle-formats ...')
74
+ def _(): _run_service("03-controle-formats")
75
+
76
+ @app.command(name='4', help='lance le service 04-validation-metier ...')
77
+ def _(): _run_service("04-validation-metier")
78
+
79
+ @app.command(name='5', help='lance le service 05-conversion-formats ...')
80
+ def _(): _run_service("05-conversion-formats")
81
+
82
+ @app.command(name='6', help='lance le service 06-annuaire-local ...')
83
+ def _(): _run_service("06-annuaire-local")
84
+
85
+ @app.command(name='7', help='lance le service 07-routage") ...')
86
+ def _(): _run_service("07-routage")
87
+
88
+ @app.command(name='8', help='lance le service 08-transmission-fiscale ...')
89
+ def _(): _run_service("08-transmission-fiscale")
90
+
91
+ @app.command(name='9', help='lance le service 09-gestion-cycle ...')
92
+ def _(): _run_service("09-gestion-cycle-vie")
93
+
94
+
@@ -0,0 +1,48 @@
1
+ import subprocess
2
+ from pathlib import Path
3
+
4
+ import typer
5
+
6
+ from .. import utils
7
+
8
+
9
+ app = typer.Typer()
10
+
11
+ DEFAULT_REPO_URL = "https://github.com/paxpar-tech/PA_Communautaire"
12
+
13
+
14
+ @app.command()
15
+ def tool(
16
+ install: bool = False,
17
+ ):
18
+ """Vérifie les versions d'outils et les installe si besoin"""
19
+ typer.echo("Vérification des outils...")
20
+ # TODO: check dependencies (some pytest)
21
+
22
+ # raise NotImplementedError()
23
+
24
+
25
+ @app.command()
26
+ def source(
27
+ repo_url: str = DEFAULT_REPO_URL,
28
+ uv_sync: bool = True,
29
+ ):
30
+ """Clone le dépôt git"""
31
+
32
+ target_dir: Path = utils.get_app_base_folder()
33
+ # Vérifier que le dépôt est cloné
34
+ # git pull ??
35
+
36
+ if not (target_dir / ".git").is_dir():
37
+ subprocess.call(["git", "clone", repo_url], cwd=target_dir)
38
+ # target_dir has changed since git clone created a new dir
39
+ target_dir: Path = utils.get_app_base_folder()
40
+ else:
41
+ print("git pull ...")
42
+ subprocess.call(["git", "pull"], cwd=target_dir)
43
+
44
+ # TODO: loop over all packages
45
+ # app_base_dir = Path(target_dir) / Path(repo_url).name / "packages" / "pac0"
46
+ app_base_dir = Path(target_dir) / "packages" / "pac0"
47
+ if uv_sync:
48
+ subprocess.call(["uv", "sync", "--all-packages"], cwd=app_base_dir)
@@ -0,0 +1,11 @@
1
+ import typer
2
+ import subprocess
3
+
4
+ app = typer.Typer()
5
+
6
+
7
+ @app.command()
8
+ def all():
9
+ """Lance tous les tests"""
10
+ typer.echo("Lancement de tous les tests...")
11
+ subprocess.call(["pytest", "-v"])
pac0/cli/main.py ADDED
@@ -0,0 +1,44 @@
1
+ import typer
2
+
3
+ # from pa0c.cli.cli.app import app as cli_app
4
+ from pac0.cli.command.setup import app as setup_app
5
+ from pac0.cli.command.run import app as run_app
6
+ from pac0.cli.command.test import app as test_app
7
+ from pac0.cli.command.console.app import ConsoleApp
8
+ from pac0.cli import utils
9
+
10
+ app = typer.Typer()
11
+
12
+ # Ajout des commandes CLI
13
+ # app.add_typer(cli_app, name="cli")
14
+ app.add_typer(setup_app, name="setup")
15
+ app.add_typer(run_app, name="run")
16
+ app.add_typer(test_app, name="test")
17
+
18
+
19
+ @app.command()
20
+ def console():
21
+ """Lance l'application console"""
22
+ console_app = ConsoleApp()
23
+ console_app.run()
24
+
25
+
26
+ @app.command()
27
+ def version(
28
+ full: bool = False,
29
+ ):
30
+ """Affiche la version de l'application"""
31
+ try:
32
+ from importlib.metadata import version, metadata
33
+
34
+ package_version = version("pac0-cli")
35
+ package_name = metadata("pac0-cli")["Name"]
36
+ typer.echo(f"{package_name} version {package_version}")
37
+ except Exception:
38
+ typer.echo("pac0-cli version inconnue")
39
+
40
+ if full:
41
+ print(f"app_base_folder = {utils.get_app_base_folder()}")
42
+
43
+ if __name__ == "__main__":
44
+ app()
pac0/cli/utils.py ADDED
@@ -0,0 +1,36 @@
1
+ import os
2
+ from pathlib import Path
3
+
4
+ import typer
5
+
6
+
7
+ def get_app_base_folder(
8
+ up: str = "PA_Communautaire",
9
+ create: bool = True,
10
+ check: bool = True,
11
+ ) -> Path:
12
+ '''
13
+ Détermine le chemin de l'application.
14
+ up: si non vide, permets de *remonter* jusqu'à ce répertoire (utile en dev)
15
+ create: crée le chemin de répertoire si besoin
16
+ check: vérifie si le répertoire existe
17
+ '''
18
+ # env var ou répertoire courant
19
+ repo_path = Path(os.environ.get("PAC0_BASE_PATH") or ".").resolve()
20
+
21
+ if up != "":
22
+ if (repo_path / up).is_dir():
23
+ repo_path = repo_path / up
24
+ elif up in (p := repo_path.parts):
25
+ repo_path = Path('/'.join(p[0:p.index(up)+1])[1:])
26
+
27
+ if create and not repo_path.exists():
28
+ repo_path.mkdir(parents=True, exist_ok=True)
29
+
30
+ if check and not repo_path.exists():
31
+ typer.echo(
32
+ "Erreur: Le dépôt n'est pas cloné. Exécutez 'pac-cli setup source' d'abord."
33
+ )
34
+ raise typer.Exit(code=1)
35
+
36
+ return repo_path
@@ -0,0 +1,49 @@
1
+ Metadata-Version: 2.3
2
+ Name: pac0-cli
3
+ Version: 0.6.0
4
+ Summary: Outil en ligne de commande (CLI) du projet PAC
5
+ Author: Philippe ENTZMANN
6
+ Author-email: Philippe ENTZMANN <philippe@entzmann.name>
7
+ Requires-Dist: typer>=0.9.0
8
+ Requires-Dist: textual>=0.70.0
9
+ Requires-Dist: pyyaml>=6.0
10
+ Requires-Python: >=3.13
11
+ Description-Content-Type: text/markdown
12
+
13
+ # pac cli
14
+
15
+ ```
16
+ ______________________________
17
+ ________________ ________ __ \
18
+ _____ __ \ __ `/ ___/ / / /
19
+ ____ /_/ / /_/ // /__ / /_/ /
20
+ ___ .___/\__,_/ \___/ \____/
21
+ __/_/
22
+
23
+ ```
24
+
25
+ Outil en ligne de commade (CLI) du projet pac (Plateforme Agréée Communautaire).
26
+ En plus de l'usage CLI, un mode application console est disponible.
27
+
28
+ Caractéristiques principales:
29
+ - utilise les librairies python typer et textual
30
+ - appelé par la commande `pac-cli` or `pac`
31
+ - publié sur pypi avec le nom `pac-cli`
32
+
33
+ Caractéristiques principales de la version CLI:
34
+ - commande `pac-cli setup tool` qui vérifie les versions d'outils et les installe si besoin (selon un fichier YAML de référence). Exemple: nats-server, natscli, seaweedfs ...
35
+ - commande `pac-cli setup source` qui clone le dépôt github https://github.com/paxpar-tech/PA_Communautaire
36
+ - commande `pac-cli run pac0` qui lance `uv run fastapi dev src/pac0/service/api_gateway/main.py` du dépôt cloné
37
+ - commande `pac-cli run pac0 --svc 01-api-gateway` qui lance `uv run fastapi dev src/pac0/service/api_gateway/main.py` du dépôt cloné ou un autre service selon la valeur de `--svc`
38
+ - commande `pac-cli test all` qui lance une commande via subprocess
39
+
40
+
41
+ Caractéristiques principales de la version console:
42
+ - commande `pac-cli` ou `pac-cli console` qui lance la version console
43
+ - reproduire l'ergonomie générale de l'application console [k9s](https://k9scli.io/)
44
+ - avoir une palette de commande
45
+ - avoir des raccourcis clavier
46
+ - avoir une page `services` où lister les services pac0
47
+ - pouvoir afficher le log d'un service
48
+ - avoir une page `stats` où afficher des compteurs (factures reçues, factures traitées, erreur, ...)
49
+ - avoir une page `tests` où lister les tests depuis un fichier xml testsuites
@@ -0,0 +1,16 @@
1
+ pac0/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ pac0/cli/command/console/app.py,sha256=r9tccUbTFgtXAG7j8UR9cjlw722h3xrRlPSZk9dpVXQ,1414
3
+ pac0/cli/command/console/screens/services.py,sha256=Ka1pC_YlyshUOpCdpVVSuJ9HpnVubg5zp8JnjHiHqQ8,1038
4
+ pac0/cli/command/console/screens/stats.py,sha256=72en91wLKU6XXGFpvHNNvYk5ZfF2vVnVGYHaift1kWc,618
5
+ pac0/cli/command/console/screens/tests.py,sha256=3Sz0pK7TDtA22ewhYCqefAmoHsqZe1QE9ZUrqiH-5l8,1046
6
+ pac0/cli/command/console/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ pac0/cli/command/console/widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ pac0/cli/command/run.py,sha256=jEPQQg7lUuMzf6gbA223p7C_nx-Tbg5reWSRvHRVWVQ,2769
9
+ pac0/cli/command/setup.py,sha256=-QsRwgJlBuApt7JvD1dJkjb1Dh_FV0FJi14ijjns7xM,1259
10
+ pac0/cli/command/test.py,sha256=J76CpfOIpLD49_0It6UG8uWzoayg8HjmfD3a4LHRihA,198
11
+ pac0/cli/main.py,sha256=efutWmz90cn56p2mrnQv04RxOyQkqp8L9keD8f2s_qE,1128
12
+ pac0/cli/utils.py,sha256=9ZBTpndp0Y8WTUyNtd3AHewYToTHGB9VkUlGTltpCvY,1035
13
+ pac0_cli-0.6.0.dist-info/WHEEL,sha256=XV0cjMrO7zXhVAIyyc8aFf1VjZ33Fen4IiJk5zFlC3g,80
14
+ pac0_cli-0.6.0.dist-info/entry_points.txt,sha256=G1ivGStFhWmI22qni1eUpRnPi-hQhrDGKEpMmISBmzo,126
15
+ pac0_cli-0.6.0.dist-info/METADATA,sha256=dapXGAR5QIT-6S9tIviDDeb5TbRLjFP2Muyk8olFXdA,2133
16
+ pac0_cli-0.6.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.9.26
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,6 @@
1
+ [console_scripts]
2
+ pac = pac0.cli.main:app
3
+ pac0 = pac0.cli.main:app
4
+ pac0-cli = pac0.cli.main:app
5
+ pac0_cli = pac0.cli.main:app
6
+