Search code examples
pythonpython-3.xevalpython-importhy

python3/hy - When using hy.eval, imports and globals are not shared


I understand how to use hy.read_str and hy.eval from python to evaluate an hy expression from within python. However, when I use this methodology, imports and globals are not shared between the hy and python environments. Consider this example:

import hy
def hyeval(x=None):
    if x is None:
        return None
    try:
        return hy.eval(hy.read_str(str(x)))
    except Exception as e:
        print('!!! exception: {}'.format(e))
        return None
import datetime  # this is ignored within `hyeval` calls
now = hyeval('((. datetime datetime now))')
print('result: {}'.format(now))

This prints ...

!!! exception: name 'datetime' is not defined
result: None

Even if I do the following, it generates the same exception ...

... etc. ...
hyeval('(import datetime)')
now = hyeval('((. datetime datetime now))')
print('result: {}'.format(now))

I have to explicitly import datetime within the string passed to my hyeval function ...

... etc. ...
now = hyeval('((do (import datetime) (. datetime datetime now)))')
print('result: {}'.format(now))

This properly prints the following ...

result: 2017-09-22 09:41:49.771139

If I re-invoke the ((. datetime datetime now)) call via a string, I have to keep repeating the (import datetime) call via a (do ...) block.

Is there any way when invoking hy strings from within python that imports and globals can be remembered between successive calls to hy.read_str/hy.eval, or that the python globals and imports can be recognized when invoking strings via hy?


Solution

  • I figured it out: if the second argument to hy.eval is globals(), the python environment's globals and imports are available when performing the hy string evaluation ...

    import hy
    def hyeval(x=None, g=None):
        if x is None:
            return None
        try:
            if not g:
                g = globals()
            return hy.eval(hy.read_str(str(x)), g)
        except Exception as e:
            print('!!! exception: {}'.format(e))
            return None
    import datetime
    now = hyeval('((. datetime datetime now))')
    print('result: {}'.format(now))
    

    This correctly prints the following ...

    result: 2017-09-22 10:25:36.752656