Skip to content

Instantly share code, notes, and snippets.

@k7hoven
Last active April 18, 2016 14:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save k7hoven/21c5532ce19b306b08bb4e82cfe5a609 to your computer and use it in GitHub Desktop.
Save k7hoven/21c5532ce19b306b08bb4e82cfe5a609 to your computer and use it in GitHub Desktop.
oneline.py .-- draft Python 3.5+ module to execute/evaluate lines of code with automatic imports
#!/usr/bin/env python3
# coding: utf-8
# Written by Koos Zevenhoven, after the python-ideas discussion
# and code by 'Random832' here:
# https://mail.python.org/pipermail//python-ideas/2016-April/039448.html
import types
import sys
import importlib
class ImportDict(dict):
def __init__(self, check_fun):
self._check = check_fun
def __getitem__(self, x):
try:
return super().__getitem__(x)
except KeyError as e:
if not self._check(x):
raise
mod = autoimport(x, e)
self[x] = mod
return mod
class ImportModule(types.ModuleType):
def __getattr__(self, x):
try:
return self.__getattribute__(x)
except AttributeError as e:
self.__setattr__(x, None)
return autoimport('.'.join((self.__name__, x)), e, parent = self)
def autoimport(name, exc_when_no_module, *, parent = None):
try:
if parent:
# Avoid infinite recursion by pre-creating the name binding
setattr(parent, name, None)
mod = importlib.import_module(name)
mod.__class__ = ImportModule
return mod
except ImportError as e:
if parent:
delattr(parent, name) # clean up name binding
if e.msg.startswith("No module named "):
raise exc_when_no_module from None
else:
raise e from None
def isallowedmodule(name):
# Here, one may want to check whether name is a stdlib module
# For now, all imports are allowed
return True
def autoimport_run(code_lines, *,
check_fun = isallowedmodule,
display = print):
aidict = ImportDict(check_fun)
for line in code_lines:
try:
display(eval(line, aidict))
except SyntaxError:
exec(line, aidict)
if __name__ == '__main__':
# autoimport_run also takes a 'display' argument, which by default
# is print, but it could also be something else. One could, for
# instance, imagine having each element from an iterable be printed
# on its own line.
autoimport_run(sys.argv[1:])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment