Package: jsbuilder
jsbuilder — convert Python code to JavaScript stringsJust annotate a Python function with@jsand then callstr()on it to get
a fully-working JavaScript version of that function. Why?Because why not.(If you like this, check outhtbuild. It's the
HTML equivalent of jsbuilder: an HTML string builder for Python folks who don't
like templating languages.)InstallationJust PIP it!pipinstalljsbuilderSimple Examplefromjsbuilderimportjs@jsdefjs_code():defsum_and_check_if_42(a,b):c=a+bifc==42:returnTrueelse:returnFalseresult=sum_and_check_if_42(10,30)console.log("Is it 42?",result)Now you can just callstr(js_code)orprint(js_code)to see the JavaScript
version of that code:(Note: the code below has been pretty-printed for clarity)functionsum_and_check_if_42(a,b){varc=(a+b);if(c===42){returntrue}else{returnfalse}};result=sum_and_check_if_42(10,30);console.log("Is it 42?",result)Complex ExampleHere's some code that was copy/pasted directly from the D3 documentation,
then converted to Python:fromjsbuilderimportjs@jsdefjs_code():bleed=100width=960height=760pack=(d3.layout.pack().sort(None).size([width,height+bleed*2]).padding(2))svg=(d3.select("body").append("svg").attr("width",width).attr("height",height).append("g").attr("transform","translate(0,"+(-bleed)+")"))defjson_read(js,error,json):iferror:raiseerrornode=(svg.selectAll(".node").data(pack.nodes(flatten(json))).filter(lambdad:notd.children).enter().append("g").attr("class","node").attr("transform",lambdad:"translate("+d.x+","+d.y+")"))(node.append("circle").attr("r",lambdad:d.r))(node.append("text").text(lambdad:d.name).style("font-size",lambdad:Math.min(2*d.r,(2*d.r-8)/getComputedTextLength()*24)+"px").attr("dy",".35em"))d3.json("README.json",json_read)defflatten(root):nodes=[]defrecurse(node):ifnode.children:node.children.forEach(recurse)else:nodes.push({"name":node.name,"value":node.size})recurse(root)return{"children":nodes}And the JS-converted version is:varbleed=100;varwidth=960;varheight=760;varpack=d3.layout.pack().sort(null).size([width,(height+(bleed*2))]).padding(2);varsvg=d3.select("body").append("svg").attr("width",width).attr("height",height).append("g").attr("transform",(("translate(0,"+(-bleed))+")"));functionjson_read(js,error,json){if(error){thrownewError(error)}else{};varnode=svg.selectAll(".node").data(pack.nodes(flatten(json))).filter(((d)=>((!d.children)))).enter().append("g").attr("class","node").attr("transform",((d)=>((((("translate("+d.x)+",")+d.y)+")"))));node.append("circle").attr("r",((d)=>(d.r)));node.append("text").text(((d)=>(d.name))).style("font-size",((d)=>((Math.min((2*d.r),((((2*d.r)-8)/getComputedTextLength())*24))+"px")))).attr("dy",".35em")};d3.json("README.json",json_read);functionflatten(root){varnodes=[];functionrecurse(node){if(node.children){node.children.forEach(recurse)}else{nodes.push({"name":node.name,"value":node.size})}};recurse(root);return{"children":nodes}}SupportSome Python features are not yet supported (likeassertandasync) and others will likely never be, since they don't have an obvious analogue in JS (like slices, and theinoperator).For a full list, see thesource code.Also note that Python has some keywords likefromthat are not keywords in JavaScript, so you cannot use those directly in your code for things like variable names and object members. If you really need to, you'll have to find work-arounds. For example, instead ofArray.from()you'll have to useArray['from']().For loopsForloops are a tricky one! They're supported, but Python and JS have different enough syntaxes forforloops that a perfect conversion isn't possible. Instead, Python'sforis being mapped to JS's.forEach(). So you can do:forwordin["hello","hi","whattup"]:console.log(word)...since that translates to:["hello","hi","whattup"].forEach((word,_i)=>console.log(word))And note that if you're using things likerange()andenumerate(), those don't exist in JS so you'll have to define them first. For example:defrange(n):returnArray['from'](Array(n).keys())foriinrange(10):console.log(i)...which translates to:functionrange(n){returnArray["from"](Array(n).keys())};range(10).forEach((i,_i)=>{console.log(i)})Related: did you notice how you get a free_ivariable in the JS version of thefor/forEachloop? Feel free to use that variable inside the Python version of your JS code, sinceenumerate()doesn't work!Variable declarationsCode like this in Python gets translated correctly to JS:# Pythona=0a=10// JavaScriptvara=0;a=10And so do slightly more complex cases like:# Pythondeffoo(b):a=0a=b=c=10// JavaScriptfunctionfoo(b){vara=0;a=10;b=10;varc=10}However, because of the way Python and JS variable hoisting work, variable
declarations in places likeif/elseblocks are not handled differently in
the two worlds. In particular, this Python codeifx:a=10else:a=100becomes this JS codeif(x){vara=10}else{a=100}...which is correct, but rather odd!If for any reason you need to solve this, just declare the variable above theif:# Pythona=Noneifx:a=10else:a=100// JavaScriptvara=nullif(x){a=10}else{a=100}