PLearn 0.1
Plide.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 
00003 // Plide.cc
00004 //
00005 // Copyright (C) 2006 Nicolas Chapados
00006 //
00007 // Redistribution and use in source and binary forms, with or without
00008 // modification, are permitted provided that the following conditions are met:
00009 //
00010 //  1. Redistributions of source code must retain the above copyright
00011 //     notice, this list of conditions and the following disclaimer.
00012 //
00013 //  2. Redistributions in binary form must reproduce the above copyright
00014 //     notice, this list of conditions and the following disclaimer in the
00015 //     documentation and/or other materials provided with the distribution.
00016 //
00017 //  3. The name of the authors may not be used to endorse or promote
00018 //     products derived from this software without specific prior written
00019 //     permission.
00020 //
00021 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
00022 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00023 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
00024 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00025 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00026 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00027 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00028 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00029 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00030 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00031 //
00032 // This file is part of the PLearn library. For more information on the PLearn
00033 // library, go to the PLearn Web site at www.plearn.org
00034 
00035 // Authors: Nicolas Chapados
00036 
00039 #define PL_LOG_MODULE_NAME "Plide"
00040 
00041 // Python includes must come first
00042 #include <plearn/python/PythonCodeSnippet.h>
00043 
00044 // From C++ stdlib
00045 #include <map>
00046 #include <sstream>
00047 
00048 // From boost
00049 #include <boost/smart_ptr.hpp>
00050 
00051 // From PLearn
00052 #include "Plide.h"
00053 #include "plearn_main.h"
00054 #include "PLearnCommandRegistry.h"
00055 #include <plearn/base/TypeFactory.h>
00056 #include <plearn/base/ProgressBar.h>
00057 #include <plearn/io/fileutils.h>             // chdir
00058 #include <plearn/io/openString.h>
00059 #include <plearn/io/StringPStreamBuf.h>
00060 #include <plearn/io/pl_log.h>
00061 #include <plearn/io/PyPLearnScript.h>
00062 
00063 namespace PLearn {
00064 using namespace std;
00065 
00066 //#####  Progress Bar that's mapped to Plide Window  ##########################
00067 
00068 class PlideProgressPlugin : public ProgressBarPlugin
00069 {
00070 public:
00071     PlideProgressPlugin(PythonCodeSnippet* python)
00072         : m_python(python)
00073     {
00074         PLASSERT( m_python );
00075     }
00076 
00078     virtual ~PlideProgressPlugin();
00079 
00081     virtual void addProgressBar(ProgressBar* pb);
00082 
00084     virtual void killProgressBar(ProgressBar* pb);
00085 
00087     virtual void update(ProgressBar* pb, unsigned long newpos);
00088 
00089 protected:
00091     PythonCodeSnippet* m_python;
00092     
00095     map<ProgressBar*, int> m_progress_ids;
00096 };
00097 
00098 PlideProgressPlugin::~PlideProgressPlugin()
00099 {
00100     PLASSERT( m_python );
00101     for (map<ProgressBar*, int>::const_iterator it = m_progress_ids.begin(),
00102              end = m_progress_ids.end() ; it != end ; ++it)
00103     {
00104         // Don't call killProgressBar since iterators might be invalidated
00105         m_python->invoke("ReleaseProgressBar", int(it->second));
00106     }
00107     m_progress_ids.clear();
00108 }
00109 
00110 void PlideProgressPlugin::addProgressBar(ProgressBar* pb)
00111 {
00112     PLASSERT( pb && m_python );
00113     if (m_progress_ids.find(pb) == m_progress_ids.end()) {
00114         m_progress_ids[pb] =
00115             m_python->invoke("AllocateProgressBar", pb->title).as<int>();
00116     }
00117 }
00118 
00119 void PlideProgressPlugin::killProgressBar(ProgressBar* pb)
00120 {
00121     PLASSERT( pb && m_python );
00122     map<ProgressBar*, int>::iterator found = m_progress_ids.find(pb);
00123     if (found != m_progress_ids.end()) {
00124         m_python->invoke("ReleaseProgressBar", int(found->second));
00125         m_progress_ids.erase(found);
00126     }
00127 }
00128 
00129 void PlideProgressPlugin::update(ProgressBar* pb, unsigned long newpos)
00130 {
00131     PLASSERT( pb && m_python );
00132     map<ProgressBar*, int>::const_iterator found = m_progress_ids.find(pb);
00133     if (found != m_progress_ids.end()) {
00134         int progress_id = found->second;
00135         double fraction = double(newpos) / double(pb->maxpos);
00136         m_python->invoke("ProgressUpdate", progress_id, fraction);
00137     }
00138 }
00139 
00140 
00141 //#####  PlideLogPStreamBuf  ##################################################
00142 
00146 class PlideLogPStreamBuf : public StringPStreamBuf
00147 {
00148     typedef StringPStreamBuf inherited;
00149 
00150 public:
00151     PlideLogPStreamBuf(string* s, PythonCodeSnippet* python)
00152         : inherited(s, "w"),
00153           m_python(python),
00154           m_requested_verbosity(-1)
00155     { }
00156 
00158     void outputParameters(const string& module_name, int requested_verbosity);
00159 
00162     virtual void flush();
00163 
00164 protected:
00165     PythonCodeSnippet* m_python;
00166     string m_module_name;
00167     int m_requested_verbosity;
00168 };
00169 
00170 void PlideLogPStreamBuf::outputParameters(const string& module_name, int requested_verbosity)
00171 {
00172     m_module_name = module_name;
00173     m_requested_verbosity = requested_verbosity;
00174 }
00175 
00176 void PlideLogPStreamBuf::flush()
00177 {
00178     PLASSERT( st && m_python );
00179     inherited::flush();
00180     if (! st->empty()) {
00181         m_python->invoke("LogAppend", m_module_name, m_requested_verbosity, *st);
00182         st->clear();
00183     }
00184 }
00185 
00186 
00190 class PlideLogPlugin : public PL_LogPlugin
00191 {
00192 public:
00193     PlideLogPlugin(PythonCodeSnippet* python)
00194         : m_string(new std::string),
00195           m_streambuf(new PlideLogPStreamBuf(m_string.get(), python)),
00196           m_pstream(m_streambuf)
00197     { }
00198 
00199     virtual PStream& getStream(PStream::mode_t outmode, const string& module_name,
00200                                int requested_verbosity);
00201 
00202 protected:
00203     boost::scoped_ptr<std::string> m_string;
00204     PP<PlideLogPStreamBuf>         m_streambuf;
00205     PStream                        m_pstream;
00206 };
00207 
00208 PStream& PlideLogPlugin::getStream(PStream::mode_t outmode, const string& module_name,
00209                                    int requested_verbosity)
00210 {
00211     PLASSERT( m_streambuf );
00212     m_pstream.setOutMode(outmode);
00213     m_streambuf->outputParameters(module_name, requested_verbosity);
00214     m_streambuf->flush();
00215     return m_pstream;
00216 }
00217 
00218 
00219 
00220 //#####  Implementation of Command  ###########################################
00221 
00223 PLearnCommandRegistry Plide::reg_(new Plide);
00224 
00225 Plide::Plide()
00226     : PLearnCommand(
00227         "plide",
00228         "Starts up the PLearn Integrated Development Environment (PLIDE)",
00229         "Upon running, this command starts up a graphical user interface to\n"
00230         "interface more easily with PLearn.\n"
00231         )
00232 { }
00233 
00234 const char* plide_code = "from plearn.plide.plide import *\n" ;
00235 
00237 void Plide::run(const vector<string>& args)
00238 {
00239     m_python = new PythonCodeSnippet(plide_code);
00240     m_python->build();
00241 
00242     // A bunch of injections
00243     m_python->inject("versionString",     this, &Plide::versionString);
00244     m_python->inject("getAllClassnames",  this, &Plide::getAllClassnames);
00245     m_python->inject("helpResourcesPath", this, &Plide::helpResourcesPath);
00246     m_python->inject("helpIndex",         this, &Plide::helpIndex);
00247     m_python->inject("helpCommands",      this, &Plide::helpCommands);
00248     m_python->inject("helpClasses",       this, &Plide::helpClasses);
00249     m_python->inject("helpOnCommand",     this, &Plide::helpOnCommand);
00250     m_python->inject("helpOnClass",       this, &Plide::helpOnClass);
00251     m_python->inject("setOptionLevel",    this, &Plide::setOptionLevel);
00252     m_python->inject("toggleOptionFlag",  this, &Plide::toggleOptionFlag);
00253     m_python->inject("precisOnClass",     this, &Plide::precisOnClass);
00254     m_python->inject("loggingControl",    this, &Plide::loggingControl);
00255 
00256     // Start the thing!
00257     m_python->invoke("StartPlide", args);
00258 
00259     // Link progress bar stuff to GUI elements
00260     PP<ProgressBarPlugin> previous_progress_plugin = ProgressBar::getCurrentPlugin();
00261     PP<ProgressBarPlugin> pp_ppp = new PlideProgressPlugin(m_python);
00262     ProgressBar::setPlugin(pp_ppp);
00263 
00264     // Link logging stuff to GUI elements; change stream mode to pretty ascii
00265     PL_Log::instance().outmode(PStream::pretty_ascii);
00266     PP<PL_LogPlugin> previous_log_plugin = PL_Log::instance().getCurrentPlugin();
00267     PP<PL_LogPlugin> log_plugin = new PlideLogPlugin(m_python);
00268     PL_Log::instance().setPlugin(log_plugin);
00269     
00270     // Main loop: get work, dispatch, start again
00271     while (true) {
00272         TVec<string> work = m_python->invoke("GetWork").as< TVec<string> >();
00273 
00274         if (work.size() != 4)
00275             PLERROR("%sExpected to receive a work vector with 4 elements; got %d",
00276                     __FUNCTION__, work.size());
00277 
00278         const string& request_id  = work[0];
00279         const string& script_code = work[1];
00280         const string& root_dir    = work[2];
00281         const string& script_kind = work[3];
00282         MODULE_LOG << "Got work request " << request_id
00283                    << " in directory "    << root_dir
00284                    << " with script (subset):\n"
00285                    << script_code.substr(0,100)
00286                    << endl;
00287 
00288         if (script_code == "Quit()")
00289             break;
00290 
00291         string result_code;
00292         string result_details;
00293         try {
00294             if (script_kind == "pyplearn")
00295                 executePyPLearn(script_code, root_dir);
00296             else
00297                 PLERROR("%sUnknown/unsupported script kind '%s'",
00298                         __FUNCTION__, script_kind.c_str());
00299         }
00300         catch (const PLearnError& e) {
00301             result_code = "PLearnError";
00302             result_details = e.message();
00303         }
00304         catch (const std::exception& e) {
00305             result_code = "std::exception";
00306             result_details = e.what();
00307         }
00308         catch (...) 
00309         {
00310             result_code = "UnknownError";
00311             result_details =
00312                 "uncaught unknown exception "
00313                 "(ex: out-of-memory when allocating a matrix)";
00314         }
00315 
00316         m_python->invoke("PostWorkResults", request_id, result_code, result_details);
00317     }
00318 
00319     // Finally, quit the GTK loop
00320     m_python->invoke("QuitPlide");
00321 
00322     // Bring back previous plugin before shutting down Python
00323     PL_Log::instance().setPlugin(previous_log_plugin);
00324     ProgressBar::setPlugin(previous_progress_plugin);
00325 }
00326 
00327 
00328 //#####  Injected: Utilities  #################################################
00329 
00330 PythonObjectWrapper Plide::versionString(const TVec<PythonObjectWrapper>& args) const
00331 {
00332     if (args.size() != 0)
00333         PLERROR("%sExpecting 0 argument; got %d", __FUNCTION__, args.size());
00334     return PythonObjectWrapper(version_string());
00335 }
00336 
00337 PythonObjectWrapper Plide::getAllClassnames(const TVec<PythonObjectWrapper>& args) const
00338 {
00339     if (args.size() != 0)
00340         PLERROR("%sExpecting 0 argument; got %d", __FUNCTION__, args.size());
00341 
00342     const TypeMap& tm = TypeFactory::instance().getTypeMap();
00343     TVec<string> all_classes;
00344     all_classes.resize(0, tm.size());
00345     for (TypeMap::const_iterator it = tm.begin(), end = tm.end()
00346              ; it != end ; ++it)
00347     {
00348         // Skip abstract classes
00349         if (it->second.constructor)
00350             all_classes.push_back(it->second.type_name);
00351     }
00352     return PythonObjectWrapper(all_classes);
00353 }
00354 
00355 PythonObjectWrapper Plide::helpResourcesPath(const TVec<PythonObjectWrapper>& args)
00356 {
00357 // DEPRECATED: see HelpSystem
00358 /*
00359     if (args.size() != 1)
00360         PLERROR("%sExpecting 1 argument; got %d", __FUNCTION__, args.size());
00361 
00362     PPath base_path = args[0].as<string>();
00363     m_help_config   = new HTMLHelpConfig;
00364     m_help_config->html_index_document  = "";
00365     m_help_config->html_prolog_document = base_path / "help_prolog.html";
00366     m_help_config->html_epilog_document = base_path / "help_epilog.html";
00367     
00368     m_help_command = dynamic_cast<HTMLHelpCommand*>(
00369         PLearnCommandRegistry::commands()["htmlhelp"]);
00370     if (! m_help_command)
00371         PLERROR("%sThe PLearn command 'HTMLHelpCommand' must be linked into "
00372                 "the executable in order to use the Plide help system.", __FUNCTION__);
00373 */
00374     return PythonObjectWrapper();
00375 }
00376 
00377 PythonObjectWrapper Plide::helpIndex(const TVec<PythonObjectWrapper>& args) const
00378 {
00379     if (args.size() != 0)
00380         PLERROR("%sExpecting 0 argument; got %d", __FUNCTION__, args.size());
00381 
00382     PLASSERT( m_help_config && m_help_command );
00383     ostringstream os;
00384     m_help_command->helpIndex(os, m_help_config);
00385     return PythonObjectWrapper(os.str());
00386 }
00387 
00388 PythonObjectWrapper Plide::helpCommands(const TVec<PythonObjectWrapper>& args) const
00389 {
00390     if (args.size() != 0)
00391         PLERROR("%sExpecting 0 argument; got %d", __FUNCTION__, args.size());
00392 
00393     PLASSERT( m_help_config && m_help_command );
00394     ostringstream os;
00395     m_help_command->helpCommands(os, m_help_config);
00396     return PythonObjectWrapper(os.str());
00397 }
00398 
00399 PythonObjectWrapper Plide::helpClasses(const TVec<PythonObjectWrapper>& args) const
00400 {
00401     if (args.size() != 0)
00402         PLERROR("%sExpecting 0 argument; got %d", __FUNCTION__, args.size());
00403 
00404     PLASSERT( m_help_config && m_help_command );
00405     ostringstream os;
00406     m_help_command->helpClasses(os, m_help_config);
00407     return PythonObjectWrapper(os.str());
00408 }
00409 
00410 PythonObjectWrapper Plide::helpOnCommand(const TVec<PythonObjectWrapper>& args) const
00411 {
00412     if (args.size() != 1)
00413         PLERROR("%sExpecting 1 argument; got %d", __FUNCTION__, args.size());
00414 
00415     PLASSERT( m_help_config && m_help_command );
00416     ostringstream os;
00417     m_help_command->helpOnCommand(args[0].as<string>(), os, m_help_config);
00418     return PythonObjectWrapper(os.str());
00419 }
00420 
00421 PythonObjectWrapper Plide::helpOnClass(const TVec<PythonObjectWrapper>& args) const
00422 {
00423     if (args.size() != 1)
00424         PLERROR("%sExpecting 1 argument; got %d", __FUNCTION__, args.size());
00425 
00426     PLASSERT( m_help_config && m_help_command );
00427     ostringstream os;
00428     m_help_command->helpOnClass(args[0].as<string>(), os, m_help_config);
00429     return PythonObjectWrapper(os.str());
00430 }
00431 
00432 PythonObjectWrapper Plide::setOptionLevel(const TVec<PythonObjectWrapper>& args) const
00433 {
00434     if (args.size() != 1)
00435         PLERROR("%sExpecting 1 argument; got %d", __FUNCTION__, args.size());
00436     OptionBase::OptionLevel desired_level = args[0].as<OptionBase::OptionLevel>();
00437     OptionBase::setCurrentOptionLevel(desired_level);
00438     return PythonObjectWrapper();
00439 }
00440 
00441 PythonObjectWrapper Plide::toggleOptionFlag(const TVec<PythonObjectWrapper>& args) const
00442 {
00443     if (args.size() != 1)
00444         PLERROR("%sExpecting 1 argument; got %d", __FUNCTION__, args.size());
00445     OptionBase::flag_t flag_to_toggle = args[0].as<OptionBase::flag_t>();
00446     OptionBase::setCurrentFlags(OptionBase::getCurrentFlags() ^ flag_to_toggle);
00447     return PythonObjectWrapper();
00448 }
00449 
00450 
00451 PythonObjectWrapper Plide::precisOnClass(const TVec<PythonObjectWrapper>& args) const
00452 {
00453     if (args.size() != 1)
00454         PLERROR("%sExpecting 1 argument; got %d", __FUNCTION__, args.size());
00455 
00456     string classname = args[0].as<string>();
00457     if (TypeFactory::instance().isRegistered(classname)) {
00458         const TypeMapEntry& tme = TypeFactory::instance().getTypeMapEntry(classname);
00459         OptionList& options = (*tme.getoptionlist_method)();
00460         TVec<string> build_options;
00461         build_options.resize(0, options.size());
00462 
00463         // Determine buildoptions
00464         for (OptionList::iterator it=options.begin(), end=options.end()
00465                  ; it != end ; ++it)
00466         {
00467             int flags = (*it)->flags();
00468             if (flags & OptionBase::buildoption)
00469                 build_options.push_back((*it)->optionname());
00470         }
00471         return PythonObjectWrapper(make_pair(tme.one_line_descr, build_options));
00472     }
00473     else
00474         return PythonObjectWrapper();        // None
00475 }
00476 
00477 
00478 PythonObjectWrapper Plide::loggingControl(const TVec<PythonObjectWrapper>& args) const
00479 {
00480     if (args.size() != 2)
00481         PLERROR("%sExpecting 2 arguments; got %d", __FUNCTION__, args.size());
00482 
00483     int desired_verbosity = args[0].as<int>();
00484     vector<string> module_names = args[1].as< vector<string> >();
00485     PL_Log::instance().verbosity(desired_verbosity);
00486     PL_Log::instance().enableNamedLogging(module_names);
00487     return PythonObjectWrapper();
00488 }
00489 
00490 
00491 //#####  Work Executors  ######################################################
00492 
00493 void Plide::executePyPLearn(const string& script_code, const string& root_dir) const
00494 {
00495     PLearn::chdir(PPath(root_dir));
00496     PStream pyplearn_in = openString(script_code, PStream::plearn_ascii);
00497     PP<PyPLearnScript> pyplearn_script = new PyPLearnScript;
00498     pyplearn_in >> pyplearn_script;
00499     PLASSERT( pyplearn_script );
00500 
00501     string pyplearn_script_string = pyplearn_script->getScript();
00502     PStream plearn_in = openString(pyplearn_script_string,
00503                                    PStream::plearn_ascii);
00504     while (plearn_in.good()) {
00505         PP<Object> o = readObject(plearn_in);
00506         o->run();
00507         plearn_in.skipBlanksAndCommentsAndSeparators();
00508     }
00509 
00510     // Save out experiment.plearn and metainfos.txt
00511     pyplearn_script->close();
00512 }
00513 
00514 } // end of namespace PLearn
00515 
00516 
00517 /*
00518   Local Variables:
00519   mode:c++
00520   c-basic-offset:4
00521   c-file-style:"stroustrup"
00522   c-file-offsets:((innamespace . 0)(inline-open . 0))
00523   indent-tabs-mode:nil
00524   fill-column:79
00525   End:
00526 */
00527 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines