3
0
mirror of https://github.com/triqs/dft_tools synced 2024-12-25 05:43:40 +01:00

ipython triqs magic v1

- first version of triqs magic for the notebook
- add add_preamble to the wrap_generator.
This commit is contained in:
Olivier Parcollet 2014-06-01 15:59:11 +02:00
parent 3fe400d34c
commit 28a12c7b2f
4 changed files with 229 additions and 0 deletions

View File

@ -17,11 +17,14 @@ find_package(PythonWrapperMacro)
SET(PYTHON_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/__init__.py
${CMAKE_CURRENT_BINARY_DIR}/version.py
${CMAKE_CURRENT_BINARY_DIR}/magic.py
)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.py.in ${CMAKE_CURRENT_BINARY_DIR}/version.py)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/utility/mpi.py.in ${CMAKE_CURRENT_BINARY_DIR}/utility/mpi.py)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/magic.py.in ${CMAKE_CURRENT_BINARY_DIR}/magic.py @ONLY)
install (FILES ${PYTHON_SOURCES} DESTINATION ${TRIQS_PYTHON_LIB_DEST})
install (FILES ${PYTHON_SOURCES} DESTINATION ${TRIQS_PYTHON_LIB_DEST})
# All subdirs

217
pytriqs/magic.py.in Normal file
View File

@ -0,0 +1,217 @@
"""
=====================
Triqs magic
=====================
{TRIQS_DOC}
"""
import imp,os,sys,subprocess, hashlib
from IPython.core.error import UsageError
from IPython.core.magic import Magics, magics_class, line_magic, cell_magic
from IPython.core import display, magic_arguments
from IPython.utils import py3compat
from IPython.utils.io import capture_output
from IPython.utils.path import get_ipython_cache_dir
__version__ = '0.1.0'
triqs_path = "@CMAKE_INSTALL_PREFIX@"
converter_include_path = triqs_path + "/include/pytriqs/converters/"
generator_path = triqs_path + "/share/triqs/wrap_generator"
cmakelist = """
list(APPEND CMAKE_MODULE_PATH %s/share/triqs/cmake)
cmake_minimum_required(VERSION 2.8)
project(triqs_magic CXX)
set(CMAKE_BUILD_TYPE Release)
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
find_package(TRIQS REQUIRED)
include_directories(${CMAKE_SOURCE_DIR} ${TRIQS_INCLUDE_ALL})
add_library(ext MODULE ext_wrap.cpp)
#add_library(ext MODULE ext.cpp ext_wrap.cpp)
set_target_properties(ext PROPERTIES PREFIX "") #eliminate the lib in front of the module name
target_link_libraries(ext ${TRIQS_LIBRARY_ALL})
"""%triqs_path
mod_dict = {
'gf' :
"""
module.use_module('gf')
module.add_using('namespace triqs::gfs')
""",
'parameters' :
"""
module.use_module('parameters')
module.add_using('namespace triqs::params')
""",}
def desc_file(c_decl, use) :
s = """
from wrap_generator import *
module = module_(full_name = "ext", doc = "")
module.add_include("<triqs/arrays.hpp>")
module.add_using("namespace triqs::arrays")
module.add_preamble('#include "./ext.cpp"')
"""
mod_list = sum((x.split(',') for x in use), [])
for m in mod_list :
s+= mod_dict[m]
for f in c_decl :
s+= 'module.add_function("%s")\n'%f
return s + "module.generate_code()\n"
@magics_class
class TriqsMagics(Magics):
def __init__(self, shell):
super(TriqsMagics, self).__init__(shell=shell)
self._reloads = {}
self._code_cache = {}
self._lib_dir = os.path.join(get_ipython_cache_dir(), 'triqs')
if not os.path.exists(self._lib_dir):
os.makedirs(self._lib_dir)
def _import_all(self, module, verbosity=0):
imported = []
for k, v in module.__dict__.items():
if not k.startswith('__'):
self.shell.push({k: v})
imported.append(k)
if verbosity > 0 and imported:
print("\nOk. The following objects are ready to use: %s" % ", ".join(imported))
def extract_signature(self,code):
acc = []
for l in code.splitlines() :
ll = l.strip()
if ll.startswith("#") or ll.startswith("using") : continue
acc.append(l)
if l.count('{') : break
s = ''.join(acc).split('{',1)[0] # everything before {
#print "signature", s
return [s]
@magic_arguments.magic_arguments()
@magic_arguments.argument(
"-v", "--verbosity", action="count", default=0,
help="increase output verbosity"
)
@magic_arguments.argument(
'-u', "--use", action='append', default=[],
help="""Modules used"""
)
@cell_magic
def triqs(self, line, cell=None):
"""Compile and import everything from a Triqs code cell.
The content of the cell is written to a `.cpp` file in the
directory `IPYTHONDIR/triqs` using a filename with the hash of the
code. A python wrapper is then generated from the function signature.
Those files are then compiled.
The resulting module is imported and all of its symbols are injected into the user's namespace.
Usage
=====
Prepend ``%%triqs`` to your triqs code in a cell::
``%%triqs
! put your code here.
``
"""
try:
# custom saved arguments
saved_defaults = vars(
magic_arguments.parse_argstring(self.triqs,
self.shell.db['triqs']))
self.triqs.parser.set_defaults(**saved_defaults)
except KeyError:
saved_defaults = {'verbosity': 0}
if '-v' in line:
self.triqs.parser.set_defaults(verbosity=0)
args = magic_arguments.parse_argstring(self.triqs, line)
code = cell if cell.endswith('\n') else cell + '\n'
key = code, line, sys.version_info, sys.executable
c_decl = self.extract_signature(code)
if args.verbosity>1 :
print "Found function of signature"
for f in c_decl :
print f
module_name = "ext"
module_dirname = os.path.join(self._lib_dir, "_triqs_magic_" + hashlib.md5(str(key).encode('utf-8')).hexdigest())
module_path = os.path.join(module_dirname, 'ext.so')
try :
os.mkdir(module_dirname)
except :
pass
old_cwd = os.getcwd()
try:
os.chdir(module_dirname)
with open('ext_desc.py', 'w') as f:
f.write(desc_file(c_decl, args.use))
with open('CMakeLists.txt', 'w') as f:
f.write(cmakelist)
with open('ext.cpp', 'w') as f:
f.write(code)
# Call the wrapper generator
command_generator = """
PYTHONPATH={generator_path} python ext_desc.py {generator_path}/wrapper.mako.cpp ext_wrap.cpp {generator_path}/py_converter_wrapper.mako.hpp conv.hpp {converter_include_path}
""".format(**globals())
try :
out_generator = subprocess.check_output(command_generator, stderr=subprocess.STDOUT, shell=True)
except subprocess.CalledProcessError as E :
print '---------- Wrapper generator error -------\n' + E.output
return
if args.verbosity>0 : print "---------- Wrapper generator ------", out_generator
# Call cmake
command_cmake = "cmake . -DTRIQS_PATH=" + triqs_path
try :
out_cmake = subprocess.check_output(command_cmake, stderr=subprocess.STDOUT, shell=True)
except subprocess.CalledProcessError as E :
print '---------- Cmake error -------\n' + E.output
return
if args.verbosity>0 : print "---------- Cmake ------", out_cmake
# Call make
command_make = "make -j2"
try :
out_make = subprocess.check_output(command_make, stderr=subprocess.STDOUT, shell=True)
except subprocess.CalledProcessError as E :
print '---------- Make error -------\n' + E.output
return
if args.verbosity>0 : print "---------- Make ------", out_make
finally:
os.chdir(old_cwd)
self._code_cache[key] = module_path
module = imp.load_dynamic(module_name, module_path)
self._import_all(module, verbosity=args.verbosity)
__doc__ = __doc__.format(TRIQS_DOC=' ' * 8 + TriqsMagics.triqs.__doc__)
def load_ipython_extension(ip):
"""Load the extension in IPython."""
ip.register_magics(TriqsMagics)

View File

@ -591,6 +591,7 @@ class module_ :
self.python_functions = {}
self.hidden_python_functions = {}
self.module_path_list = []
self._preamble = ''
def add_class(self, cls):
"""
@ -666,6 +667,12 @@ class module_ :
"""
self.using.append(ns)
def add_preamble(self, preamble) :
"""
Add the using statement into the generated wrapper (and NOT the header).
"""
self._preamble += preamble + '\n'
def use_module(self, modulename) :
"""
From the name of the module :

View File

@ -19,6 +19,8 @@ using ${ns};
#include <triqs/utility/signal_handler.hpp>
using namespace triqs::py_tools;
${module._preamble}
//--------------------- a dict of python function used in the module but not exposed to user (cf init function) ----------------
%if len(module.python_functions) + len(module.hidden_python_functions) > 0 :