Newer
Older
#! /usr/bin/env python
"""Creates a simple template for exporting a class to Python
"""
import optparse
import os
import re
import sys
def get_exportfile(headerfile):
"""
For the given header path create a path to the corresponding
export file in the PythonInterface
"""
# We need to find the submodule from the Mantid package
submodule = get_submodule(headerfile)
frameworkdir = get_frameworkdir(headerfile)
exportpath = os.path.join(frameworkdir, 'PythonInterface', 'mantid', submodule, 'src')
exportfile = os.path.join(exportpath, os.path.basename(headerfile).replace('.h','.cpp'))
return exportfile
def get_unittest_file(headerfile):
"""
For the given header path create a path to the corresponding
Python unit test file
"""
frameworkdir = get_frameworkdir(headerfile)
testpath = os.path.join(frameworkdir, 'PythonInterface', 'test', 'python')
return os.path.join(testpath, os.path.basename(headerfile).replace('.h','Test.py'))
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
def get_submodule(headerfile):
"""
Returns the corresponding Python submodule for the header
"""
return get_namespace(headerfile).lower()
def get_namespace(headerfile):
"""
Returns the Mantid namespace that the header resides in
"""
matches = re.match(r".*inc/Mantid([a-z,A-z]*)/.*\.h", headerfile)
if matches:
namespace = matches.group(1)
else:
raise RuntimeError("Unknown header path style. Cannot extract Mantid namespace name.")
return namespace
def get_frameworkdir(headerfile):
"""
Returns the Framework directory
"""
if 'Framework' in headerfile:
matches = re.match(r"(.*Framework/).*\.h", headerfile)
if matches:
frameworkdir = matches.group(1)
else:
raise RuntimeError("Unknown header path style. Cannot extract Framework directory.")
else:
raise RuntimeError("Script must be run from outside the Framework directory")
return frameworkdir
def get_classname(headerfile):
"""
Returns the classname from a given file. At the moment it just uses the file name
"""
filename = os.path.basename(headerfile)
return os.path.splitext(filename)[0]
def get_include(headerfile):
"""
Returns the relative include path for inclusion in the code
"""
matches = re.match(r".*inc/(Mantid[a-z,A-z]*/.*\.h)", headerfile)
if matches:
return matches.group(1)
else:
raise RuntimeError("Unable to determine include path from given header")
def get_modulepath(frameworkdir, submodule):
"""Creates a path to the requested submodule
"""
return os.path.join(frameworkdir, 'PythonInterface', 'mantid',submodule)
def write_export_file(headerfile, overwrite):
# Where are we writing the output
exportfile = get_exportfile(headerfile)
print 'Writing export file \"%s\" '% os.path.basename(exportfile)
if os.path.exists(exportfile) and not overwrite:
raise RuntimeError("Export file '%s' already exists, use the --overwrite option to overwrite the file." % exportfile)
namespace = get_namespace(headerfile)
classname = get_classname(headerfile)
include = get_include(headerfile)
cppcode = """#include "%(header)s"
#include <boost/python/class.hpp>
using Mantid::%(namespace)s::%(class)s;
using namespace boost::python;
void export_%(class)s()
{
class_<%(class)s,boost::noncopyable>("%(class)s", no_init)
;
}
"""
cppfile = file(exportfile, 'w')
cppfile.write(cppcode % {'header':include, 'namespace':namespace,'class':classname})
cppfile.close()
print 'Generated export file "%s"' % os.path.basename(exportfile)
print
print " ** Add this to the EXPORT_FILES variable in '%s'" % \
os.path.join(get_modulepath(get_frameworkdir(headerfile), get_submodule(headerfile)), 'CMakeLists.txt')
return exportfile
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
def write_unittest(headerfile, overwrite):
"""
Write a unit test for the given header
"""
filename = get_unittest_file(headerfile)
print 'Writing unit test \"%s\" '% os.path.basename(filename)
if os.path.exists(filename) and not overwrite:
raise RuntimeError("A unit test file '%s' already exists, use the --overwrite-test option to overwrite the file." % filename)
classname = get_classname(headerfile)
pytest = \
"""import unittest
from mantid import %(classname)s
class %(classname)sTest(object):
def test_something(self):
self.fail("Test something")
if __name__ == '__main__':
unittest.main()
"""
unittest = open(filename, 'w')
unittest.write(pytest % {'classname':classname})
unittest.close()
print 'Generated unit test file "%s"' % os.path.basename(filename)
print
print " ** Add this to the TEST_PY_FILES variable in '%s'" % \
os.path.join('PythonInterface', 'CMakeLists.txt')
def main():
"""Main function
"""
parser = optparse.OptionParser(usage="usage: %prog [options] headerfile ", description="Creates a simple template for exporting a class to Python along with a unit test")
parser.add_option("--overwrite", "-o", dest='overwrite', action='store_true', default=False, help='If the file already exists, overwrite it')
parser.add_option("--export-only", "-e", dest='export_only', action='store_true', default=False, help='If True only attempt to generate the export file')
parser.add_option("--test-only", "-t", dest='test_only', action='store_true', default=False, help='If True only attempt to generate the unit test')
parser.add_option("--overwrite-test", "-w", dest='overwrite_test', action='store_true', default=False, help='If true overwrite a test file if it exists')
if len(args) != 1:
parser.error("Incorrect number of arguments")
headerfile = args[0]
if not os.path.exists(headerfile):
# Sanity
if options.export_only and options.test_only:
parser.error("The export_only and test_only options are mutually exclusive, please specify only one.")
# Generate
if not options.test_only:
write_export_file(os.path.abspath(headerfile), options.overwrite)
# Unit test
if not options.export_only:
write_unittest(os.path.abspath(headerfile), options.overwrite_test)
if __name__ == '__main__':
main()