PLearn 0.1
|
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 :