Newer
Older
Janik Zikovsky
committed
#!/usr/bin/env python
""" Utility for generating a class file, header, and test file """
import sys
import os
try:
import argparse
useArgparse = True
except ImportError, e:
import optparse # deprecated in v2.7
useArgparse = False
Janik Zikovsky
committed
import datetime
Janik Zikovsky
committed
import re
import cmakelists_utils
from cmakelists_utils import *
Janik Zikovsky
committed
VERSION = "1.0"
Janik Zikovsky
committed
#======================================================================
def write_header(subproject, classname, filename, args):
Janik Zikovsky
committed
"""Write a class header file"""
print "Writing header file to %s" % filename
f = open(filename, 'w')
Janik Zikovsky
committed
guard = "MANTID_%s_%s_H_" % (subproject.upper(), classname.upper())
# Create an Algorithm header; will not use it if not an algo
algorithm_header = """
virtual const std::string name() const;
virtual int version() const;
virtual const std::string category() const;
virtual const std::string summary() const;
private:
void init();
void exec();
# ---- Find the author, default to blank string ----
author = ""
try:
author = commands.getoutput('git config user.name')
except:
pass
alg_class_declare = " : public API::Algorithm"
alg_include = '#include "MantidAPI/Algorithm.h"'
algorithm_header = ""
alg_class_declare = ""
alg_include = ""
# The full text
Janik Zikovsky
committed
s = """#ifndef %s
#define %s
Janik Zikovsky
committed
#include "MantidKernel/System.h"
Janik Zikovsky
committed
namespace Mantid
{
namespace %s
{
/** %s : TODO: DESCRIPTION
Copyright © %s ISIS Rutherford Appleton Laboratory, NScD Oak Ridge National Laboratory & European Spallation Source
Gigg, Martyn Anthony
committed
This file is part of Mantid.
Mantid is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
Mantid is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
File change history is stored at: <https://github.com/mantidproject/mantid>
Gigg, Martyn Anthony
committed
Code Documentation is available at: <http://doxygen.mantidproject.org>
*/
class DLLExport %s %s
Janik Zikovsky
committed
{
public:
%s();
Janik Zikovsky
committed
};
} // namespace %s
Gigg, Martyn Anthony
committed
} // namespace Mantid
Janik Zikovsky
committed
#endif /* %s */""" % (guard, guard,
alg_include, subproject, classname,
datetime.datetime.now().date().year, classname, alg_class_declare,
classname, classname, algorithm_header, subproject, guard)
Janik Zikovsky
committed
f.write(s)
f.close()
Janik Zikovsky
committed
#======================================================================
def write_source(subproject, classname, filename, args):
Janik Zikovsky
committed
"""Write a class source file"""
print "Writing source file to %s" % filename
f = open(filename, 'w')
algorithm_top = """
using Mantid::Kernel::Direction;
using Mantid::API::WorkspaceProperty;
// Register the algorithm into the AlgorithmFactory
DECLARE_ALGORITHM(%s)
""" % (classname)
algorithm_source = """
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
//----------------------------------------------------------------------------------------------
/// Algorithms name for identification. @see Algorithm::name
const std::string %s::name() const { return "%s"; }
/// Algorithm's version for identification. @see Algorithm::version
int %s::version() const { return 1; };
/// Algorithm's category for identification. @see Algorithm::category
const std::string %s::category() const { return TODO: FILL IN A CATEGORY;}
/// Algorithm's summary for use in the GUI and help. @see Algorithm::summary
const std::string %s::summary() const { return TODO: FILL IN A SUMMARY;};
//----------------------------------------------------------------------------------------------
/** Initialize the algorithm's properties.
*/
void %s::init() {
declareProperty(
new WorkspaceProperty<>("InputWorkspace", "", Direction::Input),
"An input workspace.");
declareProperty(
new WorkspaceProperty<>("OutputWorkspace", "", Direction::Output),
"An output workspace.");
}
//----------------------------------------------------------------------------------------------
/** Execute the algorithm.
*/
void %s::exec() {
// TODO Auto-generated execute stub
}
""" % (classname, classname, classname, classname, classname, classname, classname)
algorithm_top = ""
algorithm_source = ""
# ------- Now the normal class text ------------------------------
s = """#include "Mantid%s/%s%s.h"
namespace Mantid {
namespace %s {
//----------------------------------------------------------------------------------------------
/** Constructor
*/
%s::%s() {}
//----------------------------------------------------------------------------------------------
/** Destructor
*/
%s::~%s() {}
} // namespace %s
} // namespace Mantid""" % (
subproject, args.subfolder, classname, subproject, algorithm_top,
classname, classname, classname, classname, algorithm_source, subproject)
Janik Zikovsky
committed
f.write(s)
f.close()
Janik Zikovsky
committed
#======================================================================
def write_test(subproject, classname, filename, args):
Janik Zikovsky
committed
"""Write a class test file"""
print "Writing test file to %s" % filename
f = open(filename, 'w')
guard = "MANTID_%s_%sTEST_H_" % (subproject.upper(), classname.upper())
algorithm_test = """
void test_Init()
{
%s alg;
TS_ASSERT_THROWS_NOTHING( alg.initialize() )
TS_ASSERT( alg.isInitialized() )
}
Janik Zikovsky
committed
void test_exec()
{
// Name of the output workspace.
std::string outWSName("%sTest_OutputWS");
Janik Zikovsky
committed
%s alg;
TS_ASSERT_THROWS_NOTHING( alg.initialize() )
TS_ASSERT( alg.isInitialized() )
TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("REPLACE_PROPERTY_NAME_HERE!!!!", "value") );
TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("OutputWorkspace", outWSName) );
Janik Zikovsky
committed
TS_ASSERT_THROWS_NOTHING( alg.execute(); );
TS_ASSERT( alg.isExecuted() );
Janik Zikovsky
committed
// Retrieve the workspace from data service. TODO: Change to your desired type
Workspace_sptr ws;
TS_ASSERT_THROWS_NOTHING( ws = AnalysisDataService::Instance().retrieveWS<Workspace>(outWSName) );
Janik Zikovsky
committed
TS_ASSERT(ws);
if (!ws) return;
Janik Zikovsky
committed
// TODO: Check the results
Janik Zikovsky
committed
// Remove workspace from the data service.
AnalysisDataService::Instance().remove(outWSName);
}
""" % (classname,classname,classname);
algorithm_test = ""
Janik Zikovsky
committed
s = """#ifndef %s
#define %s
#include <cxxtest/TestSuite.h>
#include "Mantid%s/%s%s.h"
Janik Zikovsky
committed
using Mantid::%s::%s;
using namespace Mantid::API;
Janik Zikovsky
committed
class %sTest : public CxxTest::TestSuite
{
public:
// This pair of boilerplate methods prevent the suite being created statically
// This means the constructor isn't called when running other tests
static %sTest *createSuite() { return new %sTest(); }
static void destroySuite( %sTest *suite ) { delete suite; }
%s
void test_Something()
Janik Zikovsky
committed
{
TSM_ASSERT( "You forgot to write a test!", 0);
Janik Zikovsky
committed
}
};
#endif /* %s */""" % (
guard, guard, subproject, args.subfolder, classname,
subproject, classname, classname, classname, classname, classname,
Janik Zikovsky
committed
f.write(s)
f.close()
#======================================================================
def write_rst(subproject, classname, filename, args):
"""Write an algorithm rst documentation file"""
print "Writing rst file to %s" % filename
f = open(filename, 'w')
s = """
.. algorithm::
.. summary::
.. alias::
.. properties::
Description
-----------
TODO: Enter a full rst-markup description of your algorithm here.
Usage
-----
.. Try not to use files in your examples,
but if you cannot avoid it then the (small) files must be added to
autotestdata\UsageData and the following tag unindented
.. include:: ../usagedata-note.txt
**Example - %s**
.. testcode:: %sExample
# Create a host workspace
ws = CreateWorkspace(DataX=range(0,3), DataY=(0,2))
or
ws = CreateSampleWorkspace()
wsOut = %s()
# Print the result
print "The output workspace has %%i spectra" %% wsOut.getNumberHistograms()
Output:
.. testoutput:: %sExample
The output workspace has ?? spectra
.. categories::
""" % (classname,classname,classname,classname)
f.write(s)
f.close()
Janik Zikovsky
committed
#======================================================================
def generate(subproject, classname, overwrite, args):
Janik Zikovsky
committed
# Directory at base of subproject
basedir, header_folder = find_basedir(args.project, subproject)
headerfile = os.path.join(basedir, "inc", header_folder, args.subfolder + classname + ".h")
Gigg, Martyn Anthony
committed
sourcefile = os.path.join(basedir, "src", args.subfolder + classname + ".cpp")
testfile = os.path.join(basedir, "test", classname + "Test.h")
#up two from the subproject basedir and then docs\source\algorithms
mantiddir = os.path.dirname(os.path.dirname(basedir))
rstfile = os.path.join(mantiddir, "docs", "source", "algorithms", classname + "-v1.rst")
if args.header and not overwrite and os.path.exists(headerfile):
print "\nError! Header file %s already exists. Use --force to overwrite.\n" % headerfile
return
if args.cpp and not overwrite and os.path.exists(sourcefile):
print "\nError! Source file %s already exists. Use --force to overwrite.\n" % sourcefile
return
if args.test and not overwrite and os.path.exists(testfile):
print "\nError! Test file %s already exists. Use --force to overwrite.\n" % testfile
if args.rst and args.alg and not overwrite and os.path.exists(rstfile):
print "\nError! Rst documentation file %s already exists. Use --force to overwrite.\n" % rstfile
return
if args.header:
write_header(subproject, classname, headerfile, args)
if args.cpp:
write_source(subproject, classname, sourcefile, args)
if args.test:
write_test(subproject, classname, testfile, args)
if args.rst and args.alg:
write_rst(subproject, classname, rstfile, args)
# Insert into the cmake list
add_to_cmake(subproject, classname, args, args.subfolder)
print "\n Files were added to Framework/%s/CMakeLists.txt !" % (subproject)
# if not test_only:
# print "\tsrc/%s.cpp" % (classname)
# print "\tinc/Mantid%s/%s.h" % (subproject, classname)
# print "\ttest/%sTest.h" % (classname)
Janik Zikovsky
committed
Janik Zikovsky
committed
Janik Zikovsky
committed
#======================================================================
if __name__ == "__main__":
parser = None
if useArgparse:
parser = argparse.ArgumentParser(description='Utility to create Mantid class files: header, source and test. version ' + VERSION)
parser.add_argument('subproject', metavar='SUBPROJECT', type=str,
help='The subproject under Framework/; e.g. Kernel')
parser.add_argument('classname', metavar='CLASSNAME', type=str,
help='Name of the class to create')
parser.add_argument('--force', dest='force', action='store_const',
const=True, default=False,
help='Force overwriting existing files. Use with caution!')
parser.add_argument('--no-header', dest='header', action='store_const',
const=False, default=True,
help="Don't create the header file")
parser.add_argument('--no-test', dest='test', action='store_const',
const=False, default=True,
help="Don't create the test file")
parser.add_argument('--no-cpp', dest='cpp', action='store_const',
const=False, default=True,
help="Don't create the cpp file")
parser.add_argument('--no-rst', dest='rst', action='store_const',
const=False, default=True,
help="Don't create the rst file")
parser.add_argument('--alg', dest='alg', action='store_const',
const=True, default=False,
help='Create an Algorithm stub. This adds some methods common to algorithms.')
parser.add_argument('--subfolder', dest='subfolder',
default="",
help='Put the source under a subfolder below the main part of the project, e.g. Geometry/Instrument.')
parser.add_argument('--project', dest='project',
default="Framework",
help='The project in which this goes. Default: Framework. Can be MantidQt, Vates')
else:
parser = optparse.OptionParser("Usage: %prog SUBPROJECT CLASSNAME [options]", None,
optparse.Option, VERSION, 'error', 'Utility to create Mantid class files: header, source and test.')
parser.add_option('--force', dest='force', action='store_const',
const=True, default=False,
help='Force overwriting existing files. Use with caution!')
parser.add_option('--no-header', dest='header', action='store_const',
const=False, default=True,
help="Don't create the header file")
parser.add_option('--no-test', dest='test', action='store_const',
const=False, default=True,
help="Don't create the test file")
parser.add_option('--no-cpp', dest='cpp', action='store_const',
const=False, default=True,
help="Don't create the cpp file")
parser.add_option('--no-rst', dest='rst', action='store_const',
const=False, default=True,
help="Don't create the rst file")
parser.add_option('--alg', dest='alg', action='store_const',
const=True, default=False,
help='Create an Algorithm stub. This adds some methods common to algorithms.')
parser.add_option('--subfolder', dest='subfolder',
default="",
help='Put the source under a subfolder below the main part of the project, e.g. Geometry/Instrument.')
parser.add_option('--project', dest='project',
default="Framework",
help='The project in which this goes. Default: Framework. Can be MantidQt, Vates')
args = None
if useArgparse:
args = parser.parse_args()
else:
(options, myargs) = parser.parse_args()
args = options
args.subproject = myargs[0]
args.classname = myargs[1]
subproject = args.subproject
classname = args.classname
overwrite = args.force
# Make sure the subfolders end with a /
if args.subfolder != "":
if args.subfolder[-1:] != "/":
args.subfolder += "/"
generate(subproject, classname, overwrite, args)