frappectl 0.13.1__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.
- frappectl/__init__.py +8 -0
- frappectl/__main__.py +4 -0
- frappectl/cli.py +148 -0
- frappectl/client.py +591 -0
- frappectl/commands/__init__.py +1 -0
- frappectl/commands/api.py +101 -0
- frappectl/commands/assistant.py +270 -0
- frappectl/commands/auth.py +391 -0
- frappectl/commands/doc.py +346 -0
- frappectl/commands/doctype.py +133 -0
- frappectl/commands/file.py +137 -0
- frappectl/commands/guide.py +73 -0
- frappectl/commands/method.py +295 -0
- frappectl/commands/report.py +93 -0
- frappectl/commands/update.py +345 -0
- frappectl/config.py +492 -0
- frappectl/errors.py +186 -0
- frappectl/helpers.py +149 -0
- frappectl/oauth.py +456 -0
- frappectl/output.py +155 -0
- frappectl/py.typed +0 -0
- frappectl/session.py +67 -0
- frappectl-0.13.1.dist-info/METADATA +177 -0
- frappectl-0.13.1.dist-info/RECORD +27 -0
- frappectl-0.13.1.dist-info/WHEEL +4 -0
- frappectl-0.13.1.dist-info/entry_points.txt +3 -0
- frappectl-0.13.1.dist-info/licenses/LICENSE +21 -0
frappectl/__init__.py
ADDED
frappectl/__main__.py
ADDED
frappectl/cli.py
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"""frappectl — top-level Typer app and global options."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
import typer
|
|
9
|
+
|
|
10
|
+
from . import __version__
|
|
11
|
+
from .commands import api as api_cmd
|
|
12
|
+
from .commands import assistant as assistant_cmd
|
|
13
|
+
from .commands import auth, doc, doctype, file, report
|
|
14
|
+
from .commands import guide as guide_cmd
|
|
15
|
+
from .commands import method as method_cmd
|
|
16
|
+
from .commands import update as update_cmd
|
|
17
|
+
from .config import ConfigError
|
|
18
|
+
from .errors import FrappeError, UsageError
|
|
19
|
+
from .output import Ctx, fail
|
|
20
|
+
|
|
21
|
+
app = typer.Typer(
|
|
22
|
+
name="frappectl",
|
|
23
|
+
help="frappectl — a command-line client for Frappe sites.",
|
|
24
|
+
no_args_is_help=True,
|
|
25
|
+
add_completion=True,
|
|
26
|
+
rich_markup_mode="rich",
|
|
27
|
+
context_settings={"help_option_names": ["-h", "--help"]},
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
app.add_typer(auth.app, name="auth")
|
|
31
|
+
app.add_typer(doc.app, name="doc")
|
|
32
|
+
app.add_typer(doctype.app, name="doctype")
|
|
33
|
+
app.add_typer(file.app, name="file")
|
|
34
|
+
app.add_typer(report.app, name="report")
|
|
35
|
+
app.add_typer(method_cmd.app, name="method")
|
|
36
|
+
# `frappectl api <path>` — single command, mounted directly.
|
|
37
|
+
app.command(name="api", help=api_cmd.api.__doc__)(api_cmd.api)
|
|
38
|
+
# `frappectl guide` — static usage primer; the first thing an agent should run.
|
|
39
|
+
app.command(name="guide", help=guide_cmd.guide.__doc__)(guide_cmd.guide)
|
|
40
|
+
# `frappectl update` — self-upgrade via the uv/pip backend it was installed with.
|
|
41
|
+
app.command(name="update", help=update_cmd.update.__doc__)(update_cmd.update)
|
|
42
|
+
# `frappectl assistant [tool] -- <args>` — launch a CLI agent as a Frappe
|
|
43
|
+
# assistant. allow_extra_args/ignore_unknown_options let trailing args (and
|
|
44
|
+
# the child tool's own flags) pass through untouched via ctx.args.
|
|
45
|
+
app.command(
|
|
46
|
+
name="assistant",
|
|
47
|
+
help=assistant_cmd.assistant.__doc__,
|
|
48
|
+
context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
|
|
49
|
+
)(assistant_cmd.assistant)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _version_callback(value: bool) -> None:
|
|
53
|
+
if value:
|
|
54
|
+
typer.echo(f"frappectl {__version__}")
|
|
55
|
+
raise typer.Exit()
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@app.callback()
|
|
59
|
+
def _root(
|
|
60
|
+
ctx: typer.Context,
|
|
61
|
+
site: Optional[str] = typer.Option(
|
|
62
|
+
None, "-s", "--site", help="Profile to use (overrides the default profile)."
|
|
63
|
+
),
|
|
64
|
+
json_out: bool = typer.Option(
|
|
65
|
+
False, "--json", help="Force JSON output (default when piped)."
|
|
66
|
+
),
|
|
67
|
+
yes: bool = typer.Option(
|
|
68
|
+
False, "--yes", "-y", help="Assume yes for confirmation prompts."
|
|
69
|
+
),
|
|
70
|
+
debug: bool = typer.Option(
|
|
71
|
+
False,
|
|
72
|
+
"--debug",
|
|
73
|
+
help="Print each HTTP request (and server SQL, where available) to stderr.",
|
|
74
|
+
),
|
|
75
|
+
version: bool = typer.Option(
|
|
76
|
+
False,
|
|
77
|
+
"--version",
|
|
78
|
+
callback=_version_callback,
|
|
79
|
+
is_eager=True,
|
|
80
|
+
help="Show version.",
|
|
81
|
+
),
|
|
82
|
+
) -> None:
|
|
83
|
+
"""Global options apply to every subcommand."""
|
|
84
|
+
ctx.obj = Ctx(json_mode=json_out, assume_yes=yes, profile=site, debug=debug)
|
|
85
|
+
# Passive, best-effort "a newer version exists" nudge. No-op in JSON/piped
|
|
86
|
+
# mode and for dev checkouts; network-throttled to once a day.
|
|
87
|
+
update_cmd.notify_if_outdated(ctx.obj)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
# Global flags that must reach the top-level callback. We hoist them to the
|
|
91
|
+
# front of argv so they work in gh-style trailing position too, e.g.
|
|
92
|
+
# frappectl doc list "Sales Invoice" --json
|
|
93
|
+
# is rewritten to `frappectl --json doc list "Sales Invoice"`.
|
|
94
|
+
_VALUELESS_GLOBALS = {"--json", "--yes", "-y", "--debug"}
|
|
95
|
+
_VALUED_GLOBALS = {"-s", "--site"}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _hoist_globals(argv: list[str]) -> list[str]:
|
|
99
|
+
hoisted: list[str] = []
|
|
100
|
+
rest: list[str] = []
|
|
101
|
+
i = 0
|
|
102
|
+
seen_ddash = False
|
|
103
|
+
while i < len(argv):
|
|
104
|
+
tok = argv[i]
|
|
105
|
+
if tok == "--":
|
|
106
|
+
seen_ddash = True
|
|
107
|
+
rest.append(tok)
|
|
108
|
+
i += 1
|
|
109
|
+
continue
|
|
110
|
+
if not seen_ddash and tok in _VALUELESS_GLOBALS:
|
|
111
|
+
# Normalize -y to --yes for the callback.
|
|
112
|
+
hoisted.append("--yes" if tok == "-y" else tok)
|
|
113
|
+
i += 1
|
|
114
|
+
continue
|
|
115
|
+
if not seen_ddash and tok in _VALUED_GLOBALS:
|
|
116
|
+
hoisted.append("--site")
|
|
117
|
+
if i + 1 < len(argv):
|
|
118
|
+
hoisted.append(argv[i + 1])
|
|
119
|
+
i += 2
|
|
120
|
+
else:
|
|
121
|
+
i += 1
|
|
122
|
+
continue
|
|
123
|
+
if not seen_ddash and (tok.startswith("--site=") or tok.startswith("-s=")):
|
|
124
|
+
hoisted.extend(["--site", tok.split("=", 1)[1]])
|
|
125
|
+
i += 1
|
|
126
|
+
continue
|
|
127
|
+
rest.append(tok)
|
|
128
|
+
i += 1
|
|
129
|
+
return hoisted + rest
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def main() -> None:
|
|
133
|
+
sys.argv = [sys.argv[0]] + _hoist_globals(sys.argv[1:])
|
|
134
|
+
try:
|
|
135
|
+
app()
|
|
136
|
+
except UsageError as e:
|
|
137
|
+
fail(e.message, 2)
|
|
138
|
+
sys.exit(2)
|
|
139
|
+
except FrappeError as e:
|
|
140
|
+
fail(e.message, 1)
|
|
141
|
+
sys.exit(1)
|
|
142
|
+
except ConfigError as e:
|
|
143
|
+
fail(str(e), 2)
|
|
144
|
+
sys.exit(2)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
if __name__ == "__main__":
|
|
148
|
+
main()
|