<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[步科 的博客]]></title>
  <link href="http://buke.github.io/atom.xml" rel="self"/>
  <link href="http://buke.github.io/"/>
  <updated>2014-04-11T12:33:16+08:00</updated>
  <id>http://buke.github.io/</id>
  <author>
    <name><![CDATA[步科]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[OpenERP 邮件发送问题修复 -- 解决 qq/163 等邮箱发送失败问题]]></title>
    <link href="http://buke.github.io/blog/2014/04/11/openerp-send-mail-header-fixed/"/>
    <updated>2014-04-11T11:24:00+08:00</updated>
    <id>http://buke.github.io/blog/2014/04/11/openerp-send-mail-header-fixed</id>
    <content type="html"><![CDATA[<p>openerp-mail-server-smtp-user</p>

<p>Fixed email from header.修复OpenERP 邮件头From 格式错误。</p>

<p>默认情况下，OpenERP 打包邮件时, 直接使用 email from 作为邮件头的 From 值。如qq/163等邮箱会严格校验email from 和 发件人帐号是否一致，如不一致则返回发送失败。如以下情况：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>OE 默认情况
</span><span class='line'>发件人为： admin@ex.com
</span><span class='line'>发送账户为：11111@qq.com
</span><span class='line'>
</span><span class='line'>OE 打包邮件内容为 email['From'] == 'admin@ex.com' (qq/163 校验失败)
</span><span class='line'>
</span><span class='line'>安装本模块后：
</span><span class='line'>发件人为： admin@ex.com
</span><span class='line'>发送账户为：11111@qq.com
</span><span class='line'>
</span><span class='line'>OE 打包邮件内容为 email['From'] == 'admin@ex.com &lt;11111@qq.com> ' (qq/163 校验成功)</span></code></pre></td></tr></table></div></figure>


<p>下载地址： <a href="https://github.com/buke/openerp-mail-server-smtp-user">https://github.com/buke/openerp-mail-server-smtp-user</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[使用 inotify 监视 python 源码文件自动重新加载进程]]></title>
    <link href="http://buke.github.io/blog/2013/07/01/using-inotify-detected-python-source-file-and-autoreload-process/"/>
    <updated>2013-07-01T17:40:00+08:00</updated>
    <id>http://buke.github.io/blog/2013/07/01/using-inotify-detected-python-source-file-and-autoreload-process</id>
    <content type="html"><![CDATA[<p>在上一篇文章 <a href="%E4%BF%AE%E6%94%B9py%E6%96%87%E4%BB%B6%E8%87%AA%E5%8A%A8%E9%87%8D%E5%90%AF%E5%8A%A0%E8%BD%BD%E8%BF%9B%E7%A8%8B%E6%96%B9%E6%B3%95">http://buke.github.io/blog/2013/06/30/reload-the-process-when-source-chage-is-detected/</a> 中，实现了监视 py 文件并自动重启进程。</p>

<p>但核心实现是定时轮询获取文件的最新修改时间，效率低下而且很不 pythonic。</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'>    <span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
</span><span class='line'>        <span class="k">try</span><span class="p">:</span>
</span><span class='line'>            <span class="n">print_stdout</span><span class="p">(</span><span class="n">process</span><span class="p">)</span>
</span><span class='line'>            <span class="n">max_mtime</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">file_times</span><span class="p">(</span><span class="n">PATH</span><span class="p">,</span><span class="n">extension</span><span class="p">))</span>
</span><span class='line'>            <span class="k">if</span> <span class="n">max_mtime</span> <span class="o">&gt;</span> <span class="n">last_mtime</span><span class="p">:</span>
</span><span class='line'>                <span class="n">last_mtime</span> <span class="o">=</span> <span class="n">max_mtime</span>
</span><span class='line'>                <span class="k">print</span> <span class="s">&#39;Restarting process...&#39;</span>
</span><span class='line'>                <span class="n">stop_process</span><span class="p">(</span><span class="n">process</span><span class="p">)</span>
</span><span class='line'>                <span class="n">process</span> <span class="o">=</span> <span class="n">start_process</span><span class="p">(</span><span class="n">command</span><span class="p">)</span>
</span><span class='line'>            <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">WAIT</span><span class="p">)</span>
</span><span class='line'>        <span class="k">except</span> <span class="p">(</span><span class="ne">KeyboardInterrupt</span><span class="p">,</span> <span class="ne">SystemExit</span><span class="p">):</span>
</span><span class='line'>                <span class="k">print</span> <span class="s">&quot;Caught KeyboardInterrupt, terminating process&quot;</span>
</span><span class='line'>                <span class="n">stop_process</span><span class="p">(</span><span class="n">process</span><span class="p">)</span>
</span><span class='line'>                <span class="k">break</span>
</span></code></pre></td></tr></table></div></figure>


<p>对于程序员来说，定时轮询基本是不能接受滴 ~</p>

<p>所幸的是，linxu 2.6 + 开始在内核提供 inotify，为监控文件变化提供了良好的事件支持。来自 wiki 的介绍：</p>

<p>inotify是Linux核心子系统之一，做为文件系统的附加功能，它可监控文件系统并将异动通知应用程序。本系统的出现取代了旧有Linux核心里，拥有类似功能之dnotify模块。</p>

<p>因此，https://github.com/buke/autoreload for linux 使用 pyinotify 模块加以改进。 完整代码如下：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
<span class='line-number'>96</span>
<span class='line-number'>97</span>
<span class='line-number'>98</span>
<span class='line-number'>99</span>
<span class='line-number'>100</span>
<span class='line-number'>101</span>
<span class='line-number'>102</span>
<span class='line-number'>103</span>
<span class='line-number'>104</span>
<span class='line-number'>105</span>
<span class='line-number'>106</span>
<span class='line-number'>107</span>
<span class='line-number'>108</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="c">#!/usr/bin/env python</span>
</span><span class='line'><span class="c"># -*- coding: utf-8 -*-</span>
</span><span class='line'><span class="c">##############################################################################</span>
</span><span class='line'><span class="c"># AutoReload Process Using inofify</span>
</span><span class='line'><span class="c"># wangbuke &lt;wangbuke@gmail.com&gt;</span>
</span><span class='line'><span class="c"># taken from https://github.com/stevekrenzel/autoreload</span>
</span><span class='line'><span class="c">#</span>
</span><span class='line'><span class="c"># To use autoreload:</span>
</span><span class='line'><span class="c"># 1. Make sure the script is executable by running chmod +x autoreload</span>
</span><span class='line'><span class="c"># 2. Run ./autoreload &lt;path&gt; &lt;ext1,ext2,extn&gt; &lt;cmd&gt;</span>
</span><span class='line'><span class="c"># e.g: $ ./autoreload &#39;.&#39; &#39;.py,.xml,.conf&#39; &#39;./openerp-server -c openerp-server.conf&#39;</span>
</span><span class='line'><span class="c">#</span>
</span><span class='line'><span class="c">##############################################################################</span>
</span><span class='line'>
</span><span class='line'><span class="kn">import</span> <span class="nn">os</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">signal</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">subprocess</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">sys</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">time</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">pyinotify</span>
</span><span class='line'><span class="kn">from</span> <span class="nn">pyinotify</span> <span class="kn">import</span> <span class="n">log</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">ReloadNotifier</span><span class="p">(</span><span class="n">pyinotify</span><span class="o">.</span><span class="n">Notifier</span><span class="p">):</span>
</span><span class='line'>    <span class="k">def</span> <span class="nf">loop</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">callback</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">daemonize</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="o">**</span><span class="n">args</span><span class="p">):</span>
</span><span class='line'>        <span class="k">if</span> <span class="n">daemonize</span><span class="p">:</span>
</span><span class='line'>            <span class="bp">self</span><span class="o">.</span><span class="n">__daemonize</span><span class="p">(</span><span class="o">**</span><span class="n">args</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>        <span class="c"># Read and process events forever</span>
</span><span class='line'>        <span class="k">while</span> <span class="mi">1</span><span class="p">:</span>
</span><span class='line'>            <span class="k">try</span><span class="p">:</span>
</span><span class='line'>                <span class="bp">self</span><span class="o">.</span><span class="n">_default_proc_fun</span><span class="o">.</span><span class="n">_print_stdout</span><span class="p">()</span>
</span><span class='line'>                <span class="bp">self</span><span class="o">.</span><span class="n">process_events</span><span class="p">()</span>
</span><span class='line'>                <span class="k">if</span> <span class="p">(</span><span class="n">callback</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">)</span> <span class="ow">and</span> <span class="p">(</span><span class="n">callback</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="ow">is</span> <span class="bp">True</span><span class="p">):</span>
</span><span class='line'>                    <span class="k">break</span>
</span><span class='line'>                <span class="n">ref_time</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>
</span><span class='line'>                <span class="c"># check_events is blocking</span>
</span><span class='line'>                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">check_events</span><span class="p">():</span>
</span><span class='line'>                    <span class="bp">self</span><span class="o">.</span><span class="n">_sleep</span><span class="p">(</span><span class="n">ref_time</span><span class="p">)</span>
</span><span class='line'>                    <span class="bp">self</span><span class="o">.</span><span class="n">read_events</span><span class="p">()</span>
</span><span class='line'>            <span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span>
</span><span class='line'>                <span class="c"># Stop monitoring if sigint is caught (Control-C).</span>
</span><span class='line'>                <span class="n">log</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">&#39;Pyinotify stops monitoring.&#39;</span><span class="p">)</span>
</span><span class='line'>                <span class="bp">self</span><span class="o">.</span><span class="n">_default_proc_fun</span><span class="o">.</span><span class="n">_stop_process</span><span class="p">()</span>
</span><span class='line'>                <span class="k">break</span>
</span><span class='line'>        <span class="c"># Close internals</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">stop</span><span class="p">()</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">OnChangeHandler</span><span class="p">(</span><span class="n">pyinotify</span><span class="o">.</span><span class="n">ProcessEvent</span><span class="p">):</span>
</span><span class='line'>    <span class="k">def</span> <span class="nf">my_init</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">cwd</span><span class="p">,</span> <span class="n">extension</span><span class="p">,</span> <span class="n">cmd</span><span class="p">):</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">cwd</span> <span class="o">=</span> <span class="n">cwd</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">extensions</span> <span class="o">=</span> <span class="n">extension</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&#39;,&#39;</span><span class="p">)</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">cmd</span> <span class="o">=</span> <span class="n">cmd</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">process</span> <span class="o">=</span> <span class="bp">None</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">_start_process</span><span class="p">()</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">def</span> <span class="nf">_start_process</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">process</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">Popen</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">cmd</span><span class="p">,</span> <span class="n">shell</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">preexec_fn</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">setsid</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">def</span> <span class="nf">_stop_process</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span><span class='line'>        <span class="n">os</span><span class="o">.</span><span class="n">killpg</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">process</span><span class="o">.</span><span class="n">pid</span><span class="p">,</span> <span class="n">signal</span><span class="o">.</span><span class="n">SIGTERM</span><span class="p">)</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">process</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">def</span> <span class="nf">_restart_process</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span><span class='line'>        <span class="k">print</span> <span class="s">&#39;==&gt; Modification detected, restart process. &lt;==&#39;</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">_stop_process</span><span class="p">()</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">_start_process</span><span class="p">()</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">def</span> <span class="nf">_print_stdout</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span><span class='line'>        <span class="n">stdout</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">process</span><span class="o">.</span><span class="n">stdout</span>
</span><span class='line'>        <span class="k">if</span> <span class="n">stdout</span> <span class="o">!=</span> <span class="bp">None</span><span class="p">:</span>
</span><span class='line'>            <span class="k">print</span> <span class="n">stdout</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">def</span> <span class="nf">process_IN_CREATE</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">event</span><span class="p">):</span>
</span><span class='line'>        <span class="k">if</span> <span class="nb">any</span><span class="p">(</span><span class="n">event</span><span class="o">.</span><span class="n">pathname</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="n">ext</span><span class="p">)</span> <span class="k">for</span> <span class="n">ext</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">extensions</span><span class="p">)</span> <span class="ow">or</span> <span class="s">&quot;IN_ISDIR&quot;</span> <span class="ow">in</span> <span class="n">event</span><span class="o">.</span><span class="n">maskname</span><span class="p">:</span>
</span><span class='line'>            <span class="bp">self</span><span class="o">.</span><span class="n">_restart_process</span><span class="p">()</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">def</span> <span class="nf">process_IN_DELETE</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">event</span><span class="p">):</span>
</span><span class='line'>        <span class="k">if</span> <span class="nb">any</span><span class="p">(</span><span class="n">event</span><span class="o">.</span><span class="n">pathname</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="n">ext</span><span class="p">)</span> <span class="k">for</span> <span class="n">ext</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">extensions</span><span class="p">)</span> <span class="ow">or</span> <span class="s">&quot;IN_ISDIR&quot;</span> <span class="ow">in</span> <span class="n">event</span><span class="o">.</span><span class="n">maskname</span><span class="p">:</span>
</span><span class='line'>            <span class="bp">self</span><span class="o">.</span><span class="n">_restart_process</span><span class="p">()</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">def</span> <span class="nf">process_IN_CLOSE_WRITE</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">event</span><span class="p">):</span>
</span><span class='line'>        <span class="k">if</span> <span class="nb">any</span><span class="p">(</span><span class="n">event</span><span class="o">.</span><span class="n">pathname</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="n">ext</span><span class="p">)</span> <span class="k">for</span> <span class="n">ext</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">extensions</span><span class="p">)</span> <span class="ow">or</span> <span class="s">&quot;IN_ISDIR&quot;</span> <span class="ow">in</span> <span class="n">event</span><span class="o">.</span><span class="n">maskname</span><span class="p">:</span>
</span><span class='line'>            <span class="bp">self</span><span class="o">.</span><span class="n">_restart_process</span><span class="p">()</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">def</span> <span class="nf">process_IN_MOVED_FROM</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">event</span><span class="p">):</span>
</span><span class='line'>        <span class="k">if</span> <span class="nb">any</span><span class="p">(</span><span class="n">event</span><span class="o">.</span><span class="n">pathname</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="n">ext</span><span class="p">)</span> <span class="k">for</span> <span class="n">ext</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">extensions</span><span class="p">)</span> <span class="ow">or</span> <span class="s">&quot;IN_ISDIR&quot;</span> <span class="ow">in</span> <span class="n">event</span><span class="o">.</span><span class="n">maskname</span><span class="p">:</span>
</span><span class='line'>            <span class="bp">self</span><span class="o">.</span><span class="n">_restart_process</span><span class="p">()</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">def</span> <span class="nf">process_IN_MOVED_TO</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">event</span><span class="p">):</span>
</span><span class='line'>        <span class="k">if</span> <span class="nb">any</span><span class="p">(</span><span class="n">event</span><span class="o">.</span><span class="n">pathname</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="n">ext</span><span class="p">)</span> <span class="k">for</span> <span class="n">ext</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">extensions</span><span class="p">)</span> <span class="ow">or</span> <span class="s">&quot;IN_ISDIR&quot;</span> <span class="ow">in</span> <span class="n">event</span><span class="o">.</span><span class="n">maskname</span><span class="p">:</span>
</span><span class='line'>            <span class="bp">self</span><span class="o">.</span><span class="n">_restart_process</span><span class="p">()</span>
</span><span class='line'>
</span><span class='line'><span class="k">def</span> <span class="nf">autoreload</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">extension</span><span class="p">,</span> <span class="n">cmd</span><span class="p">):</span>
</span><span class='line'>    <span class="n">wm</span> <span class="o">=</span> <span class="n">pyinotify</span><span class="o">.</span><span class="n">WatchManager</span><span class="p">()</span>
</span><span class='line'>    <span class="n">handler</span> <span class="o">=</span> <span class="n">OnChangeHandler</span><span class="p">(</span><span class="n">cwd</span><span class="o">=</span><span class="n">path</span><span class="p">,</span> <span class="n">extension</span><span class="o">=</span><span class="n">extension</span><span class="p">,</span> <span class="n">cmd</span><span class="o">=</span><span class="n">cmd</span><span class="p">)</span>
</span><span class='line'>    <span class="n">notifier</span> <span class="o">=</span> <span class="n">ReloadNotifier</span><span class="p">(</span><span class="n">wm</span><span class="p">,</span> <span class="n">default_proc_fun</span><span class="o">=</span><span class="n">handler</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">mask</span> <span class="o">=</span> <span class="n">pyinotify</span><span class="o">.</span><span class="n">IN_CLOSE_WRITE</span> <span class="o">|</span> <span class="n">pyinotify</span><span class="o">.</span><span class="n">IN_MOVED_FROM</span> <span class="o">|</span> <span class="n">pyinotify</span><span class="o">.</span><span class="n">IN_MOVED_TO</span> <span class="o">|</span> <span class="n">pyinotify</span><span class="o">.</span><span class="n">IN_CREATE</span> <span class="o">|</span> <span class="n">pyinotify</span><span class="o">.</span><span class="n">IN_DELETE</span> <span class="o">|</span> <span class="n">pyinotify</span><span class="o">.</span><span class="n">IN_DELETE_SELF</span> <span class="o">|</span> <span class="n">pyinotify</span><span class="o">.</span><span class="n">IN_MOVE_SELF</span>
</span><span class='line'>    <span class="n">wm</span><span class="o">.</span><span class="n">add_watch</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">mask</span><span class="p">,</span> <span class="n">rec</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">auto_add</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">print</span> <span class="s">&#39;==&gt; Start monitoring </span><span class="si">%s</span><span class="s"> (type c^c to exit) &lt;==&#39;</span> <span class="o">%</span> <span class="n">path</span>
</span><span class='line'>    <span class="n">notifier</span><span class="o">.</span><span class="n">loop</span><span class="p">()</span>
</span><span class='line'>
</span><span class='line'><span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&#39;__main__&#39;</span><span class="p">:</span>
</span><span class='line'>    <span class="n">path</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
</span><span class='line'>    <span class="n">extension</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
</span><span class='line'>    <span class="n">cmd</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span>
</span><span class='line'>    <span class="n">autoreload</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">extension</span><span class="p">,</span> <span class="n">cmd</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>用法：
1. $ chmod +x autoreload (修改为可执行文件)</p>

<ol>
<li>Run ./autoreload <path> &lt;ext1,ext2,extn> <cmd>
e.g: $ ./autoreload &#8216;.&#8217; &#8216;.py,.xml,.conf&#8217; &#8216;./openerp-server -c openerp-server.conf&#8217;</li>
</ol>


<p>以上代码已开源并发布在<a href="https://github.com/buke/autoreload">https://github.com/buke/autoreload</a> ， 欢迎反馈意见和建议！</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[修改py文件自动重启加载进程方法]]></title>
    <link href="http://buke.github.io/blog/2013/06/30/reload-the-process-when-source-chage-is-detected/"/>
    <updated>2013-06-30T22:49:00+08:00</updated>
    <id>http://buke.github.io/blog/2013/06/30/reload-the-process-when-source-chage-is-detected</id>
    <content type="html"><![CDATA[<p>一般来说我们的 Python 程序在运行时会自动编译为 .pyc 文件，这样可以加快 Python 程序的启动速度。但在开发调试的时，我们不得不频繁重启进程，让人不胜其烦。</p>

<p>秉承“不会偷懒的程序员不是好程序员”的原则，写了个 autoreload 脚本(兼容 linux/windows)，项目开源地址 <a href="https://github.com/buke/autoreload">https://github.com/buke/autoreload</a></p>

<p>完整代码如下：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="c">#!/usr/bin/env python</span>
</span><span class='line'><span class="c"># -*- coding: utf-8 -*-</span>
</span><span class='line'><span class="c">##############################################################################</span>
</span><span class='line'><span class="c">#    AutoReload Process</span>
</span><span class='line'><span class="c">#    wangbuke &lt;wangbuke@gmail.com&gt;</span>
</span><span class='line'><span class="c">#    taken from https://github.com/stevekrenzel/autoreload</span>
</span><span class='line'><span class="c">#    </span>
</span><span class='line'><span class="c">#    To use autoreload:    </span>
</span><span class='line'><span class="c">#    1. Make sure the script is executable by running chmod +x autoreload</span>
</span><span class='line'><span class="c">#    2. Run ./autoreload &lt;command to run and reload&gt; </span>
</span><span class='line'><span class="c">#       e.g: $ ./autoreload openerp-server</span>
</span><span class='line'><span class="c">#    </span>
</span><span class='line'><span class="c">##############################################################################</span>
</span><span class='line'>
</span><span class='line'><span class="kn">import</span> <span class="nn">sys</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">subprocess</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">time</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">os</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">signal</span>
</span><span class='line'>
</span><span class='line'><span class="n">PATH</span> <span class="o">=</span> <span class="s">&#39;.&#39;</span>
</span><span class='line'><span class="n">WAIT</span> <span class="o">=</span> <span class="mi">1</span>
</span><span class='line'>
</span><span class='line'><span class="k">def</span> <span class="nf">start_process</span><span class="p">(</span><span class="n">cmd</span><span class="p">):</span>
</span><span class='line'>    <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">name</span> <span class="o">==</span> <span class="s">&#39;nt&#39;</span><span class="p">:</span>
</span><span class='line'>        <span class="n">process</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">Popen</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="n">shell</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
</span><span class='line'>    <span class="k">else</span><span class="p">:</span>
</span><span class='line'>        <span class="n">process</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">Popen</span><span class="p">(</span><span class="n">cmd</span><span class="p">,</span> <span class="n">shell</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">preexec_fn</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">setsid</span><span class="p">)</span>
</span><span class='line'>    <span class="k">return</span> <span class="n">process</span>
</span><span class='line'>
</span><span class='line'><span class="k">def</span> <span class="nf">stop_process</span><span class="p">(</span><span class="n">process</span><span class="p">):</span>
</span><span class='line'>    <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">name</span> <span class="o">==</span> <span class="s">&#39;nt&#39;</span><span class="p">:</span>
</span><span class='line'>        <span class="n">process</span><span class="o">.</span><span class="n">kill</span><span class="p">()</span>
</span><span class='line'>    <span class="k">else</span><span class="p">:</span>
</span><span class='line'>        <span class="n">os</span><span class="o">.</span><span class="n">killpg</span><span class="p">(</span><span class="n">process</span><span class="o">.</span><span class="n">pid</span><span class="p">,</span> <span class="n">signal</span><span class="o">.</span><span class="n">SIGTERM</span><span class="p">)</span> <span class="c"># Send the signal to all the process groups</span>
</span><span class='line'>    <span class="n">process</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span>
</span><span class='line'>
</span><span class='line'><span class="k">def</span> <span class="nf">file_filter</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
</span><span class='line'>    <span class="k">return</span> <span class="p">(</span><span class="ow">not</span> <span class="n">name</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">&quot;.&quot;</span><span class="p">))</span> <span class="ow">and</span> <span class="p">(</span><span class="ow">not</span> <span class="n">name</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s">&quot;.pyc&quot;</span><span class="p">))</span>  <span class="ow">and</span> <span class="p">(</span><span class="ow">not</span> <span class="n">name</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s">&quot;.pyo&quot;</span><span class="p">))</span><span class="ow">and</span> <span class="p">(</span><span class="ow">not</span> <span class="n">name</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s">&quot;.swp&quot;</span><span class="p">))</span>
</span><span class='line'>
</span><span class='line'><span class="k">def</span> <span class="nf">file_times</span><span class="p">(</span><span class="n">path</span><span class="p">):</span>
</span><span class='line'>    <span class="k">for</span> <span class="n">root</span><span class="p">,</span> <span class="n">dirs</span><span class="p">,</span> <span class="n">files</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">walk</span><span class="p">(</span><span class="n">path</span><span class="p">):</span>
</span><span class='line'>        <span class="k">for</span> <span class="nb">file</span> <span class="ow">in</span> <span class="nb">filter</span><span class="p">(</span><span class="n">file_filter</span><span class="p">,</span> <span class="n">files</span><span class="p">):</span>
</span><span class='line'>            <span class="k">yield</span> <span class="n">os</span><span class="o">.</span><span class="n">stat</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">root</span><span class="p">,</span> <span class="nb">file</span><span class="p">))</span><span class="o">.</span><span class="n">st_mtime</span>
</span><span class='line'>
</span><span class='line'><span class="k">def</span> <span class="nf">print_stdout</span><span class="p">(</span><span class="n">process</span><span class="p">):</span>
</span><span class='line'>    <span class="n">stdout</span> <span class="o">=</span> <span class="n">process</span><span class="o">.</span><span class="n">stdout</span>
</span><span class='line'>    <span class="k">if</span> <span class="n">stdout</span> <span class="o">!=</span> <span class="bp">None</span><span class="p">:</span>
</span><span class='line'>        <span class="k">print</span> <span class="n">stdout</span>
</span><span class='line'>
</span><span class='line'><span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">command</span> <span class="o">=</span> <span class="s">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">:])</span>
</span><span class='line'>    <span class="n">process</span> <span class="o">=</span> <span class="n">start_process</span><span class="p">(</span><span class="n">command</span><span class="p">)</span>
</span><span class='line'>    <span class="n">last_mtime</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">file_times</span><span class="p">(</span><span class="n">PATH</span><span class="p">))</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
</span><span class='line'>        <span class="k">try</span><span class="p">:</span>
</span><span class='line'>            <span class="n">print_stdout</span><span class="p">(</span><span class="n">process</span><span class="p">)</span>
</span><span class='line'>            <span class="n">max_mtime</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">file_times</span><span class="p">(</span><span class="n">PATH</span><span class="p">))</span>
</span><span class='line'>            <span class="k">if</span> <span class="n">max_mtime</span> <span class="o">&gt;</span> <span class="n">last_mtime</span><span class="p">:</span>
</span><span class='line'>                <span class="n">last_mtime</span> <span class="o">=</span> <span class="n">max_mtime</span>
</span><span class='line'>                <span class="k">print</span> <span class="s">&#39;Restarting process...&#39;</span>
</span><span class='line'>                <span class="n">stop_process</span><span class="p">(</span><span class="n">process</span><span class="p">)</span>
</span><span class='line'>                <span class="n">process</span> <span class="o">=</span> <span class="n">start_process</span><span class="p">(</span><span class="n">command</span><span class="p">)</span>
</span><span class='line'>            <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">WAIT</span><span class="p">)</span>
</span><span class='line'>        <span class="k">except</span> <span class="p">(</span><span class="ne">KeyboardInterrupt</span><span class="p">,</span> <span class="ne">SystemExit</span><span class="p">):</span>
</span><span class='line'>                <span class="k">print</span> <span class="s">&quot;Caught KeyboardInterrupt, terminating process&quot;</span>
</span><span class='line'>                <span class="n">stop_process</span><span class="p">(</span><span class="n">process</span><span class="p">)</span>
</span><span class='line'>                <span class="k">break</span>
</span><span class='line'>
</span><span class='line'><span class="c"># vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:</span>
</span></code></pre></td></tr></table></div></figure>


<p>可配置参数：
* PATH = &#8216;.&#8217; #默认为 autoreload 文件所在的当前目录。
* WAIT = 1 # 默认扫描间隔，单位秒</p>

<p>用法:
1、修改该文件为可执行脚步 (windows 下执行 python autoreload)</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ chomd +x ./autorelaod</span></code></pre></td></tr></table></div></figure>


<p>2、运行</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ ./autoreload "openerp-server -c openerp-server.conf"</span></code></pre></td></tr></table></div></figure>


<p>项目开源地址 <a href="https://github.com/buke/autoreload">https://github.com/buke/autoreload</a> ,  如有意见或建议请到上面地址提交反馈。谢谢！</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[复制 Virtualbox/vmware linux虚拟机网络无法访问错误的解决方法]]></title>
    <link href="http://buke.github.io/blog/2013/06/27/fix-eth0-network-interface-when-cloning-centos-slash-redhat-or-debian-slash-ubuntu-virtual-machines-using-virtualbox-or-vmware/"/>
    <updated>2013-06-27T16:36:00+08:00</updated>
    <id>http://buke.github.io/blog/2013/06/27/fix-eth0-network-interface-when-cloning-centos-slash-redhat-or-debian-slash-ubuntu-virtual-machines-using-virtualbox-or-vmware</id>
    <content type="html"><![CDATA[<p>使用 VirtualBox/VMWare 复制 centos/redhat 或 debian/ubuntu 虚拟机时，如果你选择了初始化网卡MAC地址，复制之后往往会发现网络无法使用。</p>

<p>如执行以下命令则提示错误</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># ifup eth0
</span><span class='line'>Device eth0 does not seem to be present, delaying initialisation</span></code></pre></td></tr></table></div></figure>


<p>原因是VirtualBox/VMWare 在复制时改变了网卡的MAC地址，和原虚拟机网卡eth0地址不符。</p>

<p>解决办法：</p>

<p>1、删除网络规则文件</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># rm -f /etc/udev/rules.d/70-persistent-net.rules</span></code></pre></td></tr></table></div></figure>


<p>2、修改 eth0 的配置文件 (debian/ubuntu 跳过)</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># vim /etc/sysconfig/network-scripts/ifcfg-eth0
</span><span class='line'>删除 HWADDR 和 UUID 行即可</span></code></pre></td></tr></table></div></figure>


<p>3、重启</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># reboot</span></code></pre></td></tr></table></div></figure>


<p>完成！</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[使用 Eclipse Pydev 调试 GreenOpenERP For Windows]]></title>
    <link href="http://buke.github.io/blog/2013/06/27/using-eclipse-pydev-to-debug-green-openerp-for-windows/"/>
    <updated>2013-06-27T13:32:00+08:00</updated>
    <id>http://buke.github.io/blog/2013/06/27/using-eclipse-pydev-to-debug-green-openerp-for-windows</id>
    <content type="html"><![CDATA[<h2>关于 GreenOpenERP</h2>

<p>OpenERP 绿色版 For Windows，源码运行，解压即用，集成 python/postgresql/openerp</p>

<p>相关介绍和下载，请看 <a href="http://buke.github.io/blog/2013/03/10/greenopenerp-portable-openerp-for-windows/">http://buke.github.io/blog/2013/03/10/greenopenerp-portable-openerp-for-windows/</a></p>

<h2>关于 Eclipse 和 Pydev</h2>

<p>Eclipse, 请到<a href="http://www.eclipse.org/">http://www.eclipse.org/</a> 下载安装。</p>

<p>Pydev, 请到<a href="http://pydev.org/">http://pydev.org/</a> 下载安装。(推荐使用eclipse 在线安装 pydev，打开eclipse 后，点击菜单 “help” -> &#8220;Install New Software&#8221;, 输入 “http://pydev.org/updates” 刷新后选择 pydev 安装即可。)</p>

<h2>源码调试 GreenOpenERP</h2>

<p>此处假设您已经安装好 Eclipse 和 Pydev，并可以正确运行。</p>

<h3>1、下载 GreenOpenERP</h3>

<p>从<a href="http://sourceforge.net/projects/greenopenerp/files/">http://sourceforge.net/projects/greenopenerp/files/</a> 下载并解压 GreenOpenERP-7.0-xxxxxxxx-xxxxxx</p>

<h3>2、配置 pydev 的 python interpreters</h3>

<p>打开 eclipse ， 选择菜单 “Window” -> &#8220;Preferences&#8221;</p>

<p><img src="http://buke.github.io/images/my/pydev-0.png"></p>

<p>点击 pydev，选择 Interpreter - Python , 如有旧的Interpreter 请先删除。点击 New ，在弹出的窗口中 Browse 到下载解压的 GreenOpenERP-7.0-xxxxxxxx-xxxxxx\python\python.exe</p>

<p><img src="http://buke.github.io/images/my/pydev-1.png"></p>

<p>选择 Select All， 然后点击 OK</p>

<p><img src="http://buke.github.io/images/my/pydev-2.png"></p>

<p>回到刚才窗口， python interpreters 的相关参数应已配好。点击 Apply 后，点 Ok</p>

<p><img src="http://buke.github.io/images/my/pydev-3.png"></p>

<h3>3、选择 pydev 开发界面。</h3>

<p>Eclipse 默认是 java 开发界面，点击右上角的小图表，在弹出的窗口选择 pydev</p>

<p><img src="http://buke.github.io/images/my/pydev-4.png"></p>

<h3>4、导入 GreenOpenERP Project</h3>

<p>在 Package Explorer 界面内点击右键，在弹出的菜单里选择 Import</p>

<p><img src="http://buke.github.io/images/my/pydev-5.png"></p>

<p>选择 Existing Project into Workspace 后，点 Next</p>

<p><img src="http://buke.github.io/images/my/pydev-6.png"></p>

<p>点击 Browse 后，选择解压后的 GreenOpenERP 文件夹, 随后点击 Finish</p>

<p><img src="http://buke.github.io/images/my/pydev-7.png"></p>

<h3>5、启动 Postgresql</h3>

<p>运行 GreenOpenERP 文件夹的 start-pg.bat 启动 pg 数据库。（关闭pg 数据库则运行 stop-pg.bat）</p>

<h3>6、启动调试</h3>

<p>在相应文件设置好断点后（也可不设置断点），在 eclipse 的 Package Explorer 界面右键点击 openerp-server, 在弹出菜单选择 Debug As -> Python Run</p>

<p><img src="http://buke.github.io/images/my/pydev-8.png"></p>

<h3>7、完成</h3>

<p>送断点调试界面图一张</p>

<p><img src="http://buke.github.io/images/my/pydev-9.png"></p>

<h3>8、注意事项</h3>

<ul>
<li>调试前需运行 start-pg.bat 启动数据库。</li>
<li>如需关闭数据库，请运行 stop-pg.bat 关闭。切勿直接关闭cmd窗口。</li>
<li>正常运行(非调试)和关闭 GreenOpenERP，请运行 start.bat 和 stop.bat .</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[openerp 使用 postgresql 存储过程和视图]]></title>
    <link href="http://buke.github.io/blog/2013/04/22/openerp-postgresql-stored-procedure-and-view/"/>
    <updated>2013-04-22T13:21:00+08:00</updated>
    <id>http://buke.github.io/blog/2013/04/22/openerp-postgresql-stored-procedure-and-view</id>
    <content type="html"><![CDATA[<p>OpenERP 使用 postgresql 存储过程和试图，步骤如下：</p>

<p>STEP1: 在模块的 init 函数中定义存储过程</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'>    <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">cr</span><span class="p">):</span>
</span><span class='line'>        <span class="sd">&#39;&#39;&#39; create stored procedure &#39;&#39;&#39;</span>
</span><span class='line'>        <span class="n">cr</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;&quot;&quot;CREATE OR REPLACE FUNCTION fn_fi_report_childs(int)</span>
</span><span class='line'><span class="s">        RETURNS TABLE(id int) AS $$</span>
</span><span class='line'><span class="s">            WITH RECURSIVE t AS (</span>
</span><span class='line'><span class="s">                SELECT id,parent_id  FROM fi_report WHERE id = $1</span>
</span><span class='line'><span class="s">              UNION ALL</span>
</span><span class='line'><span class="s">                SELECT fi_report.id, fi_report.parent_id FROM fi_report, t WHERE fi_report.parent_id = t.id</span>
</span><span class='line'><span class="s">            )</span>
</span><span class='line'><span class="s">            SELECT id FROM t;</span>
</span><span class='line'><span class="s">        $$ LANGUAGE SQL</span>
</span><span class='line'><span class="s">            &quot;&quot;&quot;</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>或者定义视图</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'>    <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">cr</span><span class="p">):</span>
</span><span class='line'>        <span class="n">tools</span><span class="o">.</span><span class="n">drop_view_if_exists</span><span class="p">(</span><span class="n">cr</span><span class="p">,</span> <span class="s">&#39;analytic_entries_report&#39;</span><span class="p">)</span>
</span><span class='line'>        <span class="n">cr</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;&quot;&quot;</span>
</span><span class='line'><span class="s">            create or replace view analytic_entries_report as (</span>
</span><span class='line'><span class="s">                 select</span>
</span><span class='line'><span class="s">                     min(a.id) as id,</span>
</span><span class='line'><span class="s">                     count(distinct a.id) as nbr,</span>
</span><span class='line'><span class="s">                     a.date as date,</span>
</span><span class='line'><span class="s">                     to_char(a.date, &#39;YYYY&#39;) as year,</span>
</span><span class='line'><span class="s">                     to_char(a.date, &#39;MM&#39;) as month,</span>
</span><span class='line'><span class="s">                     to_char(a.date, &#39;YYYY-MM-DD&#39;) as day,</span>
</span><span class='line'><span class="s">                     a.user_id as user_id,</span>
</span><span class='line'><span class="s">                     a.name as name,</span>
</span><span class='line'><span class="s">                     analytic.partner_id as partner_id,</span>
</span><span class='line'><span class="s">                     a.company_id as company_id,</span>
</span><span class='line'><span class="s">                     a.currency_id as currency_id,</span>
</span><span class='line'><span class="s">                     a.account_id as account_id,</span>
</span><span class='line'><span class="s">                     a.general_account_id as general_account_id,</span>
</span><span class='line'><span class="s">                     a.journal_id as journal_id,</span>
</span><span class='line'><span class="s">                     a.move_id as move_id,</span>
</span><span class='line'><span class="s">                     a.product_id as product_id,</span>
</span><span class='line'><span class="s">                     a.product_uom_id as product_uom_id,</span>
</span><span class='line'><span class="s">                     sum(a.amount) as amount,</span>
</span><span class='line'><span class="s">                     sum(a.unit_amount) as unit_amount</span>
</span><span class='line'><span class="s">                 from</span>
</span><span class='line'><span class="s">                     account_analytic_line a, account_analytic_account analytic</span>
</span><span class='line'><span class="s">                 where analytic.id = a.account_id</span>
</span><span class='line'><span class="s">                 group by</span>
</span><span class='line'><span class="s">                     a.date, a.user_id,a.name,analytic.partner_id,a.company_id,a.currency_id,</span>
</span><span class='line'><span class="s">                     a.account_id,a.general_account_id,a.journal_id,</span>
</span><span class='line'><span class="s">                     a.move_id,a.product_id,a.product_uom_id</span>
</span><span class='line'><span class="s">            )</span>
</span><span class='line'><span class="s">        &quot;&quot;&quot;</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>STEP2: 在模块的函数中使用存储过程</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'>    <span class="k">def</span> <span class="nf">get_amount</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span><span class="n">cr</span><span class="p">,</span><span class="n">uid</span><span class="p">,</span><span class="nb">id</span><span class="p">,</span><span class="n">period_id</span><span class="p">,</span><span class="n">context</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
</span><span class='line'>        <span class="n">cr</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&#39;SELECT * FROM fn_fi_report_childs(</span><span class="si">%s</span><span class="s">)&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nb">id</span><span class="p">,))</span>
</span></code></pre></td></tr></table></div></figure>


<p>而视图的话，则如普通的表一样使用。</p>

<p>STEP3: 完成！</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[GreenOpenERP -- 绿色版 OpenERP For Windows]]></title>
    <link href="http://buke.github.io/blog/2013/03/10/greenopenerp-portable-openerp-for-windows/"/>
    <updated>2013-03-10T21:43:00+08:00</updated>
    <id>http://buke.github.io/blog/2013/03/10/greenopenerp-portable-openerp-for-windows</id>
    <content type="html"><![CDATA[<p>OpenERP 绿色版 For Windows，源码运行，解压即用，集成 python/postgresql/openerp。</p>

<h2>软件版本</h2>

<ul>
<li>OpenERP (OpenERP 版本不定时更新, 看博主心情 :P )</li>
<li>Python=2.7.3</li>
<li>Postgresql=9.2.3</li>
</ul>


<h2>用法</h2>

<p>下载解压ZIP文件，然后运行 *.bat 批处理文件即可。（注意文件路径：不能含有中文等非西文字符）</p>

<h2>执行脚本</h2>

<ul>
<li>start.bat &#8211; 运行 Postgresql 和 Openerp</li>
<li>start-hide.bat &#8211; 隐藏命令行窗口，运行Postgresql 和 Openerp</li>
<li>stop.bat &#8211; 停止 Postgresql 和 Openerp</li>
<li>bin/pgAdmin3.exe &#8211; 运行 start.bat 之后，可以运行 pgAdmin 管理PG</li>
</ul>


<h2>下载地址</h2>

<p><a href="http://sourceforge.net/projects/greenopenerp/files/">http://sourceforge.net/projects/greenopenerp/files/</a></p>

<p>作者: wangbuke <a href="&#109;&#97;&#x69;&#108;&#116;&#x6f;&#x3a;&#x77;&#x61;&#x6e;&#x67;&#98;&#x75;&#107;&#101;&#x40;&#103;&#109;&#97;&#105;&#x6c;&#46;&#x63;&#111;&#x6d;">&#x77;&#97;&#x6e;&#x67;&#98;&#117;&#107;&#101;&#x40;&#103;&#109;&#x61;&#x69;&#x6c;&#46;&#x63;&#111;&#109;</a></p>

<p>博客: http://buke.github.com/</p>

<h2>UPDATE</h2>

<p>添加 6.1.1 版本下载</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[OpenERP 模块动态加载原理及启动代码分析]]></title>
    <link href="http://buke.github.io/blog/2013/02/26/openerp-dynamic-loading-and-booting-way/"/>
    <updated>2013-02-26T15:48:00+08:00</updated>
    <id>http://buke.github.io/blog/2013/02/26/openerp-dynamic-loading-and-booting-way</id>
    <content type="html"><![CDATA[<p>一般来说我们在编程中，对象定义都是预先定义好的。一些 OOP 语言（包括 Python/Java）允许对象是 自省的（也称为 反射）。即，自省对象能够描述自己：实例属于哪个类？类有哪些祖先？对象可以用哪些方法和属性？自省让处理对象的函数或方法根据传递给函数或方法的对象类型来做决定。即允许对象在运行时动态改变方法成员等属性。</p>

<p>得益于OpenERP ORM 模型的精巧设计，实际上 OpenERP 运行时也是动态读取模块信息并动态构建对象的。如在模块开发中，继承了 &#8216;res.users&#8217;, 新增一个方法或新增一个字段。在OpenERP 导入该模块后， OpenERP 会马上重构 &#8216;res.users&#8217; 对象并将新增的方法或字段添加到该对象。那么，OpenERP 是如何做到这点的呢？ 让我们从OpenERP 的启动部分开始分析：</p>

<p>首先，OpenERP 启动相关的服务, 这时并没有建立数据库链接和载入对象</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'>    <span class="k">if</span> <span class="ow">not</span> <span class="n">config</span><span class="p">[</span><span class="s">&quot;stop_after_init&quot;</span><span class="p">]:</span>
</span><span class='line'>        <span class="n">setup_pid_file</span><span class="p">()</span>
</span><span class='line'>        <span class="c"># Some module register themselves when they are loaded so we need the</span>
</span><span class='line'>        <span class="c"># services to be running before loading any registry.</span>
</span><span class='line'>        <span class="k">if</span> <span class="n">config</span><span class="p">[</span><span class="s">&#39;workers&#39;</span><span class="p">]:</span>
</span><span class='line'>            <span class="n">openerp</span><span class="o">.</span><span class="n">service</span><span class="o">.</span><span class="n">start_services_workers</span><span class="p">()</span>
</span><span class='line'>        <span class="k">else</span><span class="p">:</span>
</span><span class='line'>            <span class="n">openerp</span><span class="o">.</span><span class="n">service</span><span class="o">.</span><span class="n">start_services</span><span class="p">()</span>
</span></code></pre></td></tr></table></div></figure>


<p>不过可以在配置文件中指定 &#8216;db_name&#8217; 参数，可以让 OpenERP 在启动时加载指定数据库的对象并启动 Cron。 实际生产环境中建议启用该参数，否则需要在启动OpenERP后，登录一次OpenERP 在会加载对象并启动CRON</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'>    <span class="k">if</span> <span class="n">config</span><span class="p">[</span><span class="s">&#39;db_name&#39;</span><span class="p">]:</span>
</span><span class='line'>        <span class="k">for</span> <span class="n">dbname</span> <span class="ow">in</span> <span class="n">config</span><span class="p">[</span><span class="s">&#39;db_name&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&#39;,&#39;</span><span class="p">):</span>
</span><span class='line'>            <span class="n">preload_registry</span><span class="p">(</span><span class="n">dbname</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>不指定 &#8216;db_name&#8217; 参数情况下，OpenERP 会直到用户登录时才会初始化指定数据库。</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="k">def</span> <span class="nf">login</span><span class="p">(</span><span class="n">db</span><span class="p">,</span> <span class="n">login</span><span class="p">,</span> <span class="n">password</span><span class="p">):</span>
</span><span class='line'>    <span class="n">pool</span> <span class="o">=</span> <span class="n">pooler</span><span class="o">.</span><span class="n">get_pool</span><span class="p">(</span><span class="n">db</span><span class="p">)</span>
</span><span class='line'>    <span class="n">user_obj</span> <span class="o">=</span> <span class="n">pool</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;res.users&#39;</span><span class="p">)</span>
</span><span class='line'>    <span class="k">return</span> <span class="n">user_obj</span><span class="o">.</span><span class="n">login</span><span class="p">(</span><span class="n">db</span><span class="p">,</span> <span class="n">login</span><span class="p">,</span> <span class="n">password</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>打开 get_db 和 get_db_and_pool 定义</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="k">def</span> <span class="nf">get_db</span><span class="p">(</span><span class="n">db_name</span><span class="p">):</span>
</span><span class='line'>    <span class="sd">&quot;&quot;&quot;Return a database connection. The corresponding registry is initialized.&quot;&quot;&quot;</span>
</span><span class='line'>    <span class="k">return</span> <span class="n">get_db_and_pool</span><span class="p">(</span><span class="n">db_name</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
</span><span class='line'>
</span><span class='line'>
</span><span class='line'><span class="k">def</span> <span class="nf">get_db_and_pool</span><span class="p">(</span><span class="n">db_name</span><span class="p">,</span> <span class="n">force_demo</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">status</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">update_module</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span>
</span><span class='line'>    <span class="sd">&quot;&quot;&quot;Create and return a database connection and a newly initialized registry.&quot;&quot;&quot;</span>
</span><span class='line'>    <span class="n">registry</span> <span class="o">=</span> <span class="n">RegistryManager</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">db_name</span><span class="p">,</span> <span class="n">force_demo</span><span class="p">,</span> <span class="n">status</span><span class="p">,</span> <span class="n">update_module</span><span class="p">)</span>
</span><span class='line'>    <span class="k">return</span> <span class="n">registry</span><span class="o">.</span><span class="n">db</span><span class="p">,</span> <span class="n">registry</span>
</span></code></pre></td></tr></table></div></figure>


<p>顺藤摸瓜，看RegistryManager.new 定义</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'>            <span class="k">try</span><span class="p">:</span>
</span><span class='line'>                <span class="c"># This should be a method on Registry</span>
</span><span class='line'>                <span class="n">openerp</span><span class="o">.</span><span class="n">modules</span><span class="o">.</span><span class="n">load_modules</span><span class="p">(</span><span class="n">registry</span><span class="o">.</span><span class="n">db</span><span class="p">,</span> <span class="n">force_demo</span><span class="p">,</span> <span class="n">status</span><span class="p">,</span> <span class="n">update_module</span><span class="p">)</span>
</span><span class='line'>            <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
</span><span class='line'>                <span class="k">del</span> <span class="n">cls</span><span class="o">.</span><span class="n">registries</span><span class="p">[</span><span class="n">db_name</span><span class="p">]</span>
</span><span class='line'>                <span class="k">raise</span>
</span></code></pre></td></tr></table></div></figure>


<p>然后看到 load_modules, 终于要加载了，嘿嘿。</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'>        <span class="c"># STEP 1: LOAD BASE (must be done before module dependencies can be computed for later steps) </span>
</span><span class='line'>        <span class="n">graph</span> <span class="o">=</span> <span class="n">openerp</span><span class="o">.</span><span class="n">modules</span><span class="o">.</span><span class="n">graph</span><span class="o">.</span><span class="n">Graph</span><span class="p">()</span>
</span><span class='line'>        <span class="n">graph</span><span class="o">.</span><span class="n">add_module</span><span class="p">(</span><span class="n">cr</span><span class="p">,</span> <span class="s">&#39;base&#39;</span><span class="p">,</span> <span class="n">force</span><span class="p">)</span>
</span><span class='line'>        <span class="k">if</span> <span class="ow">not</span> <span class="n">graph</span><span class="p">:</span>
</span><span class='line'>            <span class="n">_logger</span><span class="o">.</span><span class="n">critical</span><span class="p">(</span><span class="s">&#39;module base cannot be loaded! (hint: verify addons-path)&#39;</span><span class="p">)</span>
</span><span class='line'>            <span class="k">raise</span> <span class="n">osv</span><span class="o">.</span><span class="n">osv</span><span class="o">.</span><span class="n">except_osv</span><span class="p">(</span><span class="n">_</span><span class="p">(</span><span class="s">&#39;Could not load base module&#39;</span><span class="p">),</span> <span class="n">_</span><span class="p">(</span><span class="s">&#39;module base cannot be loaded! (hint: verify addons-path)&#39;</span><span class="p">))</span>
</span><span class='line'>
</span><span class='line'>        <span class="c"># processed_modules: for cleanup step after install</span>
</span><span class='line'>        <span class="c"># loaded_modules: to avoid double loading</span>
</span><span class='line'>        <span class="n">report</span> <span class="o">=</span> <span class="n">pool</span><span class="o">.</span><span class="n">_assertion_report</span>
</span><span class='line'>        <span class="n">loaded_modules</span><span class="p">,</span> <span class="n">processed_modules</span> <span class="o">=</span> <span class="n">load_module_graph</span><span class="p">(</span><span class="n">cr</span><span class="p">,</span> <span class="n">graph</span><span class="p">,</span> <span class="n">status</span><span class="p">,</span> <span class="n">perform_checks</span><span class="o">=</span><span class="n">update_module</span><span class="p">,</span> <span class="n">report</span><span class="o">=</span><span class="n">report</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>        <span class="k">if</span> <span class="n">tools</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&#39;load_language&#39;</span><span class="p">]:</span>
</span><span class='line'>            <span class="k">for</span> <span class="n">lang</span> <span class="ow">in</span> <span class="n">tools</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&#39;load_language&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&#39;,&#39;</span><span class="p">):</span>
</span><span class='line'>                <span class="n">tools</span><span class="o">.</span><span class="n">load_language</span><span class="p">(</span><span class="n">cr</span><span class="p">,</span> <span class="n">lang</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>        <span class="c"># STEP 2: Mark other modules to be loaded/updated</span>
</span><span class='line'>        <span class="k">if</span> <span class="n">update_module</span><span class="p">:</span>
</span><span class='line'>            <span class="n">modobj</span> <span class="o">=</span> <span class="n">pool</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;ir.module.module&#39;</span><span class="p">)</span>
</span><span class='line'>            <span class="k">if</span> <span class="p">(</span><span class="s">&#39;base&#39;</span> <span class="ow">in</span> <span class="n">tools</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&#39;init&#39;</span><span class="p">])</span> <span class="ow">or</span> <span class="p">(</span><span class="s">&#39;base&#39;</span> <span class="ow">in</span> <span class="n">tools</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&#39;update&#39;</span><span class="p">]):</span>
</span><span class='line'>                <span class="n">_logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s">&#39;updating modules list&#39;</span><span class="p">)</span>
</span><span class='line'>                <span class="n">modobj</span><span class="o">.</span><span class="n">update_list</span><span class="p">(</span><span class="n">cr</span><span class="p">,</span> <span class="n">SUPERUSER_ID</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>            <span class="n">_check_module_names</span><span class="p">(</span><span class="n">cr</span><span class="p">,</span> <span class="n">itertools</span><span class="o">.</span><span class="n">chain</span><span class="p">(</span><span class="n">tools</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&#39;init&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">keys</span><span class="p">(),</span> <span class="n">tools</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&#39;update&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">keys</span><span class="p">()))</span>
</span><span class='line'>
</span><span class='line'>            <span class="n">mods</span> <span class="o">=</span> <span class="p">[</span><span class="n">k</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">tools</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&#39;init&#39;</span><span class="p">]</span> <span class="k">if</span> <span class="n">tools</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&#39;init&#39;</span><span class="p">][</span><span class="n">k</span><span class="p">]]</span>
</span><span class='line'>            <span class="k">if</span> <span class="n">mods</span><span class="p">:</span>
</span><span class='line'>                <span class="n">ids</span> <span class="o">=</span> <span class="n">modobj</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">cr</span><span class="p">,</span> <span class="n">SUPERUSER_ID</span><span class="p">,</span> <span class="p">[</span><span class="s">&#39;&amp;&#39;</span><span class="p">,</span> <span class="p">(</span><span class="s">&#39;state&#39;</span><span class="p">,</span> <span class="s">&#39;=&#39;</span><span class="p">,</span> <span class="s">&#39;uninstalled&#39;</span><span class="p">),</span> <span class="p">(</span><span class="s">&#39;name&#39;</span><span class="p">,</span> <span class="s">&#39;in&#39;</span><span class="p">,</span> <span class="n">mods</span><span class="p">)])</span>
</span><span class='line'>                <span class="k">if</span> <span class="n">ids</span><span class="p">:</span>
</span><span class='line'>                    <span class="n">modobj</span><span class="o">.</span><span class="n">button_install</span><span class="p">(</span><span class="n">cr</span><span class="p">,</span> <span class="n">SUPERUSER_ID</span><span class="p">,</span> <span class="n">ids</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>            <span class="n">mods</span> <span class="o">=</span> <span class="p">[</span><span class="n">k</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">tools</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&#39;update&#39;</span><span class="p">]</span> <span class="k">if</span> <span class="n">tools</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&#39;update&#39;</span><span class="p">][</span><span class="n">k</span><span class="p">]]</span>
</span><span class='line'>            <span class="k">if</span> <span class="n">mods</span><span class="p">:</span>
</span><span class='line'>                <span class="n">ids</span> <span class="o">=</span> <span class="n">modobj</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">cr</span><span class="p">,</span> <span class="n">SUPERUSER_ID</span><span class="p">,</span> <span class="p">[</span><span class="s">&#39;&amp;&#39;</span><span class="p">,</span> <span class="p">(</span><span class="s">&#39;state&#39;</span><span class="p">,</span> <span class="s">&#39;=&#39;</span><span class="p">,</span> <span class="s">&#39;installed&#39;</span><span class="p">),</span> <span class="p">(</span><span class="s">&#39;name&#39;</span><span class="p">,</span> <span class="s">&#39;in&#39;</span><span class="p">,</span> <span class="n">mods</span><span class="p">)])</span>
</span><span class='line'>                <span class="k">if</span> <span class="n">ids</span><span class="p">:</span>
</span><span class='line'>                    <span class="n">modobj</span><span class="o">.</span><span class="n">button_upgrade</span><span class="p">(</span><span class="n">cr</span><span class="p">,</span> <span class="n">SUPERUSER_ID</span><span class="p">,</span> <span class="n">ids</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>            <span class="n">cr</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;update ir_module_module set state=</span><span class="si">%s</span><span class="s"> where name=</span><span class="si">%s</span><span class="s">&quot;</span><span class="p">,</span> <span class="p">(</span><span class="s">&#39;installed&#39;</span><span class="p">,</span> <span class="s">&#39;base&#39;</span><span class="p">))</span>
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>        <span class="c"># STEP 3: Load marked modules (skipping base which was done in STEP 1)</span>
</span><span class='line'>        <span class="c"># IMPORTANT: this is done in two parts, first loading all installed or</span>
</span><span class='line'>        <span class="c">#            partially installed modules (i.e. installed/to upgrade), to</span>
</span><span class='line'>        <span class="c">#            offer a consistent system to the second part: installing</span>
</span><span class='line'>        <span class="c">#            newly selected modules.</span>
</span><span class='line'>        <span class="c">#            We include the modules &#39;to remove&#39; in the first step, because</span>
</span><span class='line'>        <span class="c">#            they are part of the &quot;currently installed&quot; modules. They will</span>
</span><span class='line'>        <span class="c">#            be dropped in STEP 6 later, before restarting the loading</span>
</span><span class='line'>        <span class="c">#            process.</span>
</span><span class='line'>        <span class="n">states_to_load</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;installed&#39;</span><span class="p">,</span> <span class="s">&#39;to upgrade&#39;</span><span class="p">,</span> <span class="s">&#39;to remove&#39;</span><span class="p">]</span>
</span><span class='line'>        <span class="n">processed</span> <span class="o">=</span> <span class="n">load_marked_modules</span><span class="p">(</span><span class="n">cr</span><span class="p">,</span> <span class="n">graph</span><span class="p">,</span> <span class="n">states_to_load</span><span class="p">,</span> <span class="n">force</span><span class="p">,</span> <span class="n">status</span><span class="p">,</span> <span class="n">report</span><span class="p">,</span> <span class="n">loaded_modules</span><span class="p">,</span> <span class="n">update_module</span><span class="p">)</span>
</span><span class='line'>        <span class="n">processed_modules</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">processed</span><span class="p">)</span>
</span><span class='line'>        <span class="k">if</span> <span class="n">update_module</span><span class="p">:</span>
</span><span class='line'>            <span class="n">states_to_load</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;to install&#39;</span><span class="p">]</span>
</span><span class='line'>            <span class="n">processed</span> <span class="o">=</span> <span class="n">load_marked_modules</span><span class="p">(</span><span class="n">cr</span><span class="p">,</span> <span class="n">graph</span><span class="p">,</span> <span class="n">states_to_load</span><span class="p">,</span> <span class="n">force</span><span class="p">,</span> <span class="n">status</span><span class="p">,</span> <span class="n">report</span><span class="p">,</span> <span class="n">loaded_modules</span><span class="p">,</span> <span class="n">update_module</span><span class="p">)</span>
</span><span class='line'>            <span class="n">processed_modules</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">processed</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>这里，第一步是加载核心模块 [&#8216;base&#8217;]，第二步加载需要升级或预载的模块，第三步加载已安装的模块。实际加载语句是：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'>        <span class="n">processed</span> <span class="o">=</span> <span class="n">load_marked_modules</span><span class="p">(</span><span class="n">cr</span><span class="p">,</span> <span class="n">graph</span><span class="p">,</span> <span class="n">states_to_load</span><span class="p">,</span> <span class="n">force</span><span class="p">,</span> <span class="n">status</span><span class="p">,</span> <span class="n">report</span><span class="p">,</span> <span class="n">loaded_modules</span><span class="p">,</span> <span class="n">update_module</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>查看 load_marked_module 定义：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="k">def</span> <span class="nf">load_marked_modules</span><span class="p">(</span><span class="n">cr</span><span class="p">,</span> <span class="n">graph</span><span class="p">,</span> <span class="n">states</span><span class="p">,</span> <span class="n">force</span><span class="p">,</span> <span class="n">progressdict</span><span class="p">,</span> <span class="n">report</span><span class="p">,</span> <span class="n">loaded_modules</span><span class="p">,</span> <span class="n">perform_checks</span><span class="p">):</span>
</span><span class='line'>    <span class="sd">&quot;&quot;&quot;Loads modules marked with ``states``, adding them to ``graph`` and</span>
</span><span class='line'><span class="sd">       ``loaded_modules`` and returns a list of installed/upgraded modules.&quot;&quot;&quot;</span>
</span><span class='line'>    <span class="n">processed_modules</span> <span class="o">=</span> <span class="p">[]</span>
</span><span class='line'>    <span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
</span><span class='line'>        <span class="n">cr</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;SELECT name from ir_module_module WHERE state IN </span><span class="si">%s</span><span class="s">&quot;</span> <span class="p">,(</span><span class="nb">tuple</span><span class="p">(</span><span class="n">states</span><span class="p">),))</span>
</span><span class='line'>        <span class="n">module_list</span> <span class="o">=</span> <span class="p">[</span><span class="n">name</span> <span class="k">for</span> <span class="p">(</span><span class="n">name</span><span class="p">,)</span> <span class="ow">in</span> <span class="n">cr</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span> <span class="k">if</span> <span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">graph</span><span class="p">]</span>
</span><span class='line'>        <span class="n">graph</span><span class="o">.</span><span class="n">add_modules</span><span class="p">(</span><span class="n">cr</span><span class="p">,</span> <span class="n">module_list</span><span class="p">,</span> <span class="n">force</span><span class="p">)</span>
</span><span class='line'>        <span class="n">_logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">&#39;Updating graph with </span><span class="si">%d</span><span class="s"> more modules&#39;</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">module_list</span><span class="p">))</span>
</span><span class='line'>        <span class="n">loaded</span><span class="p">,</span> <span class="n">processed</span> <span class="o">=</span> <span class="n">load_module_graph</span><span class="p">(</span><span class="n">cr</span><span class="p">,</span> <span class="n">graph</span><span class="p">,</span> <span class="n">progressdict</span><span class="p">,</span> <span class="n">report</span><span class="o">=</span><span class="n">report</span><span class="p">,</span> <span class="n">skip_modules</span><span class="o">=</span><span class="n">loaded_modules</span><span class="p">,</span> <span class="n">perform_checks</span><span class="o">=</span><span class="n">perform_checks</span><span class="p">)</span>
</span><span class='line'>        <span class="n">processed_modules</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">processed</span><span class="p">)</span>
</span><span class='line'>        <span class="n">loaded_modules</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">loaded</span><span class="p">)</span>
</span><span class='line'>        <span class="k">if</span> <span class="ow">not</span> <span class="n">processed</span><span class="p">:</span> <span class="k">break</span>
</span><span class='line'>    <span class="k">return</span> <span class="n">processed_modules</span>
</span></code></pre></td></tr></table></div></figure>


<p>重点是 load_module_graph</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'>    <span class="c"># register, instantiate and initialize models for each modules</span>
</span><span class='line'>    <span class="k">for</span> <span class="n">index</span><span class="p">,</span> <span class="n">package</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">graph</span><span class="p">):</span>
</span><span class='line'>        <span class="n">module_name</span> <span class="o">=</span> <span class="n">package</span><span class="o">.</span><span class="n">name</span>
</span><span class='line'>        <span class="n">module_id</span> <span class="o">=</span> <span class="n">package</span><span class="o">.</span><span class="n">id</span>
</span><span class='line'>
</span><span class='line'>        <span class="k">if</span> <span class="n">skip_modules</span> <span class="ow">and</span> <span class="n">module_name</span> <span class="ow">in</span> <span class="n">skip_modules</span><span class="p">:</span>
</span><span class='line'>            <span class="k">continue</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">_logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">&#39;module </span><span class="si">%s</span><span class="s">: loading objects&#39;</span><span class="p">,</span> <span class="n">package</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
</span><span class='line'>        <span class="n">migrations</span><span class="o">.</span><span class="n">migrate_module</span><span class="p">(</span><span class="n">package</span><span class="p">,</span> <span class="s">&#39;pre&#39;</span><span class="p">)</span>
</span><span class='line'>        <span class="n">load_openerp_module</span><span class="p">(</span><span class="n">package</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">models</span> <span class="o">=</span> <span class="n">pool</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">cr</span><span class="p">,</span> <span class="n">package</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">loaded_modules</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">package</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
</span><span class='line'>        <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">package</span><span class="p">,</span> <span class="s">&#39;init&#39;</span><span class="p">)</span> <span class="ow">or</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">package</span><span class="p">,</span> <span class="s">&#39;update&#39;</span><span class="p">)</span> <span class="ow">or</span> <span class="n">package</span><span class="o">.</span><span class="n">state</span> <span class="ow">in</span> <span class="p">(</span><span class="s">&#39;to install&#39;</span><span class="p">,</span> <span class="s">&#39;to upgrade&#39;</span><span class="p">):</span>
</span><span class='line'>            <span class="n">init_module_models</span><span class="p">(</span><span class="n">cr</span><span class="p">,</span> <span class="n">package</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">models</span><span class="p">)</span>
</span><span class='line'>        <span class="n">pool</span><span class="o">.</span><span class="n">_init_modules</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">package</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
</span><span class='line'>        <span class="n">status</span><span class="p">[</span><span class="s">&#39;progress&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">index</span><span class="p">)</span> <span class="o">/</span> <span class="nb">len</span><span class="p">(</span><span class="n">graph</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>主要是下面2句，</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'>        <span class="n">load_openerp_module</span><span class="p">(</span><span class="n">package</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">models</span> <span class="o">=</span> <span class="n">pool</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">cr</span><span class="p">,</span> <span class="n">package</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>先看 load_openerp_module</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'>    <span class="n">initialize_sys_path</span><span class="p">()</span>
</span><span class='line'>    <span class="k">try</span><span class="p">:</span>
</span><span class='line'>        <span class="n">mod_path</span> <span class="o">=</span> <span class="n">get_module_path</span><span class="p">(</span><span class="n">module_name</span><span class="p">)</span>
</span><span class='line'>        <span class="n">zip_mod_path</span> <span class="o">=</span> <span class="s">&#39;&#39;</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">mod_path</span> <span class="k">else</span> <span class="n">mod_path</span> <span class="o">+</span> <span class="s">&#39;.zip&#39;</span>
</span><span class='line'>        <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isfile</span><span class="p">(</span><span class="n">zip_mod_path</span><span class="p">):</span>
</span><span class='line'>            <span class="nb">__import__</span><span class="p">(</span><span class="s">&#39;openerp.addons.&#39;</span> <span class="o">+</span> <span class="n">module_name</span><span class="p">)</span>
</span><span class='line'>        <span class="k">else</span><span class="p">:</span>
</span><span class='line'>            <span class="n">zimp</span> <span class="o">=</span> <span class="n">zipimport</span><span class="o">.</span><span class="n">zipimporter</span><span class="p">(</span><span class="n">zip_mod_path</span><span class="p">)</span>
</span><span class='line'>            <span class="n">zimp</span><span class="o">.</span><span class="n">load_module</span><span class="p">(</span><span class="n">module_name</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>上面代码中 import 了一个模块。如果您看过 digitalsatori 校长的大作 <a href="http://shine-it.net/index.php/topic,5771.msg14289.html">OpenERP与Python 元编程</a>, 下面就涉及到元类了：</p>

<p> import 的时候 就会调用元类的构造函数</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'>    <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">name</span><span class="p">,</span> <span class="n">bases</span><span class="p">,</span> <span class="n">attrs</span><span class="p">):</span>
</span><span class='line'>        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_register</span><span class="p">:</span>
</span><span class='line'>            <span class="bp">self</span><span class="o">.</span><span class="n">_register</span> <span class="o">=</span> <span class="bp">True</span>
</span><span class='line'>            <span class="nb">super</span><span class="p">(</span><span class="n">MetaModel</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">bases</span><span class="p">,</span> <span class="n">attrs</span><span class="p">)</span>
</span><span class='line'>            <span class="k">return</span>
</span><span class='line'>
</span><span class='line'>        <span class="c"># The (OpenERP) module name can be in the `openerp.addons` namespace</span>
</span><span class='line'>        <span class="c"># or not. For instance module `sale` can be imported as</span>
</span><span class='line'>        <span class="c"># `openerp.addons.sale` (the good way) or `sale` (for backward</span>
</span><span class='line'>        <span class="c"># compatibility).</span>
</span><span class='line'>        <span class="n">module_parts</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__module__</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&#39;.&#39;</span><span class="p">)</span>
</span><span class='line'>        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">module_parts</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">2</span> <span class="ow">and</span> <span class="n">module_parts</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s">&#39;openerp&#39;</span> <span class="ow">and</span> \
</span><span class='line'>            <span class="n">module_parts</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="s">&#39;addons&#39;</span><span class="p">:</span>
</span><span class='line'>            <span class="n">module_name</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__module__</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&#39;.&#39;</span><span class="p">)[</span><span class="mi">2</span><span class="p">]</span>
</span><span class='line'>        <span class="k">else</span><span class="p">:</span>
</span><span class='line'>            <span class="n">module_name</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__module__</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&#39;.&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
</span><span class='line'>        <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s">&#39;_module&#39;</span><span class="p">):</span>
</span><span class='line'>            <span class="bp">self</span><span class="o">.</span><span class="n">_module</span> <span class="o">=</span> <span class="n">module_name</span>
</span><span class='line'>
</span><span class='line'>        <span class="c"># Remember which models to instanciate for this module.</span>
</span><span class='line'>        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_custom</span><span class="p">:</span>
</span><span class='line'>            <span class="bp">self</span><span class="o">.</span><span class="n">module_to_models</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_module</span><span class="p">,</span> <span class="p">[])</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>上面的代码基本上就是将自身类加入到 module_to_models 字典中。</p>

<p>然后我们来看pool.load</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'>    <span class="k">def</span> <span class="nf">load</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">cr</span><span class="p">,</span> <span class="n">module</span><span class="p">):</span>
</span><span class='line'>        <span class="sd">&quot;&quot;&quot; Load a given module in the registry.</span>
</span><span class='line'>
</span><span class='line'><span class="sd">        At the Python level, the modules are already loaded, but not yet on a</span>
</span><span class='line'><span class="sd">        per-registry level. This method populates a registry with the given</span>
</span><span class='line'><span class="sd">        modules, i.e. it instanciates all the classes of a the given module</span>
</span><span class='line'><span class="sd">        and registers them in the registry.</span>
</span><span class='line'>
</span><span class='line'><span class="sd">        &quot;&quot;&quot;</span>
</span><span class='line'>        <span class="n">models_to_load</span> <span class="o">=</span> <span class="p">[]</span> <span class="c"># need to preserve loading order</span>
</span><span class='line'>        <span class="c"># Instantiate registered classes (via the MetaModel automatic discovery</span>
</span><span class='line'>        <span class="c"># or via explicit constructor call), and add them to the pool.</span>
</span><span class='line'>        <span class="k">for</span> <span class="n">cls</span> <span class="ow">in</span> <span class="n">openerp</span><span class="o">.</span><span class="n">osv</span><span class="o">.</span><span class="n">orm</span><span class="o">.</span><span class="n">MetaModel</span><span class="o">.</span><span class="n">module_to_models</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">module</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="p">[]):</span>
</span><span class='line'>            <span class="c"># models register themselves in self.models</span>
</span><span class='line'>            <span class="n">model</span> <span class="o">=</span> <span class="n">cls</span><span class="o">.</span><span class="n">create_instance</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">cr</span><span class="p">)</span>
</span><span class='line'>            <span class="k">if</span> <span class="n">model</span><span class="o">.</span><span class="n">_name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">models_to_load</span><span class="p">:</span>
</span><span class='line'>                <span class="c"># avoid double-loading models whose declaration is split</span>
</span><span class='line'>                <span class="n">models_to_load</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">model</span><span class="o">.</span><span class="n">_name</span><span class="p">)</span>
</span><span class='line'>        <span class="k">return</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">models</span><span class="p">[</span><span class="n">m</span><span class="p">]</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">models_to_load</span><span class="p">]</span>
</span></code></pre></td></tr></table></div></figure>


<p>这里我们可以看到 MetaModel 的身影，cls.create_instance(self, cr) 这里就是动态构造对象的核心代码。</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'>        <span class="n">parent_names</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">cls</span><span class="p">,</span> <span class="s">&#39;_inherit&#39;</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span>
</span><span class='line'>        <span class="c"># 判断是否有继承父类 </span>
</span><span class='line'>        <span class="k">if</span> <span class="n">parent_names</span><span class="p">:</span>
</span><span class='line'>            <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">parent_names</span><span class="p">,</span> <span class="p">(</span><span class="nb">str</span><span class="p">,</span> <span class="nb">unicode</span><span class="p">)):</span>
</span><span class='line'>                <span class="n">name</span> <span class="o">=</span> <span class="n">cls</span><span class="o">.</span><span class="n">_name</span> <span class="ow">or</span> <span class="n">parent_names</span>
</span><span class='line'>                <span class="n">parent_names</span> <span class="o">=</span> <span class="p">[</span><span class="n">parent_names</span><span class="p">]</span>
</span><span class='line'>            <span class="k">else</span><span class="p">:</span>
</span><span class='line'>                <span class="n">name</span> <span class="o">=</span> <span class="n">cls</span><span class="o">.</span><span class="n">_name</span>
</span><span class='line'>            <span class="k">if</span> <span class="ow">not</span> <span class="n">name</span><span class="p">:</span>
</span><span class='line'>                <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="s">&#39;_name is mandatory in case of multiple inheritance&#39;</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>            <span class="k">for</span> <span class="n">parent_name</span> <span class="ow">in</span> <span class="p">((</span><span class="nb">type</span><span class="p">(</span><span class="n">parent_names</span><span class="p">)</span><span class="o">==</span><span class="nb">list</span><span class="p">)</span> <span class="ow">and</span> <span class="n">parent_names</span> <span class="ow">or</span> <span class="p">[</span><span class="n">parent_names</span><span class="p">]):</span>
</span><span class='line'>                <span class="c"># 读取父类</span>
</span><span class='line'>                <span class="n">parent_model</span> <span class="o">=</span> <span class="n">pool</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">parent_name</span><span class="p">)</span>
</span><span class='line'>                <span class="k">if</span> <span class="ow">not</span> <span class="n">parent_model</span><span class="p">:</span>
</span><span class='line'>                    <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="s">&#39;The model &quot;</span><span class="si">%s</span><span class="s">&quot; specifies an unexisting parent class &quot;</span><span class="si">%s</span><span class="s">&quot;</span><span class="se">\n</span><span class="s">&#39;</span>
</span><span class='line'>                        <span class="s">&#39;You may need to add a dependency on the parent class</span><span class="se">\&#39;</span><span class="s"> module.&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">parent_name</span><span class="p">))</span>
</span><span class='line'>                <span class="k">if</span> <span class="ow">not</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">cls</span><span class="p">,</span> <span class="s">&#39;_original_module&#39;</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span> <span class="ow">and</span> <span class="n">name</span> <span class="o">==</span> <span class="n">parent_model</span><span class="o">.</span><span class="n">_name</span><span class="p">:</span>
</span><span class='line'>                    <span class="n">cls</span><span class="o">.</span><span class="n">_original_module</span> <span class="o">=</span> <span class="n">parent_model</span><span class="o">.</span><span class="n">_original_module</span>
</span><span class='line'>                <span class="n">parent_class</span> <span class="o">=</span> <span class="n">parent_model</span><span class="o">.</span><span class="n">__class__</span>
</span><span class='line'>                <span class="n">nattr</span> <span class="o">=</span> <span class="p">{}</span>
</span><span class='line'>                <span class="c"># 复制父类属性</span>
</span><span class='line'>                <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">attributes</span><span class="p">:</span>
</span><span class='line'>                    <span class="n">new</span> <span class="o">=</span> <span class="n">copy</span><span class="o">.</span><span class="n">copy</span><span class="p">(</span><span class="nb">getattr</span><span class="p">(</span><span class="n">parent_model</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="p">{}))</span>
</span><span class='line'>                    <span class="k">if</span> <span class="n">s</span> <span class="o">==</span> <span class="s">&#39;_columns&#39;</span><span class="p">:</span>
</span><span class='line'>                        <span class="c"># Don&#39;t _inherit custom fields.</span>
</span><span class='line'>                        <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">new</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span>
</span><span class='line'>                            <span class="k">if</span> <span class="n">new</span><span class="p">[</span><span class="n">c</span><span class="p">]</span><span class="o">.</span><span class="n">manual</span><span class="p">:</span>
</span><span class='line'>                                <span class="k">del</span> <span class="n">new</span><span class="p">[</span><span class="n">c</span><span class="p">]</span>
</span><span class='line'>                        <span class="c"># Duplicate float fields because they have a .digits</span>
</span><span class='line'>                        <span class="c"># cache (which must be per-registry, not server-wide).</span>
</span><span class='line'>                        <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">new</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span>
</span><span class='line'>                            <span class="k">if</span> <span class="n">new</span><span class="p">[</span><span class="n">c</span><span class="p">]</span><span class="o">.</span><span class="n">_type</span> <span class="o">==</span> <span class="s">&#39;float&#39;</span><span class="p">:</span>
</span><span class='line'>                                <span class="n">new</span><span class="p">[</span><span class="n">c</span><span class="p">]</span> <span class="o">=</span> <span class="n">copy</span><span class="o">.</span><span class="n">copy</span><span class="p">(</span><span class="n">new</span><span class="p">[</span><span class="n">c</span><span class="p">])</span>
</span><span class='line'>                    <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">new</span><span class="p">,</span> <span class="s">&#39;update&#39;</span><span class="p">):</span>
</span><span class='line'>                        <span class="n">new</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">cls</span><span class="o">.</span><span class="n">__dict__</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="p">{}))</span>
</span><span class='line'>                    <span class="k">elif</span> <span class="n">s</span><span class="o">==</span><span class="s">&#39;_constraints&#39;</span><span class="p">:</span>
</span><span class='line'>                        <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">cls</span><span class="o">.</span><span class="n">__dict__</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="p">[]):</span>
</span><span class='line'>                            <span class="n">exist</span> <span class="o">=</span> <span class="bp">False</span>
</span><span class='line'>                            <span class="k">for</span> <span class="n">c2</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">new</span><span class="p">)):</span>
</span><span class='line'>                                <span class="c">#For _constraints, we should check field and methods as well</span>
</span><span class='line'>                                <span class="k">if</span> <span class="n">new</span><span class="p">[</span><span class="n">c2</span><span class="p">][</span><span class="mi">2</span><span class="p">]</span><span class="o">==</span><span class="n">c</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="ow">and</span> <span class="p">(</span><span class="n">new</span><span class="p">[</span><span class="n">c2</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="n">c</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> \
</span><span class='line'>                                        <span class="ow">or</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">new</span><span class="p">[</span><span class="n">c2</span><span class="p">][</span><span class="mi">0</span><span class="p">],</span><span class="s">&#39;__name__&#39;</span><span class="p">,</span> <span class="bp">True</span><span class="p">)</span> <span class="o">==</span> \
</span><span class='line'>                                            <span class="nb">getattr</span><span class="p">(</span><span class="n">c</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="s">&#39;__name__&#39;</span><span class="p">,</span> <span class="bp">False</span><span class="p">)):</span>
</span><span class='line'>                                    <span class="c"># If new class defines a constraint with</span>
</span><span class='line'>                                    <span class="c"># same function name, we let it override</span>
</span><span class='line'>                                    <span class="c"># the old one.</span>
</span><span class='line'>
</span><span class='line'>                                    <span class="n">new</span><span class="p">[</span><span class="n">c2</span><span class="p">]</span> <span class="o">=</span> <span class="n">c</span>
</span><span class='line'>                                    <span class="n">exist</span> <span class="o">=</span> <span class="bp">True</span>
</span><span class='line'>                                    <span class="k">break</span>
</span><span class='line'>                            <span class="k">if</span> <span class="ow">not</span> <span class="n">exist</span><span class="p">:</span>
</span><span class='line'>                                <span class="n">new</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
</span><span class='line'>                    <span class="k">else</span><span class="p">:</span>
</span><span class='line'>                        <span class="n">new</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">cls</span><span class="o">.</span><span class="n">__dict__</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="p">[]))</span>
</span><span class='line'>                    <span class="n">nattr</span><span class="p">[</span><span class="n">s</span><span class="p">]</span> <span class="o">=</span> <span class="n">new</span>
</span><span class='line'>
</span><span class='line'>                <span class="c"># Keep links to non-inherited constraints, e.g. useful when exporting translations</span>
</span><span class='line'>                <span class="n">nattr</span><span class="p">[</span><span class="s">&#39;_local_constraints&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">cls</span><span class="o">.</span><span class="n">__dict__</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;_constraints&#39;</span><span class="p">,</span> <span class="p">[])</span>
</span><span class='line'>                <span class="n">nattr</span><span class="p">[</span><span class="s">&#39;_local_sql_constraints&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">cls</span><span class="o">.</span><span class="n">__dict__</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;_sql_constraints&#39;</span><span class="p">,</span> <span class="p">[])</span>
</span><span class='line'>                <span class="c"># 调用元类构造函数</span>
</span><span class='line'>                <span class="n">cls</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="p">(</span><span class="n">cls</span><span class="p">,</span> <span class="n">parent_class</span><span class="p">),</span> <span class="nb">dict</span><span class="p">(</span><span class="n">nattr</span><span class="p">,</span> <span class="n">_register</span><span class="o">=</span><span class="bp">False</span><span class="p">))</span>
</span><span class='line'>        <span class="k">else</span><span class="p">:</span>
</span><span class='line'>            <span class="n">cls</span><span class="o">.</span><span class="n">_local_constraints</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">cls</span><span class="p">,</span> <span class="s">&#39;_constraints&#39;</span><span class="p">,</span> <span class="p">[])</span>
</span><span class='line'>            <span class="n">cls</span><span class="o">.</span><span class="n">_local_sql_constraints</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">cls</span><span class="p">,</span> <span class="s">&#39;_sql_constraints&#39;</span><span class="p">,</span> <span class="p">[])</span>
</span><span class='line'>
</span><span class='line'>        <span class="k">if</span> <span class="ow">not</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">cls</span><span class="p">,</span> <span class="s">&#39;_original_module&#39;</span><span class="p">,</span> <span class="bp">None</span><span class="p">):</span>
</span><span class='line'>            <span class="n">cls</span><span class="o">.</span><span class="n">_original_module</span> <span class="o">=</span> <span class="n">cls</span><span class="o">.</span><span class="n">_module</span>
</span><span class='line'>        <span class="c"># 构造对象</span>
</span><span class='line'>        <span class="n">obj</span> <span class="o">=</span> <span class="nb">object</span><span class="o">.</span><span class="n">__new__</span><span class="p">(</span><span class="n">cls</span><span class="p">)</span>
</span><span class='line'>        <span class="c"># 初始化对象</span>
</span><span class='line'>        <span class="n">obj</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="n">pool</span><span class="p">,</span> <span class="n">cr</span><span class="p">)</span>
</span><span class='line'>        <span class="k">return</span> <span class="n">obj</span>
</span></code></pre></td></tr></table></div></figure>


<p>上面代码很重要，可以看到首先是判断该对象是否有继承父类，如果没有就直接构造，和动态没有什么关系。</p>

<p>如果有继承父类, 就复制父类属性, 这里就是动态构建类的做法。</p>

<p>假如有不同模块，都继承了同一个父类，那么如何保证类成员和属性是否加载完整或覆盖呢？ 答案在于这句代码：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'>                <span class="n">parent_model</span> <span class="o">=</span> <span class="n">pool</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">parent_name</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>Registry.get 的定义</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'>    <span class="k">def</span> <span class="nf">get</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">model_name</span><span class="p">):</span>
</span><span class='line'>        <span class="sd">&quot;&quot;&quot; Return a model for a given name or None if it doesn&#39;t exist.&quot;&quot;&quot;</span>
</span><span class='line'>        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">models</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">model_name</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>最后看看obj.<strong>init</strong>(pool, cr)初始化对象，做了什么动作？</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'>    <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">pool</span><span class="p">,</span> <span class="n">cr</span><span class="p">):</span>
</span><span class='line'>        <span class="sd">&quot;&quot;&quot; Initialize a model and make it part of the given registry.</span>
</span><span class='line'>
</span><span class='line'><span class="sd">        - copy the stored fields&#39; functions in the osv_pool,</span>
</span><span class='line'><span class="sd">        - update the _columns with the fields found in ir_model_fields,</span>
</span><span class='line'><span class="sd">        - ensure there is a many2one for each _inherits&#39;d parent,</span>
</span><span class='line'><span class="sd">        - update the children&#39;s _columns,</span>
</span><span class='line'><span class="sd">        - give a chance to each field to initialize itself.</span>
</span><span class='line'>
</span><span class='line'><span class="sd">        &quot;&quot;&quot;</span>
</span><span class='line'>        <span class="n">pool</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_name</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">pool</span> <span class="o">=</span> <span class="n">pool</span>
</span></code></pre></td></tr></table></div></figure>


<p>pool.add(self._name, self) 定义如下：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'>    <span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">model_name</span><span class="p">,</span> <span class="n">model</span><span class="p">):</span>
</span><span class='line'>        <span class="sd">&quot;&quot;&quot; Add or replace a model in the registry.&quot;&quot;&quot;</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">models</span><span class="p">[</span><span class="n">model_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">model</span>
</span></code></pre></td></tr></table></div></figure>


<p>到这里应该很非常清楚，Registry.models 保存了对象的 model 信息。这样多个对象继承同一父类时，按照加载顺序先后动态构建相关的类。</p>

<p>至此，OpenERP 启动时动态加载模块分析完成。如模块安装、升级、卸载等, 则是通过 signal_registry_change 和 check_registry_signaling 处理，重新载入 Registry, 然后重新构建 OpenERP 对象。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Openerp Web PDF Report Preview &amp; Print 模块升级至 7.0]]></title>
    <link href="http://buke.github.io/blog/2013/02/22/openerp-web-pdf-report-preview-and-print-update-7-dot-0/"/>
    <updated>2013-02-22T19:18:00+08:00</updated>
    <id>http://buke.github.io/blog/2013/02/22/openerp-web-pdf-report-preview-and-print-update-7-dot-0</id>
    <content type="html"><![CDATA[<p>Openerp Web PDF Report Preview &amp; Print</p>

<p>下载地址： <a href="https://github.com/buke/openerp-web-pdf-preview-print">https://github.com/buke/openerp-web-pdf-preview-print</a></p>

<p>简介：</p>

<p>将OpenERP 的PDF报表打印下载功能，改为直接在浏览器中预览打印。</p>

<ul>
<li>For IE， 需要安装 Adobe Reader。</li>
<li>For Firefox 19 + , 神马都不用安装。</li>
<li>For Chrome, 神马都不用安装。</li>
</ul>


<p>以上在windows 上测试通过。如果浏览器阻止了弹出窗口，请点允许弹出窗口。</p>

<p>系统要求：</p>

<ul>
<li>OpenERP 7.0</li>
</ul>


<p>注：</p>

<ol>
<li>openerp-7.0-20130222-002152 下测试通过</li>
<li>之前版本可能会出现以下错误：</li>
</ol>


<p>TypeError: this.get_action_manager(&#8230;) is undefined on Firefox</p>

<p>TypeError: Cannot call method &#8216;get_title&#8217; of undefined on Chrome / IE</p>

<p>解决办法有2种</p>

<p>F5 刷新页面重新加载 或者  升级OpenERP 版本</p>

<p><img src="http://buke.github.io/images/my/oe-pdf-7.jpg"></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Tryton 相关软件简介及名字背后的神话]]></title>
    <link href="http://buke.github.io/blog/2013/01/28/trytons-name-and-myth-introdution/"/>
    <updated>2013-01-28T23:06:00+08:00</updated>
    <id>http://buke.github.io/blog/2013/01/28/trytons-name-and-myth-introdution</id>
    <content type="html"><![CDATA[<p>Tryton 是一个MVC三层架构、高性能的通用应用ERP平台，基于 GPL-3 协议发布。其主要特点是模块化设计、可扩展性和安全。2008 年，Tryton 从 TinyERP  4.2 分支fork，并发布了1.0版本。不过到现在为止，Tryton 基本上重构了全部底层代码。到2012年9月，Tryton 已推出 2.6 版本。</p>

<p>Tryton的名字来源于Triton，传说中Triton是希腊神话中海之信使，海王波塞冬和海后安菲特里忒的儿子。另外海王星的命名体系也是来源于希腊海神，Triton 就是海卫一的名字。有意思的是 Tryton 相关的软件，大多也是希腊海中诸神命名。</p>

<p>下面介绍下 Tryton 相关软件和名字来源：</p>

<p>1、Tryton</p>

<p><img src="http://buke.github.io/images/my/tirton.jpg"></p>

<p>简介：gtk 客户端</p>

<p>名字来源：Triton ，希腊神话中海之信使，海王波塞冬和海后安菲特里忒的儿子。和他老爸一样，他也带着三叉戟，此外他还带着一个海螺号角，传说大海中可怕的声音就是这个号角发出。</p>

<p>同时也是海卫一的名字。</p>

<p>2、Trytond</p>

<p>简介：Tryton 后台守护进程，Trytond 是 Tryton daemon 的缩写。</p>

<p>3、trytond_xxx-2.6.0</p>

<p>简介：trytond 模块，XXX 是模块名字，2.6.0 是版本号</p>

<p>4、Neso</p>

<p>简介：tryton 可独立运行的客户端+服务端。windows 下使用sqlite 数据库，在单用户情况下使用。</p>

<p>名字来源：海洋仙女涅瑞伊得斯Nereides之一，仙女涅索Neso一名意为【住在岛上】，源自古希腊语的nesos‘岛屿’。如印度尼西亚Indonesia则意为【印度群岛】。</p>

<p>同时也是海卫十三的名字。</p>

<p>5、Proteus</p>

<p>简介：tryton 客户端API库，可以像类库一样读取 tryton server。</p>

<p>名字来源：Proteus 海神波塞冬之子，他负责放牧Poseidon的一群海豹。相比而言，Proteus是海神中最善于变幻的一位，他曾经被从特洛伊战场返航的Menelaus紧紧抓住，为了摆脱这个人，Proteus变成了狮子、虎豹、野猪、流水、熊熊烈火和风等。</p>

<p>同时也是海卫八的名字。</p>

<p>6、SAO</p>

<p>简介：tryton web 客户端（尚在开发中 http://hg.tryton.org/sandbox/sao）。</p>

<p>名字来源：海洋仙女涅瑞伊得斯Nereides之一，仙女 Sao 被认为是拯救水手，保障水手安全的海中仙女。
同时也是海卫十一的名字。</p>

<p>7、Nereid</p>

<p>简介：整合Flask 的web 框架，使用tryton 为后台。由 openlabs.co.in 开发。</p>

<p>名字来源：海洋仙女涅瑞伊德Nereides，Nereid为其单数，Nereides为海神涅柔斯Nereus与大洋神女多里斯Doris的五十个女儿。
同时也是海卫二的名字。</p>

<p><img src="http://buke.github.io/images/my/nereides.jpg"></p>

<p> 下一个是谁？</p>

<p>海王星 Neptunus （Neptunus 是罗马神话中 波塞冬 的名字） 海王星有13颗已知的天然卫星</p>

<p>海卫一 <strong> Triton </strong></p>

<p>海卫二 <strong> Nereid </strong></p>

<p>海卫三 Naiad</p>

<p>海卫四 Thalassa</p>

<p>海卫五 Despina</p>

<p>海卫六 Galatea</p>

<p>海卫七 Larissa</p>

<p>海卫八 <strong> Proteus </strong></p>

<p>海卫九 Halimede</p>

<p>海卫十 Psamathe</p>

<p>海卫十一 <strong> Sao </strong></p>

<p>海卫十二 Laomedeia</p>

<p>海卫十三 <strong> Neso </strong></p>

<p>目前为止，Tryton 的相关软件都以海王星的卫星命名，猜猜看下一个是那个？</p>

<p>参考资料：
海王星的卫星 http://zh.wikipedia.org/wiki/%E6%B5%B7%E7%8E%8B%E6%98%9F%E7%9A%84%E5%8D%AB%E6%98%9F</p>

<p>果壳 稻草人语</p>

<p>http://www.guokr.com/blog/431784/</p>

<p>http://www.guokr.com/blog/380892/</p>

<p>http://www.guokr.com/blog/101070/</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[OpenERP 负载平衡]]></title>
    <link href="http://buke.github.io/blog/2013/01/21/openerp-load-balance/"/>
    <updated>2013-01-21T15:11:00+08:00</updated>
    <id>http://buke.github.io/blog/2013/01/21/openerp-load-balance</id>
    <content type="html"><![CDATA[<p> OpenERP 7.0 带来了许多新特性，架构上也有许多改进。其中可配置 worker 参数，可使 OpenERP 运行在多进程模式，突破GIL的限制，有效利用了现代多核CPU的性能。但默认情况下，OpenERP 只能运行于一台服务器，对于提供SAAS服务或并发很大的情况下，单台服务器的性能是有限的。本文介绍实现 OpenERP 负载平衡的方法和原理。</p>

<p>一、架构</p>

<pre><code>┌──────────────────────────────────────────────┐
│                   Nginx                      │
└──────────────────────────────────────────────┘
        /              |                \
┌────────────┐   ┌────────────┐    ┌────────────┐
│ OE Server  │   │ OE Server  │    │ OE Server  │
└────────────┘   └────────────┘    └────────────┘
         \             |                /
┌───────────────────────────────────────────────┐
│                Redis Server                   │
└───────────────────────────────────────────────┘
</code></pre>

<p>注：实现负载平衡的关键点在于 cache 和 session 共享。</p>

<p>二、Web 服务器配置</p>

<p>WEB 服务器选择 Nginx + upstream 配置，可参考 “使用Nginx Upstream 部署 OpenERP ” http://my.oschina.net/wangbuke/blog/67450 。</p>

<p>默认情况下，nginx 采用轮询的方式，将请求分发到多个 OE Server 里。建议改为 ip_hash 方式，如：</p>

<pre><code>upstream bakend {
     ip_hash;
     server 192.168.0.11:8069;
     server 192.168.0.12:8069;
}
</code></pre>

<p>三、OpenERP 的 Session 和 Cache 处理</p>

<p>3.1 OpenERP Web Session 处理</p>

<p>OpenERP 中的Session 处理默认用FilesystemSessionStore，使用文件系统存储用户 session  。如 openerp/addons/web/http.py</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="k">class</span> <span class="nc">Root</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span><span class='line'>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">session_store</span> <span class="o">=</span> <span class="n">werkzeug</span><span class="o">.</span><span class="n">contrib</span><span class="o">.</span><span class="n">sessions</span><span class="o">.</span><span class="n">FilesystemSessionStore</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
</span><span class='line'>        <span class="bp">self</span><span class="o">.</span><span class="n">session_lock</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">Lock</span><span class="p">()</span>
</span></code></pre></td></tr></table></div></figure>


<p>那么我们只要将OpenERP 中的SessionStore，改为 RedisSessionStore，RedisSessionStore 可参考https://gist.github.com/1451947 。</p>

<p>修改方法，可以直接修改 http.py 文件。
或是和我一样，重写一个库，重载 session_context 方法，这样可以不修改OpenERP的源文件，方便以后升级。</p>

<p>3.2 OpenERP LRU Cache 处理</p>

<p>openerp/tools/cache.py 中 ormcache 和 ormcache_multi 是 OpenERP 中非常重要的缓存类。OpenERP ORM 大部分的方法调用都会经过 @tools.ormcache 或 @ormcache_multi 修饰。经过修饰后，结果会被缓存，这个缓存是存放于内存中。 这个就是OE在加载一次数据后，第二次会明显快很多的原因。还有，通过web 界面翻译OE术语不能实时生效，也是因为缓存没有更新。</p>

<p>可以修改ormcache 和 ormcache_multi 类，以使用 redis 缓存。关键代码如下：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'>    <span class="k">def</span> <span class="nf">lookup</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">self2</span><span class="p">,</span> <span class="n">cr</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">):</span>
</span><span class='line'>        <span class="n">key</span> <span class="o">=</span> <span class="n">args</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">skiparg</span><span class="o">-</span><span class="mi">2</span><span class="p">:]</span>
</span><span class='line'>        <span class="n">key</span> <span class="o">=</span> <span class="s">&#39;</span><span class="si">%s</span><span class="s">:</span><span class="si">%s</span><span class="s">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">method</span><span class="o">.</span><span class="n">__name__</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">key</span><span class="p">))</span>
</span><span class='line'>        <span class="c">#key = md5(key).hexdigest()</span>
</span><span class='line'>        <span class="n">hash_name</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">db_key_template</span> <span class="o">%</span> <span class="n">cr</span><span class="o">.</span><span class="n">dbname</span>
</span><span class='line'>        <span class="n">value</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">redis</span><span class="o">.</span><span class="n">hget</span><span class="p">(</span><span class="n">hash_name</span><span class="p">,</span> <span class="n">key</span><span class="p">)</span>
</span><span class='line'>        <span class="k">if</span> <span class="n">value</span><span class="p">:</span>
</span><span class='line'>            <span class="bp">self</span><span class="o">.</span><span class="n">stat_hit</span> <span class="o">+=</span> <span class="mi">1</span>
</span><span class='line'>            <span class="k">return</span> <span class="n">loads</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
</span><span class='line'>        <span class="k">else</span><span class="p">:</span>
</span><span class='line'>            <span class="bp">self</span><span class="o">.</span><span class="n">stat_miss</span> <span class="o">+=</span> <span class="mi">1</span>
</span><span class='line'>            <span class="n">value</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">method</span><span class="p">(</span><span class="n">self2</span><span class="p">,</span> <span class="n">cr</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span>
</span><span class='line'>            <span class="bp">self</span><span class="o">.</span><span class="n">redis</span><span class="o">.</span><span class="n">hset</span><span class="p">(</span><span class="n">hash_name</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">dumps</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">HIGHEST_PROTOCOL</span><span class="p">))</span>
</span><span class='line'>            <span class="bp">self</span><span class="o">.</span><span class="n">redis</span><span class="o">.</span><span class="n">expire</span><span class="p">(</span><span class="n">hash_name</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">timeout</span><span class="p">)</span>
</span><span class='line'>            <span class="k">return</span> <span class="n">value</span>
</span></code></pre></td></tr></table></div></figure>


<p>缓存的值使用 cPickle 序列化后，将每个键值对存放于 redis 的 哈希表中。</p>

<p>3.3 auth_openid 模块</p>

<p>auth_openid模块也使用文件系统存储用户登录凭证。如：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="k">class</span> <span class="nc">OpenIDController</span><span class="p">(</span><span class="n">openerp</span><span class="o">.</span><span class="n">addons</span><span class="o">.</span><span class="n">web</span><span class="o">.</span><span class="n">http</span><span class="o">.</span><span class="n">Controller</span><span class="p">):</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">_store</span> <span class="o">=</span> <span class="n">filestore</span><span class="o">.</span><span class="n">FileOpenIDStore</span><span class="p">(</span><span class="n">_storedir</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>如果您启用了这个模块，那么这里也需要修改为存储在redis中。如果没有启用此模块，则无需理会。</p>

<p>相关实现可参考，https://github.com/bbangert/openid-redis/blob/master/openidredis/<strong>init</strong>.py</p>

<p>四、OpenERP Cron 处理</p>

<p>默认情况下，每个OpenERP Server 实例都会运行一个 cron 进程任务。这里建议只允许一个实例运行CRON。把OpenERP 7.0 的配置参数 max_cron_threads 设置为0 ，即可禁止cron。相关代码如下：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'>    <span class="k">def</span> <span class="nf">process_spawn</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span><span class='line'>        <span class="k">while</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">workers_http</span><span class="p">)</span> <span class="o">&lt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">population</span><span class="p">:</span>
</span><span class='line'>            <span class="bp">self</span><span class="o">.</span><span class="n">worker_spawn</span><span class="p">(</span><span class="n">WorkerHTTP</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">workers_http</span><span class="p">)</span>
</span><span class='line'>        <span class="k">while</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">workers_cron</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">config</span><span class="p">[</span><span class="s">&#39;max_cron_threads&#39;</span><span class="p">]:</span>
</span><span class='line'>            <span class="bp">self</span><span class="o">.</span><span class="n">worker_spawn</span><span class="p">(</span><span class="n">WorkerCron</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">workers_cron</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>五、OpenERP Module RegistryManager 处理</p>

<p>OpenERP Module Registry 主要负责管理OE的对象。一般是安装或更新的模块时候，会根据定义来更新数据库。 在OE多进程模式下，OE会自动管理 Module Registry ，相关的更新信息会存放在数据库里。RegistryManager  会检测是否有更新，如有更新将会自动清除缓存并重新载入。相关代码如下：</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'>    <span class="nd">@classmethod</span>
</span><span class='line'>    <span class="k">def</span> <span class="nf">setup_multi_process_signaling</span><span class="p">(</span><span class="n">cls</span><span class="p">,</span> <span class="n">cr</span><span class="p">):</span>
</span><span class='line'>        <span class="k">if</span> <span class="ow">not</span> <span class="n">openerp</span><span class="o">.</span><span class="n">multi_process</span><span class="p">:</span>
</span><span class='line'>            <span class="k">return</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@classmethod</span>
</span><span class='line'>    <span class="k">def</span> <span class="nf">check_registry_signaling</span><span class="p">(</span><span class="n">cls</span><span class="p">,</span> <span class="n">db_name</span><span class="p">):</span>
</span><span class='line'>        <span class="k">if</span> <span class="n">openerp</span><span class="o">.</span><span class="n">multi_process</span> <span class="ow">and</span> <span class="n">db_name</span> <span class="ow">in</span> <span class="n">cls</span><span class="o">.</span><span class="n">registries</span><span class="p">:</span>
</span></code></pre></td></tr></table></div></figure>


<p>这里，实际上无需做改动,上面只是说明情况。只需让OE运行在多进程模式即可（也就是配置 worker 参数）。</p>

<p>六、完成！</p>

<p>经过以上几个步骤，可以让OpenERP 运行于多台服务器，通过Redis 分布式缓存处理相关的 Cache 和 Session，从而实现 OpenERP 负载平衡。</p>

<p>注：
1、本文仅讨论 OpenERP 负载平衡部署方式，并不涉及 Postgresql 和 Redis 的负载平衡，相应的方法请自行搜索。
2、鉴于OpenERP SA 官方已不再维护 GTK 客户端，并没有对GTK客户端的情况进行完整测试。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[OpenERP 自动编码去BOM（可用excel编辑）]]></title>
    <link href="http://buke.github.io/blog/2012/09/05/openerp-web-import-chardet/"/>
    <updated>2012-09-05T15:00:00+08:00</updated>
    <id>http://buke.github.io/blog/2012/09/05/openerp-web-import-chardet</id>
    <content type="html"><![CDATA[<p>openerp-web-import-chardet</p>

<p>作者：wangbuke@gmail.com</p>

<p>源码托管地址： https://github.com/buke/openerp-web-import-chardet</p>

<p>OE apps 下载地址： http://apps.openerp.com/addon/8098</p>

<h1>功能：</h1>

<p>自动检测OpenERP 导入的CSV文件编码 自动移除UTF8文件的BOM。安装完之后，就可以直接用EXCEL WPS等编辑好的CSV文件，导入到OpenERP中。</p>

<h1>支持编码：</h1>

<ul>
<li>ASCII, UTF-8</li>
<li>Big5, GBK, GB2312, HZ-GB, HZ-GB-2312 (简体/繁体中文)</li>
<li>EUC-JP, SHIFT_JIS, ISO-2022-JP (日文)</li>
<li>EUC-KR, ISO-2022-KR (韩文)</li>
<li>KOI8-R, MacCyrillic, IBM855, IBM866, ISO-8859-5, windows-1251 (斯拉夫文)</li>
<li>ISO-8859-2, windows-1250 (匈牙利文)</li>
<li>ISO-8859-5, windows-1251 (保加利亚文)</li>
<li>windows-1252 (英文)</li>
<li>ISO-8859-7, windows-1253 (希腊文)</li>
<li>ISO-8859-8, windows-1255 (希伯来文)</li>
<li>TIS-620 (泰文)</li>
</ul>


<h1>依赖模块:</h1>

<p>python chardet (本模块已内含chardet-1.1。如果系统安装了新版本，则使用您安装的新版本.)</p>

<p><img src="http://buke.github.io/images/my/oe-chardet.jpg"></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[OpenERP PyChart 中文报表模块（支持CJK语言）]]></title>
    <link href="http://buke.github.io/blog/2012/08/19/openerp-pychart-unicode-report/"/>
    <updated>2012-08-19T15:44:00+08:00</updated>
    <id>http://buke.github.io/blog/2012/08/19/openerp-pychart-unicode-report</id>
    <content type="html"><![CDATA[<p>OpenERP PyChart Unicode Report (Support CJK Font)</p>

<p>作者：wangbuke@gmail.com</p>

<p>源码托管地址：https://github.com/buke/openerp-pychart-unicode-report</p>

<p>OpenERP 官方APP下载地址： http://apps.openerp.com/addon/8009</p>

<p>支持pychart中文报表，如“库存预测”、“工作中心负载” 等报表。</p>

<h1>模块原理</h1>

<p>让pychart 生成svg 文件，然后用cairosvg 模块生成PDF报表。</p>

<h1>依赖模块</h1>

<p>python-cairo python-cairosvg</p>

<p>Debian/Ubuntu安装方法： $ su apt-get install python-cairo python-cairosvg</p>

<h1>安装与设置</h1>

<h2>1、安装字体</h2>

<p>复制您所用的字体文件，如simsun.ttc 到系统目录下。</p>

<p>debian/ubuntu: $ sudo cp simsun.ttc /usr/share/fonts</p>

<p>windows :  C:> copy simsun.ttc  c:/windows/fonts</p>

<h3>2、配置pychart 报表字体 默认使用宋体</h3>

<p>修改openerp 配置文件 openerp-server.conf , 添加以下参数：</p>

<p>pychart_ttfont_name = Simsun</p>

<p>注：默认是宋体，如使用默认值则无需修改 conf 文件</p>

<p>祝你好运 ~</p>

<p><img src="http://buke.github.io/images/my/oe-pychart-report.jpg"></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[开源模块 Openerp Web PDF Report Preview & Print 简介]]></title>
    <link href="http://buke.github.io/blog/2012/08/02/openerp-web-pdf-report-preview-and-print/"/>
    <updated>2012-08-02T15:32:00+08:00</updated>
    <id>http://buke.github.io/blog/2012/08/02/openerp-web-pdf-report-preview-and-print</id>
    <content type="html"><![CDATA[<p>Openerp Web PDF Report Preview &amp; Print</p>

<p>下载地址： https://github.com/buke/openerp-web-pdf-preview-print</p>

<p>openerp 官方app下载 ：  http://apps.openerp.com/addon/7941</p>

<p>简介:</p>

<p>将OpenERP 的PDF报表打印下载功能，改为直接在浏览器中预览打印。</p>

<p>For IE， 需要安装 Adobe Reader。</p>

<p>For Firefox ,需要安装 Adobe Reader。</p>

<p>For Chrome, 神马都不用安装。</p>

<p>以上在windows 上测试通过。如果浏览器阻止了弹出窗口，请点允许弹出窗口。</p>

<p>系统要求：</p>

<p>OpenERP 6.1</p>

<p><img src="http://buke.github.io/images/my/oe-pdf-print.jpg"></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Taobao OpenERP Connector 简要说明]]></title>
    <link href="http://buke.github.io/blog/2012/07/18/taobao-openerp-connector/"/>
    <updated>2012-07-18T16:29:00+08:00</updated>
    <id>http://buke.github.io/blog/2012/07/18/taobao-openerp-connector</id>
    <content type="html"><![CDATA[<p>Taobao OpenERP Connector</p>

<p>项目托管地址：<a href="https://github.com/buke/openerp-taobao">https://github.com/buke/openerp-taobao</a></p>

<p>作者： wangbuke@gmail.com</p>

<h1>功能：</h1>

<ol>
<li>接受淘宝主动通知，自动添加、确认订单、发货等。</li>
<li>同步淘宝订单</li>
<li>导入淘宝产品, 同步库存</li>
<li>导入淘宝用户</li>
<li>自动评价，中差评预警</li>
<li>跟踪淘宝订单物流信息, 签收提醒</li>
<li>&#8230;. 等等等 (懒的写了，自己发现吧)</li>
</ol>


<h1>系统要求：</h1>

<ul>
<li>OpenERP 6.1</li>
<li>beanstalkd</li>
<li>pycurl</li>
</ul>


<h1>安装说明：</h1>

<h2>1. 安装beanstalkd</h2>

<h3>1.1 linux 系统</h3>

<p>debian/ubuntu: # apt-get install beanstalkd</p>

<p>redhat/centos: # yum install beanstalkd</p>

<p>安装完成之后，开启beanstalkd的持久化选项：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># vi /etc/default/beanstalkd
</span><span class='line'>
</span><span class='line'>## Defaults for the beanstalkd init script, /etc/init.d/beanstalkd on
</span><span class='line'>## Debian systems. Append ``-b /var/lib/beanstalkd'' for persistent
</span><span class='line'>## storage.
</span><span class='line'>BEANSTALKD_LISTEN_ADDR=0.0.0.0
</span><span class='line'>BEANSTALKD_LISTEN_PORT=11300
</span><span class='line'>#DAEMON_OPTS="-l $BEANSTALKD_LISTEN_ADDR -p $BEANSTALKD_LISTEN_PORT"
</span><span class='line'>DAEMON_OPTS="-l $BEANSTALKD_LISTEN_ADDR -p $BEANSTALKD_LISTEN_PORT -b /var/lib/beanstalkd"
</span><span class='line'>
</span><span class='line'>## Uncomment to enable startup during boot.
</span><span class='line'>START=yes</span></code></pre></td></tr></table></div></figure>


<h3>1.2 windows 系统</h3>

<p>beanstalkd 原生不能在windows 下运行，当然也有大牛用cgywin 编译了一个。请参考 http://software1987.de/2011/03/beanstalkd-unter-windows-mit-cygwin/  。编译后的 beanstalkd 下载地址是 http://software1987.de/wp-content/uploads/2011/03/beanstalkd-1.4.6-cygwin.zip</p>

<p>下载解压后，打开 cmd.exe 运行</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>C:\beanstalkd\bin>beanstalkd.exe -l 127.0.0.1 -p 11300 -b C:\beanstalkd</span></code></pre></td></tr></table></div></figure>


<p>注意上面的目录路径，根据您的实际情况修改。 -b 后面是目录，用于存放beanstalkd 持久化的文件。 上面是直接运行，当然您也可以创建快捷方式，或者用runasservice 工具封装成windows 的服务。</p>

<h2>2. 安装pycurl</h2>

<h3>2.1 linux 系统</h3>

<p>debian/ubuntu: # apt-get install python-pycurl</p>

<p>redhat/centos: # yum install python-pycurl</p>

<h3>2.2 windows 系统</h3>

<h4>2.2.1 OpenERP - 源码安装</h4>

<h5>2.2.1.1 安装 python （如已经安装则跳过）</h5>

<p>到 http://python.org/ 下载安装，不解释</p>

<h5>2.2.1.2 安装 pycurl（如已经安装则跳过）</h5>

<p>到 http://www.lfd.uci.edu/~gohlke/pythonlibs/#pycurl 下载对应版本的 pycurl 安装</p>

<h4>2.2.2 OpenERP - all in one</h4>

<p>all in one 的版本 在安装完以上步骤之外，还需要把 C:\Python26\Lib\site-packages 目录下的 curl 目录 和 pycurl.pyd 文件 复制到 C:\Program Files\OpenERP 6.1-20120717-233333\Server\server 目录中。（注意路径！，根据实际情况修改）不然下面的安装会提示找不到pycurl。</p>

<p>注意：我现在的all in one （OpenERP 6.1-20120717-233333\） python版本 2.6，所以使用all in one 版本的同学注意了，上面2步都要下载安装for python 2.6 版本的。 （通过看C:\Program Files\OpenERP 6.1-20120717-233333\Server\server\python26.dll这个文件的后缀可以知道python 版本）</p>

<h2>3. 安装 Taobao OpenERP Connector 模块</h2>

<p>这里和OE安装模块方法一样。首先到https://github.com/buke/openerp-taobao 下载，然后有2种方法：一种是把taobao 文件夹放到OpenERP 的 addon 目录下，第二种是把taobao 文件夹压缩为zip 文件，通过OE后台上传模块。</p>

<h2>4. OpenERP conf 文件配置参数</h2>

<p>Taobao OpenERP Connector 模块有几个默认配置参数如下：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>beanstalkd_interface = localhost
</span><span class='line'>beanstalkd_port = 11300
</span><span class='line'>taobao_stream_service = True
</span><span class='line'>taobao_stream_thread_limit = 1
</span><span class='line'>taobao_worker_thread_limit = 4</span></code></pre></td></tr></table></div></figure>


<p> 上面是默认值，如果您不需要修改则不用放入OpenERP 启动的 conf中。反之，如果你需要修改 ，则将上面几个参数写在conf 文件中。</p>

<h2>5. 关于淘宝 api 的几个问题</h2>

<p>首先登陆 open.taobao.com 创建一个 C/S 架构 自用型应用，然后开通主动通知业务。</p>

<p>App Key : 自己找，不解释</p>

<p>App Secret: 自己找，不解释</p>

<p>App SessionKey: 获取方法</p>

<ol>
<li>先访问 http://my.open.taobao.com/auth/authorize.htm?appkey={appkey}获得授权码</li>
<li>再访问 http://container.open.taobao.com/container?authcode={授权码},会得到类似如下的字符串top_appkey=1142&amp;top_parameters=xxx&amp;top_session=xxx&amp;top_sign=xxx,字符串里面的top_session值即为SessionKey</li>
</ol>


<p>根据淘宝文档说明，C/S应用的 SessionKey 有效期为一年，大家到时记得更新。</p>

<p>PS:</p>

<p>配置淘宝商店的时候出现报错的，请检查你们的淘宝应用权限 。必须是C/S架构的商家后台系统。淘宝规定请看 http://dev.open.taobao.com/bbs/read.php?tid=24315  自2012年7月12日起，“商家后台系统标签”的申请只允许商城店铺和集市三皇冠以上商家申请。</p>

<p>欢迎大家参与此项目，或者到https://github.com/buke/openerp-taobao 提需求、BUG等，也可以直接给我来信。谢谢~</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[使用Nginx Upstream 部署 OpenERP]]></title>
    <link href="http://buke.github.io/blog/2012/07/17/use-nginx-upstream-deploy-openerp/"/>
    <updated>2012-07-17T15:51:00+08:00</updated>
    <id>http://buke.github.io/blog/2012/07/17/use-nginx-upstream-deploy-openerp</id>
    <content type="html"><![CDATA[<p>Openerp 6.1 使用werkzeug 作为web服务的框架，性能比之前的cherrypy 有了很大的改善。但无论是 werkzeug 还是cherrypy ，都不是专门的web服务器。通常的做法是在openerp 之前加一个 Nginx、Apache或其他服务器。下面介绍使用Nginx Upstream 部署openerp 的方法。</p>

<h1>一 前提</h1>

<p>此处假设您已经安装好 openerp ，并运行在 127.0.0.1:8069</p>

<h1>二 安装Nginx</h1>

<p>debian/ubuntu:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># apt-get install nginx</span></code></pre></td></tr></table></div></figure>


<p>redhat/centos:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># yum install nginx</span></code></pre></td></tr></table></div></figure>


<h1>三 配置Nginx</h1>

<h2>1. 修改/etc/nginx/nginx.conf ，开启gzip 压缩</h2>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># vi /etc/nginx/nginx.conf
</span><span class='line'>
</span><span class='line'>--------------nginx.conf 需修改内容节选--------------------------
</span><span class='line'>        gzip on;
</span><span class='line'>        gzip_disable "msie6";
</span><span class='line'>
</span><span class='line'>        gzip_vary on;
</span><span class='line'>        gzip_proxied any;
</span><span class='line'>        gzip_comp_level 6;
</span><span class='line'>        gzip_buffers 16 8k;
</span><span class='line'>        gzip_http_version 1.1;
</span><span class='line'>        #添加一个类型 application/javascript
</span><span class='line'>        gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;</span></code></pre></td></tr></table></div></figure>


<p>吐槽一下，是否开启gzip，差别真不小。oe 首页加载的http://127.0.0.1/web/webclient/js 开启前文件大小是 1.4M , 开启后大小是350.6 KB （通过firebug 查看）。</p>

<h2>2. 建立 openerp 配置文件</h2>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># touch /etc/nginx/sites-enabled/openerp
</span><span class='line'># vi /etc/nginx/sites-enabled/openerp
</span><span class='line'>
</span><span class='line'>--------------------openerp 文件内容---------------------------
</span><span class='line'>
</span><span class='line'>proxy_temp_path /tmp/nginx_proxy_temp;
</span><span class='line'>proxy_cache_path  /tmp/nginx_proxy_cache levels=1:2  keys_zone=oecache:100m inactive=3d max_size=1000m;
</span><span class='line'>
</span><span class='line'>proxy_buffer_size     32k;              #设置代理服务器（nginx）保存用户头信息的缓冲区大小
</span><span class='line'>proxy_buffers         4 32k;            #proxy_buffers缓冲区，网页平均在32k以下的话，这样设置
</span><span class='line'>proxy_busy_buffers_size  64k;           #高负荷下缓冲大小（proxy_buffers*2）
</span><span class='line'>proxy_temp_file_write_size  64k;       #设定缓存文件夹大小，大于这个值，将从upstream服务器传
</span><span class='line'>
</span><span class='line'>proxy_connect_timeout      60;
</span><span class='line'>proxy_send_timeout         60;
</span><span class='line'>proxy_read_timeout         3000;
</span><span class='line'>
</span><span class='line'>upstream oeserver{
</span><span class='line'>        server 127.0.0.1:8069;
</span><span class='line'>}
</span><span class='line'>
</span><span class='line'>server {
</span><span class='line'>
</span><span class='line'>        server_name  www.example.com;
</span><span class='line'>
</span><span class='line'>        root /var/www/openerp-6.1-1/openerp/addons;
</span><span class='line'>
</span><span class='line'>        location /{
</span><span class='line'>
</span><span class='line'>                proxy_cache              oecache;
</span><span class='line'>                #proxy_cache_key "$host$request_uri$request_body";
</span><span class='line'>                proxy_cache_key $host$request_uri$request_body;
</span><span class='line'>                proxy_cache_valid  200 304 1d;
</span><span class='line'>                proxy_cache_valid  any   1d;
</span><span class='line'>
</span><span class='line'>                proxy_next_upstream http_502 http_504 error timeout invalid_header;
</span><span class='line'>                proxy_pass_header Set-Cookie;
</span><span class='line'>                proxy_set_header   Host             $host;
</span><span class='line'>                proxy_set_header   X-Real-IP        $remote_addr;
</span><span class='line'>                proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
</span><span class='line'>                proxy_redirect  off;
</span><span class='line'>
</span><span class='line'>                proxy_pass http://oeserver;
</span><span class='line'>
</span><span class='line'>                proxy_buffering on;
</span><span class='line'>                proxy_cache_valid       1d;
</span><span class='line'>                expires 1d;
</span><span class='line'>        }
</span><span class='line'>
</span><span class='line'>        location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
</span><span class='line'>                proxy_buffering on;
</span><span class='line'>                proxy_cache_valid       1d;
</span><span class='line'>                expires 1d;
</span><span class='line'>        }
</span><span class='line'>
</span><span class='line'>}</span></code></pre></td></tr></table></div></figure>


<h1>完成 ！</h1>

<p>Nginx 此处仅仅是作为 openerp 的前端WEB服务器，Nginx 还有更大的作用是可以实现Openerp 的负载平衡。此处按下不表，呵呵</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[linux 下使用 Supervisor 管理源码启动的 OpenERP]]></title>
    <link href="http://buke.github.io/blog/2012/07/16/user-supervisor-manager-openerp/"/>
    <updated>2012-07-16T22:50:00+08:00</updated>
    <id>http://buke.github.io/blog/2012/07/16/user-supervisor-manager-openerp</id>
    <content type="html"><![CDATA[<p>从源码启动openerp，简单的做法是添加启动脚本到/etc/init.d/rc.local等，让openerp 随系统启动而运行。此类方法只在系统启动时运行，但万一程序在运行中崩溃，您可能要等到用户发现不能使用了，才去重启服务器。下面请出今天的主角： supervisor   ( http://supervisord.org/)</p>

<p>Supervisor 是什么？</p>

<p>Supervisor is a client/server system that allows its users to monitor and control a number of processes on UNIX-like operating systems.
Supervisor 是一个客户端/服务器系统，允许用户监控和控制类 Unix 操作系统上的进程数。</p>

<h2>1、安装</h2>

<p>debian/ubuntu</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>apt-get install supervisor</span></code></pre></td></tr></table></div></figure>


<p>redhat/centos</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>yum install supervisor</span></code></pre></td></tr></table></div></figure>


<h2>2、建立openerp 的配置文件</h2>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># touch /etc/supervisor/conf.d/openerp.conf
</span><span class='line'># vi /etc/supervisor/conf.d/openerp.conf</span></code></pre></td></tr></table></div></figure>


<p>openerp.conf 内容</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[program:openerp]
</span><span class='line'>; openerp 启动脚本
</span><span class='line'>command=python /var/www/openerp-6.1-1/openerp-server -c /var/www/openerp-6.1-1/openerp-server.conf
</span><span class='line'>; openerp 目录
</span><span class='line'>directory=/var/www/openerp-6.1-1/
</span><span class='line'>; 是否随系统启动
</span><span class='line'>autostart=true
</span><span class='line'>; 自动重启
</span><span class='line'>autorestart=true
</span><span class='line'>; 启动时间，如果超过这个时间oe还没有挂，则视为已经启动
</span><span class='line'>startsecs=3
</span><span class='line'>; 启动用户
</span><span class='line'>user=www-data
</span><span class='line'>redirect_stderr=true
</span><span class='line'>; log 文件
</span><span class='line'>stdout_logfile=/var/www/openerp-6.1-1/openerp-server.log
</span><span class='line'>stdout_logfile_maxbytes=500MB
</span><span class='line'>stdout_logfile_backups=50
</span><span class='line'>stdout_capture_maxbytes=1MB
</span><span class='line'>stdout_events_enabled=false
</span><span class='line'>loglevel=warn</span></code></pre></td></tr></table></div></figure>


<h2>3、 完成！</h2>

<p>重启系统试试看openerp 是否已经启动。也可以想办法把openerp 搞崩溃，试试supervisor 能不能及时将openerp 重启</p>

<h2>4、 常用命令</h2>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># supervisorctl 
</span><span class='line'>openerp                          RUNNING    pid 9454, uptime 4:43:34
</span><span class='line'>supervisor> start openerp  #启动
</span><span class='line'>supervisor> stop openerp   #停止
</span><span class='line'>supervisor> restart openerp #重启
</span><span class='line'>supervisor> status openerp #查看状态</span></code></pre></td></tr></table></div></figure>



]]></content>
  </entry>
  
</feed>
