Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PyExecJS has been end-of-life since 2018 #91

Open
freddyheppell opened this issue Oct 18, 2022 · 3 comments
Open

PyExecJS has been end-of-life since 2018 #91

freddyheppell opened this issue Oct 18, 2022 · 3 comments

Comments

@freddyheppell
Copy link

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.

@UlionTse
Copy link
Owner

@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.

@freddyheppell
Copy link
Author

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.

@UlionTse
Copy link
Owner

@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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants