Skip to content

Commit

Permalink
__BRYTHON__.runPythonSource() 2nd argument can be a JS object, interp…
Browse files Browse the repository at this point in the history
…reted as script attributes. Can be used to pass execution options. Related to issue #2421
  • Loading branch information
PierreQuentel committed Apr 27, 2024
1 parent 1ba55cd commit 3092dfb
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 25 deletions.
22 changes: 17 additions & 5 deletions www/doc/en/jsobjects.md
Original file line number Diff line number Diff line change
Expand Up @@ -368,17 +368,29 @@ s1.addEventListener('load', function(script){
> translation to Javascript. The result can be executed by `eval()`
> to trigger the script execution.
*`__BRYTHON__`.runPythonSource(_src_[, _script_id_])*
*`__BRYTHON__`.runPythonSource(_src_[, _attributes_])*

> executes Python source code `src` as if it was a script with optional
> identifier _script_id_. Returns the Javascript object that represents the
> executes Python source code `src` as if it was a script with the specified
> _attributes_. If _attributes_ is a string, it is the script `id`, otherwise
> it must be a Javascript object.
> [Execution options](options.html) such as debug level, path for imports,
> etc. can be passed as attributes, for instance
<blockquote>
```xml
var src = "import some_module"
__BRYTHON__.runPythonSource(src, {pythonpath: 'my_modules', debug: 2})
```
</blockquote>

> Returns the Javascript object that represents the
> module (also available as `__BRYTHON__.getPythonModule(script_id)`)
<blockquote>
```xml
<script type="text/py-disabled" id="s1">
from browser import alert
import re

string = "script s2"
integer = 8
Expand All @@ -395,7 +407,7 @@ alert('run py-disabled')
document.getElementById('btn').addEventListener('click',
function(ev){
var script = document.getElementById('s1'),
modobj = __BRYTHON__.runPythonSource(script.innerText, 's1')
modobj = __BRYTHON__.runPythonSource(script.innerText, {id: 's1'})
console.log(modobj)
}
)
Expand Down
23 changes: 18 additions & 5 deletions www/doc/fr/jsobjects.md
Original file line number Diff line number Diff line change
Expand Up @@ -370,18 +370,31 @@ s1.addEventListener('load', function(script){
> contient la traduction de ce code source en Javascript. Le résultat
> peut être exécuté par `eval()` pour déclencher l'exécution du script.
*`__BRYTHON__`.runPythonSource(_src_[, _script_id_])*
*`__BRYTHON__`.runPythonSource(_src_[, _attributs_])*

> exécute le code source Python `src` comme s'il s'agissait d'un script avec
> comme identifiant optionnel _script_id_. Retourne l'objet Javascript qui
> représente le module (également accessible par
> `__BRYTHON__.getPythonModule(script_id)`)
> les _attributs_ spécifiés. Si _attributs_ est une chaine de caractères, elle
> correspond à l'attribut _id_. Sinon il doit s'agir d'un objet Javascript.
> Les [options d'exécution](options.html) telles que niveau de débogage,
> chemin pour les imports, etc. peuvent être passées comme attributs, par
> exemple
<blockquote>
```xml
var src = "import un_module"
__BRYTHON__.runPythonSource(src, {pythonpath: 'mes_modules', debug: 2})
```
</blockquote>


> Retourne l'objet Javascript qui représente le module (également accessible
> par `__BRYTHON__.getPythonModule(script_id)`)
<blockquote>
```xml
<script type="text/py-disabled" id="s1">
from browser import alert
import re

string = "script s2"
integer = 8
Expand Down
2 changes: 0 additions & 2 deletions www/gallery/inject_scripts.html
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,6 @@
console.log('click')
var res = __BRYTHON__.runPythonSource(document.getElementById('s1').textContent)
console.log('js', res)

// brython({ids:['s1']})
}
)
</script>
Expand Down
19 changes: 13 additions & 6 deletions www/src/brython.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,16 @@ $B.getPythonModule=function(name){return $B.imported[name]}
$B.python_to_js=function(src,script_id){
return "(function() {\n"+from_py(src,script_id)+"\nreturn locals}())"}
$B.pythonToJS=$B.python_to_js
$B.runPythonSource=function(src,script_id){var js=from_py(src,script_id)+'\nreturn locals'
var func=new Function('$B','_b_',js)
$B.imported[script_id]=func($B,$B.builtins)
function fakeScript(filename){this.options={}}
fakeScript.prototype.getAttribute=function(key){return this.options[key]?? null}
fakeScript.prototype.dispatchEvent=function(){}
$B.runPythonSource=function(src,options){var script_id
if(options){if(typeof options=='string'){script_id=options}else if(options.constructor===Object){if(options.hasOwnProperty('id')){script_id=options.id
delete options.id}}else{console.debug('invalid options argument:',options)}}
var script=new fakeScript(),url=$B.script_path=globalThis.location.href.split('#')[0]
if(options){for(var[key,value]of Object.entries(options)){script.options[key]=value}}
script_id=script_id ?? 'python_script_'+$B.UUID()
$B.run_script(script,src,script_id,url,true)
return $B.imported[script_id]}})(__BRYTHON__)
;
__BRYTHON__.ast_classes={Add:'',And:'',AnnAssign:'target,annotation,value?,simple',Assert:'test,msg?',Assign:'targets*,value,type_comment?',AsyncFor:'target,iter,body*,orelse*,type_comment?',AsyncFunctionDef:'name,args,body*,decorator_list*,returns?,type_comment?,type_params*',AsyncWith:'items*,body*,type_comment?',Attribute:'value,attr,ctx',AugAssign:'target,op,value',Await:'value',BinOp:'left,op,right',BitAnd:'',BitOr:'',BitXor:'',BoolOp:'op,values*',Break:'',Call:'func,args*,keywords*',ClassDef:'name,bases*,keywords*,body*,decorator_list*,type_params*',Compare:'left,ops*,comparators*',Constant:'value,kind?',Continue:'',Del:'',Delete:'targets*',Dict:'keys*,values*',DictComp:'key,value,generators*',Div:'',Eq:'',ExceptHandler:'type?,name?,body*',Expr:'value',Expression:'body',FloorDiv:'',For:'target,iter,body*,orelse*,type_comment?',FormattedValue:'value,conversion,format_spec?',FunctionDef:'name,args,body*,decorator_list*,returns?,type_comment?,type_params*',FunctionType:'argtypes*,returns',GeneratorExp:'elt,generators*',Global:'names*',Gt:'',GtE:'',If:'test,body*,orelse*',IfExp:'test,body,orelse',Import:'names*',ImportFrom:'module?,names*,level?',In:'',Interactive:'body*',Invert:'',Is:'',IsNot:'',JoinedStr:'values*',LShift:'',Lambda:'args,body',List:'elts*,ctx',ListComp:'elt,generators*',Load:'',Lt:'',LtE:'',MatMult:'',Match:'subject,cases*',MatchAs:'pattern?,name?',MatchClass:'cls,patterns*,kwd_attrs*,kwd_patterns*',MatchMapping:'keys*,patterns*,rest?',MatchOr:'patterns*',MatchSequence:'patterns*',MatchSingleton:'value',MatchStar:'name?',MatchValue:'value',Mod:'',Module:'body*,type_ignores*',Mult:'',Name:'id,ctx',NamedExpr:'target,value',Nonlocal:'names*',Not:'',NotEq:'',NotIn:'',Or:'',ParamSpec:'name',Pass:'',Pow:'',RShift:'',Raise:'exc?,cause?',Return:'value?',Set:'elts*',SetComp:'elt,generators*',Slice:'lower?,upper?,step?',Starred:'value,ctx',Store:'',Sub:'',Subscript:'value,slice,ctx',Try:'body*,handlers*,orelse*,finalbody*',TryStar:'body*,handlers*,orelse*,finalbody*',Tuple:'elts*,ctx',TypeAlias:'name,type_params*,value',TypeIgnore:'lineno,tag',TypeVar:'name,bound?',TypeVarTuple:'name',UAdd:'',USub:'',UnaryOp:'op,operand',While:'test,body*,orelse*',With:'items*,body*,type_comment?',Yield:'value?',YieldFrom:'value',alias:'name,asname?',arg:'arg,annotation?,type_comment?',arguments:'posonlyargs*,args*,vararg?,kwonlyargs*,kw_defaults*,kwarg?,defaults*',boolop:['And','Or'],cmpop:['Eq','NotEq','Lt','LtE','Gt','GtE','Is','IsNot','In','NotIn'],comprehension:'target,iter,ifs*,is_async',excepthandler:['ExceptHandler'],expr:['BoolOp','NamedExpr','BinOp','UnaryOp','Lambda','IfExp','Dict','Set','ListComp','SetComp','DictComp','GeneratorExp','Await','Yield','YieldFrom','Compare','Call','FormattedValue','JoinedStr','Constant','Attribute','Subscript','Starred','Name','List','Tuple','Slice'],expr_context:['Load','Store','Del'],keyword:'arg?,value',match_case:'pattern,guard?,body*',mod:['Module','Interactive','Expression','FunctionType'],operator:['Add','Sub','Mult','MatMult','Div','Mod','Pow','LShift','RShift','BitOr','BitXor','BitAnd','FloorDiv'],pattern:['MatchValue','MatchSingleton','MatchSequence','MatchMapping','MatchClass','MatchStar','MatchAs','MatchOr'],stmt:['FunctionDef','AsyncFunctionDef','ClassDef','Return','Delete','Assign','TypeAlias','AugAssign','AnnAssign','For','AsyncFor','While','If','With','AsyncWith','Match','Raise','Try','TryStar','Assert','Import','ImportFrom','Global','Nonlocal','Expr','Pass','Break','Continue'],type_ignore:['TypeIgnore'],type_param:['TypeVar','ParamSpec','TypeVarTuple'],unaryop:['Invert','Not','UAdd','USub'],withitem:'context_expr,optional_vars?'}
Expand All @@ -173,8 +180,8 @@ $B.unicode_bidi_whitespace=[9,10,11,12,13,28,29,30,31,32,133,5760,8192,8193,8194
;
__BRYTHON__.implementation=[3,12,3,'dev',0]
__BRYTHON__.version_info=[3,12,0,'final',0]
__BRYTHON__.compiled_date="2024-04-24 21:31:15.551547"
__BRYTHON__.timestamp=1713987075551
__BRYTHON__.compiled_date="2024-04-27 08:04:32.357791"
__BRYTHON__.timestamp=1714197872357
__BRYTHON__.builtin_module_names=["_ajax","_ast","_base64","_binascii","_io_classes","_json","_jsre","_locale","_multiprocessing","_posixsubprocess","_profile","_random","_sre","_sre_utils","_string","_strptime","_svg","_symtable","_tokenize","_webcomponent","_webworker","_zlib_utils","_zlib_utils1","_zlib_utils_kozh","array","builtins","dis","encoding_cp932","encoding_cp932_v2","hashlib","html_parser","marshal","math","modulefinder","posix","pyexpat","python_re","python_re_new","unicodedata"]
;

Expand Down Expand Up @@ -892,7 +899,7 @@ scripts.push(script)}else{console.log(`no script with id '${id}'`)
throw _b_.KeyError.$factory(`no script with id '${id}'`)}}}else if($B.isWebWorker){}else{scripts=python_scripts.slice()}
run_scripts(scripts)}
function convert_option(option,value){
if(option=='debug'){if(typeof value=='string' && value.match(/^\d+$/)){return parseInt(value)}else{if(value !==null && value !==undefined){console.debug(`Invalid value for debug: ${value}`)}}}else if(option=='cache' ||
if(option=='debug'){if(typeof value=='string' && value.match(/^\d+$/)){return parseInt(value)}else if(typeof value=='number'){return value}else{if(value !==null && value !==undefined){console.debug(`Invalid value for debug: ${value}`)}}}else if(option=='cache' ||
option=='indexeddb' ||
option=='static_stdlib_import'){if(value=='1' ||value.toLowerCase()=='true'){return true}else if(value=='0' ||value.toLowerCase()=='false'){return false}else{console.debug(`Invalid value for ${option}: ${value}`)}}else if(option=='ids' ||option=='pythonpath' ||option=='args'){
if(typeof value=='string'){if(value.trim().length==0){return[]}
Expand Down
42 changes: 38 additions & 4 deletions www/src/brython_builtins.js
Original file line number Diff line number Diff line change
Expand Up @@ -431,10 +431,44 @@ $B.python_to_js = function(src, script_id){

$B.pythonToJS = $B.python_to_js

$B.runPythonSource = function(src, script_id){
var js = from_py(src, script_id) + '\nreturn locals'
var func = new Function('$B', '_b_', js)
$B.imported[script_id] = func($B, $B.builtins)
function fakeScript(filename){
this.options = {}
}

fakeScript.prototype.getAttribute = function(key){
return this.options[key] ?? null
}

fakeScript.prototype.dispatchEvent = function(){
// ignore
}

$B.runPythonSource = function(src, options){
var script_id

if(options){
if(typeof options == 'string'){
script_id = options
}else if(options.constructor === Object){
if(options.hasOwnProperty('id')){
script_id = options.id
delete options.id
}
}else{
console.debug('invalid options argument:', options)
}
}
// Simulate an HTML <script> tag so we can use $B.run_script()
var script = new fakeScript(),
url = $B.script_path = globalThis.location.href.split('#')[0]
// Set options to the fake <script> tag
if(options){
for(var [key, value] of Object.entries(options)){
script.options[key] = value
}
}
script_id = script_id ?? 'python_script_' + $B.UUID()
$B.run_script(script, src, script_id, url, true)
return $B.imported[script_id]
}

Expand Down
2 changes: 2 additions & 0 deletions www/src/py2js.js
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,8 @@ function convert_option(option, value){
if(option == 'debug'){
if(typeof value == 'string' && value.match(/^\d+$/)){
return parseInt(value)
}else if(typeof value == 'number'){
return value
}else{
if(value !== null && value !== undefined){
console.debug(`Invalid value for debug: ${value}`)
Expand Down
1 change: 0 additions & 1 deletion www/src/py_import.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ $B.make_import_paths = function(filename){
path.splice(ix, 1, ...pythonpath)
}
}

// Use the defaut finder using sys.path if protocol is not file://
if($B.protocol !== "file"){
meta_path.push($B.finders.path)
Expand Down
4 changes: 2 additions & 2 deletions www/src/version_info.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
__BRYTHON__.implementation = [3, 12, 3, 'dev', 0]
__BRYTHON__.version_info = [3, 12, 0, 'final', 0]
__BRYTHON__.compiled_date = "2024-04-24 21:31:15.551547"
__BRYTHON__.timestamp = 1713987075551
__BRYTHON__.compiled_date = "2024-04-27 08:04:32.357791"
__BRYTHON__.timestamp = 1714197872357
__BRYTHON__.builtin_module_names = ["_ajax",
"_ast",
"_base64",
Expand Down

0 comments on commit 3092dfb

Please sign in to comment.