pbi-enterprise-cli 0.1.0.dev0__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.
Files changed (61) hide show
  1. pbi_cli/__init__.py +3 -0
  2. pbi_cli/_audit.py +57 -0
  3. pbi_cli/_snapshot.py +95 -0
  4. pbi_cli/backends/__init__.py +1 -0
  5. pbi_cli/backends/mock_backend.py +323 -0
  6. pbi_cli/backends/pbir_backend.py +813 -0
  7. pbi_cli/backends/protocol.py +52 -0
  8. pbi_cli/backends/tom_backend.py +650 -0
  9. pbi_cli/backends/xmla_backend.py +627 -0
  10. pbi_cli/cli.py +332 -0
  11. pbi_cli/commands/__init__.py +1 -0
  12. pbi_cli/commands/_doctor.py +84 -0
  13. pbi_cli/commands/_shared.py +88 -0
  14. pbi_cli/commands/calendar_cmd.py +186 -0
  15. pbi_cli/commands/connections.py +153 -0
  16. pbi_cli/commands/custom_visual.py +325 -0
  17. pbi_cli/commands/database.py +76 -0
  18. pbi_cli/commands/dax.py +174 -0
  19. pbi_cli/commands/deploy.py +193 -0
  20. pbi_cli/commands/docs.py +57 -0
  21. pbi_cli/commands/filter_cmd.py +235 -0
  22. pbi_cli/commands/govern.py +124 -0
  23. pbi_cli/commands/layout.py +104 -0
  24. pbi_cli/commands/measure.py +185 -0
  25. pbi_cli/commands/model.py +499 -0
  26. pbi_cli/commands/partition.py +89 -0
  27. pbi_cli/commands/repl.py +209 -0
  28. pbi_cli/commands/report.py +561 -0
  29. pbi_cli/commands/security.py +90 -0
  30. pbi_cli/commands/server_cmd.py +30 -0
  31. pbi_cli/commands/skills_cmd.py +168 -0
  32. pbi_cli/commands/source.py +581 -0
  33. pbi_cli/commands/theme.py +60 -0
  34. pbi_cli/commands/trace.py +142 -0
  35. pbi_cli/commands/visual.py +507 -0
  36. pbi_cli/commands/watch.py +145 -0
  37. pbi_cli/docs_gen/__init__.py +1 -0
  38. pbi_cli/docs_gen/confluence.py +24 -0
  39. pbi_cli/docs_gen/markdown.py +36 -0
  40. pbi_cli/governance/__init__.py +1 -0
  41. pbi_cli/governance/engine.py +70 -0
  42. pbi_cli/governance/rules/__init__.py +85 -0
  43. pbi_cli/governance/rules/measure_brackets.py +27 -0
  44. pbi_cli/governance/rules/measure_description.py +41 -0
  45. pbi_cli/governance/rules/measure_format.py +38 -0
  46. pbi_cli/governance/rules/measure_naming.py +93 -0
  47. pbi_cli/governance/rules/table_pascal_case.py +44 -0
  48. pbi_cli/intelligence/__init__.py +1 -0
  49. pbi_cli/intelligence/layout_engine.py +192 -0
  50. pbi_cli/intelligence/measure_generator.py +40 -0
  51. pbi_cli/intelligence/theme_generator.py +193 -0
  52. pbi_cli/intelligence/visual_builder.py +429 -0
  53. pbi_cli/intelligence/visual_recommender.py +42 -0
  54. pbi_cli/server/__init__.py +1 -0
  55. pbi_cli/server/api.py +185 -0
  56. pbi_enterprise_cli-0.1.0.dev0.dist-info/METADATA +103 -0
  57. pbi_enterprise_cli-0.1.0.dev0.dist-info/RECORD +61 -0
  58. pbi_enterprise_cli-0.1.0.dev0.dist-info/WHEEL +5 -0
  59. pbi_enterprise_cli-0.1.0.dev0.dist-info/entry_points.txt +2 -0
  60. pbi_enterprise_cli-0.1.0.dev0.dist-info/licenses/LICENSE +21 -0
  61. pbi_enterprise_cli-0.1.0.dev0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,209 @@
1
+ """pbi repl — interactive REPL with tab completion, history, and persistent connection."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import readline
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ import click
10
+ from rich.console import Console
11
+
12
+ console = Console()
13
+
14
+ _HISTORY_FILE = Path.home() / ".pbi-cli" / "repl_history"
15
+ _COMMANDS = [
16
+ "model info",
17
+ "model tables",
18
+ "model columns",
19
+ "model relationships",
20
+ "model lint",
21
+ "model stats",
22
+ "measure list",
23
+ "measure add",
24
+ "measure update",
25
+ "measure delete",
26
+ "measure generate",
27
+ "dax query",
28
+ "dax validate",
29
+ "dax test",
30
+ "source profile",
31
+ "source scaffold",
32
+ "report pages",
33
+ "report page-add",
34
+ "report page-delete",
35
+ "report bookmark-list",
36
+ "report bookmark-add",
37
+ "report bookmark-delete",
38
+ "visual list",
39
+ "visual add",
40
+ "govern check",
41
+ "govern fix",
42
+ "govern rules",
43
+ "security roles",
44
+ "security role-add",
45
+ "partition list",
46
+ "partition add",
47
+ "partition refresh",
48
+ "trace start",
49
+ "trace stop",
50
+ "trace fetch",
51
+ "connections list",
52
+ "connections last",
53
+ "deploy snapshot",
54
+ "deploy diff",
55
+ "database export-tmdl",
56
+ "database import-tmdl",
57
+ "database diff-tmdl",
58
+ "doctor",
59
+ "help",
60
+ "exit",
61
+ "quit",
62
+ ]
63
+
64
+
65
+ class _PbiCompleter:
66
+ """Tab-completion provider for the pbi REPL."""
67
+
68
+ def __init__(self, commands: list[str]) -> None:
69
+ self.commands = commands
70
+ self.matches: list[str] = []
71
+
72
+ def complete(self, text: str, state: int) -> str | None:
73
+ if state == 0:
74
+ if text:
75
+ self.matches = [c for c in self.commands if c.startswith(text)]
76
+ else:
77
+ self.matches = list(self.commands)
78
+ try:
79
+ return self.matches[state]
80
+ except IndexError:
81
+ return None
82
+
83
+
84
+ def _load_history() -> None:
85
+ _HISTORY_FILE.parent.mkdir(parents=True, exist_ok=True)
86
+ if _HISTORY_FILE.exists():
87
+ try:
88
+ readline.read_history_file(str(_HISTORY_FILE)) # type: ignore[attr-defined]
89
+ except Exception:
90
+ pass
91
+ readline.set_history_length(1000) # type: ignore[attr-defined]
92
+
93
+
94
+ def _save_history() -> None:
95
+ try:
96
+ readline.write_history_file(str(_HISTORY_FILE)) # type: ignore[attr-defined]
97
+ except Exception:
98
+ pass
99
+
100
+
101
+ @click.command("repl")
102
+ @click.option(
103
+ "--backend",
104
+ default="desktop",
105
+ type=click.Choice(["desktop", "xmla", "mock"]),
106
+ help="Backend to connect to.",
107
+ )
108
+ @click.option("--port", default=None, type=int, help="Desktop server port.")
109
+ @click.option("--no-history", is_flag=True, help="Disable command history persistence.")
110
+ @click.pass_context
111
+ def repl(ctx: click.Context, backend: str, port: int | None, no_history: bool) -> None:
112
+ """Start an interactive pbi REPL with tab completion and command history.
113
+
114
+ Maintains a persistent connection for the session so you don't have to
115
+ reconnect on every command.
116
+
117
+ \b
118
+ Controls:
119
+ Tab — command completion
120
+ Up/Down — command history
121
+ Ctrl+D/exit — quit
122
+ help — list all commands
123
+
124
+ \b
125
+ Example session:
126
+ $ pbi repl
127
+ pbi> model tables
128
+ pbi> measure list --table Sales
129
+ pbi> dax query "EVALUATE {[Total Revenue]}"
130
+ """
131
+
132
+ # Set up readline completion
133
+ completer = _PbiCompleter(_COMMANDS)
134
+ readline.set_completer(completer.complete) # type: ignore[attr-defined]
135
+ readline.parse_and_bind("tab: complete") # type: ignore[attr-defined]
136
+
137
+ if not no_history:
138
+ _load_history()
139
+
140
+ # Set up a fake context for the session backend
141
+ ctx.ensure_object(dict)
142
+ ctx.obj["backend"] = backend
143
+ if port:
144
+ ctx.obj["port"] = port
145
+
146
+ _print_banner(backend)
147
+
148
+ # Try connecting eagerly for desktop backend
149
+ session_backend: Any = None
150
+ if backend == "mock":
151
+ from pbi_cli.backends.mock_backend import MockTomBackend
152
+
153
+ session_backend = MockTomBackend()
154
+ session_backend.connect()
155
+ model_name = session_backend.model_info().get("name", "MockModel")
156
+ console.print(f"[green]Connected[/green] ({backend}) — [bold]{model_name}[/bold]")
157
+ else:
158
+ console.print(f"[dim]Backend: {backend} — will connect on first command.[/dim]")
159
+
160
+ try:
161
+ while True:
162
+ try:
163
+ # Use plain input() since rich can't handle readline input
164
+ line = input("pbi> ").strip()
165
+ except (EOFError, KeyboardInterrupt):
166
+ console.print("\n[dim]Bye![/dim]")
167
+ break
168
+
169
+ if not line:
170
+ continue
171
+ if line.lower() in ("exit", "quit", "q"):
172
+ console.print("[dim]Bye![/dim]")
173
+ break
174
+ if line.lower() == "help":
175
+ _print_help()
176
+ continue
177
+
178
+ _dispatch(ctx, line, session_backend)
179
+
180
+ finally:
181
+ if not no_history:
182
+ _save_history()
183
+
184
+
185
+ def _print_banner(backend: str) -> None:
186
+ console.print("\n[bold blue]pbi-cli interactive REPL[/bold blue]")
187
+ console.print(
188
+ f" Backend: [cyan]{backend}[/cyan] | Tab: complete | ↑↓: history | Ctrl+D: exit\n"
189
+ )
190
+
191
+
192
+ def _print_help() -> None:
193
+ console.print("[bold]Available commands:[/bold]")
194
+ for cmd in _COMMANDS:
195
+ console.print(f" pbi {cmd}")
196
+
197
+
198
+ def _dispatch(ctx: click.Context, line: str, session_backend: Any) -> None:
199
+ """Parse and execute a REPL line by delegating to the main CLI."""
200
+ import subprocess
201
+
202
+ args = ["pbi"] + line.split()
203
+ # Pass current backend flag
204
+ backend = ctx.obj.get("backend", "desktop")
205
+ args = ["pbi", "--backend", backend] + line.split()
206
+ try:
207
+ subprocess.run(args, capture_output=False)
208
+ except Exception as exc:
209
+ console.print(f"[red]Error:[/red] {exc}")