77
88def main ():
99 """
10- Command-line interface for **Brian2Wasm**.
11-
12- Usage
13- -----
14- ``python -m brian2wasm <script.py> [--no-server] [--skip-install]``
15-
16- Parameters
17- ----------
18- script : str
19- Path to the user’s Python model. The file **must** end with
20- ``.py`` and must not call ``set_device`` itself – the CLI inserts
21- the appropriate ``set_device('wasm_standalone', …)`` line
22- automatically.
23- --no-server : flag, optional
24- Generate the WASM/HTML output without starting the local preview
25- web-server (sets the ``BRIAN2WASM_NO_SERVER`` environment
26- variable for the subprocess).
27- --skip-install : flag, optional
28- Run Brian2WASM without checking or installing EMSDK. Use this if
29- you are sure EMSDK is already installed and configured in your
30- environment.
31-
32- Behaviour
33- ---------
34- 1. Validates that *script* exists and is a ``.py`` file.
35- 2. Looks for an ``<scriptname>.html`` file in the same directory.
36- * If found, passes the HTML file to ``set_device`` so the custom
37- template is used.
38- * Otherwise falls back to the default template.
39- 3. Unless *--skip-install* is given, verifies EMSDK installation
40- (Pixi/Conda/CONDA_EMSDK_DIR) and attempts to activate it.
41- 4. Prepends the required ``set_device('wasm_standalone', …)`` call to
42- the script source in-memory.
43- 5. Executes the modified script with its own directory as working
44- directory, so any relative paths inside the model behave as
45- expected.
46-
47- Exit status
48- -----------
49- * ``0`` – build finished successfully (and server started unless
50- *--no-server* was given).
51- * ``1`` – any error (missing file, not a ``.py`` file, EMSDK not found
52- or not activated, exception during model execution, etc.).
53- """
10+ Command-line interface entry point for Brian2Wasm.
11+
12+ This function validates the given script, injects the required
13+ ``set_device('wasm_standalone', …)`` call, ensures EMSDK is
14+ available (unless skipped), and executes the modified script.
15+
16+ Parameters
17+ ----------
18+ script : str
19+ Path to the Python model file. The file must exist, end with
20+ ``.py``, and must not call ``set_device`` directly, since this
21+ function injects the correct call automatically.
22+ --no-server : bool, optional
23+ If given, generates the WASM/HTML output without starting the
24+ local preview web server. Internally sets the environment
25+ variable ``BRIAN2WASM_NO_SERVER=1``.
26+ --skip-install : bool, optional
27+ If given, skips EMSDK installation and activation checks.
28+ Use this flag when you are certain EMSDK is already installed
29+ and properly configured in your environment.
30+
31+ Raises
32+ ------
33+ FileNotFoundError
34+ If the provided script path does not exist.
35+ ValueError
36+ If the provided file is not a Python ``.py`` script.
37+ RuntimeError
38+ If execution of the modified script fails for any reason.
39+ SystemExit
40+ If errors occur during validation or script execution, the
41+ process exits with status code ``1``.
42+
43+ Returns
44+ -------
45+ None
46+ This function is intended as a CLI entry point and does not
47+ return a value.
48+ """
5449
5550 parser = argparse .ArgumentParser (
5651 description = "Brian2WASM CLI"
@@ -76,10 +71,10 @@ def main():
7671 # Check if the script exists and is a Python file
7772 if not os .path .isfile (script_path ):
7873 full_path = os .path .abspath (script_path )
79- print (f"❌ Error: File '{ full_path } ' does not exist." , file = sys .stderr )
74+ print (f"Error: File '{ full_path } ' does not exist." , file = sys .stderr )
8075 sys .exit (1 )
8176 if not script_path .endswith (".py" ):
82- print (f"❌ Error: File '{ script_path } ' is not a Python script (.py)." , file = sys .stderr )
77+ print (f"Error: File '{ script_path } ' is not a Python script (.py)." , file = sys .stderr )
8378 sys .exit (1 )
8479
8580 if not args .skip_install :
@@ -101,14 +96,14 @@ def main():
10196
10297 # Inject required lines at the top
10398 if has_html_file :
104- print (f"✅ HTML file found: '{ html_file_path } '" )
99+ print (f"HTML file found: '{ html_file_path } '" )
105100 injection = (
106101 "from brian2 import set_device\n "
107102 "import brian2wasm\n "
108103 f"set_device('wasm_standalone', directory='{ script_name } ', html_file='{ html_file } ')\n "
109104 )
110105 else :
111- print ("ℹ️ HTML file not found: using default HTML template." )
106+ print ("HTML file not found: using default HTML template." )
112107 injection = (
113108 "from brian2 import set_device\n "
114109 "import brian2wasm\n "
@@ -125,26 +120,55 @@ def main():
125120 if args .no_server :
126121 os .environ ['BRIAN2WASM_NO_SERVER' ] = '1'
127122
128- print (f"📄 Script path: { os .path .abspath (script_path )} " )
129- print (f"📁 Directory: { script_dir } " )
123+ print (f"Script path: { os .path .abspath (script_path )} " )
124+ print (f"Directory: { script_dir } " )
130125 exec_globals = {'__name__' : '__main__' , '__file__' : os .path .abspath (script_path )}
131126 compiled_script = compile (modified_script , script_path , 'exec' )
132127 exec (compiled_script , exec_globals )
133128
134129 except Exception as e :
135- print (f"❌ Error running script: { e } " , file = sys .stderr )
130+ print (f"Error running script: { e } " , file = sys .stderr )
136131 sys .exit (1 )
137132
138133 finally :
139134 os .chdir (original_cwd )
140135
141136
142137def check_emsdk ():
138+ """
139+ Verify that the Emscripten SDK (EMSDK) is installed and attempt to activate it.
140+
141+ This function checks for EMSDK in the current environment, using either
142+ the system path (``emsdk`` executable) or the ``CONDA_EMSDK_DIR`` variable.
143+ If EMSDK is missing, it prints installation instructions and exits.
144+ If EMSDK is found but not activated, it attempts to activate the latest
145+ version, optionally prompting the user to install and activate it.
146+
147+ Parameters
148+ ----------
149+ None
150+ This function takes no arguments.
151+
152+ Raises
153+ ------
154+ SystemExit
155+ If EMSDK is not found, not activated, or installation/activation
156+ fails, the process exits with status code ``1``.
157+ RuntimeError
158+ If subprocess execution encounters an unexpected failure during
159+ EMSDK activation.
160+
161+ Returns
162+ -------
163+ None
164+ This function is intended as a setup check and does not
165+ return a value. Its success or failure is indicated by process exit.
166+ """
143167 emsdk = shutil .which ("emsdk" )
144168 conda_emsdk_dir = os .environ .get ("CONDA_EMSDK_DIR" )
145169
146170 if not emsdk and not conda_emsdk_dir :
147- print ("❌ EMSDK and CONDA_EMSDK_DIR not found. That means EMSDK is not installed." )
171+ print ("EMSDK and CONDA_EMSDK_DIR not found. That means EMSDK is not installed." )
148172 print (" ➤ If you are using **Pixi**, run:" )
149173 print (" pixi add emsdk && pixi install" )
150174 print (" ➤ If you are using **Conda**, run:" )
@@ -153,20 +177,20 @@ def check_emsdk():
153177 print (" https://emscripten.org/index.html#" )
154178 sys .exit (1 )
155179
156- print (f"✅ EMSDK is installed and CONDA_EMSDK_DIR is found" )
180+ print (f"EMSDK is installed and CONDA_EMSDK_DIR is found" )
157181
158182 try :
159- print ("🔧 Attempting to activate EMSDK with: emsdk activate latest" )
183+ print ("Attempting to activate EMSDK with: emsdk activate latest" )
160184 result = subprocess .run (["./emsdk" , "activate" , "latest" ], cwd = conda_emsdk_dir , check = False , capture_output = True , text = True )
161185 if result .returncode != 0 :
162- print ("❌ Failed to activate EMSDK:" )
186+ print ("Failed to activate EMSDK:" )
163187 choice = input ("Do you want to install and activate EMSDK now? (y/n) " )
164188 if choice == 'y' :
165189 try :
166190 subprocess .run (["./emsdk" , "install" , "latest" ], cwd = conda_emsdk_dir , check = True )
167- print ("✅ EMSDK install & activation succeeded. You can run the script now." )
191+ print ("EMSDK install & activation succeeded. You can run the script now." )
168192 except subprocess .CalledProcessError as e :
169- print ("❌ Failed to activate EMSDK:" )
193+ print ("Failed to activate EMSDK:" )
170194 print (" ➤ Please run the following manually in your terminal and try again:" )
171195 print (" cd $CONDA_EMSDK_DIR && ./emsdk install latest && ./emsdk activate latest" )
172196 else :
@@ -175,9 +199,9 @@ def check_emsdk():
175199
176200 sys .exit (1 )
177201 else :
178- print ("✅ EMSDK activation succeeded." )
202+ print ("EMSDK activation succeeded." )
179203 except Exception as e :
180- print (f"❌ Error while running EMSDK activation: { e } " )
204+ print (f"Error while running EMSDK activation: { e } " )
181205 sys .exit (1 )
182206
183207
0 commit comments