-
-
Notifications
You must be signed in to change notification settings - Fork 6.2k
Expand file tree
/
Copy path__init__.py
More file actions
124 lines (107 loc) · 4.19 KB
/
Copy path__init__.py
File metadata and controls
124 lines (107 loc) · 4.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
import os as _os
import sys as _sys
# Are we the `unsloth` console script, rather than a library import? Both the
# stream guard below and the `-np<N>` rewrite further down are entry-point
# behaviour and must not reach into a host application that imports us.
_entry_base = _os.path.basename(_sys.argv[0]).lower() if _sys.argv else ""
_is_entry_point = _entry_base in {"unsloth", "unsloth.exe"}
# Typer renders help via rich, whose box characters cp1252 and cp437 cannot encode,
# so `unsloth --help` dies once stdout is a pipe or a file. Windows gets UTF-8, as
# unsloth/__init__ already does; elsewhere the caller's encoding is kept and only
# the error handler is relaxed, so an explicit PYTHONIOENCODING still picks the
# bytes and only loses unencodable glyphs. Before typer, which binds the stream.
if _is_entry_point:
_to_utf8 = _sys.platform == "win32"
for _name in ("stdout", "stderr"):
_stream = getattr(_sys, _name, None)
try:
if "utf" not in (_stream.encoding or "").lower():
_stream.reconfigure(encoding = "utf-8" if _to_utf8 else None, errors = "replace")
except Exception:
pass
del _name, _stream, _to_utf8
import typer
from importlib.metadata import version as package_version, PackageNotFoundError
from unsloth_cli.commands.train import train
from unsloth_cli.commands.inference import inference
from unsloth_cli.commands.chat import chat
from unsloth_cli.commands.start import start_app
from unsloth_cli.commands.export import export, list_checkpoints
from unsloth_cli.commands.studio import (
run as studio_run,
studio_app,
_expand_attached_np_short,
)
# Canonicalise `-np<N>` only under the `unsloth` console-script;
# third-party scripts that import unsloth_cli keep their argv intact.
if _is_entry_point:
_expand_attached_np_short()
del _entry_base, _is_entry_point
def show_version(value: bool):
if value:
try:
version = package_version("unsloth")
except PackageNotFoundError:
version = "unknown"
typer.echo(f"unsloth {version}")
raise typer.Exit()
app = typer.Typer(
help = "Command-line interface for Unsloth training, inference, and export.",
context_settings = {"help_option_names": ["-h", "--help"]},
)
@app.callback()
def main(
version: bool = typer.Option(
None,
"--version",
"-V",
callback = show_version,
is_eager = True,
help = "Show version and exit.",
),
):
if (
_sys.platform == "win32"
): # this block catches unsloth running inside of System32 or any subdirs, this WILL cause errors if not prevented.
_cwd = _os.path.normcase(_os.path.normpath(_os.getcwd()))
_system32 = _os.path.normcase(
_os.path.normpath(_os.path.join(_os.environ.get("WINDIR", r"C:\Windows"), "System32"))
)
if _cwd == _system32 or _cwd.startswith(_system32 + _os.sep):
typer.secho(
"Refusing to run Unsloth inside System32 as it will lead to Errors.\n"
"cd to a normal working directory and try again.",
fg = "red",
err = True,
)
raise typer.Exit(code = 1)
app.command()(train)
app.command()(inference)
app.command()(chat)
app.command()(export)
app.command("list-checkpoints")(list_checkpoints)
app.add_typer(studio_app, name = "studio", help = "Unsloth Studio commands.")
app.add_typer(
start_app,
name = "start",
help = "Start a coding agent (Claude, Codex, OpenClaw, OpenCode, Hermes, Pi) against Unsloth.",
)
# Backwards-compatible hidden alias: `unsloth connect` routes to `unsloth start`.
app.add_typer(
start_app,
name = "connect",
hidden = True,
help = "Deprecated alias for `unsloth start`.",
)
# Top-level `unsloth run` aliases `unsloth studio run`; same context
# so unknown flags still pass through to llama-server.
app.command(
"run",
context_settings = {
"allow_extra_args": True,
"ignore_unknown_options": True,
},
help = "Alias for `unsloth studio run`.",
)(studio_run)