33import shutil
44import sys
55
6- from argparse import ArgumentParser , RawTextHelpFormatter
6+ from argparse import Namespace
77from functools import partial
88from textwrap import indent
9- from typing import Any , List , Union
9+ from typing import List , Union , cast
1010
1111from sanic .app import Sanic
1212from sanic .application .logo import get_logo
1313from sanic .cli .arguments import Group
14- from sanic .log import error_logger
15- from sanic .worker .inspector import inspect
14+ from sanic .cli .base import SanicArgumentParser , SanicHelpFormatter
15+ from sanic .cli .inspector import make_inspector_parser
16+ from sanic .cli .inspector_client import InspectorClient
17+ from sanic .log import Colors , error_logger
1618from sanic .worker .loader import AppLoader
1719
1820
19- class SanicArgumentParser (ArgumentParser ):
20- ...
21-
22-
2321class SanicCLI :
2422 DESCRIPTION = indent (
2523 f"""
@@ -46,7 +44,7 @@ def __init__(self) -> None:
4644 self .parser = SanicArgumentParser (
4745 prog = "sanic" ,
4846 description = self .DESCRIPTION ,
49- formatter_class = lambda prog : RawTextHelpFormatter (
47+ formatter_class = lambda prog : SanicHelpFormatter (
5048 prog ,
5149 max_help_position = 36 if width > 96 else 24 ,
5250 indent_increment = 4 ,
@@ -58,16 +56,27 @@ def __init__(self) -> None:
5856 self .main_process = (
5957 os .environ .get ("SANIC_RELOADER_PROCESS" , "" ) != "true"
6058 )
61- self .args : List [ Any ] = []
59+ self .args : Namespace = Namespace ()
6260 self .groups : List [Group ] = []
61+ self .inspecting = False
6362
6463 def attach (self ):
64+ if sys .argv [1 ] == "inspect" :
65+ self .inspecting = True
66+ self .parser .description = get_logo (True )
67+ make_inspector_parser (self .parser )
68+ return
69+
6570 for group in Group ._registry :
6671 instance = group .create (self .parser )
6772 instance .attach ()
6873 self .groups .append (instance )
6974
7075 def run (self , parse_args = None ):
76+ if self .inspecting :
77+ self ._inspector ()
78+ return
79+
7180 legacy_version = False
7281 if not parse_args :
7382 # This is to provide backwards compat -v to display version
@@ -86,52 +95,21 @@ def run(self, parse_args=None):
8695 self .args = self .parser .parse_args (args = parse_args )
8796 self ._precheck ()
8897 app_loader = AppLoader (
89- self .args .module ,
90- self .args .factory ,
91- self .args .simple ,
92- self .args ,
98+ self .args .module , self .args .factory , self .args .simple , self .args
9399 )
94100
101+ if self .args .inspect or self .args .inspect_raw or self .args .trigger :
102+ self ._inspector_legacy (app_loader )
103+ return
104+
95105 try :
96106 app = self ._get_app (app_loader )
97107 kwargs = self ._build_run_kwargs ()
98108 except ValueError as e :
99109 error_logger .exception (f"Failed to run app: { e } " )
100110 else :
101- if (
102- self .args .inspect
103- or self .args .inspect_raw
104- or self .args .trigger
105- or self .args .scale is not None
106- ):
107- os .environ ["SANIC_IGNORE_PRODUCTION_WARNING" ] = "true"
108- else :
109- for http_version in self .args .http :
110- app .prepare (** kwargs , version = http_version )
111-
112- if (
113- self .args .inspect
114- or self .args .inspect_raw
115- or self .args .trigger
116- or self .args .scale is not None
117- ):
118- if self .args .scale is not None :
119- if self .args .scale <= 0 :
120- error_logger .error ("There must be at least 1 worker" )
121- sys .exit (1 )
122- action = f"scale={ self .args .scale } "
123- else :
124- action = self .args .trigger or (
125- "raw" if self .args .inspect_raw else "pretty"
126- )
127- inspect (
128- app .config .INSPECTOR_HOST ,
129- app .config .INSPECTOR_PORT ,
130- action ,
131- )
132- del os .environ ["SANIC_IGNORE_PRODUCTION_WARNING" ]
133- return
134-
111+ for http_version in self .args .http :
112+ app .prepare (** kwargs , version = http_version )
135113 if self .args .single :
136114 serve = Sanic .serve_single
137115 elif self .args .legacy :
@@ -140,6 +118,53 @@ def run(self, parse_args=None):
140118 serve = partial (Sanic .serve , app_loader = app_loader )
141119 serve (app )
142120
121+ def _inspector_legacy (self , app_loader : AppLoader ):
122+ host = port = None
123+ module = cast (str , self .args .module )
124+ if ":" in module :
125+ maybe_host , maybe_port = module .rsplit (":" , 1 )
126+ if maybe_port .isnumeric ():
127+ host , port = maybe_host , int (maybe_port )
128+ if not host :
129+ app = self ._get_app (app_loader )
130+ host , port = app .config .INSPECTOR_HOST , app .config .INSPECTOR_PORT
131+
132+ action = self .args .trigger or "info"
133+
134+ InspectorClient (
135+ str (host ), int (port or 6457 ), False , self .args .inspect_raw , ""
136+ ).do (action )
137+ sys .stdout .write (
138+ f"\n { Colors .BOLD } { Colors .YELLOW } WARNING:{ Colors .END } "
139+ "You are using the legacy CLI command that will be removed in "
140+ f"{ Colors .RED } v23.3{ Colors .END } . See ___ or checkout the new "
141+ "style commands:\n \n \t "
142+ f"{ Colors .YELLOW } sanic inspect --help{ Colors .END } \n "
143+ )
144+
145+ def _inspector (self ):
146+ args = sys .argv [2 :]
147+ self .args , unknown = self .parser .parse_known_args (args = args )
148+ if unknown :
149+ for arg in unknown :
150+ if arg .startswith ("--" ):
151+ key , value = arg .split ("=" )
152+ setattr (self .args , key .lstrip ("-" ), value )
153+
154+ kwargs = {** self .args .__dict__ }
155+ host = kwargs .pop ("host" )
156+ port = kwargs .pop ("port" )
157+ secure = kwargs .pop ("secure" )
158+ raw = kwargs .pop ("raw" )
159+ action = kwargs .pop ("action" ) or "info"
160+ api_key = kwargs .pop ("api_key" )
161+ positional = kwargs .pop ("positional" , None )
162+ if action == "<custom>" and positional :
163+ action = positional [0 ]
164+ if len (positional ) > 1 :
165+ kwargs ["args" ] = positional [1 :]
166+ InspectorClient (host , port , secure , raw , api_key ).do (action , ** kwargs )
167+
143168 def _precheck (self ):
144169 # Custom TLS mismatch handling for better diagnostics
145170 if self .main_process and (
0 commit comments