translators icon indicating copy to clipboard operation
translators copied to clipboard

PyExecJS has been end-of-life since 2018

Open freddyheppell opened this issue 2 years ago • 3 comments

PyExecJS is no longer maintained and hasn't been updated since 2018, since the main reason for that package was to deal with Node not being available for Windows, which is no longer an issue. They recommend to just call Node through subprocess directly, passing in the code you want to execute with stdin.

I've had a look at the calls to execjs and the only one I think might be an issue is this one because of the use of .call(), however I think this can be replicated by creating the function call in JS and appending it to the code that is currently passed into .compile().

If you would like, I'd be happy to look into this further and open a PR.

freddyheppell avatar Oct 18 '22 09:10 freddyheppell

@freddyheppell Hello friend Yes, I also had been sad to know that it was EOL, but I really didn't find a better package about javascript. I understand your idea, you think I need it because of call(), but it's actually compile() that I need it.

UlionTse avatar Oct 19 '22 23:10 UlionTse

Sorry I wasn't completely clear in my original message.

The PyExecJS package was made at a point where Node wasn't available for Windows, so you'd have to use a different JS runtime for windows - PyExecJS was designed to automatically choose and provide the same API for each.

Now everyone can use Node, you can just call it directly using subprocess. For example

sp = subprocess.run('node', text=True, input="console.log('hello world')", capture_output=True)
print(sp.stdout) # prints hello world

However, the downside to this approach is that you can't access the contents of variables straight away. Instead, you'd have to cause them to be outputted, e.g. by adding some extra JS on the end console.log() the output you need. For example, for the call in GoogleTranslateV2.get_info(), you would need to execute something like

js = f"""
var o={data_str};
console.log(\{"bl": o["cfb2h"], "f.sid": o["FdrFJe"]\});
"""
sp = subprocess.run('node', text=True, input=js, capture_output=True)
return json.loads(sp.stdout)

Although of course you would actually write some helper functions to do this.

I am happy to have a go at this myself and submit a PR.

freddyheppell avatar Oct 20 '22 13:10 freddyheppell

@freddyheppell Anyway, welcome your PR. The following problems may provide you with some ideas. Good luck!

import json
import subprocess
import execjs


def run_js(js_code, method='subprocess'):
    if method not in ('subprocess', 'execjs'):
        raise
    if method == 'subprocess':
        result = subprocess.run('node', input=f'console.log({js_code});', text=True, capture_output=True).stdout
        return result, type(result)
    result = execjs.eval(js_code)
    return result, type(result)


if __name__ == '__main__':
    js1 = """{"bl": "cfb2h", "sid": "FdrFJe"}"""
    js2 = "'red yellow blue'.split(' ')"

    print('subprocess: ', run_js(js_code=js1, method='subprocess'))  # keys lack double quotes, not okay
    print('execjs: ', run_js(js_code=js1, method='execjs'))  # dict, okay

    print('subprocess: ', run_js(js_code=js2, method='subprocess'))  # str, after eval() ok
    print('execjs: ', run_js(js_code=js2, method='execjs'))  # list, ok

UlionTse avatar Oct 21 '22 09:10 UlionTse