33from typing import Callable , Dict , List , Any
44
55# web imports
6+ from flask import Blueprint
67from flask_executor import Executor
78from flask_executor .futures import Future
89
1415logger = get_logger ()
1516
1617
17- class Shell2HTTP (object ):
18+ class Shell2HTTP (Blueprint ):
1819 """
19- Flask-Shell2HTTP base entrypoint class.
20- The only public API available to users.
20+ Flask-Shell2HTTP's base entrypoint. This is the only public API available to users.
21+
22+ This is a subclass of `Flask.Blueprint` so it accepts
23+ all the same arguments and functionality of a generic ``Flask.Blueprint`` instance..
2124
2225 Attributes:
23- app: Flask application instance.
24- executor: Flask-Executor instance
25- base_url_prefix (str): base prefix to apply to endpoints. Defaults to "/".
26+ executor: ``flask_executor.Executor`` instance
27+ import_name: The name of the blueprint package, usually
28+ ``__name__``. This helps locate the ``root_path`` for the
29+ blueprint.
30+ static_folder: A folder with static files that should be
31+ served by the blueprint's static route. The path is relative to
32+ the blueprint's root path. Blueprint static files are disabled
33+ by default.
34+ static_url_path: The url to serve static files from.
35+ Defaults to ``static_folder``. If the blueprint does not have
36+ a ``url_prefix``, the app's static route will take precedence,
37+ and the blueprint's static files won't be accessible.
38+ template_folder: A folder with templates that should be added
39+ to the app's template search path. The path is relative to the
40+ blueprint's root path. Blueprint templates are disabled by
41+ default. Blueprint templates have a lower precedence than those
42+ in the app's templates folder.
43+ url_prefix: A path to prepend to all of the blueprint's URLs,
44+ to make them distinct from the rest of the app's routes.
45+ subdomain: A subdomain that blueprint routes will match on by
46+ default.
47+ url_defaults: A dict of default values that blueprint routes
48+ will receive by default.
49+ root_path: By default, the blueprint will automatically this
50+ based on ``import_name``. In certain situations this automatic
51+ detection can fail, so the path can be specified manually
52+ instead.
2653
2754 Example::
2855
2956 app = Flask(__name__)
3057 executor = Executor(app)
31- shell2http = Shell2HTTP(app=app, executor=executor, base_url_prefix ="/tasks/ ")
58+ shell2http = Shell2HTTP(executor, 'tasks', __name__, url_prefix ="/tasks")
3259 """
3360
34- __commands : "OrderedDict[str, str]" = OrderedDict ()
35- __url_prefix : str = "/"
36-
37- def __init__ (
38- self , app = None , executor : Executor = None , base_url_prefix : str = "/"
39- ) -> None :
40- self .__url_prefix = base_url_prefix
41- if app and executor :
42- self .init_app (app , executor )
43-
44- def init_app (self , app , executor : Executor ) -> None :
45- """
46- For use with Flask's `Application Factory`_ method.
47-
48- Example::
49-
50- executor = Executor()
51- shell2http = Shell2HTTP(base_url_prefix="/commands/")
52- app = Flask(__name__)
53- executor.init_app(app)
54- shell2http.init_app(app=app, executor=executor)
55-
56- .. _Application Factory:
57- https://flask.palletsprojects.com/en/1.1.x/patterns/appfactories/
58- """
59- self .app = app
60- self .__executor : Executor = executor
61- self .__init_extension ()
62-
63- def __init_extension (self ) -> None :
64- """
65- Adds the Shell2HTTP() instance to `app.extensions` list.
66- For internal use only.
67- """
68- if not hasattr (self .app , "extensions" ):
69- self .app .extensions = dict ()
61+ __commands : "OrderedDict[str, str]"
62+ __executor : Executor
7063
71- self .app .extensions ["shell2http" ] = self
64+ def __init__ (self , executor : Executor , * args , ** kwargs ):
65+ self .__commands = OrderedDict ()
66+ self .__executor = executor
67+ super ().__init__ (* args , ** kwargs )
7268
7369 def register_command (
7470 self ,
@@ -78,11 +74,14 @@ def register_command(
7874 decorators : List = [],
7975 ) -> None :
8076 """
81- Function to map a shell command to an endpoint.
77+ Function to map a shell command to an endpoint or route.
78+
79+ This internally registers the route via the ``Blueprint.add_url_rule`` method
80+ so you can enjoy all the same features and powers of a blueprint instance.
8281
8382 Args:
8483 endpoint (str):
85- - your command would live here: ``/{base_url_prefix }/{endpoint}``
84+ - your command would live here: ``/{url_prefix }/{endpoint}``
8685 command_name (str):
8786 - The base command which can be executed from the given endpoint.
8887 - If ``command_name='echo'``, then all arguments passed
@@ -115,15 +114,15 @@ def my_callback_fn(context: dict, future: Future) -> None:
115114 decorators=[],
116115 )
117116 """
118- uri : str = self .__construct_route (endpoint )
119117 # make sure the given endpoint is not already registered
120- cmd_already_exists = self .__commands .get (uri )
118+ cmd_already_exists = self .__commands .get (endpoint )
121119 if cmd_already_exists :
122- logger . error (
120+ err_msg = (
123121 "Failed to register since given endpoint: "
124122 f"'{ endpoint } ' already maps to command: '{ cmd_already_exists } '."
125123 )
126- return None
124+ logger .error (err_msg )
125+ raise AssertionError (err_msg )
127126
128127 # else, add new URL rule
129128 view_func = Shell2HttpAPI .as_view (
@@ -136,12 +135,15 @@ def my_callback_fn(context: dict, future: Future) -> None:
136135 for dec in decorators :
137136 view_func = dec (view_func )
138137 # register URL rule
139- self .app . add_url_rule (
140- uri ,
138+ self .add_url_rule (
139+ endpoint ,
141140 view_func = view_func ,
142141 )
143- self .__commands .update ({uri : command_name })
144- logger .info (f"New endpoint: '{ uri } ' registered for command: '{ command_name } '." )
142+ self .__commands .update ({endpoint : command_name })
143+ logger .info (
144+ f"New endpoint: '{ self .url_prefix } /{ endpoint } ' "
145+ f"registered for command: '{ command_name } '."
146+ )
145147
146148 def get_registered_commands (self ) -> "OrderedDict[str, str]" :
147149 """
@@ -153,9 +155,3 @@ def get_registered_commands(self) -> "OrderedDict[str, str]":
153155 i.e. mapping of registered commands and their URLs.
154156 """
155157 return self .__commands
156-
157- def __construct_route (self , endpoint : str ) -> str :
158- """
159- For internal use only.
160- """
161- return self .__url_prefix + endpoint
0 commit comments