<div class="section" id="object-oriented-suites">
<span id="index-0"></span>
<p>Python’s object oriented design features allows considerable flexibility
in how we design and structure our <a class="reference internal" href="/wiki/display/ECFLOW/Glossary#term-suite-definition"><em class="xref std std-term">suite definition</em></a>.</p>
<p>Each suite will have a different set of forces which determine how it should
be designed.</p>
<p>Lets consider how we would design the tutorial examples in a more object oriented manner.
We start with some design criteria we must meet.</p>
<ul class="simple">
<li>The default variables (ECF_HOME,etc) must be configurable and independent of the suites</li>
<li>New suites must enable automatic job creation checking</li>
<li>We need to write out definition as a separate file</li>
<li>New suites should be able to re-use the “boiler plate” code defined by the above requirements</li>
</ul>
<p>Here is possible design, that uses inheritance and the template design pattern:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c">#!/usr/bin/env python2.7</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">ecflow</span>
<span class="k">class</span> <span class="nc">DefaultVariables</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="sd">"""Provide the setup variables for each suite"""</span>
<span class="k">def</span> <span class="nf">add_to</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">node</span><span class="p">):</span>
<span class="sd">"""Adds ECF_INCLUDE,ECF_HOME to the input node"""</span>
<span class="n">node</span><span class="o">.</span><span class="n">add_variable</span><span class="p">(</span><span class="s">"ECF_INCLUDE"</span><span class="p">,</span> <span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s">"HOME"</span><span class="p">)</span> <span class="o">+</span> <span class="s">"/course"</span><span class="p">)</span>
<span class="n">node</span><span class="o">.</span><span class="n">add_variable</span><span class="p">(</span><span class="s">"ECF_HOME"</span><span class="p">,</span> <span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s">"HOME"</span><span class="p">)</span> <span class="o">+</span> <span class="s">"/course"</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">BaseSuiteBuilder</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="sd">"""Abstract class. Add default variables to suite and enable job creation </span>
<span class="sd"> checking for any derived suite</span>
<span class="sd"> """</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">default_variables</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">defs</span> <span class="o">=</span> <span class="n">ecflow</span><span class="o">.</span><span class="n">Defs</span><span class="p">()</span>
<span class="c"># use derived class name as suite name</span>
<span class="bp">self</span><span class="o">.</span><span class="n">suite</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">defs</span><span class="o">.</span><span class="n">add_suite</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__name__</span><span class="p">)</span>
<span class="n">default_variables</span><span class="o">.</span><span class="n">add_to</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">suite</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_build_definition_hook</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">"""Derived suite should override this function to build the suite</span>
<span class="sd"> Should not be called explicitly. How could we enforce this ?</span>
<span class="sd"> """</span>
<span class="k">pass</span>
<span class="k">def</span> <span class="nf">setup</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">"""Template/skeleton function. </span>
<span class="sd"> Provides common algorithm for *all* derivatives</span>
<span class="sd"> Uses Holly wood principle.</span>
<span class="sd"> """</span>
<span class="c"># Build the suite</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_build_definition_hook</span><span class="p">()</span>
<span class="c"># check job creation. Could use an assert</span>
<span class="n">job_check_result</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">defs</span><span class="o">.</span><span class="n">check_job_creation</span><span class="p">()</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">job_check_result</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">print</span> <span class="s">"Job creation failed</span><span class="se">\n</span><span class="s">"</span> <span class="o">+</span> <span class="n">job_check_result</span>
<span class="c"># Allows definition creation to be separated from the load</span>
<span class="c"># Use the class name as the name of the definition file</span>
<span class="bp">self</span><span class="o">.</span><span class="n">defs</span><span class="o">.</span><span class="n">save_as_defs</span><span class="p">(</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__name__</span> <span class="o">+</span> <span class="s">".def"</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">SuiteBuilder</span><span class="p">(</span><span class="n">BaseSuiteBuilder</span><span class="p">):</span>
<span class="sd">"""My example suite. Generates SuiteBuilder.def"""</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">default_variables</span><span class="p">):</span>
<span class="n">BaseSuiteBuilder</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">default_variables</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_build_definition_hook</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">f1</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">suite</span><span class="o">.</span><span class="n">add_family</span><span class="p">(</span><span class="s">"family"</span><span class="p">)</span>
<span class="n">f1</span><span class="o">.</span><span class="n">add_task</span><span class="p">(</span><span class="s">"task1"</span><span class="p">)</span>
<span class="n">f1</span><span class="o">.</span><span class="n">add_task</span><span class="p">(</span><span class="s">"task2"</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">TestSuite</span><span class="p">(</span><span class="n">BaseSuiteBuilder</span><span class="p">):</span>
<span class="sd">"""My test suite. Generates TestSuite.def"""</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">default_variables</span><span class="p">):</span>
<span class="n">BaseSuiteBuilder</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">default_variables</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_build_definition_hook</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">suite</span><span class="o">.</span><span class="n">add_task</span><span class="p">(</span><span class="s">"task1"</span><span class="p">)</span>
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>
<span class="n">my_suite</span> <span class="o">=</span> <span class="n">SuiteBuilder</span><span class="p">(</span><span class="n">DefaultVariables</span><span class="p">())</span>
<span class="n">my_suite</span><span class="o">.</span><span class="n">setup</span><span class="p">()</span>
<span class="n">my_test_suite</span> <span class="o">=</span> <span class="n">TestSuite</span><span class="p">(</span><span class="n">DefaultVariables</span><span class="p">())</span>
<span class="n">my_test_suite</span><span class="o">.</span><span class="n">setup</span><span class="p">()</span>
</pre></div>
</div>
</div>
|