Ural penguins
http://uralbash.ru/blog/atom.xml
2022-03-24T15:23:00Z
ABlog
Python прекрасен во всём
http://uralbash.ru/articles/2022/python_korabl/
2022-03-24T15:23:00Z
2022-03-24T15:23:00Z
Uralbash
<div class="section" id="python">
<div align="center" class="align-center"><img alt="Python" src="../_images/Python-logo-notext.svg" width="400px" /></div>
</div>
Ошибка fatal error: stdlib.h: No such file or directory
http://uralbash.ru/articles/2019/stdlib-error/
2019-07-11T15:23:00Z
2019-07-11T15:23:00Z
Uralbash
<div class="section" id="fatal-error-stdlib-h-no-such-file-or-directory">
<p>Такая ошибка может возникнуть при компиляции программ на <cite>C++</cite> в <cite>Linux</cite>.
В моем случае это была библиотека на <cite>Qt</cite>.</p>
<div class="literal-block-wrapper docutils container" id="id1">
<div class="code-block-caption"><span class="caption-text">Ошибка компиляции Qt модуля</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ g++ -c -pipe -g -std<span class="o">=</span>gnu++11 -Wall -W -D_REENTRANT -fPIC -DQT_BLUETOOTH_LIB -DQT_CORE_LIB -I. -isystem /usr/include -isystem /usr/include/x86_64-linux-gnu/qt5 -isystem /usr/include/x86_64-linux-gnu/qt5/QtBluetooth -isystem /usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -o main.o src/main.cpp
In file included from /usr/include/c++/7/bits/stl_algo.h:59:0,
from /usr/include/c++/7/algorithm:62,
from /usr/include/x86_64-linux-gnu/qt5/QtCore/qglobal.h:109,
from /usr/include/x86_64-linux-gnu/qt5/QtCore/qcoreapplication.h:43,
from /usr/include/x86_64-linux-gnu/qt5/QtCore/QCoreApplication:1,
from src/main.cpp:6:
/usr/include/c++/7/cstdlib:75:15: fatal error: stdlib.h: No such file or directory
<span class="c1">#include_next <stdlib.h></span>
^~~~~~~~~~
compilation terminated.
Makefile:497: recipe <span class="k">for</span> target <span class="s1">'main.o'</span> failed
make: *** <span class="o">[</span>main.o<span class="o">]</span> Error <span class="m">1</span>
</pre></div>
</div>
</div>
<p>Возникает только в последних версиях <cite>gcc</cite>, видимо заголовки как то не
правильно собраны в дистрибутиве <cite>Ubuntu 18.04</cite>. Поэтому для решения установим
по умолчанию компилятор <cite>gcc</cite> 5-ой версии.</p>
<p>Установка:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo apt install gcc-5 g++-5
</pre></div>
</div>
<p>Добавим его в список:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 <span class="m">50</span> --slave /usr/bin/g++ g++ /usr/bin/g++-5
</pre></div>
</div>
<p>И поменяем значение дефолтного компилятора:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo update-alternatives --config gcc
There are <span class="m">2</span> choices <span class="k">for</span> the alternative gcc <span class="o">(</span>providing /usr/bin/gcc<span class="o">)</span>.
Selection Path Priority Status
------------------------------------------------------------
<span class="m">0</span> /usr/bin/gcc-8 <span class="m">80</span> auto mode
* <span class="m">1</span> /usr/bin/gcc-5 <span class="m">50</span> manual mode
<span class="m">2</span> /usr/bin/gcc-8 <span class="m">80</span> manual mode
Press <enter> to keep the current choice<span class="o">[</span>*<span class="o">]</span>, or <span class="nb">type</span> selection number: <span class="m">1</span>
</pre></div>
</div>
<p>Теперь в системе используется по умолчанию <cite>gcc</cite> 5-ой версии и все собирается без ошибок.</p>
</div>
Python инфографика
http://uralbash.ru/articles/2017/python/
2017-09-19T21:41:00Z
2017-09-19T21:41:00Z
Uralbash
<div class="section" id="python">
<p>Последнее время крупные компании всё чаще выбирают Python для разных проектов.
И правда, для многих задач Python имеет замечательные решения.</p>
<img alt="Python инфографика" src="_static/2017/get-the-job-done-faster-with-python.jpg" />
<p>Источник <a class="reference external" href="https://pythontips.com/2017/09/19/13-python-libraries-to-keep-you-busy/">https://pythontips.com/2017/09/19/13-python-libraries-to-keep-you-busy/</a></p>
</div>
C# .Net Core для Linux
http://uralbash.ru/articles/2017/netcore/
2017-09-01T21:35:00Z
2017-09-01T21:35:00Z
Uralbash
<div class="section" id="c-net-core-linux">
<p>Благодаря популярности <code class="docutils literal"><span class="pre">Java</span></code> язык <code class="docutils literal"><span class="pre">C#</span></code> обрел ещё большую популярность, да
так, что теперь доступен на <cite>Linux</cite>. Я конечно не испытываю симпатий к этим
языкам и <code class="docutils literal"><span class="pre">.Net</span></code> стеку в целом, но <cite>OpenSource</cite> и доступность в <cite>Linux</cite> не
может не радовать. Ниже рассмотрим пример как развернуть проект на <code class="docutils literal"><span class="pre">.NET</span>
<span class="pre">Core</span></code> и отправить <cite>HTTP</cite> запрос.</p>
<div class="admonition note">
<p class="first admonition-title">Примечание</p>
<p class="last">Это статья из лекций
<a class="reference external" href="http://lecturesnet.readthedocs.io/net/requests/csharp.html">http://lecturesnet.readthedocs.io/net/requests/csharp.html</a></p>
</div>
<div class="section" id="c">
<h2>C#</h2>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<ul class="last simple">
<li><a class="reference external" href="https://www.microsoft.com/net/download/linux">https://www.microsoft.com/net/download/linux</a></li>
<li><a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient">HttpClient Class</a></li>
</ul>
</div>
<p><a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient">HttpClient Class</a>
содержится в поставке <code class="docutils literal"><span class="pre">.NET</span> <span class="pre">Core</span></code> для <code class="docutils literal"><span class="pre">Linux</span></code>. Создадим проект на C#
отправляющий HTTP запрос.</p>
<p>Первой командой создается проект из шаблона, затем устанавливаются зависимости
и запускается программа.</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ dotnet new Console
$ dotnet restore
$ dotnet run
</pre></div>
</div>
<p>HTTP запрос выполняется асинхронно.</p>
<div class="literal-block-wrapper docutils container" id="id2">
<div class="code-block-caption"><span class="caption-text">Program.cs</span></div>
<div class="highlight-csharp"><div class="highlight"><pre><span></span><span class="k">using</span> <span class="nn">System</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.Net.Http</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.Net.Http.Headers</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.Threading.Tasks</span><span class="p">;</span>
<span class="k">namespace</span> <span class="nn">ConsoleApplication</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">Program</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">Main</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">args</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">MainAsync</span><span class="p">().</span><span class="n">Wait</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">static</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">MainAsync</span><span class="p">()</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">client</span> <span class="p">=</span> <span class="k">new</span> <span class="n">HttpClient</span><span class="p">();</span>
<span class="n">client</span><span class="p">.</span><span class="n">DefaultRequestHeaders</span><span class="p">.</span><span class="n">Accept</span><span class="p">.</span><span class="n">Clear</span><span class="p">();</span>
<span class="n">client</span><span class="p">.</span><span class="n">DefaultRequestHeaders</span><span class="p">.</span><span class="n">Accept</span><span class="p">.</span><span class="n">Add</span><span class="p">(</span>
<span class="k">new</span> <span class="nf">MediaTypeWithQualityHeaderValue</span><span class="p">(</span>
<span class="s">"application/vnd.github.v3+json"</span>
<span class="p">)</span>
<span class="p">);</span>
<span class="n">client</span><span class="p">.</span><span class="n">DefaultRequestHeaders</span><span class="p">.</span><span class="n">Add</span><span class="p">(</span>
<span class="s">"User-Agent"</span><span class="p">,</span>
<span class="s">".NET Foundation Repository Reporter"</span>
<span class="p">);</span>
<span class="kt">var</span> <span class="n">stringTask</span> <span class="p">=</span> <span class="n">client</span><span class="p">.</span><span class="n">GetStringAsync</span><span class="p">(</span>
<span class="s">"https://api.github.com/orgs/ustu/repos"</span>
<span class="p">);</span>
<span class="kt">var</span> <span class="n">msg</span> <span class="p">=</span> <span class="k">await</span> <span class="n">stringTask</span><span class="p">;</span>
<span class="n">Console</span><span class="p">.</span><span class="n">Write</span><span class="p">(</span><span class="n">msg</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
<p>Результат выполнения программы.</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ dotnet run
Project net <span class="o">(</span>.NETCoreApp,Version<span class="o">=</span>v1.1<span class="o">)</span> will be compiled because inputs were modified
Compiling net <span class="k">for</span> .NETCoreApp,Version<span class="o">=</span>v1.1
Compilation succeeded.
<span class="m">0</span> Warning<span class="o">(</span>s<span class="o">)</span>
<span class="m">0</span> Error<span class="o">(</span>s<span class="o">)</span>
Time elapsed <span class="m">00</span>:00:01.0363043
<span class="o">[{</span><span class="s2">"id"</span>:25028386,<span class="s2">"name"</span>:<span class="s2">"urfu_sphinx_theme"</span>,<span class="s2">"full_name"</span>:<span class="s2">"ustu/urfu_sphinx_theme"</span>,<span class="s2">"owner"</span>:<span class="o">{</span><span class="s2">"log</span>
<span class="s2">in"</span>:<span class="s2">"ustu"</span>,<span class="s2">"id"</span>:9111291,<span class="s2">"avatar_url"</span>:<span class="s2">"https://avatars0.githubusercontent.com/u/9111291?v=4"</span>,<span class="s2">"</span>
<span class="s2">gravatar_id"</span>:<span class="s2">""</span>,<span class="s2">"url"</span>:<span class="s2">"https://api.github.com/users/ustu"</span>,<span class="s2">"html_url"</span>:<span class="s2">"https://github.com/ustu</span>
<span class="s2">"</span>,<span class="s2">"followers_url"</span>:<span class="s2">"https://api.github.com/users/ustu/followers"</span>,<span class="s2">"following_url"</span>:<span class="s2">"https://api.</span>
<span class="s2">github.com/users/ustu/following{/other_user}"</span>,<span class="s2">"gists_url"</span>:<span class="s2">"https://api.github.com/users/ustu/</span>
<span class="s2">gists{/gist_id}"</span>,<span class="s2">"starred_url"</span>:<span class="s2">"https://api.github.com/users/ustu/starred{/owner}{/repo}"</span>,<span class="s2">"su</span>
<span class="s2">bscriptions_url"</span>:<span class="s2">"https://api.github.com/users/ustu/subscriptions"</span>,<span class="s2">"organizations_url"</span>:<span class="s2">"https</span>
<span class="s2">://api.github.com/users/ustu/orgs"</span>,<span class="s2">"repos_url"</span>:<span class="s2">"https://api.github.com/users/ustu/repos"</span>,<span class="s2">"eve</span>
<span class="s2">nts_url"</span>:<span class="s2">"https://api.github.com/users/ustu/events{/privacy}"</span>,<span class="s2">"received_events_url"</span>:<span class="s2">"https://</span>
<span class="s2">api.github.com/users/ustu/received_events"</span>,<span class="s2">"type"</span>:<span class="s2">"Organization"</span>,<span class="s2">"site_admin"</span>:false<span class="o">}</span>,<span class="s2">"private</span>
<span class="s2">"</span>:false,<span class="s2">"html_url"</span>:<span class="s2">"https://github.com/ustu/urfu_sphinx_theme"</span>,<span class="s2">"description"</span>:null,<span class="s2">"fork"</span>:fals
e,<span class="s2">"url"</span>:<span class="s2">"https://api.github.com/repos/ustu/urfu_sphinx_theme"</span>,<span class="s2">"forks_url"</span>:<span class="s2">"https://api.github</span>
<span class="s2">.com/repos/ustu/urfu_sphinx_theme/forks"</span>,<span class="s2">"keys_url"</span>:<span class="s2">"https://api.github.com/repos/ustu/urfu_s</span>
<span class="s2">phinx_theme/keys{/key_id}"</span>,<span class="s2">"collaborators_url"</span>:<span class="s2">"https://api.github.com/repos/ustu/urfu_sphinx</span>
<span class="s2">_theme/collaborators{/collaborator}"</span>,<span class="s2">"teams_url"</span>:<span class="s2">"https://api.github.com/repos/ustu/urfu_sphi</span>
</pre></div>
</div>
<p>Пользуйтесь, радуйтесь, пишите на том, что вы любите.</p>
</div>
</div>
Сборка пакета для Nix
http://uralbash.ru/articles/2017/nixpkgs-contribute/
2017-08-28T19:33:00Z
2017-08-28T19:33:00Z
Uralbash
<div class="section" id="nix">
<p><a class="reference external" href="https://nixos.org/nixpkgs/">Nix</a> - замечательный пакетный менеджер, который
работает на <cite>MacOS</cite> и любом дистрибутиве <cite>Linux</cite>, причем из-за своей
функциональной чистоты и изоляции зависимостей, гарантировано выдает всегда
одинаковый результат.</p>
<p>На сегодняшний день <cite>Nix</cite> имеет огромную базу пакетов, которая ежедневно
пополняется. Для сборки своего пакета потребуется знание языка <a class="reference external" href="https://nixos.org/nix/manual/#chap-writing-nix-expressions">Nix
expression</a>. Это
чистый функциональный язык созданный специально для пакетного менеджера <cite>Nix</cite> и
операционной системы <a class="reference external" href="https://nixos.org/">NixOS</a>.</p>
<div class="admonition note">
<p class="first admonition-title">Примечание</p>
<ul class="last simple">
<li>Ресурсы по <a class="reference internal" href="../pages/nixos/#nixos"><span class="std std-ref">NixOS</span></a></li>
<li>Статьи <a class="reference external" href="http://uralbash.ru/blog/tag/nix/">http://uralbash.ru/blog/tag/nix/</a></li>
</ul>
</div>
<p>Для примера создадим сборку пакета языка программирования <a class="reference external" href="http://www.red-lang.org/">Red</a>. Будем следовать оф. документации
<a class="reference external" href="https://nixos.org/nixpkgs/manual/#chap-quick-start">https://nixos.org/nixpkgs/manual/#chap-quick-start</a>.</p>
<div class="section" id="id2">
<h2>1. Скачиваем исходники</h2>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ git clone git://github.com/NixOS/nixpkgs.git
$ <span class="nb">cd</span> nixpkgs
</pre></div>
</div>
</div>
<div class="section" id="id3">
<h2>2. Добавляем директорию с новым пакетом</h2>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last">Правила именования файлов
<a class="reference external" href="https://nixos.org/nixpkgs/manual/#sec-organisation">https://nixos.org/nixpkgs/manual/#sec-organisation</a></p>
</div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ mkdir pkgs/development/interpreters/red/
</pre></div>
</div>
</div>
<div class="section" id="default-nix">
<h2>3. Создаем файл описания пакета <code class="docutils literal"><span class="pre">default.nix</span></code></h2>
<p>Заготовка для нашего пакета будет выглядеть так:</p>
<div class="highlight-nix"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="p">{</span> stdenv<span class="p">,</span> fetchFromGitHub <span class="p">}:</span>
stdenv<span class="o">.</span>mkDerivation <span class="k">rec</span> <span class="p">{</span>
<span class="ss">src =</span> fetchFromGitHub <span class="p">{</span>
<span class="ss">rev =</span> <span class="s2">"6a43c767fa2e85d668b83f749158a18e62c30f70"</span><span class="p">;</span>
<span class="ss">owner =</span> <span class="s2">"red"</span><span class="p">;</span>
<span class="ss">repo =</span> <span class="s2">"red"</span><span class="p">;</span>
<span class="ss">sha256 =</span> <span class="s2">"1zh6xc728bs7r4v5jz1jjrdk0xd838xsxmvy9gfg75a3zffm0slr"</span><span class="p">;</span>
<span class="p">};</span>
<span class="ss">configurePhase =</span> <span class="s1">''</span>
<span class="s1"> ''</span><span class="p">;</span>
<span class="ss">buildPhase =</span> <span class="s1">''</span>
<span class="s1"> ''</span><span class="p">;</span>
<span class="ss">installPhase =</span> <span class="s1">''</span>
<span class="s1"> ''</span><span class="p">;</span>
<span class="ss">meta =</span> <span class="k">with</span> stdenv<span class="o">.</span>lib<span class="p">;</span> <span class="p">{</span>
<span class="ss">description =</span> <span class="s1">''</span>
<span class="s1"> New programming language strongly inspired by Rebol, but with a</span>
<span class="s1"> broader field of usage thanks to its native-code compiler, from system</span>
<span class="s1"> programming to high-level scripting, while providing modern support for</span>
<span class="s1"> concurrency and multi-core CPUs</span>
<span class="s1"> ''</span><span class="p">;</span>
<span class="ss">maintainers =</span> <span class="k">with</span> maintainers<span class="p">;</span> <span class="p">[</span> uralbash <span class="p">];</span>
<span class="ss">platforms =</span> <span class="p">[</span> <span class="s2">"i686-linux"</span> <span class="s2">"x86_64-linux"</span> <span class="p">];</span>
<span class="ss">license =</span> licenses<span class="o">.</span>bsd3<span class="p">;</span>
<span class="ss">homepage =</span> <span class="l">http://www.red-lang.org/</span><span class="p">;</span>
<span class="p">};</span>
<span class="p">}</span>
</pre></div>
</td></tr></table></div>
<p>В первой строке указан импорт необходимых нам функций.</p>
<div class="highlight-nix"><div class="highlight"><pre><span></span><span class="p">{</span> stdenv<span class="p">,</span> fetchFromGitHub <span class="p">}:</span>
</pre></div>
</div>
<p>Далее забираем исходники с <cite>GitHub</cite> при помощи функции <code class="docutils literal"><span class="pre">fetchFromGitHub</span></code>.</p>
<div class="highlight-nix"><div class="highlight"><pre><span></span><span class="ss">src =</span> fetchFromGitHub <span class="p">{</span>
<span class="ss">rev =</span> <span class="s2">"6a43c767fa2e85d668b83f749158a18e62c30f70"</span><span class="p">;</span>
<span class="ss">owner =</span> <span class="s2">"red"</span><span class="p">;</span>
<span class="ss">repo =</span> <span class="s2">"red"</span><span class="p">;</span>
<span class="ss">sha256 =</span> <span class="s2">"1zh6xc728bs7r4v5jz1jjrdk0xd838xsxmvy9gfg75a3zffm0slr"</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</div>
<p>Что бы посчитать хэш (sha256) нам потребуется утилита <code class="docutils literal"><span class="pre">nix-prefetch-git</span></code>.</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ nix-prefetch-git https://github.com/red/red 6a43c767fa2e85d668b83f749158a18e62c30f70
Initialized empty Git repository in /tmp/git-checkout-tmp-Jzca0REG/red-6a43c76/.git/
fatal: Invalid refspec '+refs/tags/v0.6.3^{}'
remote: Counting objects: 52473, done.
remote: Total 52473 (delta 0), reused 0 (delta 0), pack-reused 52473
Receiving objects: 100% (52473/52473), 20.39 MiB | 1.50 MiB/s, done.
Resolving deltas: 100% (35793/35793), done.
From https://github.com/red/red
Switched to a new branch 'fetchgit'
removing `.git'...
git revision is 6a43c767fa2e85d668b83f749158a18e62c30f70
path is /nix/store/qp10dy2plvskbv0zjpcg9mmrsszd1a6i-red-6a43c76
git human-readable version is v0.6.3
Commit date is 2017-07-17 21:25:27 +0800
hash is 1zh6xc728bs7r4v5jz1jjrdk0xd838xsxmvy9gfg75a3zffm0slr
{
"url": "https://github.com/red/red",
"rev": "6a43c767fa2e85d668b83f749158a18e62c30f70",
"date": "2017-07-17T21:25:27+08:00",
<span class="hll"> "sha256": "1zh6xc728bs7r4v5jz1jjrdk0xd838xsxmvy9gfg75a3zffm0slr",
</span> "fetchSubmodules": true
}
</pre></div>
</div>
<p>В конце файла указывается мета информация:</p>
<div class="highlight-nix"><div class="highlight"><pre><span></span><span class="ss">meta =</span> <span class="k">with</span> stdenv<span class="o">.</span>lib<span class="p">;</span> <span class="p">{</span>
<span class="ss">description =</span> <span class="s1">''</span>
<span class="s1"> New programming language strongly inspired by Rebol, but with a</span>
<span class="s1"> broader field of usage thanks to its native-code compiler, from system</span>
<span class="s1"> programming to high-level scripting, while providing modern support for</span>
<span class="s1"> concurrency and multi-core CPUs</span>
<span class="s1"> ''</span><span class="p">;</span>
<span class="ss">maintainers =</span> <span class="k">with</span> maintainers<span class="p">;</span> <span class="p">[</span> uralbash <span class="p">];</span>
<span class="ss">platforms =</span> <span class="p">[</span> <span class="s2">"i686-linux"</span> <span class="s2">"x86_64-linux"</span> <span class="p">];</span>
<span class="ss">license =</span> licenses<span class="o">.</span>bsd3<span class="p">;</span>
<span class="ss">homepage =</span> <span class="l">http://www.red-lang.org/</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</div>
<p>Сама сборка происходит в 3 директивах <code class="docutils literal"><span class="pre">configurePhase</span></code>, <code class="docutils literal"><span class="pre">buildPhase</span></code>,
<code class="docutils literal"><span class="pre">installPhase</span></code>. Если их не указывать, то по умолчанию будут выполняться
<code class="docutils literal"><span class="pre">./configure</span></code>, <code class="docutils literal"><span class="pre">make</span></code>, <code class="docutils literal"><span class="pre">make</span> <span class="pre">install</span></code> соответственно. Т.к. <code class="docutils literal"><span class="pre">Red</span></code> не
использует <code class="docutils literal"><span class="pre">autotools</span></code> для сборки, то нам придется вручную прописать все
необходимые шаги. Что бы не изобретать велосипед возьмем за основу пакет из
<code class="docutils literal"><span class="pre">Arch</span> <span class="pre">Linux</span></code> <a class="reference external" href="https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=red">https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=red</a>.</p>
<p><code class="docutils literal"><span class="pre">Red</span></code> требует 32х битный <code class="docutils literal"><span class="pre">curl</span></code>, добавим его в окружение сборки:</p>
<div class="highlight-nix"><div class="highlight"><pre><span></span><span class="p">{</span> stdenv<span class="p">,</span> stdenv_32bit<span class="p">,</span> pkgsi686Linux<span class="p">,</span> fetchFromGitHub<span class="p">,</span> fetchurl <span class="p">}:</span>
<span class="o">...</span>
<span class="ss">buildInputs =</span> <span class="p">[</span> pkgsi686Linux<span class="o">.</span>curl stdenv_32bit <span class="p">];</span>
</pre></div>
</div>
<p>Скачаем <a class="reference external" href="http://www.rebol.com/">Rebol</a>. При помощи него собирается
интерпретатор <code class="docutils literal"><span class="pre">Red</span></code>.</p>
<div class="highlight-nix"><div class="highlight"><pre><span></span><span class="o">...</span>
<span class="ss">rebol =</span> fetchurl <span class="p">{</span>
<span class="ss">url =</span> <span class="s2">"http://www.rebol.com/downloads/v278/rebol-core-278-4-2.tar.gz"</span><span class="p">;</span>
<span class="ss">sha256 =</span> <span class="s2">"1c1v0pyhf3d8z98qc93a5zmx0bbl0qq5lr8mbkdgygqsq2bv2xbz"</span><span class="p">;</span>
<span class="p">};</span>
<span class="ss">r2 =</span> <span class="s2">"./rebol/releases/rebol-core/rebol"</span><span class="p">;</span>
<span class="o">...</span>
</pre></div>
</div>
<p>В нашем случае, что добавлять в фазы установки имеет очень условных характер.
Поделим следующим образом - в фазу конфигурации добавим распаковку <code class="docutils literal"><span class="pre">Rebol</span></code>:</p>
<div class="highlight-nix"><div class="highlight"><pre><span></span><span class="ss">configurePhase =</span> <span class="s1">''</span>
<span class="s1"> # Download rebol</span>
<span class="s1"> mkdir rebol/</span>
<span class="s1"> tar -xzvf </span><span class="si">${</span>rebol<span class="si">}</span><span class="s1"> -C rebol/</span>
<span class="s1"> patchelf --set-interpreter \</span>
<span class="s1"> </span><span class="si">${</span>stdenv_32bit<span class="o">.</span>cc<span class="o">.</span>libc<span class="o">.</span>out<span class="si">}</span><span class="s1">/lib/32/ld-linux.so.2 \</span>
<span class="s1"> </span><span class="si">${</span>r2<span class="si">}</span><span class="s1"></span>
<span class="s1">''</span><span class="p">;</span>
</pre></div>
</div>
<p>Заметьте <code class="docutils literal"><span class="pre">r2</span></code> это переменная, которую мы объявили выше. А <a class="reference external" href="https://nixos.org/patchelf.html">PatchELF</a> это мега крутая утилита, которой можно
подменять динамические зависимости в бинарниках, не пересобирая их. Мы изменили
путь до <code class="docutils literal"><span class="pre">ld-linux.so.2</span></code> файла, т.к. в <code class="docutils literal"><span class="pre">NixOS</span></code> он имеет нестандартный путь.</p>
<div class="admonition note">
<p class="first admonition-title">Примечание</p>
<p class="last">При этом если такой пакет собирать в Ubuntu то патчить rebol нет
необходимости, он подхватит зависимость из стандартного пути. Но для
большей универсальности это необходимо.</p>
</div>
<p>После условной конфигурации приступим к сборке интерпретатора <code class="docutils literal"><span class="pre">Red</span></code>. Все шаги
выполняются относительно директории с исходными кодами с GitHub:</p>
<div class="highlight-nix"><div class="highlight"><pre><span></span><span class="ss">buildPhase =</span> <span class="s1">''</span>
<span class="s1"> # Do tests</span>
<span class="s1"> #</span><span class="si">${</span>r2<span class="si">}</span><span class="s1"> -qw run-all.r</span>
<span class="s1"> # Build test</span>
<span class="s1"> </span><span class="si">${</span>r2<span class="si">}</span><span class="s1"> -qw red.r tests/hello.red</span>
<span class="s1"> # Compiling the Red console...</span>
<span class="s1"> </span><span class="si">${</span>r2<span class="si">}</span><span class="s1"> -qw red.r -r environment/console/console.red</span>
<span class="s1"> # Generating docs...</span>
<span class="s1"> cd docs</span>
<span class="s1"> ../</span><span class="si">${</span>r2<span class="si">}</span><span class="s1"> -qw makedoc2.r red-system-specs.txt</span>
<span class="s1"> ../</span><span class="si">${</span>r2<span class="si">}</span><span class="s1"> -qw makedoc2.r red-system-quick-test.txt</span>
<span class="s1"> cd ../</span>
<span class="s1">''</span><span class="p">;</span>
</pre></div>
</div>
<p>Установка:</p>
<div class="highlight-nix"><div class="highlight"><pre><span></span><span class="ss">installPhase =</span> <span class="s1">''</span>
<span class="s1"> mkdir $out</span>
<span class="s1"> # Install</span>
<span class="s1"> install -d $out/opt/red</span>
<span class="s1"> find quick-test -type f -executable -print0 | xargs -0 rm</span>
<span class="s1"> cp -R * $out/opt/red/</span>
<span class="s1"> rm -rf $out/opt/red/rebol</span>
<span class="s1"> install -Dm755 console $out/bin/red</span>
<span class="s1"> install -Dm644 BSD-3-License.txt \</span>
<span class="s1"> $out/share/licenses/</span><span class="si">${</span>name<span class="si">}</span><span class="s1">/BSD-3-License.txt</span>
<span class="s1"> install -Dm644 BSL-License.txt \</span>
<span class="s1"> $out/share/licenses/</span><span class="si">${</span>name<span class="si">}</span><span class="s1">/BSL-License.txt</span>
<span class="s1"> install -Dm644 docs/red-system-quick-test.html \</span>
<span class="s1"> $out/share/doc/</span><span class="si">${</span>name<span class="si">}</span><span class="s1">/red-system-quick-test.html</span>
<span class="s1"> install -Dm644 docs/red-system-specs.html \</span>
<span class="s1"> $out/share/doc/</span><span class="si">${</span>name<span class="si">}</span><span class="s1">/red-system-specs.html</span>
<span class="s1"> # PathElf</span>
<span class="s1"> patchelf --set-interpreter \</span>
<span class="s1"> </span><span class="si">${</span>stdenv_32bit<span class="o">.</span>cc<span class="o">.</span>libc<span class="o">.</span>out<span class="si">}</span><span class="s1">/lib/32/ld-linux.so.2 \</span>
<span class="s1"> $out/opt/red/console</span>
<span class="s1"> patchelf --set-rpath </span><span class="si">${</span>pkgsi686Linux<span class="o">.</span>curl<span class="o">.</span>out<span class="si">}</span><span class="s1">/lib \</span>
<span class="s1"> $out/opt/red/console</span>
<span class="s1"> patchelf --set-interpreter \</span>
<span class="s1"> </span><span class="si">${</span>stdenv_32bit<span class="o">.</span>cc<span class="o">.</span>libc<span class="o">.</span>out<span class="si">}</span><span class="s1">/lib/32/ld-linux.so.2 \</span>
<span class="s1"> $out/bin/red</span>
<span class="s1"> patchelf --set-rpath </span><span class="si">${</span>pkgsi686Linux<span class="o">.</span>curl<span class="o">.</span>out<span class="si">}</span><span class="s1">/lib \</span>
<span class="s1"> $out/bin/red</span>
<span class="s1">''</span><span class="p">;</span>
</pre></div>
</div>
</div>
<div class="section" id="id4">
<h2>4. Добавление в общий список пакетов</h2>
<p>Почти все готово, осталось добавить новый пакет в общий список и собрать.</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ vim pkgs/top-level/all-packages.nix
</pre></div>
</div>
<div class="highlight-nix"><div class="highlight"><pre><span></span><span class="o">...</span>
<span class="ss">rascal =</span> callPackage <span class="o">..</span><span class="l">/development/interpreters/rascal</span> <span class="p">{</span> <span class="p">};</span>
<span class="hll"><span class="ss">red =</span> callPackage <span class="o">..</span><span class="l">/development/interpreters/red</span> <span class="p">{</span> <span class="p">};</span>
</span>
<span class="ss">regina =</span> callPackage <span class="o">..</span><span class="l">/development/interpreters/regina</span> <span class="p">{</span> <span class="p">};</span>
<span class="o">...</span>
</pre></div>
</div>
</div>
<div class="section" id="id5">
<h2>5. Сборка</h2>
<p>Сборка пакета выполняется командой <code class="docutils literal"><span class="pre">nix-build</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ nix-build -A red
</pre></div>
</div>
<p>Или если необходимо его сразу установить в окружение:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ nix-build -f . -iA red
</pre></div>
</div>
<p>Полный исходник выглядит так:</p>
<div class="literal-block-wrapper docutils container" id="id6">
<div class="code-block-caption"><span class="caption-text">default.nix</span></div>
<div class="highlight-nix"><div class="highlight"><pre><span></span><span class="p">{</span> stdenv<span class="p">,</span> stdenv_32bit<span class="p">,</span> pkgsi686Linux<span class="p">,</span> fetchFromGitHub<span class="p">,</span> fetchurl <span class="p">}:</span>
stdenv<span class="o">.</span>mkDerivation <span class="k">rec</span> <span class="p">{</span>
<span class="ss">name =</span> <span class="s2">"red-v</span><span class="si">${</span>version<span class="si">}</span><span class="s2">"</span><span class="p">;</span>
<span class="ss">version =</span> <span class="s2">"0.6.3"</span><span class="p">;</span>
<span class="ss">src =</span> fetchFromGitHub <span class="p">{</span>
<span class="ss">rev =</span> <span class="s2">"6a43c767fa2e85d668b83f749158a18e62c30f70"</span><span class="p">;</span>
<span class="ss">owner =</span> <span class="s2">"red"</span><span class="p">;</span>
<span class="ss">repo =</span> <span class="s2">"red"</span><span class="p">;</span>
<span class="ss">sha256 =</span> <span class="s2">"1zh6xc728bs7r4v5jz1jjrdk0xd838xsxmvy9gfg75a3zffm0slr"</span><span class="p">;</span>
<span class="p">};</span>
<span class="ss">rebol =</span> fetchurl <span class="p">{</span>
<span class="ss">url =</span> <span class="s2">"http://www.rebol.com/downloads/v278/rebol-core-278-4-2.tar.gz"</span><span class="p">;</span>
<span class="ss">sha256 =</span> <span class="s2">"1c1v0pyhf3d8z98qc93a5zmx0bbl0qq5lr8mbkdgygqsq2bv2xbz"</span><span class="p">;</span>
<span class="p">};</span>
<span class="ss">buildInputs =</span> <span class="p">[</span> pkgsi686Linux<span class="o">.</span>curl stdenv_32bit <span class="p">];</span>
<span class="ss">r2 =</span> <span class="s2">"./rebol/releases/rebol-core/rebol"</span><span class="p">;</span>
<span class="ss">configurePhase =</span> <span class="s1">''</span>
<span class="s1"> # Download rebol</span>
<span class="s1"> mkdir rebol/</span>
<span class="s1"> tar -xzvf </span><span class="si">${</span>rebol<span class="si">}</span><span class="s1"> -C rebol/</span>
<span class="s1"> patchelf --set-interpreter \</span>
<span class="s1"> </span><span class="si">${</span>stdenv_32bit<span class="o">.</span>cc<span class="o">.</span>libc<span class="o">.</span>out<span class="si">}</span><span class="s1">/lib/32/ld-linux.so.2 \</span>
<span class="s1"> </span><span class="si">${</span>r2<span class="si">}</span><span class="s1"></span>
<span class="s1"> ''</span><span class="p">;</span>
<span class="ss">buildPhase =</span> <span class="s1">''</span>
<span class="s1"> # Do tests</span>
<span class="s1"> #</span><span class="si">${</span>r2<span class="si">}</span><span class="s1"> -qw run-all.r</span>
<span class="s1"> # Build test</span>
<span class="s1"> </span><span class="si">${</span>r2<span class="si">}</span><span class="s1"> -qw red.r tests/hello.red</span>
<span class="s1"> # Compiling the Red console...</span>
<span class="s1"> </span><span class="si">${</span>r2<span class="si">}</span><span class="s1"> -qw red.r -r environment/console/console.red</span>
<span class="s1"> # Generating docs...</span>
<span class="s1"> cd docs</span>
<span class="s1"> ../</span><span class="si">${</span>r2<span class="si">}</span><span class="s1"> -qw makedoc2.r red-system-specs.txt</span>
<span class="s1"> ../</span><span class="si">${</span>r2<span class="si">}</span><span class="s1"> -qw makedoc2.r red-system-quick-test.txt</span>
<span class="s1"> cd ../</span>
<span class="s1"> ''</span><span class="p">;</span>
<span class="ss">installPhase =</span> <span class="s1">''</span>
<span class="s1"> mkdir $out</span>
<span class="s1"> # Install</span>
<span class="s1"> install -d $out/opt/red</span>
<span class="s1"> find quick-test -type f -executable -print0 | xargs -0 rm</span>
<span class="s1"> cp -R * $out/opt/red/</span>
<span class="s1"> rm -rf $out/opt/red/rebol</span>
<span class="s1"> install -Dm755 console $out/bin/red</span>
<span class="s1"> install -Dm644 BSD-3-License.txt \</span>
<span class="s1"> $out/share/licenses/</span><span class="si">${</span>name<span class="si">}</span><span class="s1">/BSD-3-License.txt</span>
<span class="s1"> install -Dm644 BSL-License.txt \</span>
<span class="s1"> $out/share/licenses/</span><span class="si">${</span>name<span class="si">}</span><span class="s1">/BSL-License.txt</span>
<span class="s1"> install -Dm644 docs/red-system-quick-test.html \</span>
<span class="s1"> $out/share/doc/</span><span class="si">${</span>name<span class="si">}</span><span class="s1">/red-system-quick-test.html</span>
<span class="s1"> install -Dm644 docs/red-system-specs.html \</span>
<span class="s1"> $out/share/doc/</span><span class="si">${</span>name<span class="si">}</span><span class="s1">/red-system-specs.html</span>
<span class="s1"> # PathElf</span>
<span class="s1"> patchelf --set-interpreter \</span>
<span class="s1"> </span><span class="si">${</span>stdenv_32bit<span class="o">.</span>cc<span class="o">.</span>libc<span class="o">.</span>out<span class="si">}</span><span class="s1">/lib/32/ld-linux.so.2 \</span>
<span class="s1"> $out/opt/red/console</span>
<span class="s1"> patchelf --set-rpath </span><span class="si">${</span>pkgsi686Linux<span class="o">.</span>curl<span class="o">.</span>out<span class="si">}</span><span class="s1">/lib \</span>
<span class="s1"> $out/opt/red/console</span>
<span class="s1"> patchelf --set-interpreter \</span>
<span class="s1"> </span><span class="si">${</span>stdenv_32bit<span class="o">.</span>cc<span class="o">.</span>libc<span class="o">.</span>out<span class="si">}</span><span class="s1">/lib/32/ld-linux.so.2 \</span>
<span class="s1"> $out/bin/red</span>
<span class="s1"> patchelf --set-rpath </span><span class="si">${</span>pkgsi686Linux<span class="o">.</span>curl<span class="o">.</span>out<span class="si">}</span><span class="s1">/lib \</span>
<span class="s1"> $out/bin/red</span>
<span class="s1"> ''</span><span class="p">;</span>
<span class="ss">meta =</span> <span class="k">with</span> stdenv<span class="o">.</span>lib<span class="p">;</span> <span class="p">{</span>
<span class="ss">description =</span> <span class="s1">''</span>
<span class="s1"> New programming language strongly inspired by Rebol, but with a</span>
<span class="s1"> broader field of usage thanks to its native-code compiler, from system</span>
<span class="s1"> programming to high-level scripting, while providing modern support for</span>
<span class="s1"> concurrency and multi-core CPUs</span>
<span class="s1"> ''</span><span class="p">;</span>
<span class="ss">maintainers =</span> <span class="k">with</span> maintainers<span class="p">;</span> <span class="p">[</span> uralbash <span class="p">];</span>
<span class="ss">platforms =</span> <span class="p">[</span> <span class="s2">"i686-linux"</span> <span class="s2">"x86_64-linux"</span> <span class="p">];</span>
<span class="ss">license =</span> licenses<span class="o">.</span>bsd3<span class="p">;</span>
<span class="ss">homepage =</span> <span class="l">http://www.red-lang.org/</span><span class="p">;</span>
<span class="p">};</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
<p>Готовый пакет можно отправить в основную ветку <code class="docutils literal"><span class="pre">nixpkgs</span></code>. Перед этим лучше
почитать как правильно делать <code class="docutils literal"><span class="pre">pull</span> <span class="pre">request</span></code>:</p>
<ul class="simple">
<li><a class="reference external" href="https://nixos.org/nixpkgs/manual/#idm140737317358720">https://nixos.org/nixpkgs/manual/#idm140737317358720</a></li>
<li><a class="reference external" href="https://nixos.org/nixpkgs/manual/#sec-reviewing-contributions">https://nixos.org/nixpkgs/manual/#sec-reviewing-contributions</a></li>
</ul>
<p>В следующей статье я постараюсь описать как собирать свой собственный <code class="docutils literal"><span class="pre">NixOS</span></code>
дистрибутив с шахматами и балеринами.</p>
</div>
</div>
C++: Приведение Enum структур к общему виду в шаблонах
http://uralbash.ru/articles/2017/cpp-enum/
2017-08-16T17:11:00Z
2017-08-16T17:11:00Z
Uralbash
<div class="section" id="c-enum">
<p>Задача - создать шаблонную функцию, в которой в зависимости от типа
перечисления выбирается нужный индекс в контейнере <code class="docutils literal"><span class="pre">vector</span></code>. Попробуем решить
задачу в лоб, создадим 3 перечисления и выберем нужный индекс в шаблоне.</p>
<div class="literal-block-wrapper docutils container" id="id1">
<div class="code-block-caption"><span class="caption-text">Использование enum в шаблоне напрямую</span></div>
<div class="highlight-cpp"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><vector></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><iostream> // cout</span><span class="cp"></span>
<span class="k">struct</span> <span class="n">PEOPLE</span> <span class="p">{</span>
<span class="k">enum</span> <span class="p">{</span>
<span class="n">PEOPLE_ID</span><span class="p">,</span> <span class="c1">// 0</span>
<span class="n">FIRSTNAME</span><span class="p">,</span> <span class="c1">// 1</span>
<span class="n">LASTNAME</span> <span class="c1">// 2</span>
<span class="p">};</span>
<span class="p">};</span>
<span class="k">struct</span> <span class="n">STUDENT</span> <span class="p">{</span>
<span class="k">enum</span> <span class="p">{</span>
<span class="n">LASTNAME</span><span class="p">,</span> <span class="c1">// 0</span>
<span class="n">FIRSTNAME</span><span class="p">,</span> <span class="c1">// 1</span>
<span class="n">SALARY</span><span class="p">,</span> <span class="c1">// 2</span>
<span class="n">_ID</span><span class="p">,</span> <span class="c1">// 3</span>
<span class="p">};</span>
<span class="p">};</span>
<span class="k">struct</span> <span class="n">EMPLOYE</span> <span class="p">{</span>
<span class="k">enum</span> <span class="p">{</span>
<span class="n">LASTNAME</span><span class="p">,</span> <span class="c1">// 0</span>
<span class="n">_ID</span><span class="p">,</span> <span class="c1">// 1</span>
<span class="n">FIRSTNAME</span><span class="p">,</span> <span class="c1">// 2</span>
<span class="n">SALARY</span> <span class="c1">// 3</span>
<span class="p">};</span>
<span class="p">};</span>
<span class="k">typedef</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">></span> <span class="n">t_item</span><span class="p">;</span>
<span class="k">template</span> <span class="o"><</span><span class="k">class</span> <span class="nc">T</span><span class="o">></span>
<span class="kt">void</span> <span class="n">printHuman</span><span class="p">(</span><span class="n">t_item</span> <span class="n">item</span><span class="p">,</span> <span class="n">T</span> <span class="n">_type</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">salary</span> <span class="o">=</span> <span class="s">"0.00 $"</span><span class="p">;</span>
<span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">human_id</span> <span class="o">=</span> <span class="s">"-1"</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">bool</span> <span class="n">isStudent</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">is_same</span><span class="o"><</span><span class="n">T</span><span class="p">,</span> <span class="n">STUDENT</span><span class="o">>::</span><span class="n">value</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">bool</span> <span class="n">isEmploye</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">is_same</span><span class="o"><</span><span class="n">T</span><span class="p">,</span> <span class="n">EMPLOYE</span><span class="o">>::</span><span class="n">value</span><span class="p">;</span>
<span class="c1">// PEOPLE</span>
<span class="k">if</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">is_same</span><span class="o"><</span><span class="n">T</span><span class="p">,</span> <span class="n">PEOPLE</span><span class="o">>::</span><span class="n">value</span><span class="p">)</span> <span class="p">{</span>
<span class="n">human_id</span> <span class="o">=</span> <span class="n">item</span><span class="p">.</span><span class="n">at</span><span class="p">(</span><span class="n">PEOPLE</span><span class="o">::</span><span class="n">PEOPLE_ID</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// STUDENT || EMPLOYE</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">isStudent</span> <span class="o">||</span> <span class="n">isEmploye</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Выбираем поле в зависимости от типа структуры</span>
<span class="hll"> <span class="n">salary</span> <span class="o">=</span> <span class="n">item</span><span class="p">.</span><span class="n">at</span><span class="p">(</span><span class="n">T</span><span class="o">::</span><span class="n">SALARY</span><span class="p">);</span>
</span><span class="hll"> <span class="n">human_id</span> <span class="o">=</span> <span class="n">item</span><span class="p">.</span><span class="n">at</span><span class="p">(</span><span class="n">T</span><span class="o">::</span><span class="n">_ID</span><span class="p">);</span>
</span> <span class="p">}</span>
<span class="c1">// Отобажаем на экране</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">human_id</span>
<span class="o"><<</span> <span class="s">"</span><span class="se">\t\t</span><span class="s">"</span>
<span class="o"><<</span> <span class="n">item</span><span class="p">.</span><span class="n">at</span><span class="p">(</span><span class="n">T</span><span class="o">::</span><span class="n">FIRSTNAME</span><span class="p">)</span>
<span class="o"><<</span> <span class="s">"</span><span class="se">\t\t</span><span class="s">"</span>
<span class="o"><<</span> <span class="n">item</span><span class="p">.</span><span class="n">at</span><span class="p">(</span><span class="n">T</span><span class="o">::</span><span class="n">LASTNAME</span><span class="p">)</span>
<span class="o"><<</span> <span class="s">"</span><span class="se">\t\t</span><span class="s">"</span>
<span class="o"><<</span> <span class="n">salary</span>
<span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="n">main</span><span class="p">()</span>
<span class="p">{</span>
<span class="c1">// Создаем людей разных типов</span>
<span class="n">t_item</span> <span class="n">vasya</span><span class="p">{</span><span class="s">"1"</span><span class="p">,</span> <span class="s">"Vasya"</span><span class="p">,</span> <span class="s">"Vasnetsov"</span><span class="p">};</span> <span class="c1">// PEOPLE</span>
<span class="n">t_item</span> <span class="n">petya</span><span class="p">{</span><span class="s">"Иванов"</span><span class="p">,</span> <span class="s">"Petr"</span><span class="p">,</span> <span class="s">"10.00 $"</span><span class="p">,</span> <span class="s">"13"</span><span class="p">};</span> <span class="c1">// STUDENT</span>
<span class="n">t_item</span> <span class="n">bjarne</span><span class="p">{</span><span class="s">"Бьёрн"</span><span class="p">,</span> <span class="s">"66"</span><span class="p">,</span> <span class="s">"Straustrup"</span><span class="p">,</span> <span class="s">"100 000.00 $"</span><span class="p">};</span> <span class="c1">// EMPLOYE</span>
<span class="c1">// Выводим информацию о людях</span>
<span class="n">printHuman</span><span class="p">(</span><span class="n">vasya</span><span class="p">,</span> <span class="n">PEOPLE</span><span class="p">());</span>
<span class="n">printHuman</span><span class="p">(</span><span class="n">petya</span><span class="p">,</span> <span class="n">STUDENT</span><span class="p">());</span>
<span class="n">printHuman</span><span class="p">(</span><span class="n">bjarne</span><span class="p">,</span> <span class="n">EMPLOYE</span><span class="p">());</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</td></tr></table></div>
</div>
<p>Скомпилируем пример с добавлением <code class="docutils literal"><span class="pre">C++11</span></code>.</p>
<div class="literal-block-wrapper docutils container" id="id2">
<div class="code-block-caption"><span class="caption-text">Попытка компиляции enum в шаблоне</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ g++ -std<span class="o">=</span>c++11 main.cpp -o enum-example
main-bad.cpp: In instantiation of ‘void printHuman<span class="o">(</span>t_item, T<span class="o">)</span> <span class="o">[</span>with <span class="nv">T</span> <span class="o">=</span> PEOPLE<span class="p">;</span> <span class="nv">t_item</span> <span class="o">=</span> std::vector<std::__cxx11::basic_string<char> ><span class="o">]</span>’:
main-bad.cpp:78:30: required from here
main-bad.cpp:55:14: error: ‘SALARY’ is not a member of ‘PEOPLE’
<span class="nv">salary</span> <span class="o">=</span> item.at<span class="o">(</span>T::SALARY<span class="o">)</span><span class="p">;</span>
^
main-bad.cpp:56:14: error: ‘_ID’ is not a member of ‘PEOPLE’
<span class="nv">human_id</span> <span class="o">=</span> item.at<span class="o">(</span>T::_ID<span class="o">)</span><span class="p">;</span>
^
Makefile:7: recipe <span class="k">for</span> target <span class="s1">'bad'</span> failed
make: *** <span class="o">[</span>bad<span class="o">]</span> Error <span class="m">1</span>
</pre></div>
</div>
</div>
<p>Получаем ошибку, т.к. подстановка типа перечисления <code class="docutils literal"><span class="pre">PEOPLE</span></code> не имеет
атрибутов <code class="docutils literal"><span class="pre">_ID</span></code> и <code class="docutils literal"><span class="pre">SALARY</span></code>.</p>
<p>Что бы обойти эту проблему выведем тип с помощью <code class="docutils literal"><span class="pre">std::conditional</span></code>.</p>
<div class="literal-block-wrapper docutils container" id="id3">
<div class="code-block-caption"><span class="caption-text">Использование enum в шаблоне через выведение типа енума</span></div>
<div class="highlight-cpp"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">printHuman</span><span class="p">(</span><span class="n">t_item</span> <span class="n">item</span><span class="p">,</span> <span class="n">T</span> <span class="n">_type</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">salary</span> <span class="o">=</span> <span class="s">"0.00 $"</span><span class="p">;</span>
<span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">human_id</span> <span class="o">=</span> <span class="s">"-1"</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">bool</span> <span class="n">isStudent</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">is_same</span><span class="o"><</span><span class="n">T</span><span class="p">,</span> <span class="n">STUDENT</span><span class="o">>::</span><span class="n">value</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">bool</span> <span class="n">isEmploye</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">is_same</span><span class="o"><</span><span class="n">T</span><span class="p">,</span> <span class="n">EMPLOYE</span><span class="o">>::</span><span class="n">value</span><span class="p">;</span>
<span class="c1">// PEOPLE</span>
<span class="k">if</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">is_same</span><span class="o"><</span><span class="n">T</span><span class="p">,</span> <span class="n">PEOPLE</span><span class="o">>::</span><span class="n">value</span><span class="p">)</span> <span class="p">{</span>
<span class="n">human_id</span> <span class="o">=</span> <span class="n">item</span><span class="p">.</span><span class="n">at</span><span class="p">(</span><span class="n">PEOPLE</span><span class="o">::</span><span class="n">PEOPLE_ID</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// STUDENT || EMPLOYE</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">isStudent</span> <span class="o">||</span> <span class="n">isEmploye</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Выбираем поле в зависимости от типа структуры</span>
<span class="hll"> <span class="k">typedef</span> <span class="n">std</span><span class="o">::</span><span class="n">conditional</span><span class="o"><</span><span class="n">isStudent</span><span class="p">,</span> <span class="n">STUDENT</span><span class="p">,</span> <span class="n">EMPLOYE</span><span class="o">></span> <span class="n">cond</span><span class="p">;</span>
</span><span class="hll"> <span class="n">salary</span> <span class="o">=</span> <span class="n">item</span><span class="p">.</span><span class="n">at</span><span class="p">(</span><span class="n">cond</span><span class="o">::</span><span class="n">type</span><span class="o">::</span><span class="n">SALARY</span><span class="p">);</span>
</span><span class="hll"> <span class="n">human_id</span> <span class="o">=</span> <span class="n">item</span><span class="p">.</span><span class="n">at</span><span class="p">(</span><span class="n">cond</span><span class="o">::</span><span class="n">type</span><span class="o">::</span><span class="n">_ID</span><span class="p">);</span>
</span> <span class="p">}</span>
<span class="c1">// Отобажаем на экране</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">human_id</span>
<span class="o"><<</span> <span class="s">"</span><span class="se">\t\t</span><span class="s">"</span>
<span class="o"><<</span> <span class="n">item</span><span class="p">.</span><span class="n">at</span><span class="p">(</span><span class="n">T</span><span class="o">::</span><span class="n">FIRSTNAME</span><span class="p">)</span>
<span class="o"><<</span> <span class="s">"</span><span class="se">\t\t</span><span class="s">"</span>
<span class="o"><<</span> <span class="n">item</span><span class="p">.</span><span class="n">at</span><span class="p">(</span><span class="n">T</span><span class="o">::</span><span class="n">LASTNAME</span><span class="p">)</span>
<span class="o"><<</span> <span class="s">"</span><span class="se">\t\t</span><span class="s">"</span>
<span class="o"><<</span> <span class="n">salary</span>
<span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</td></tr></table></div>
</div>
<p>В результате программа скомпилируется без ошибок. Это происходит потому, что
<code class="docutils literal"><span class="pre">conditional</span></code> реализует свой шаблон на базе только двух нужных нам enum’ов
(<code class="docutils literal"><span class="pre">STUDENT</span></code>, <code class="docutils literal"><span class="pre">EMPLOY</span></code>).</p>
<div class="literal-block-wrapper docutils container" id="id4">
<div class="code-block-caption"><span class="caption-text">Компиляция и запуск</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ g++ -std<span class="o">=</span>c++11 main.cpp -o enum-example
$ ./enum-example
<span class="m">1</span> Vasya Vasnetsov <span class="m">0</span>.00 $
<span class="m">13</span> Petr Иванов <span class="m">10</span>.00 $
<span class="m">66</span> Straustrup Бьёрн <span class="m">100</span> <span class="m">000</span>.00 $
</pre></div>
</div>
</div>
</div>
Сборка libprotobuf под Windows
http://uralbash.ru/articles/2017/protobuf-mingw/
2017-08-10T19:50:00Z
2017-08-10T19:50:00Z
Uralbash
<div class="section" id="libprotobuf-windows">
<p>Сборка сей библиотеки из исходников под Windows не такая уж простая задача, как
может показаться на первый взгляд. Ее можно осуществлять при помощи Visual
Studio (cl.exe) или компилятора mingw.</p>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last"><a class="reference external" href="https://developers.google.com/protocol-buffers/">Protobuf</a></p>
</div>
<p>Вариант с mingw мне показался более родной и простой, поэтому начнем с установки MSYS2.</p>
<div class="admonition note">
<p class="first admonition-title">Примечание</p>
<p class="last">Скачать MSYS2 можно по адресу <a class="reference external" href="http://msys2.org">http://msys2.org</a></p>
</div>
<p>После установки в открывшейся консоле устанавливаем все необходимое. Protobuf
из пакетов нужен потому, что при сборке из исходных кодов будет использоваться
утилита <code class="docutils literal"><span class="pre">protoc.exe</span></code>.</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ pacman -S vim binutils base-devel unzip
$ pacman -S mingw-w64-i686-toolchain mingw-w64-i686-protobuf
</pre></div>
</div>
<p>Пропишем компилятор в окружение и симлинк на <code class="docutils literal"><span class="pre">protoc.exe</span></code>.</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ <span class="nv">PATH</span><span class="o">=</span>/mingw32/bin/:<span class="nv">$PATH</span>
$ ln -s /mingw32/bin/protoc.exe /usr/bin/protoc.exe
</pre></div>
</div>
<p>Готовый пакет для pacman’а позаимствуем у ArchLinux из AUR
(<a class="reference external" href="https://aur.archlinux.org/packages/mingw-w64-protobuf/">https://aur.archlinux.org/packages/mingw-w64-protobuf/</a>).</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ wget https://aur.archlinux.org/cgit/aur.git/snapshot/mingw-w64-protobuf.tar.gz
$ tar -zxf mingw-w64-protobuf.tar.gz
$ <span class="nb">cd</span> mingw-w64-protobuf
$ vim PKGBUILD
</pre></div>
</div>
<p>Закомментим зависимости из файла сборки PKGBUILD и переименуем
<code class="docutils literal"><span class="pre">${_arch}-strip</span></code> в <code class="docutils literal"><span class="pre">strip</span></code>.</p>
<div class="literal-block-wrapper docutils container" id="id1">
<div class="code-block-caption"><span class="caption-text">PKGBUILD</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># Contributor: Benoit Favre <benoit.favre@gmail.com></span>
<span class="nv">pkgname</span><span class="o">=(</span><span class="s1">'mingw-w64-protobuf'</span><span class="o">)</span>
<span class="nv">_pkgname</span><span class="o">=</span>protobuf
<span class="nv">pkgver</span><span class="o">=</span><span class="m">3</span>.3.1
<span class="nv">pkgrel</span><span class="o">=</span><span class="m">1</span>
<span class="nv">pkgdesc</span><span class="o">=</span><span class="s2">"Protocol Buffers - Google's data interchange format (mingw-w64)"</span>
<span class="nv">arch</span><span class="o">=(</span><span class="s1">'any'</span><span class="o">)</span>
<span class="nv">url</span><span class="o">=</span><span class="s1">'https://developers.google.com/protocol-buffers/'</span>
<span class="nv">license</span><span class="o">=(</span><span class="s1">'BSD'</span><span class="o">)</span>
<span class="hll"><span class="c1">#depends=('mingw-w64-crt' 'mingw-w64-zlib')</span>
</span><span class="hll"><span class="c1">#makedepends=('mingw-w64-configure' 'protobuf')</span>
</span><span class="nv">options</span><span class="o">=(</span>!strip !buildflags staticlibs<span class="o">)</span>
<span class="nv">source</span><span class="o">=(</span><span class="s2">"https://github.com/google/protobuf/archive/v</span><span class="si">${</span><span class="nv">pkgver</span><span class="si">}</span><span class="s2">.tar.gz"</span><span class="o">)</span>
<span class="nv">md5sums</span><span class="o">=(</span><span class="s1">'20c685147753b515ce380421442044b5'</span><span class="o">)</span>
<span class="nv">_architectures</span><span class="o">=</span><span class="s2">"i686-w64-mingw32 x86_64-w64-mingw32"</span>
build<span class="o">()</span> <span class="o">{</span>
<span class="nb">cd</span> <span class="si">${</span><span class="nv">srcdir</span><span class="si">}</span>/<span class="si">${</span><span class="nv">_pkgname</span><span class="si">}</span>-<span class="si">${</span><span class="nv">pkgver</span><span class="si">}</span>
./autogen.sh
<span class="k">for</span> _arch in <span class="si">${</span><span class="nv">_architectures</span><span class="si">}</span><span class="p">;</span> <span class="k">do</span>
mkdir -p build-<span class="si">${</span><span class="nv">_arch</span><span class="si">}</span> <span class="o">&&</span> <span class="nb">pushd</span> build-<span class="si">${</span><span class="nv">_arch</span><span class="si">}</span>
<span class="si">${</span><span class="nv">_arch</span><span class="si">}</span>-configure --with-protoc<span class="o">=</span>/usr/bin/protoc ..
make
<span class="nb">popd</span>
<span class="k">done</span>
<span class="o">}</span>
package<span class="o">()</span> <span class="o">{</span>
<span class="k">for</span> _arch in <span class="si">${</span><span class="nv">_architectures</span><span class="si">}</span><span class="p">;</span> <span class="k">do</span>
<span class="nb">cd</span> <span class="s2">"</span><span class="si">${</span><span class="nv">srcdir</span><span class="si">}</span><span class="s2">"</span>/<span class="si">${</span><span class="nv">_pkgname</span><span class="si">}</span>-<span class="si">${</span><span class="nv">pkgver</span><span class="si">}</span>/build-<span class="si">${</span><span class="nv">_arch</span><span class="si">}</span>
make <span class="nv">DESTDIR</span><span class="o">=</span><span class="s2">"</span><span class="nv">$pkgdir</span><span class="s2">"</span> install
rm <span class="s2">"</span><span class="si">${</span><span class="nv">pkgdir</span><span class="si">}</span><span class="s2">"</span>/usr/<span class="si">${</span><span class="nv">_arch</span><span class="si">}</span>/bin/*.exe
<span class="hll"> strip --strip-unneeded <span class="s2">"</span><span class="nv">$pkgdir</span><span class="s2">"</span>/usr/<span class="si">${</span><span class="nv">_arch</span><span class="si">}</span>/bin/*.dll
</span><span class="hll"> strip -g <span class="s2">"</span><span class="nv">$pkgdir</span><span class="s2">"</span>/usr/<span class="si">${</span><span class="nv">_arch</span><span class="si">}</span>/lib/*.a
</span> <span class="k">done</span>
<span class="o">}</span>
</pre></div>
</div>
</div>
<p>Собираем пакет утилитой <a class="reference external" href="https://www.archlinux.org/pacman/makepkg.8.html">makepkg</a>.</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ <span class="nv">CARCH</span><span class="o">=</span>i686 makepkg -Acs
<span class="o">==</span>> Сборка пакета mingw-w64-protobuf <span class="m">3</span>.3.1-1 <span class="o">(</span><span class="m">10</span> авг <span class="m">2017</span> г. <span class="m">19</span>:03:34<span class="o">)</span>
<span class="o">==</span>> Проверка зависимостей для запуска...
<span class="o">==</span>> Проверка зависимостей для сборки...
<span class="o">==</span>> Получение исходных файлов...
-> Найден v3.3.1.tar.gz
<span class="o">==</span>> Проверка файлов <span class="nb">source</span> с использованием md5sums...
v3.3.1.tar.gz ... <span class="nv">Готово</span>
<span class="o">==</span>> Распаковка исходных файлов...
-> Распаковка <span class="s1">'v3.3.1.tar.gz'</span> с помощью <span class="nv">bsdtar</span>
<span class="o">==</span>> Удаление директории <span class="s1">'$pkgdir/'</span>...
<span class="o">==</span>> Запускается build<span class="o">()</span>...
Google Mock not present. Fetching gmock-1.7.0 from the web...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
<span class="m">100</span> <span class="m">129</span> <span class="m">0</span> <span class="m">129</span> <span class="m">0</span> <span class="m">0</span> <span class="m">153</span> <span class="m">0</span> --:--:-- --:--:-- --:--:-- <span class="m">163</span>
<span class="m">100</span> 362k <span class="m">100</span> 362k <span class="m">0</span> <span class="m">0</span> 160k <span class="m">0</span> <span class="m">0</span>:00:02 <span class="m">0</span>:00:02 --:--:-- 603k
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
<span class="m">100</span> <span class="m">129</span> <span class="m">0</span> <span class="m">129</span> <span class="m">0</span> <span class="m">0</span> <span class="m">145</span> <span class="m">0</span> --:--:-- --:--:-- --:--:-- <span class="m">145</span>
<span class="m">100</span> 618k <span class="m">100</span> 618k <span class="m">0</span> <span class="m">0</span> 195k <span class="m">0</span> <span class="m">0</span>:00:03 <span class="m">0</span>:00:03 --:--:-- 355k
+ autoreconf -f -i -Wall,no-obsolete
libtoolize: putting auxiliary files in AC_CONFIG_AUX_DIR, <span class="s1">'build-aux'</span>.
libtoolize: copying file <span class="s1">'build-aux/ltmain.sh'</span>
libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, <span class="s1">'m4'</span>.
libtoolize: copying file <span class="s1">'m4/libtool.m4'</span>
libtoolize: copying file <span class="s1">'m4/ltoptions.m4'</span>
libtoolize: copying file <span class="s1">'m4/ltsugar.m4'</span>
libtoolize: copying file <span class="s1">'m4/ltversion.m4'</span>
libtoolize: copying file <span class="s1">'m4/lt~obsolete.m4'</span>
configure.ac:27: installing <span class="s1">'build-aux/compile'</span>
configure.ac:30: installing <span class="s1">'build-aux/config.guess'</span>
configure.ac:30: installing <span class="s1">'build-aux/config.sub'</span>
configure.ac:24: installing <span class="s1">'build-aux/install-sh'</span>
configure.ac:24: installing <span class="s1">'build-aux/missing'</span>
Makefile.am: installing <span class="s1">'build-aux/depcomp'</span>
parallel-tests: installing <span class="s1">'build-aux/test-driver'</span>
libtoolize: putting auxiliary files in AC_CONFIG_AUX_DIR, <span class="s1">'build-aux'</span>.
libtoolize: copying file <span class="s1">'build-aux/ltmain.sh'</span>
libtoolize: Consider adding <span class="s1">'AC_CONFIG_MACRO_DIRS([m4])'</span> to configure.ac,
libtoolize: and rerunning libtoolize and aclocal.
libtoolize: Consider adding <span class="s1">'-I m4'</span> to ACLOCAL_AMFLAGS in Makefile.am.
configure.ac:22: installing <span class="s1">'build-aux/compile'</span>
configure.ac:25: installing <span class="s1">'build-aux/config.guess'</span>
configure.ac:25: installing <span class="s1">'build-aux/config.sub'</span>
configure.ac:19: installing <span class="s1">'build-aux/install-sh'</span>
configure.ac:19: installing <span class="s1">'build-aux/missing'</span>
Makefile.am: installing <span class="s1">'build-aux/depcomp'</span>
parallel-tests: installing <span class="s1">'build-aux/test-driver'</span>
libtoolize: putting auxiliary files in <span class="s1">'.'</span>.
libtoolize: copying file <span class="s1">'./ltmain.sh'</span>
libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, <span class="s1">'m4'</span>.
libtoolize: copying file <span class="s1">'m4/libtool.m4'</span>
libtoolize: copying file <span class="s1">'m4/ltoptions.m4'</span>
libtoolize: copying file <span class="s1">'m4/ltsugar.m4'</span>
libtoolize: copying file <span class="s1">'m4/ltversion.m4'</span>
libtoolize: copying file <span class="s1">'m4/lt~obsolete.m4'</span>
configure.ac:66: installing <span class="s1">'./ar-lib'</span>
configure.ac:61: installing <span class="s1">'./compile'</span>
configure.ac:46: installing <span class="s1">'./config.guess'</span>
configure.ac:46: installing <span class="s1">'./config.sub'</span>
configure.ac:48: installing <span class="s1">'./install-sh'</span>
configure.ac:48: installing <span class="s1">'./missing'</span>
benchmarks/Makefile.am: installing <span class="s1">'./depcomp'</span>
parallel-tests: installing <span class="s1">'./test-driver'</span>
+ rm -rf autom4te.cache config.h.in~
+ <span class="nb">exit</span> <span class="m">0</span>
~/mingw-w64-protobuf/src/protobuf-3.3.1/build-i686-w64-mingw32 ~/mingw-w64-protobuf/src/protobuf-3.3.1
/home/user/mingw-w64-protobuf/PKGBUILD: line <span class="m">24</span>: i686-w64-mingw32-configure: команда не <span class="nv">найдена</span>
<span class="o">==</span>> ОШИБКА: Произошел сбой в build<span class="o">()</span>.
Прерывание...
</pre></div>
</div>
<p>Для сборки требуется скрипт <code class="docutils literal"><span class="pre">configure</span></code> как его поставить в MinGW из оф. реп
я не знаю, поэтому ставим по тому же принципу из исходников (<a class="reference external" href="https://aur.archlinux.org/packages/mingw-w64-configure/">https://aur.archlinux.org/packages/mingw-w64-configure/</a>).</p>
<p>Перед сборкой также важно закомментировать зависимости:</p>
<div class="literal-block-wrapper docutils container" id="id2">
<div class="code-block-caption"><span class="caption-text">PKGBUILD</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nv">pkgname</span><span class="o">=</span>mingw-w64-configure
<span class="nv">pkgver</span><span class="o">=</span><span class="m">0</span>.1
<span class="nv">pkgrel</span><span class="o">=</span><span class="m">1</span>
<span class="nv">arch</span><span class="o">=(</span>any<span class="o">)</span>
<span class="nv">pkgdesc</span><span class="o">=</span><span class="s2">"configure wrapper for MinGW (mingw-w64)"</span>
<span class="c1">#depends=('mingw-w64-gcc' 'mingw-w64-pkg-config')</span>
<span class="nv">license</span><span class="o">=(</span><span class="s2">"GPL"</span><span class="o">)</span>
<span class="nv">url</span><span class="o">=</span><span class="s2">"http://fedoraproject.org/wiki/MinGW"</span>
<span class="nv">source</span><span class="o">=(</span><span class="s2">"mingw-configure.sh"</span><span class="o">)</span>
<span class="nv">md5sums</span><span class="o">=(</span><span class="s1">'SKIP'</span><span class="o">)</span>
<span class="nv">_architectures</span><span class="o">=</span><span class="s2">"i686-w64-mingw32 x86_64-w64-mingw32"</span>
build<span class="o">()</span> <span class="o">{</span>
<span class="k">for</span> _arch in <span class="si">${</span><span class="nv">_architectures</span><span class="si">}</span><span class="p">;</span> <span class="k">do</span>
sed <span class="s2">"s|@TRIPLE@|</span><span class="si">${</span><span class="nv">_arch</span><span class="si">}</span><span class="s2">|g"</span> mingw-configure.sh > <span class="si">${</span><span class="nv">_arch</span><span class="si">}</span>-configure
<span class="k">done</span>
<span class="o">}</span>
package<span class="o">()</span> <span class="o">{</span>
install -d <span class="s2">"</span><span class="si">${</span><span class="nv">pkgdir</span><span class="si">}</span><span class="s2">"</span>/usr/bin
<span class="k">for</span> _arch in <span class="si">${</span><span class="nv">_architectures</span><span class="si">}</span><span class="p">;</span> <span class="k">do</span>
install -m <span class="m">755</span> <span class="si">${</span><span class="nv">_arch</span><span class="si">}</span>-configure <span class="s2">"</span><span class="si">${</span><span class="nv">pkgdir</span><span class="si">}</span><span class="s2">"</span>/usr/bin/
<span class="k">done</span>
<span class="o">}</span>
</pre></div>
</div>
</div>
<p>Сборка <code class="docutils literal"><span class="pre">configure</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ <span class="nb">cd</span> ../
$ wget https://aur.archlinux.org/cgit/aur.git/snapshot/mingw-w64-configure.tar.gz
$ tar -zxf mingw-w64-configure.tar.gz
$ <span class="nb">cd</span> mingw-w64-configure/
$ <span class="nv">CARCH</span><span class="o">=</span>i686 makepkg -Acs
$ pacman -U mingw-w64-configure-0.1-1-any.pkg.tar.xz
</pre></div>
</div>
<p>Теперь все готово для сборки Protobuf:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ <span class="nb">cd</span> ../mingw-w64-protobuf/
$ <span class="nv">CARCH</span><span class="o">=</span>i686 makepkg -Acs
</pre></div>
</div>
<p>В результате получим архив с dll-ками и заголовочными файлами. Вот так просто и
лаконично, хотя лучше поставить ArchLinux в виртуалку и собрать там тоже самое
без лишних хлопот.</p>
</div>
Firebird Developmen Studio на Linux
http://uralbash.ru/articles/2016/ibexpert/
2016-11-16T21:25:00Z
2016-11-16T21:25:00Z
Uralbash
<div class="section" id="firebird-developmen-studio-linux">
<p><cite>Firebird</cite> - это опенсорс, версионная СУБД, с регистронезависимыми названиями
таблиц и полей (как у <cite>Oracle</cite>), которая хранит каждую базу в одном отдельном
файле (как sqlite, но требует наличия сервера, хотя бы embeded). Из минусов
можно отметить довольно скудную систему типов, индексов и по сути отсутствие
возможности горизонтального масштабирования. Также многие библиотеки, ОРМ и
прочее игнорируют поддержку этой СУБД, однако <cite>FireBird</cite> сильно популярен
(был?) на территории СНГ, поэтому довольно часто приходится с ним работать.</p>
<p>Из GUI инструментов есть <cite>FlameRobin</cite> с простым интерфейсом, <cite>SQL</cite> редактором,
просмотром <cite>DDL</cite> и пожалуй всё, любое редактирование таблиц запросами.</p>
<p>Более мощный (но не безглючный) инструмент это
<a class="reference external" href="http://www.sqlly.com/index.html">Firebird SQL Studio</a>, в нем можно даже
ER-модели рисовать и делать diff между двух баз.</p>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last">Ссылка на скачку бесплатной версии для постсоветского пространства:
<a class="reference external" href="http://www.sqlly.com/files/ibds_Setup_rus.exe">http://www.sqlly.com/files/ibds_Setup_rus.exe</a></p>
</div>
<p>Итак, наша задача завести его на Linux. Естественно, как и всё что пришло из
<a class="reference external" href="https://ru.wikipedia.org/wiki/Interbase">Delphi</a> работает только под
Windows, поэтому рассмотрим вариант запуска сего продукта в <cite>Wine</cite>.</p>
<p>Запускаем команду <code class="docutils literal"><span class="pre">winecfg</span></code> и устанавливаем совместимость с <cite>Windows 98</cite> (и
это в 2016 году!):</p>
<img alt="_static/2016/wine_ibexpert.png" class="align-center" src="_static/2016/wine_ibexpert.png" />
<p>Затем прописываем нужные <cite>dll</cite>-ки:</p>
<img alt="_static/2016/wine_ibexpert_lib.png" class="align-center" src="_static/2016/wine_ibexpert_lib.png" />
<p>Теперь ВАЖНЫЙ момент, если у вас не <cite>ru_RU.cp1251</cite> локаль. Именно по локале
софт определяет, что вы из СНГ и делает его бесплатным. Поэтому, прежде чем
запустить установщик нужно эту локаль добавить:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo locale-gen ru_RU.cp1251
</pre></div>
</div>
<p>И переконфигурировать окружение поставив напротив <cite>ru_RU.cp1251</cite> галочку:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo dpkg-reconfigure locales
</pre></div>
</div>
<p>Вот теперь можно запускать установщик, а так-как у меня по умолчанию стоит
локаль <cite>en_US.UTF-8</cite>, то предварительно передав ему флаг <code class="docutils literal"><span class="pre">LC_ALL</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ <span class="nv">LC_ALL</span><span class="o">=</span>ru_RU.CP1251 wine ibds_Setup_rus.exe
</pre></div>
</div>
<p>Устанавливается в папку
<code class="docutils literal"><span class="pre">~/.wine/drive_c/Program\</span> <span class="pre">Files/IB-FB\</span> <span class="pre">Development\</span> <span class="pre">Studio/</span></code>, запускается
командой:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ <span class="nv">LC_ALL</span><span class="o">=</span>ru_RU.cp1251 wine <span class="se">\</span>
~/.wine/drive_c/Program<span class="se">\ </span>Files/IB-FB<span class="se">\ </span>Development<span class="se">\ </span>Studio/ControlCenter.exe
</pre></div>
</div>
<p>После чего вы увидите интерфейс программы на русском языке.</p>
<img alt="_static/2016/ibexpert_main.png" class="align-center" src="_static/2016/ibexpert_main.png" />
<p>Но это ещё не всё, что бы программа заработала ей нужна библиотеке <cite>gds32.dll</cite>,
ее необходимо подложить в директорию <code class="docutils literal"><span class="pre">~/.wine/drive_c/windows/system32/</span></code>.</p>
<div class="admonition note">
<p class="first admonition-title">Примечание</p>
<p class="last">Обычно библиотека называется <code class="docutils literal"><span class="pre">libfbclient.dll</span></code>, просто скопируйте её и
переименуйте в <code class="docutils literal"><span class="pre">gds32.dll</span></code>.</p>
</div>
<p>Но мне это делать лень поэтому, как обычно, из пушки по воробьям. Берем
скачиваем <cite>FireBird</cite> и тупо устанавливаем его в <cite>Wine</cite>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ <span class="nv">LC_ALL</span><span class="o">=</span>ru_RU.CP1251 wine ./Firebird-2.5.6.27020_0_Win32.exe
</pre></div>
</div>
<p>На этом все, теперь осталось только создать подключение к базе, программа
виндовая и будет прописывать путь типа <code class="docutils literal"><span class="pre">Z:\opt\firebird\alembic_test.fdb</span></code>,
что естественно не верно если вы сервер запустили на Линуксе, поэтому нужно его
поменять вручную на <code class="docutils literal"><span class="pre">localhost:/opt/firebird/alembic_test.fdb</span></code>.</p>
<img alt="_static/2016/ibexpert_db_path.png" class="align-center" src="_static/2016/ibexpert_db_path.png" />
<p>На этом считаю наше собрание закрытым, всем спасибо, расходимся.</p>
</div>
SETI@home в Docker
http://uralbash.ru/articles/2016/boinc-seti-home/
2016-10-31T20:04:00Z
2016-10-31T20:04:00Z
Uralbash
<div class="section" id="seti-home-docker">
<p><cite>BOINC</cite> - платформа, которая позволяет выполнять <a class="reference external" href="https://ru.wikipedia.org/wiki/%D0%94%D0%BE%D0%B1%D1%80%D0%BE%D0%B2%D0%BE%D0%BB%D1%8C%D0%BD%D1%8B%D0%B5_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F">добровольные вычисления</a>
для различных проектов. Изначально создавался для проекта <a class="reference external" href="https://ru.wikipedia.org/wiki/SETI@home">SETI@home</a>.</p>
<div class="admonition note">
<p class="first admonition-title">Примечание</p>
<ul class="last simple">
<li><a class="reference external" href="https://boinc.berkeley.edu/">https://boinc.berkeley.edu/</a></li>
<li><a class="reference external" href="https://ru.wikipedia.org/wiki/BOINC">https://ru.wikipedia.org/wiki/BOINC</a></li>
<li><a class="reference external" href="https://ru.wikipedia.org/wiki/SETI@home">https://ru.wikipedia.org/wiki/SETI@home</a></li>
</ul>
</div>
<p>Идея заключается в том, что можно задействовать часть ресурсов своей машины для
распределенных вычислений некого проекта, например <cite>SETI@home</cite> обрабатывает
сигналы с радиотелескопа (<a class="reference external" href="https://ru.wikipedia.org/wiki/Обсерватория_Аресибо">Аресибо</a>) в поисках внеземной
цивилизации, <cite>Rosetta@home</cite> вычисляет структуру белков и таких проектов
огромное множество в самых разных
областях. Обычно домашний/рабочий компьютер не загружен на 100% и какую то
часть, к примеру 20% одного ядра можно спокойно отвести на эту задачу.</p>
<div class="admonition note">
<p class="first admonition-title">Примечание</p>
<ul class="last simple">
<li><a class="reference external" href="https://github.com/laurent-malvert/docker-boinc">https://github.com/laurent-malvert/docker-boinc</a></li>
<li><a class="reference external" href="https://github.com/laurent-malvert/docker-boinccmd">https://github.com/laurent-malvert/docker-boinccmd</a></li>
</ul>
</div>
<p>Что-бы не захламлять систему я ставлю <cite>boinc</cite> в виде <cite>Docker</cite> контейнеров.
Вначале установим клиента-демона, который умеет принимать внешние команды:</p>
<div class="admonition note">
<p class="first admonition-title">Примечание</p>
<p class="last">При помощи флагов <cite>Docker</cite> можно ограничить контейнер на использование только
одного ядра на 50% загрузки <code class="docutils literal"><span class="pre">--cpu-period=50000</span></code>, <code class="docutils literal"><span class="pre">--cpu-quota=25000</span></code>,
<code class="docutils literal"><span class="pre">--cpuset-cpus="0,1"</span></code>. По умолчанию <cite>Boinc</cite> забирает все ресурсы.</p>
</div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ docker run <span class="se">\</span>
--name boinc <span class="se">\</span>
-d <span class="se">\</span>
--cpu-period<span class="o">=</span><span class="m">50000</span> <span class="se">\</span>
--cpu-quota<span class="o">=</span><span class="m">25000</span> <span class="se">\</span>
--cpuset-cpus<span class="o">=</span><span class="s2">"0,1"</span> <span class="se">\</span>
laurentmalvert/docker-boinc --allow_remote_gui_rpc
</pre></div>
</div>
<p>После этого можно останавливать/запускать <cite>Boinc</cite>, как обычный <cite>Docker</cite>
контейнер по его имени:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ docker stop boinc
$ docker start boinc
</pre></div>
</div>
<p>Теперь нужно подключиться к проекту указав свой ключ, в моем случае это
<code class="docutils literal"><span class="pre">13e79a77503e10517358c18698717413</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ docker run --rm --link boinc:boinc laurentmalvert/docker-boinccmd <span class="se">\</span>
--host boinc <span class="se">\</span>
--project_attach http://setiathome.berkeley.edu/ <span class="se">\</span>
13e79a77503e10517358c18698717413
</pre></div>
</div>
<p>Что бы получить ключ, нужно сначала зарегистрироваться на сайте проекта
<a class="reference external" href="http://setiathome.berkeley.edu">http://setiathome.berkeley.edu</a>, а затем выполнить команду:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ docker run --rm --link boinc:boinc laurentmalvert/docker-boinccmd <span class="se">\</span>
--host boinc --lookup_account http://setiathome.berkeley.edu <span class="se">\</span>
<email-address> <password>
</pre></div>
</div>
<p>Отключиться от проекта можно командой <code class="docutils literal"><span class="pre">detach</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ docker run --rm --link boinc:boinc laurentmalvert/docker-boinccmd <span class="se">\</span>
--host boinc --project http://setiathome.berkeley.edu/ detach
</pre></div>
</div>
<p>Посмотреть статус вашего профиля:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ docker run --rm --link boinc:boinc laurentmalvert/docker-boinccmd <span class="se">\</span>
--host boinc <span class="se">\</span>
--get_project_status
</pre></div>
</div>
</div>
Visual Studio Code для Python
http://uralbash.ru/articles/2016/visualstudiocode/
2016-09-07T20:48:00Z
2016-09-07T20:48:00Z
Uralbash
<div class="admonition note">
<p class="first admonition-title">Примечание</p>
<p class="last">Это статья из лекций
<a class="reference external" href="http://lectureswww.readthedocs.io/999.additions/texteditors/vscode.html">http://lectureswww.readthedocs.io/999.additions/texteditors/vscode.html</a></p>
</div>
<div class="section" id="visual-studio-code-python">
<div class="section" id="visual-studio-code">
<h2>Visual Studio Code</h2>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last"><a class="reference external" href="https://www.visualstudio.com/ru-ru/products/code-vs.aspx">https://www.visualstudio.com/ru-ru/products/code-vs.aspx</a></p>
</div>
<p><a class="reference external" href="https://code.visualstudio.com/">Visual Studio Code</a> отличный выбор для начинающего программиста,
имеет необходимый минимум:</p>
<ul class="simple">
<li>неплохую документацию</li>
<li>автодополнение кода (с использованием <a class="reference external" href="https://ru.wikipedia.org/wiki/IntelliSense">IntelliSense</a>)</li>
<li>подсветка синтаксиса</li>
<li>встроенный отладчик</li>
<li>расширение функционала за счет плагинов</li>
<li>управление системой контроля версий git</li>
<li>кроссплатформенный</li>
<li>бесплатный, с открытым исходным кодом</li>
</ul>
<p>Также редактор адаптирован для Веб-разработки и вполне подойдет для серьезных
проектов как основной инструмент редактирования кода.</p>
<div class="section" id="id1">
<h3>Установка</h3>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last"><a class="reference external" href="https://code.visualstudio.com/docs/setup/setup-overview">https://code.visualstudio.com/docs/setup/setup-overview</a></p>
</div>
<div class="section" id="linux">
<h4>Linux</h4>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last"><a class="reference external" href="https://code.visualstudio.com/docs/setup/linux">https://code.visualstudio.com/docs/setup/linux</a></p>
</div>
<ol class="arabic">
<li><p class="first">Скачиваем дистрибутив для своей ОС <a class="reference external" href="https://code.visualstudio.com/download">https://code.visualstudio.com/download</a></p>
</li>
<li><p class="first">Для Linux существуют два типа пакетов, самых популярных форматов, rpm и deb.</p>
<p>Установка в Ubuntu/Debian:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo dpkg -i <file>.deb
</pre></div>
</div>
<p>CentOS/Fedora:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo yum install <file>.rpm
</pre></div>
</div>
<p>Fedora > 22 версии:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo dnf install <file>.rpm
</pre></div>
</div>
</li>
<li><p class="first">После установки можно запустить редактор следующей командой:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ code
</pre></div>
</div>
</li>
</ol>
</div>
<div class="section" id="nix">
<h4>Nix</h4>
<p>Пакетный менеджер <a class="reference external" href="https://nixos.org/nix/">Nix</a> работает на любом Linux дистрибутиве, содержит
богатую базу уже готовых пакетов, в том числе и <a class="reference external" href="https://code.visualstudio.com/">vscode</a>.</p>
<ol class="arabic">
<li><p class="first">Установка пакетного менеджера:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ curl https://nixos.org/nix/install <span class="p">|</span> sh
</pre></div>
</div>
</li>
<li><p class="first">Установка <a class="reference external" href="https://code.visualstudio.com/">Visual Studio Code</a>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ nix-env -i vscode
</pre></div>
</div>
</li>
</ol>
</div>
</div>
<div class="section" id="id2">
<h3>Плагины</h3>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last"><a class="reference external" href="https://code.visualstudio.com/docs/editor/extension-gallery">https://code.visualstudio.com/docs/editor/extension-gallery</a></p>
</div>
<p>Редактор имеет возможность расширения функционала за счет плагинов и удобный
интерфейс их установки, доступный по нажатию кнопки:</p>
<img alt="_static/999.additions/texteditor/extension-gallery_extensions-view-icon.png" src="_static/999.additions/texteditor/extension-gallery_extensions-view-icon.png" />
<p>Из списка можно выбрать любой плагин и установить, после чего он применит свои
настройки к редактору.</p>
<img alt="_static/999.additions/texteditor/extension-gallery_extensions-popular.png" class="align-center" src="_static/999.additions/texteditor/extension-gallery_extensions-popular.png" style="width: 600px;" />
<p>Расширения можно искать введя название или ключевые слова в строке поиска,
например <cite>Python</cite>.</p>
<img alt="_static/999.additions/texteditor/extension-gallery_extensions-python.png" class="align-center" src="_static/999.additions/texteditor/extension-gallery_extensions-python.png" style="width: 600px;" />
<p>Существует огромное количество расширений для <cite>Go</cite>, <cite>C#</cite>, <cite>C/C++</cite>, <cite>Nix</cite>,
<cite>Haskell</cite>, <cite>Python</cite>, <cite>JS</cite>, <cite>TypeScript</cite> и др.</p>
</div>
<div class="section" id="python">
<h3>Python</h3>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last"><a class="reference external" href="https://code.visualstudio.com/docs/languages/python">https://code.visualstudio.com/docs/languages/python</a></p>
</div>
<p>После установки плагина <cite>Python</cite> нам становятся доступны многие функции:</p>
<ul class="simple">
<li>Автодополнение кода</li>
<li>Проверка синтаксиса</li>
<li>Отладка</li>
<li>Подсказки</li>
<li>Переход к определению функции, класса и прочее</li>
</ul>
<div class="section" id="id3">
<h4>Автодополнение</h4>
<p>Работает при наборе по нажатию <code class="kbd docutils literal"><span class="pre">Ctrl</span></code> + <code class="kbd docutils literal"><span class="pre">Space</span></code>.</p>
<video muted="" width=600px controls="" loop="" autoplay=""
poster="/images/python_python-linting-placeholder.png"
src="https://az754404.vo.msecnd.net/public/python-linting.mp4"
id="python-linting-video"></video></div>
<div class="section" id="id4">
<h4>Проверка синтаксиса</h4>
<p>Показывает ошибки в коде:</p>
<video muted="" width=600px controls="" loop="" autoplay=""
poster="/images/python_python-linting-placeholder.png"
src="https://az754404.vo.msecnd.net/public/python-linting.mp4"
id="python-linting-video"></video><p>Работает если установлены Python пакеты <cite>Pylint</cite>, <cite>Pep8</cite> или <cite>Flake8</cite>.</p>
<div class="admonition tip">
<p class="first admonition-title">Совет</p>
<div class="last highlight-bash"><div class="highlight"><pre><span></span>$ pip install -U --user pylint pep8 flake8
</pre></div>
</div>
</div>
</div>
<div class="section" id="id5">
<h4>Отладка</h4>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last"><a class="reference external" href="https://code.visualstudio.com/docs/editor/debugging">https://code.visualstudio.com/docs/editor/debugging</a></p>
</div>
<p>Встроенный в редактор отладчик позволяет отлаживать код визуально,
устанавливать точки останова мышкой и просматривать переменные в отдельном
окне. Это похоже на отладку в различных IDE, таких как <a class="reference external" href="https://www.qt.io/ide/">QtCreator</a> или
<a class="reference external" href="https://wingware.com/">Wingware</a>.</p>
<video muted="" width=600px controls="" loop="" autoplay=""
poster="/images/python_python-debugging-placeholder.png"
src="https://az754404.vo.msecnd.net/public/python-debugging.mp4"
id="python-debugging-video"></video><p>Также избавляет программиста писать мучительные строки типа <cite>printf</cite> или <cite>import
pdb;pdb.set_trace();</cite>.</p>
</div>
</div>
<div class="section" id="id6">
<h3>Настройки</h3>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last"><a class="reference external" href="https://code.visualstudio.com/docs/customization/userandworkspace">https://code.visualstudio.com/docs/customization/userandworkspace</a></p>
</div>
<p>Настройки хранятся в формате <cite>JSON</cite> и доступны из меню
<code class="docutils literal"><span class="pre">File->Preferences->User</span> <span class="pre">Settings</span></code>.</p>
<div class="section" id="id7">
<h4>Шрифт</h4>
<p>Шрифт задается в настройках <code class="docutils literal"><span class="pre">File->Preferences->User</span> <span class="pre">Settings</span></code>:</p>
<div class="highlight-text"><div class="highlight"><pre><span></span>// Place your settings in this file to overwrite the default settings
{
// Controls the font size.
<span class="hll"> "editor.fontSize": 16
</span>}
</pre></div>
</div>
</div>
<div class="section" id="tab">
<h4>Автодополнение через <Tab></h4>
<p>Более привычно дополнять код по клавише <code class="kbd docutils literal"><span class="pre"><Tab></span></code>. Для этого необходимо
открыть настройки пользователя <code class="docutils literal"><span class="pre">File->Preferences->User</span> <span class="pre">Settings</span></code> и прописать
опцию <code class="docutils literal"><span class="pre">editor.tabCompletion</span></code>:</p>
<div class="highlight-text"><div class="highlight"><pre><span></span>// Place your settings in this file to overwrite the default settings
{
// Controls the font size.
"editor.fontSize": 16,
// Insert snippets when their prefix matches. Works best when 'quickSuggestions' aren't enabled.
<span class="hll"> "editor.tabCompletion": true
</span>}
</pre></div>
</div>
</div>
<div class="section" id="id8">
<h4>Язык</h4>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last"><a class="reference external" href="https://code.visualstudio.com/docs/customization/locales">https://code.visualstudio.com/docs/customization/locales</a></p>
</div>
<ol class="arabic">
<li><p class="first">Открываем командную строку <code class="kbd docutils literal"><span class="pre">Ctrl</span></code> + <code class="kbd docutils literal"><span class="pre">Shift</span></code> + <code class="kbd docutils literal"><span class="pre">P</span></code></p>
</li>
<li><p class="first">Вводим команду <cite>Configure Language</cite></p>
<img alt="_static/999.additions/texteditor/locales_configure-language-command.png" class="align-center" src="_static/999.additions/texteditor/locales_configure-language-command.png" style="width: 600px;" />
</li>
<li><p class="first">Меняем локаль на нужную, например <code class="docutils literal"><span class="pre">ru</span></code>:</p>
<img alt="_static/999.additions/texteditor/locales_locale-intellisense.png" class="align-center" src="_static/999.additions/texteditor/locales_locale-intellisense.png" style="width: 600px;" />
<div class="highlight-text"><div class="highlight"><pre><span></span>{
// Defines VS Code's display language.
"locale": "ru"
}
</pre></div>
</div>
</li>
</ol>
</div>
<div class="section" id="id9">
<h4>Тема</h4>
<p>Цветовое оформление задается в настройках <code class="docutils literal"><span class="pre">File->Preferences->Color</span> <span class="pre">Theme</span></code>.</p>
</div>
</div>
<div class="section" id="git">
<h3>Git</h3>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last"><a class="reference external" href="https://code.visualstudio.com/docs/editor/versioncontrol">https://code.visualstudio.com/docs/editor/versioncontrol</a></p>
</div>
<p>Умеет подсвечивать изменения в файлах с предыдущего коммита, выполнять команды
<cite>git</cite> и отслеживать состояние, например какая текущая ветка.</p>
<img alt="_static/999.additions/texteditor/versioncontrol_merge.png" class="align-center" src="_static/999.additions/texteditor/versioncontrol_merge.png" style="width: 600px;" />
</div>
<div class="section" id="id10">
<h3>Python скрипты</h3>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last"><a class="reference external" href="http://trypyramid.com">http://trypyramid.com</a></p>
</div>
<p><a class="reference external" href="https://code.visualstudio.com/">Visual Studio Code</a> требует для отладки открывать не просто файл, а
директорию. Это необходимо, что бы в этом каталоге сохранить локальные
настройки редактора. Такая директория будет считаться проектом для редактора.</p>
<p>Для примера, создадим директорию <cite>hello1</cite> и откроем в редакторе <code class="docutils literal"><span class="pre">File->Open</span>
<span class="pre">Folder...</span></code>.</p>
<p>Создадим в этой директории файл <cite>myapp.py</cite>:</p>
<img alt="_static/999.additions/texteditor/vscode_add_file.png" src="_static/999.additions/texteditor/vscode_add_file.png" />
<p>Добавим в файл пример с сайта <a class="reference external" href="http://trypyramid.com">http://trypyramid.com</a></p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">wsgiref.simple_server</span> <span class="kn">import</span> <span class="n">make_server</span>
<span class="kn">from</span> <span class="nn">pyramid.config</span> <span class="kn">import</span> <span class="n">Configurator</span>
<span class="kn">from</span> <span class="nn">pyramid.response</span> <span class="kn">import</span> <span class="n">Response</span>
<span class="k">def</span> <span class="nf">hello_world</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="k">return</span> <span class="n">Response</span><span class="p">(</span><span class="s1">'Hello </span><span class="si">%(name)s</span><span class="s1">!'</span> <span class="o">%</span> <span class="n">request</span><span class="o">.</span><span class="n">matchdict</span><span class="p">)</span>
<span class="n">config</span> <span class="o">=</span> <span class="n">Configurator</span><span class="p">()</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_route</span><span class="p">(</span><span class="s1">'hello'</span><span class="p">,</span> <span class="s1">'/hello/{name}'</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_view</span><span class="p">(</span><span class="n">hello_world</span><span class="p">,</span> <span class="n">route_name</span><span class="o">=</span><span class="s1">'hello'</span><span class="p">)</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">make_wsgi_app</span><span class="p">()</span>
<span class="n">server</span> <span class="o">=</span> <span class="n">make_server</span><span class="p">(</span><span class="s1">'0.0.0.0'</span><span class="p">,</span> <span class="mi">8080</span><span class="p">,</span> <span class="n">app</span><span class="p">)</span>
<span class="n">server</span><span class="o">.</span><span class="n">serve_forever</span><span class="p">()</span>
</pre></div>
</div>
<p>Для запуска приложения, заходим в режим отладки по нажатию на кнопку:</p>
<img alt="_static/999.additions/texteditor/vscode_debugicon.png" src="_static/999.additions/texteditor/vscode_debugicon.png" />
<p>.</p>
<img alt="_static/999.additions/texteditor/vscode_debug_noconfig.png" class="align-center" src="_static/999.additions/texteditor/vscode_debug_noconfig.png" style="width: 600px;" />
<p>Пока у нас нет никаких настроек отладки/запуска проекта, но при первом
запуске редактор предложит их выбрать из существующих шаблонов.</p>
<img alt="_static/999.additions/texteditor/vscode_chose_dbg_template.png" src="_static/999.additions/texteditor/vscode_chose_dbg_template.png" />
<p>Шаблон <cite>Python</cite> создает настройки в файле <cite>launch.json</cite> в локальной директории,
которые выглядят примерно так:</p>
<div class="highlight-json"><div class="highlight"><pre><span></span><span class="p">{</span>
<span class="nt">"version"</span><span class="p">:</span> <span class="s2">"0.2.0"</span><span class="p">,</span>
<span class="nt">"configurations"</span><span class="p">:</span> <span class="p">[</span>
<span class="p">{</span>
<span class="nt">"name"</span><span class="p">:</span> <span class="s2">"Python"</span><span class="p">,</span>
<span class="nt">"type"</span><span class="p">:</span> <span class="s2">"python"</span><span class="p">,</span>
<span class="nt">"request"</span><span class="p">:</span> <span class="s2">"launch"</span><span class="p">,</span>
<span class="nt">"stopOnEntry"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="nt">"pythonPath"</span><span class="p">:</span> <span class="s2">"${config.python.pythonPath}"</span><span class="p">,</span>
<span class="nt">"program"</span><span class="p">:</span> <span class="s2">"${file}"</span><span class="p">,</span>
<span class="nt">"debugOptions"</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">"WaitOnAbnormalExit"</span><span class="p">,</span>
<span class="s2">"WaitOnNormalExit"</span><span class="p">,</span>
<span class="s2">"RedirectOutput"</span>
<span class="p">]</span>
<span class="p">},</span>
<span class="p">{</span>
<span class="nt">"name"</span><span class="p">:</span> <span class="s2">"Python Console App"</span><span class="p">,</span>
<span class="nt">"type"</span><span class="p">:</span> <span class="s2">"python"</span><span class="p">,</span>
<span class="nt">"request"</span><span class="p">:</span> <span class="s2">"launch"</span><span class="p">,</span>
<span class="nt">"stopOnEntry"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="nt">"pythonPath"</span><span class="p">:</span> <span class="s2">"${config.python.pythonPath}"</span><span class="p">,</span>
<span class="nt">"program"</span><span class="p">:</span> <span class="s2">"${file}"</span><span class="p">,</span>
<span class="nt">"externalConsole"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="nt">"debugOptions"</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">"WaitOnAbnormalExit"</span><span class="p">,</span>
<span class="s2">"WaitOnNormalExit"</span>
<span class="p">]</span>
<span class="p">},</span>
<span class="p">{</span>
<span class="nt">"name"</span><span class="p">:</span> <span class="s2">"Django"</span><span class="p">,</span>
<span class="nt">"type"</span><span class="p">:</span> <span class="s2">"python"</span><span class="p">,</span>
<span class="nt">"request"</span><span class="p">:</span> <span class="s2">"launch"</span><span class="p">,</span>
<span class="nt">"stopOnEntry"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="nt">"pythonPath"</span><span class="p">:</span> <span class="s2">"${config.python.pythonPath}"</span><span class="p">,</span>
<span class="nt">"program"</span><span class="p">:</span> <span class="s2">"${workspaceRoot}/manage.py"</span><span class="p">,</span>
<span class="nt">"args"</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">"runserver"</span><span class="p">,</span>
<span class="s2">"--noreload"</span>
<span class="p">],</span>
<span class="nt">"debugOptions"</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">"WaitOnAbnormalExit"</span><span class="p">,</span>
<span class="s2">"WaitOnNormalExit"</span><span class="p">,</span>
<span class="s2">"RedirectOutput"</span><span class="p">,</span>
<span class="s2">"DjangoDebugging"</span>
<span class="p">]</span>
<span class="p">},</span>
<span class="p">{</span>
<span class="nt">"name"</span><span class="p">:</span> <span class="s2">"Watson"</span><span class="p">,</span>
<span class="nt">"type"</span><span class="p">:</span> <span class="s2">"python"</span><span class="p">,</span>
<span class="nt">"request"</span><span class="p">:</span> <span class="s2">"launch"</span><span class="p">,</span>
<span class="nt">"stopOnEntry"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="nt">"pythonPath"</span><span class="p">:</span> <span class="s2">"${config.python.pythonPath}"</span><span class="p">,</span>
<span class="nt">"program"</span><span class="p">:</span> <span class="s2">"${workspaceRoot}/console.py"</span><span class="p">,</span>
<span class="nt">"args"</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">"dev"</span><span class="p">,</span>
<span class="s2">"runserver"</span><span class="p">,</span>
<span class="s2">"--noreload=True"</span>
<span class="p">],</span>
<span class="nt">"debugOptions"</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">"WaitOnAbnormalExit"</span><span class="p">,</span>
<span class="s2">"WaitOnNormalExit"</span><span class="p">,</span>
<span class="s2">"RedirectOutput"</span>
<span class="p">]</span>
<span class="p">},</span>
<span class="p">{</span>
<span class="nt">"name"</span><span class="p">:</span> <span class="s2">"Attach"</span><span class="p">,</span>
<span class="nt">"type"</span><span class="p">:</span> <span class="s2">"python"</span><span class="p">,</span>
<span class="nt">"request"</span><span class="p">:</span> <span class="s2">"attach"</span><span class="p">,</span>
<span class="nt">"localRoot"</span><span class="p">:</span> <span class="s2">"${workspaceRoot}"</span><span class="p">,</span>
<span class="nt">"remoteRoot"</span><span class="p">:</span> <span class="s2">"${workspaceRoot}"</span><span class="p">,</span>
<span class="nt">"port"</span><span class="p">:</span> <span class="mi">3000</span><span class="p">,</span>
<span class="nt">"secret"</span><span class="p">:</span> <span class="s2">"my_secret"</span><span class="p">,</span>
<span class="nt">"host"</span><span class="p">:</span> <span class="s2">"localhost"</span>
<span class="p">}</span>
<span class="p">]</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Это универсальный шаблон, который добавляет несколько вариантов запуска
приложений. Нас будет интересовать первый вариант <code class="docutils literal"><span class="pre">Python</span></code>, просто
запускающий python файл.</p>
<img alt="_static/999.additions/texteditor/vscode_python_dbg.png" src="_static/999.additions/texteditor/vscode_python_dbg.png" />
<p>Запущенное приложение останавливается на первой строчке, что позволяет нам
продолжать выполнение программы по шагам.</p>
<img alt="_static/999.additions/texteditor/vscode_python_run.png" class="align-center" src="_static/999.additions/texteditor/vscode_python_run.png" style="width: 600px;" />
<p>После выполнения второй строки, интерпретатор выдаст ошибку <code class="docutils literal"><span class="pre">ImportError:</span> <span class="pre">No</span>
<span class="pre">module</span> <span class="pre">named</span> <span class="pre">pyramid.config</span></code>. Это происходит из-за того что в нашем <cite>Python</cite>
окружении не установлен модуль <cite>pyramid</cite>.</p>
<img alt="_static/999.additions/texteditor/vscode_python_dbg_import_error.png" class="align-center" src="_static/999.additions/texteditor/vscode_python_dbg_import_error.png" style="width: 600px;" />
<p>Решить эту проблему можно двумя способами:</p>
<ol class="arabic">
<li><p class="first">Установить <cite>Pyramid</cite> в глобальное окружение.</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ pip install --user pyramid
</pre></div>
</div>
</li>
<li><p class="first">Создать виртуальное окружение, установить в нем <cite>Pyramid</cite> и прописать его в
настройках <a class="reference external" href="https://code.visualstudio.com/">Visual Studio Code</a>.</p>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last">Как создать <span class="xref std std-ref">virtualenv</span></p>
</div>
<ul>
<li><p class="first">Создаем виртуальное окружение:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ <span class="nb">cd</span> /path/to/hello1/
$ pyvenv hello1_env
$ <span class="nb">source</span> ./hello1_env/bin/activate
</pre></div>
</div>
</li>
<li><p class="first">Устанавливаем <cite>Pyramid</cite>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="o">(</span>hello1_env<span class="o">)</span>$ pip install pyramid
</pre></div>
</div>
</li>
<li><p class="first">Прописываем путь до виртуального окружения в настройках проекта
<a class="reference external" href="https://code.visualstudio.com/">Visual Studio Code</a> (файл <cite>launch.json</cite>):</p>
<img alt="_static/999.additions/texteditor/vscode_python_venv.png" class="align-center" src="_static/999.additions/texteditor/vscode_python_venv.png" style="width: 600px;" />
<div class="highlight-json"><div class="highlight"><pre><span></span><span class="p">{</span>
<span class="hll"> <span class="nt">"name"</span><span class="p">:</span> <span class="s2">"PythonVenv"</span><span class="p">,</span>
</span> <span class="nt">"type"</span><span class="p">:</span> <span class="s2">"python"</span><span class="p">,</span>
<span class="nt">"request"</span><span class="p">:</span> <span class="s2">"launch"</span><span class="p">,</span>
<span class="nt">"stopOnEntry"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="hll"> <span class="nt">"pythonPath"</span><span class="p">:</span> <span class="s2">"${workspaceRoot}/hello1_env/bin/python"</span><span class="p">,</span>
</span> <span class="nt">"program"</span><span class="p">:</span> <span class="s2">"${file}"</span><span class="p">,</span>
<span class="nt">"debugOptions"</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">"WaitOnAbnormalExit"</span><span class="p">,</span>
<span class="s2">"WaitOnNormalExit"</span><span class="p">,</span>
<span class="s2">"RedirectOutput"</span>
<span class="p">]</span>
<span class="p">}</span>
</pre></div>
</div>
</li>
</ul>
</li>
</ol>
<p>После этого появится возможность запускать наш скрипт в локальном виртуальном
окружении. Запущенная программа будет доступна по адресу
<a class="reference external" href="http://localhost:8080/hello/foo">http://localhost:8080/hello/foo</a>. В консоле отладчика можно наблюдать ее вывод.</p>
<img alt="_static/999.additions/texteditor/vscode_pyramid_run.png" class="align-center" src="_static/999.additions/texteditor/vscode_pyramid_run.png" style="width: 600px;" />
<p>Поставим точку останова внутри функции <code class="docutils literal"><span class="pre">hello_world</span></code>, в строке 6. Это
позволит нам остановить программу при запуске этой функции. После запуска,
программа будет нормально работать, пока мы не зайдем по адресу
<a class="reference external" href="http://localhost:8080/hello/foo">http://localhost:8080/hello/foo</a>, в этом случае запустится функция
<code class="docutils literal"><span class="pre">hello_world</span></code> и выполнение программы прервется, до тех пор пока мы ее не
продолжим вручную.</p>
<img alt="_static/999.additions/texteditor/vscode_pyramid_breakpoint.png" class="align-center" src="_static/999.additions/texteditor/vscode_pyramid_breakpoint.png" style="width: 600px;" />
<p>Примерно так выглядит процесс разработки и отладки программ на <cite>Python</cite>.
Осталось только инициализировать <cite>git</cite> репозиторий и выложить проект на
<a class="reference external" href="https://github.com">https://github.com</a>.</p>
<ol class="arabic">
<li><p class="first">Инициализируем репозиторий:</p>
<img alt="_static/999.additions/texteditor/vscode_git_init.png" class="align-center" src="_static/999.additions/texteditor/vscode_git_init.png" style="width: 600px;" />
</li>
<li><p class="first">Добавим файл <code class="docutils literal"><span class="pre">.gitignore</span></code>:</p>
<p>Для этого нам потребуется скопировать содержимое
<a class="reference external" href="https://www.gitignore.io/api/visualstudiocode,python">https://www.gitignore.io/api/visualstudiocode,python</a> в файл <code class="docutils literal"><span class="pre">.gitignore</span></code>
и добавить туда директорию <code class="docutils literal"><span class="pre">hello1_env</span></code>, что бы она не участвовала в
процессе создания версий.</p>
<img alt="_static/999.additions/texteditor/vscode_gitignore.png" class="align-center" src="_static/999.additions/texteditor/vscode_gitignore.png" style="width: 600px;" />
<div class="highlight-text"><div class="highlight"><pre><span></span># Created by https://www.gitignore.io/api/visualstudiocode,python
<span class="hll">hello1_env
</span>
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
...
</pre></div>
</div>
</li>
<li><p class="first">Создаем первый коммит</p>
<p>Для создания коммита требуется ввести комментарий и нажать на кнопку в виде
галочки.</p>
<img alt="_static/999.additions/texteditor/vscode_git_commit.png" class="align-center" src="_static/999.additions/texteditor/vscode_git_commit.png" style="width: 600px;" />
</li>
<li><p class="first">Отправляем изменения на <a class="reference external" href="https://github.com">https://github.com</a></p>
<ul class="simple">
<li>Добавляем плагин <cite>Git Easy</cite> в проект</li>
<li>Создаем репозиторий на <a class="reference external" href="https://github.com/">GitHub</a></li>
</ul>
<img alt="_static/999.additions/texteditor/github_create_repo.png" src="_static/999.additions/texteditor/github_create_repo.png" />
<ul>
<li><p class="first">Прописываем путь до гитхаба в нашем проекте, при помощи команды <code class="docutils literal"><span class="pre">Git</span>
<span class="pre">Easy:Add</span> <span class="pre">Orign</span></code></p>
<img alt="_static/999.additions/texteditor/vscode_giteasy_add_orign.png" src="_static/999.additions/texteditor/vscode_giteasy_add_orign.png" />
<img alt="_static/999.additions/texteditor/vscode_git_origin.png" src="_static/999.additions/texteditor/vscode_git_origin.png" />
</li>
<li><p class="first">Отправляем изменения на <cite>GitHub</cite>, при помощи команды
<code class="docutils literal"><span class="pre">Git</span> <span class="pre">Easy:Push</span> <span class="pre">Current</span> <span class="pre">Branch</span> <span class="pre">to</span> <span class="pre">Origin</span></code></p>
<img alt="_static/999.additions/texteditor/vscode_git_push.png" src="_static/999.additions/texteditor/vscode_git_push.png" />
<p>При успешном выполнении команды, мы должны увидеть сообщение типа:</p>
<div class="highlight-text"><div class="highlight"><pre><span></span>To github.com:uralbash/hello1.git
* [new branch] master -> master
</pre></div>
</div>
<img alt="_static/999.additions/texteditor/vscode_git_push_ok.png" class="align-center" src="_static/999.additions/texteditor/vscode_git_push_ok.png" style="width: 600px;" />
<p>Файлы будут доступны по адресу <a class="reference external" href="https://github.com/uralbash/hello1">https://github.com/uralbash/hello1</a></p>
<img alt="_static/999.additions/texteditor/github_hello1.png" class="align-center" src="_static/999.additions/texteditor/github_hello1.png" style="width: 600px;" />
</li>
</ul>
</li>
</ol>
<p>Для того что бы проверка синтаксиса заработала, необходимо создать файл
<code class="docutils literal"><span class="pre">.vscode/settings.json</span></code> и переопределить в нем глобальные настройки для
нашего проекта:</p>
<div class="highlight-text"><div class="highlight"><pre><span></span>{
"editor.fontSize": 18,
//Python
"python.pythonPath": "${workspaceRoot}/hello1_env/bin/python",
// Whether to lint Python files using pylint.
"python.linting.pylintEnabled": true,
// Whether to lint Python files using pep8
"python.linting.pep8Enabled": true,
// Whether to lint Python files using flake8
"python.linting.flake8Enabled": true
}
</pre></div>
</div>
</div>
<div class="section" id="pyramid">
<h3>Pyramid</h3>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last"><a class="reference external" href="http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/project.html">http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/project.html</a></p>
</div>
<p>Фреймворк <cite>Pyramid</cite> имеет несколько стартовых шаблонов, которые нужны для того,
что бы не начинать писать код с нуля. Рассмотрим как создать шаблон с БД
<cite>sqlite</cite> + <cite>SQLAlchemy</cite> и настроить его в <a class="reference external" href="https://code.visualstudio.com/">Visual Studio Code</a>.</p>
<p>Для начала создадим директорию <cite>hello2</cite> и виртуальное окружение <cite>hello2_env</cite>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ mkdir hello2
$ <span class="nb">cd</span> hello2/
$ pyvenv hello2_env
$ <span class="nb">source</span> hello2_env/bin/activate
$ pip install pyramid
</pre></div>
</div>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last"><a class="reference external" href="http://docs.pylonsproject.org/projects/pyramid/en/latest/pscripts/index.html">http://docs.pylonsproject.org/projects/pyramid/en/latest/pscripts/index.html</a></p>
</div>
<p>После установки <cite>Pyramid</cite>, в окружении появляется команда <code class="docutils literal"><span class="pre">pcreate</span></code>. С ее
помощью создадим проект по шаблону:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ pcreate -t alchemy .
$ ls
CHANGES.txt development.ini hello2 hello2_env MANIFEST.in production.ini pytest.ini README.txt setup.py
</pre></div>
</div>
<p>Устанавливаем его как <cite>Python</cite> пакет:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ pip install -e .
$ pserve development.ini
Starting server in PID <span class="m">17311</span>.
Serving on http://localhost:6543
</pre></div>
</div>
<p>После запуска, становится доступен адрес <a class="reference external" href="http://localhost:6543">http://localhost:6543</a></p>
<img alt="_static/999.additions/texteditor/pyramid_home.png" src="_static/999.additions/texteditor/pyramid_home.png" />
<p>Но так-как БД еще не создана, отображается страница с подсказкой как ее
инициализировать:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ initialize_hello2_db development.ini
</pre></div>
</div>
<p>Теперь мы увидим стартовую страницу шаблона <cite>alchemy</cite>.</p>
<img alt="_static/999.additions/texteditor/pyramid_home2.png" class="align-center" src="_static/999.additions/texteditor/pyramid_home2.png" style="width: 600px;" />
<p>Проект на пирамиде запускается при помощи утилиты <code class="docutils literal"><span class="pre">pserve</span></code>. Добавим
конфигурацию для <cite>Pyramid</cite> в файл настроек <code class="docutils literal"><span class="pre">launch.json</span></code>, что бы можно было
запускать/отлаживать приложение из редактора:</p>
<div class="highlight-json"><div class="highlight"><pre><span></span><span class="p">{</span>
<span class="nt">"version"</span><span class="p">:</span> <span class="s2">"0.2.0"</span><span class="p">,</span>
<span class="nt">"configurations"</span><span class="p">:</span> <span class="p">[{</span>
<span class="hll"> <span class="nt">"name"</span><span class="p">:</span> <span class="s2">"Pyramid"</span><span class="p">,</span>
</span><span class="hll"> <span class="nt">"type"</span><span class="p">:</span> <span class="s2">"python"</span><span class="p">,</span>
</span><span class="hll"> <span class="nt">"request"</span><span class="p">:</span> <span class="s2">"launch"</span><span class="p">,</span>
</span><span class="hll"> <span class="nt">"stopOnEntry"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span><span class="hll"> <span class="nt">"pythonPath"</span><span class="p">:</span> <span class="s2">"${workspaceRoot}/hello2_env/bin/python"</span><span class="p">,</span>
</span><span class="hll"> <span class="nt">"program"</span><span class="p">:</span> <span class="s2">"${workspaceRoot}/hello2_env/bin/pserve"</span><span class="p">,</span>
</span><span class="hll"> <span class="nt">"args"</span><span class="p">:</span> <span class="p">[</span><span class="s2">"${workspaceRoot}/development.ini"</span><span class="p">],</span>
</span><span class="hll"> <span class="nt">"debugOptions"</span><span class="p">:</span> <span class="p">[</span>
</span><span class="hll"> <span class="s2">"WaitOnNormalExit"</span><span class="p">,</span>
</span><span class="hll"> <span class="s2">"RedirectOutput"</span>
</span><span class="hll"> <span class="p">]</span>
</span><span class="hll"> <span class="p">}]</span>
</span><span class="p">}</span>
</pre></div>
</div>
<p>Попробуем запустить:</p>
<img alt="_static/999.additions/texteditor/vscode_pserve_run.png" class="align-center" src="_static/999.additions/texteditor/vscode_pserve_run.png" style="width: 600px;" />
<p>Поставим точку останова в функции <code class="docutils literal"><span class="pre">my_view</span></code> в файле
<code class="docutils literal"><span class="pre">hello2/views/default.py</span></code>.</p>
<img alt="_static/999.additions/texteditor/vscode_pyramid_dbg.png" class="align-center" src="_static/999.additions/texteditor/vscode_pyramid_dbg.png" style="width: 600px;" />
<p>После обновления страницы <a class="reference external" href="http://localhost:6543">http://localhost:6543</a> в браузере, программа остановит
свое выполнение в этой точке, а браузер будет ждать пока мы не закончим отладку
и не продолжим выполнение вручную.</p>
</div>
<div class="section" id="javascript">
<h3>JavaScript</h3>
<img alt="_static/999.additions/texteditor/vscode_js.png" class="align-center" src="_static/999.additions/texteditor/vscode_js.png" style="width: 600px;" />
</div>
</div>
<div class="section" id="id11">
<h2>Итог</h2>
<p>Я, конечно, использую <a class="reference external" href="http://www.vim.org">Vim</a>, но советую <a class="reference external" href="https://code.visualstudio.com/">Visual Studio Code</a>, особенно тем
кто не знает что выбрать. Очень, оказался, самодостаточный редактор, <cite>git</cite>,
дбаггер, плагины, vi-мод. Ай да Микрософт!</p>
</div>
</div>
IronLogic Z-2 USB на Linux
http://uralbash.ru/articles/2016/il-z2usb-linux/
2016-08-31T20:02:00Z
2016-08-31T20:02:00Z
Uralbash
<div class="section" id="ironlogic-z-2-usb-linux">
<img alt="_static/2016/z2usb.png" class="align-left" src="_static/2016/z2usb.png" style="width: 300px;" />
<p><code class="docutils literal"><span class="pre">Z-2</span> <span class="pre">USB</span></code> всеядный считыватель, который умеет работать на двух частотах 13,56
МГц и 125 кГц одновременно. Поддерживаемые форматы карт <code class="docutils literal"><span class="pre">EM-Marine</span></code>, <code class="docutils literal"><span class="pre">HID</span>
<span class="pre">ProxCard</span> <span class="pre">II</span></code>, <code class="docutils literal"><span class="pre">Mifare</span></code>, <code class="docutils literal"><span class="pre">Mifare</span> <span class="pre">Plus</span></code>, <code class="docutils literal"><span class="pre">Mifare-UL</span></code> (чтение/запись),
<code class="docutils literal"><span class="pre">Temic</span></code> (чтение/запись), <code class="docutils literal"><span class="pre">Cotag</span></code> (опционально).</p>
<p>Работает по USB через <code class="docutils literal"><span class="pre">FTDI</span></code> преобразователь, т.е. в компе видится как COM
порт. В ядре Linux есть модуль <code class="docutils literal"><span class="pre">ftdi_sio</span></code> для работы с такими устройствами.
Что бы система увидела ридер нужно подключить этот модуль и указать ему какое
устройство является <code class="docutils literal"><span class="pre">FTDI</span></code>.</p>
<p>Подключаем устройство и находим его в списке:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ lsusb
Bus <span class="m">002</span> Device <span class="m">002</span>: ID <span class="m">8087</span>:8001 Intel Corp.
Bus <span class="m">002</span> Device <span class="m">001</span>: ID 1d6b:0002 Linux Foundation <span class="m">2</span>.0 root hub
Bus <span class="m">001</span> Device <span class="m">002</span>: ID <span class="m">8087</span>:8009 Intel Corp.
Bus <span class="m">001</span> Device <span class="m">001</span>: ID 1d6b:0002 Linux Foundation <span class="m">2</span>.0 root hub
Bus <span class="m">004</span> Device <span class="m">001</span>: ID 1d6b:0003 Linux Foundation <span class="m">3</span>.0 root hub
Bus <span class="m">003</span> Device <span class="m">011</span>: ID 046d:c050 Logitech, Inc. RX <span class="m">250</span> Optical Mouse
<span class="hll">Bus <span class="m">003</span> Device <span class="m">016</span>: ID <span class="m">0403</span>:1234 Future Technology Devices International, Ltd IronLogic RFID Adapter <span class="o">[</span>Z-2 USB<span class="o">]</span>
</span>Bus <span class="m">003</span> Device <span class="m">001</span>: ID 1d6b:0002 Linux Foundation <span class="m">2</span>.0 root hub
</pre></div>
</div>
<p>Отключаем ридер и добавляем модуль ядра <code class="docutils literal"><span class="pre">ftdi_sio</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo modprobe ftdi_sio
</pre></div>
</div>
<p>Указываем драйверу какое устройство является <code class="docutils literal"><span class="pre">FTDI</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo <span class="nb">echo</span> <span class="m">0403</span> <span class="m">1234</span> > /sys/bus/usb-serial/drivers/ftdi_sio/new_id
</pre></div>
</div>
<p>В <code class="docutils literal"><span class="pre">Ubuntu</span></code> без root пользователя можно сделать так:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>sudo bash -c <span class="s2">"echo 0403 1234 > /sys/bus/usb-serial/drivers/ftdi_sio/new_id"</span>
</pre></div>
</div>
<p>Подключаем устройство, смотри что система его видит:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ dmesg <span class="p">|</span> tail
<span class="o">[</span><span class="m">793134</span>.996159<span class="o">]</span> usb <span class="m">3</span>-1: new full-speed USB device number <span class="m">20</span> using xhci_hcd
<span class="o">[</span><span class="m">793135</span>.131301<span class="o">]</span> usb <span class="m">3</span>-1: New USB device found, <span class="nv">idVendor</span><span class="o">=</span><span class="m">0403</span>, <span class="nv">idProduct</span><span class="o">=</span><span class="m">1234</span>
<span class="o">[</span><span class="m">793135</span>.131303<span class="o">]</span> usb <span class="m">3</span>-1: New USB device strings: <span class="nv">Mfr</span><span class="o">=</span><span class="m">1</span>, <span class="nv">Product</span><span class="o">=</span><span class="m">2</span>, <span class="nv">SerialNumber</span><span class="o">=</span><span class="m">3</span>
<span class="o">[</span><span class="m">793135</span>.131305<span class="o">]</span> usb <span class="m">3</span>-1: Product: USB IronLogic RFID Adapter
<span class="o">[</span><span class="m">793135</span>.131306<span class="o">]</span> usb <span class="m">3</span>-1: Manufacturer: ILogic
<span class="o">[</span><span class="m">793135</span>.131307<span class="o">]</span> usb <span class="m">3</span>-1: SerialNumber: IL02KQQ9
<span class="o">[</span><span class="m">793135</span>.135463<span class="o">]</span> ftdi_sio <span class="m">3</span>-1:1.0: FTDI USB Serial Device converter detected
<span class="o">[</span><span class="m">793135</span>.135502<span class="o">]</span> usb <span class="m">3</span>-1: Detected FT232RL
<span class="o">[</span><span class="m">793135</span>.135641<span class="o">]</span> usb <span class="m">3</span>-1: FTDI USB Serial Device converter now attached to ttyUSB0
</pre></div>
</div>
<p>Проверяем что драйвер привязался к устройству:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ usb-devices <span class="p">|</span> grep ftdi
I: If#<span class="o">=</span> <span class="m">0</span> <span class="nv">Alt</span><span class="o">=</span> <span class="m">0</span> <span class="c1">#EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=ftdi_sio</span>
</pre></div>
</div>
<p>Для работы с устройством без <code class="docutils literal"><span class="pre">sudo</span></code> добавим прав:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>sudo chown username:usergroup /dev/ttyUSB0
</pre></div>
</div>
<p>Далее настраиваем ридер, как обычный COM порт:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ stty -F /dev/ttyUSB0 cs8 cstopb -ixon raw speed <span class="m">9600</span>
</pre></div>
</div>
<p>Считываем данные:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ cat /dev/ttyUSB0
Em-Marine<span class="o">[</span><span class="m">0000</span><span class="o">]</span> <span class="m">125</span>,59903
No card
Em-Marine<span class="o">[</span><span class="m">0000</span><span class="o">]</span> <span class="m">125</span>,59904
No card
Em-Marine<span class="o">[</span><span class="m">0000</span><span class="o">]</span> <span class="m">125</span>,59904
No card
Em-Marine<span class="o">[</span><span class="m">7900</span><span class="o">]</span> <span class="m">108</span>,19751
No card
</pre></div>
</div>
<p>После перезагрузки все настройки сбиваются. Что бы это исправить нужно
подключить кардридер и запустить скрипт один раз под суперпользователем:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="ch">#! /bin/bash</span>
<span class="c1">#</span>
<span class="c1"># z2usb_install.sh</span>
<span class="c1"># Copyright (C) 2017 uralbash <root@uralbash.ru></span>
<span class="c1">#</span>
<span class="c1"># Distributed under terms of the MIT license.</span>
<span class="c1">#</span>
<span class="c1"># https://www.centos.org/docs/5/html/Deployment_Guide-en-US/s1-kernel-modules-persistant.html</span>
<span class="nb">echo</span> modprobe ftdi_sio >> /etc/rc.modules
chmod +x /etc/rc.modules
<span class="c1"># Make rules file</span>
<span class="nv">rules_file</span><span class="o">=</span>/etc/udev/rules.d/40-persistent-ftdi.rules
touch <span class="nv">$rules_file</span>
<span class="c1"># Set FTDI devices</span>
<span class="k">for</span> device in <span class="k">$(</span>
lsusb <span class="p">|</span> awk <span class="s1">'/FT232'</span><span class="sb">`</span>
<span class="sb">`</span><span class="s1">'|Future Technology Devices International'</span><span class="sb">`</span>
<span class="sb">`</span><span class="s1">'|Z-2 USB'</span><span class="sb">`</span>
<span class="sb">`</span><span class="s1">'|Ltd IronLogic RFID Adapter/ '</span><span class="sb">`</span>
<span class="sb">`</span><span class="s1">'{print $6}'</span>
<span class="k">)</span>
<span class="k">do</span>
<span class="nv">vendor_id</span><span class="o">=</span><span class="si">${</span><span class="nv">device</span><span class="p">:</span><span class="nv">0</span><span class="p">:</span><span class="nv">4</span><span class="si">}</span>
<span class="nv">product_id</span><span class="o">=</span><span class="si">${</span><span class="nv">device</span><span class="p">:</span><span class="nv">5</span><span class="p">:</span><span class="nv">10</span><span class="si">}</span>
<span class="nb">echo</span> <span class="s2">"bash -c \"echo </span><span class="si">${</span><span class="nv">vendor_id</span><span class="si">}</span><span class="s2"> </span><span class="si">${</span><span class="nv">product_id</span><span class="si">}</span><span class="s2"> > "</span> <span class="se">\</span>
<span class="s2">"/sys/bus/usb-serial/drivers/ftdi_sio/new_id\""</span> <span class="se">\</span>
>> /etc/rc.modules
<span class="nb">echo</span> <span class="s2">"ATTRS{idVendor}==\"</span><span class="si">${</span><span class="nv">vendor_id</span><span class="si">}</span><span class="s2">\","</span> <span class="se">\</span>
<span class="s2">"ATTRS{idProduct}==\"</span><span class="si">${</span><span class="nv">product_id</span><span class="si">}</span><span class="s2">\","</span> <span class="se">\</span>
<span class="s2">"MODE=\"0666\",GROUP=\"dialout\""</span> <span class="se">\</span>
>> <span class="nv">$rules_file</span>
<span class="k">done</span>
<span class="c1"># Add user to dialout group</span>
usermod -aG tty user
usermod -aG dialout user
</pre></div>
</div>
<p><code class="docutils literal"><span class="pre">user</span></code> нужно поменять на имя вашего пользователя. Проверялось на <cite>CentOS</cite>,
для <cite>Ubuntu</cite> возможно нужно поменять <code class="docutils literal"><span class="pre">rc.modules</span></code> на просто <code class="docutils literal"><span class="pre">modules</span></code>.</p>
</div>
Пропал доступ в Интернет в Docker контейнерах
http://uralbash.ru/articles/2016/docker-mtu/
2016-07-13T23:13:00Z
2016-07-13T23:13:00Z
Uralbash
<div class="section" id="docker">
<p>Docker начиная с версии <code class="docutils literal"><span class="pre">1.10</span></code> и выше, перестал брать значение <code class="docutils literal"><span class="pre">MTU</span></code> от
сетевого интерфейса. Теперь его нужно указывать явно:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ docker daemon --mtu<span class="o">=</span><span class="m">1372</span>
</pre></div>
</div>
<p>Это может быть причиной отсутствия Интернет.</p>
</div>
Пакетный менеджер Nix
http://uralbash.ru/articles/2016/nixpkgs/
2016-07-06T22:24:00Z
2016-07-06T22:24:00Z
Uralbash
<div class="section" id="nix">
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last"><a class="reference external" href="http://nixos.org/nix/">http://nixos.org/nix/</a></p>
</div>
<p><a class="reference external" href="https://nixos.org/nix/">Nix</a> - пакетный менеджер, который устанавливает пакеты изолированно друг от
друга. Изначально появился в процессе научной работы <a class="reference external" href="https://nixos.org/~eelco/">Eelco Dolstra</a> и позже обрел огромную популярность и сторонников
данной идеи, что в итоге сформировало очень активное сообщество, ссылки на
которое можно найти здесь <a class="reference internal" href="../pages/nixos/#nixos"><span class="std std-ref">NixOS</span></a>.</p>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last"><a class="reference external" href="https://rhodecode.com/blog/61/rhodecode-and-nix-package-manager">https://rhodecode.com/blog/61/rhodecode-and-nix-package-manager</a></p>
</div>
<p><a class="reference external" href="https://nixos.org/nix/">Nix</a> в отличии от других UNIX дистрибутивов устанавливает пакеты всегда в
одно и то же место <code class="docutils literal"><span class="pre">/nix/store/</span></code>. Внутри каждого пакета создается необходимая
структура директорий <code class="docutils literal"><span class="pre">bin</span></code>, <code class="docutils literal"><span class="pre">etc</span></code>, <code class="docutils literal"><span class="pre">lib</span></code>, и прочее. Пользователь видит
это все у себя за счет симлинков, которые прописываются при установке, см.
рисунок:</p>
<img alt="_static/2016/nix_fs.png" src="_static/2016/nix_fs.png" />
<p>Это позволяет избежать конфликта имен, при установке пакетов и иметь в системе
несколько версий одной и той же программы собранной по разному.</p>
<p>Отличительной особенностью <a class="reference external" href="https://nixos.org/nix/">nix</a>, является то, что он не зависит от
дистрибутива. Единственным требованием является поддержка <code class="docutils literal"><span class="pre">POSIX</span></code> потоков и
<code class="docutils literal"><span class="pre">C++</span></code> компилятор. Все пакеты из реп запускаются, без проблем, на любом Linux
дистрибутиве и многие платформонезависимые пакеты работают в <code class="docutils literal"><span class="pre">MacOS</span></code>. Есть
инструкции как установить <a class="reference external" href="https://nixos.org/nix/">nix</a> в <code class="docutils literal"><span class="pre">Cygwin</span></code> под <code class="docutils literal"><span class="pre">Windows</span></code>. Я пользуюсь
<a class="reference external" href="https://nixos.org/nix/">nix</a> под <code class="docutils literal"><span class="pre">CentOS6</span></code>, <code class="docutils literal"><span class="pre">CentOS7</span></code>, <code class="docutils literal"><span class="pre">Ubuntu</span></code>, <code class="docutils literal"><span class="pre">NixOS</span></code> и это работает
везде одинаково хорошо.</p>
<p>Из плюсов можно отметить:</p>
<ul class="simple">
<li>везде одинаковый интерфейс, не нужно запоминать как работает <code class="docutils literal"><span class="pre">yum</span></code>,
<code class="docutils literal"><span class="pre">apt</span></code>, <code class="docutils literal"><span class="pre">apk</span></code>, ...</li>
<li>одна репа для всех дистрибутивов, везде одинаковые версии программ</li>
<li>репа на гитхабе, это очень удобно (<a class="reference external" href="https://github.com/NixOS/nixpkgs">https://github.com/NixOS/nixpkgs</a>)</li>
<li>изолированная установка, новый пакет не может сломать остальные</li>
<li>возможность установки нескольких версий одного пакета, например <code class="docutils literal"><span class="pre">glibc</span></code></li>
<li>транзакционность - развитая модель откатки состояния</li>
<li>огромное количество пакетов, самых свежих версий</li>
<li>хранит все в одной директории <code class="docutils literal"><span class="pre">/nix</span></code>, не захламляет систему, удаляется
одной командой <code class="docutils literal"><span class="pre">rm</span> <span class="pre">-rf</span> <span class="pre">/nix</span></code></li>
</ul>
<p>Из минусов:</p>
<ul class="simple">
<li>чуть больший размер пакетов, из-за того что могут использоваться разные
версии одной и той же зависимости в разных пакетах</li>
<li>сервисы и демоны устанавливаются в виде бинарников, прописывать их в
автозапуск и систему инициализации придется вручную. Это не относится к
<code class="docutils literal"><span class="pre">NixOS</span></code></li>
</ul>
<div class="section" id="id1">
<h2>Установка</h2>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last"><a class="reference external" href="http://nixos.org/nix/manual/#ch-installing-binary">http://nixos.org/nix/manual/#ch-installing-binary</a></p>
</div>
<p>Установка крайне простая, делается одной командой:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ curl https://nixos.org/nix/install <span class="p">|</span> sh
</pre></div>
</div>
</div>
<div class="section" id="id2">
<h2>Команды</h2>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<ul class="last simple">
<li><a class="reference external" href="https://nixos.org/wiki/Cheatsheet">https://nixos.org/wiki/Cheatsheet</a></li>
<li><a class="reference external" href="http://nixos.org/nix/manual/#chap-package-management">http://nixos.org/nix/manual/#chap-package-management</a></li>
</ul>
</div>
<p><a class="reference external" href="https://nixos.org/">NixOS</a> удивительный проект с очень хорошей документацией и большим
мега-активным сообществом (<a class="reference internal" href="../pages/nixos/#nixos"><span class="std std-ref">NixOS</span></a>). Поэтому нет смысла дублировать
документацию, опишу лишь некоторые команды в сравнении с пакетным менеджером
<code class="docutils literal"><span class="pre">apt</span></code>.</p>
<div class="section" id="id3">
<h3>Установка пакетов:</h3>
<div class="literal-block-wrapper docutils container" id="id10">
<div class="code-block-caption"><span class="caption-text">apt</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo apt-get install firefox python vim
</pre></div>
</div>
</div>
<div class="literal-block-wrapper docutils container" id="id11">
<div class="code-block-caption"><span class="caption-text">nix</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ nix-env -i firefox python vim
</pre></div>
</div>
</div>
</div>
<div class="section" id="id4">
<h3>Удаление:</h3>
<div class="literal-block-wrapper docutils container" id="id12">
<div class="code-block-caption"><span class="caption-text">apt</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo apt-get remove python
</pre></div>
</div>
</div>
<div class="literal-block-wrapper docutils container" id="id13">
<div class="code-block-caption"><span class="caption-text">nix</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ nix-env -e python
</pre></div>
</div>
</div>
</div>
<div class="section" id="id5">
<h3>Обновление реп:</h3>
<div class="literal-block-wrapper docutils container" id="id14">
<div class="code-block-caption"><span class="caption-text">apt</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo apt-get update
</pre></div>
</div>
</div>
<div class="literal-block-wrapper docutils container" id="id15">
<div class="code-block-caption"><span class="caption-text">nix</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ nix-channel --update
</pre></div>
</div>
</div>
</div>
<div class="section" id="id6">
<h3>Обновление пакетов:</h3>
<div class="literal-block-wrapper docutils container" id="id16">
<div class="code-block-caption"><span class="caption-text">apt</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo apt-get upgrade
</pre></div>
</div>
</div>
<div class="literal-block-wrapper docutils container" id="id17">
<div class="code-block-caption"><span class="caption-text">nix</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ nix-env -u
</pre></div>
</div>
</div>
</div>
<div class="section" id="id7">
<h3>Информация о пакете:</h3>
<div class="literal-block-wrapper docutils container" id="id18">
<div class="code-block-caption"><span class="caption-text">apt</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ apt-cache search vim
</pre></div>
</div>
</div>
<div class="literal-block-wrapper docutils container" id="id19">
<div class="code-block-caption"><span class="caption-text">nix</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ nix-env -qaP <span class="p">|</span> grep vim
</pre></div>
</div>
</div>
</div>
<div class="section" id="id8">
<h3>Описание пакета:</h3>
<div class="literal-block-wrapper docutils container" id="id20">
<div class="code-block-caption"><span class="caption-text">apt</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ apt-cache show vim
</pre></div>
</div>
</div>
<div class="literal-block-wrapper docutils container" id="id21">
<div class="code-block-caption"><span class="caption-text">nix</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ nix-env -qaP --description <span class="p">|</span> grep vim
</pre></div>
</div>
</div>
</div>
</div>
<div class="section" id="nix-shell">
<h2>nix-shell</h2>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<ul class="last simple">
<li><a class="reference external" href="http://nixos.org/nix/manual/#sec-nix-shell">http://nixos.org/nix/manual/#sec-nix-shell</a></li>
<li><a class="reference external" href="https://habrahabr.ru/post/281611/">Nix как менеджер зависимостей для C++</a></li>
</ul>
</div>
<p><code class="docutils literal"><span class="pre">nix-shell</span></code> создает изолированное окружение (наподобие <code class="docutils literal"><span class="pre">virtualenv</span></code> в
питоне) и позволяет запускать в нем команды или выполнять <code class="docutils literal"><span class="pre">nix</span></code> скрипты.</p>
<p>Пример как создать окружение с <code class="docutils literal"><span class="pre">nodejs</span></code>, <code class="docutils literal"><span class="pre">python3</span></code> и <code class="docutils literal"><span class="pre">gnumake</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ nix-shell -p nodejs python3 gnumake
</pre></div>
</div>
<p>После этого <code class="docutils literal"><span class="pre">nodejs</span></code>, <code class="docutils literal"><span class="pre">python3</span></code> и <code class="docutils literal"><span class="pre">gnumake</span></code> появятся в нашем окружении.
Выйти из окружения можно так-же как и из bash оболочки <code class="kbd docutils literal"><span class="pre">Ctrl</span></code> + <code class="kbd docutils literal"><span class="pre">D</span></code>
или командой <code class="docutils literal"><span class="pre">exit</span></code>.</p>
<p>Понять что мы находимся в <code class="docutils literal"><span class="pre">nix-shell</span></code> сессии можно при помощи переменной
окружения:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ env <span class="p">|</span> grep IN_NIX_SHELL
<span class="nv">IN_NIX_SHELL</span><span class="o">=</span><span class="m">1</span>
</pre></div>
</div>
<p>Я добавил отображение символа снежинки <code class="docutils literal"><span class="pre">❄</span></code> в <code class="docutils literal"><span class="pre">PS1</span></code>, если <code class="docutils literal"><span class="pre">nix-shell</span></code>
сессия активна.</p>
<img alt="_static/2016/nix_shell.png" src="_static/2016/nix_shell.png" />
<p>Очень удобно создавать окружение для скриптов через shebang:</p>
<div class="literal-block-wrapper docutils container" id="id22">
<div class="code-block-caption"><span class="caption-text">shebang создает окружение для python2 и запускает в нем скрипт</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span> <span class="c1">#! /usr/bin/env nix-shell</span>
<span class="c1">#! nix-shell -i python -p python pythonPackages.prettytable</span>
<span class="kn">import</span> <span class="nn">prettytable</span>
<span class="c1"># Print a simple table.</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">prettytable</span><span class="o">.</span><span class="n">PrettyTable</span><span class="p">([</span><span class="s2">"N"</span><span class="p">,</span> <span class="s2">"N^2"</span><span class="p">])</span>
<span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">10</span><span class="p">):</span> <span class="n">t</span><span class="o">.</span><span class="n">add_row</span><span class="p">([</span><span class="n">n</span><span class="p">,</span> <span class="n">n</span> <span class="o">*</span> <span class="n">n</span><span class="p">])</span>
<span class="k">print</span> <span class="n">t</span>
</pre></div>
</div>
</div>
<div class="literal-block-wrapper docutils container" id="id23">
<div class="code-block-caption"><span class="caption-text">shebang создает окружение с утилитой cowsay и запускает в баше скрипт</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span> <span class="c1">#! /usr/bin/env nix-shell</span>
<span class="c1">#! nix-shell -i bash -p cowsay</span>
cowsay <span class="s2">"Превед nix-shell!!!"</span>
</pre></div>
</div>
</div>
<p>По умолчанию команда <code class="docutils literal"><span class="pre">nix-shell</span></code> ищет файл <code class="docutils literal"><span class="pre">default.nix</span></code> в текущей
директории и пытается его выполнить, таким образом мы можем создавать для своих
проектов своеобразное виртуальное окружение, просто положив этот файл в корень
проекта и прописав в нем необходимые пакеты и правила сборки. Такой проект
легко будет развернуть на любой системе. Отличной демонстрацией этого является
проект <a class="reference external" href="https://rhodecode.com/">RhodeCode</a> (позволяет управлять кодом как <code class="docutils literal"><span class="pre">GitLab</span></code>, но при этом
может использовать разные системы контроля версий <code class="docutils literal"><span class="pre">git</span></code>, <code class="docutils literal"><span class="pre">hg</span></code>, <code class="docutils literal"><span class="pre">svn</span></code> и
интегрируется с разными треккерами задач вплоть до <code class="docutils literal"><span class="pre">Trello</span></code>), который можно
развернуть у себя за 5 мин при помощи команды <code class="docutils literal"><span class="pre">nix-shell</span></code>
(<a class="reference external" href="https://docs.rhodecode.com/RhodeCode-Enterprise/contributing/dev-setup.html">https://docs.rhodecode.com/RhodeCode-Enterprise/contributing/dev-setup.html</a>).</p>
<p>Также <code class="docutils literal"><span class="pre">nix-shell</span></code> позволяет присваивать имена окружениям и запускать
<code class="docutils literal"><span class="pre">nix</span></code> выражения, например что бы собрать приложение изолированно от общих
установленных пакетов.</p>
<p>Более подробно, что такое язык <code class="docutils literal"><span class="pre">nixexpr</span></code> и как при помощи его собирать
пакеты и даже ОС <a class="reference external" href="https://nixos.org/">NixOS</a>, я постараюсь описать в отдельной статье.</p>
</div>
<div class="section" id="home-user">
<h2>/home/user Окружение</h2>
<p>Что бы <code class="docutils literal"><span class="pre">Ubuntu</span></code> знала о наших приложениях нужно прописать симлинк:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>ln -s <span class="si">${</span><span class="nv">HOME</span><span class="si">}</span>/.nix-profile/share/applications/ <span class="se">\</span>
<span class="si">${</span><span class="nv">HOME</span><span class="si">}</span>/.local/share/applications/
</pre></div>
</div>
</div>
<div class="section" id="id9">
<h2>Резюме</h2>
<p>Пакетный менеджер <code class="docutils literal"><span class="pre">Nix</span></code> имеет огромное количество преимуществ, которые
упрощают процессы администрирования, программирования, сборки и тестирования
ПО. Теперь на разных Линуксах все работает одинаково! А в CentOS6 есть gcc6.</p>
</div>
</div>
NixOS
http://uralbash.ru/pages/nixos/
2016-07-06T18:06:00Z
2016-07-06T18:06:00Z
Uralbash
<div class="section" id="nixos">
<span id="id1"></span>
<p>Здесь я буду собирать разные полезные ресурсы по ОС <a class="reference external" href="https://nixos.org/">NixOS</a> и пакетному
менеджеру <a class="reference external" href="https://nixos.org/nix/">nix</a>. Если вы, что то не нашли пишите в комментах.</p>
<div class="section" id="id2">
<h2>Оф. ресурсы</h2>
<ul class="simple">
<li>Официальный сайт <a class="reference external" href="https://nixos.org/">https://nixos.org/</a></li>
<li>Документация <a class="reference external" href="https://nixos.org/nixos/manual/">https://nixos.org/nixos/manual/</a> и <a class="reference external" href="https://nixos.org/nix/manual/">https://nixos.org/nix/manual/</a></li>
<li><dl class="first docutils">
<dt>Wiki <a class="reference external" href="https://nixos.org/wiki/Main_Page">https://nixos.org/wiki/Main_Page</a> (устарела)</dt>
<dd><ul class="first last">
<li>Новая Wiki <a class="reference external" href="https://nixos.wiki/wiki/Main_Page">https://nixos.wiki/wiki/Main_Page</a></li>
</ul>
</dd>
</dl>
</li>
<li>Mail рассылки <a class="reference external" href="http://lists.science.uu.nl/mailman/listinfo/nix-dev">http://lists.science.uu.nl/mailman/listinfo/nix-dev</a></li>
<li>Код <a class="reference external" href="https://github.com/NixOS/nixpkgs/">https://github.com/NixOS/nixpkgs/</a> и <a class="reference external" href="https://github.com/NixOS/nix/">https://github.com/NixOS/nix/</a></li>
<li>Донэйт <a class="reference external" href="https://nixos.org/nixos/foundation.html">https://nixos.org/nixos/foundation.html</a></li>
<li>Еженедельная рассылка: <a class="reference external" href="http://weekly.nixos.org/">http://weekly.nixos.org/</a></li>
</ul>
</div>
<div class="section" id="id3">
<h2>Полезные ссылки</h2>
<ul>
<li><p class="first"><a class="reference external" href="https://nixcloud.io/tour/">https://nixcloud.io/tour/</a> - восхитительный курс по языку <code class="docutils literal"><span class="pre">nix</span></code>.</p>
</li>
<li><p class="first"><a class="reference external" href="https://learnxinyminutes.com/docs/nix/">https://learnxinyminutes.com/docs/nix/</a> - учим синтаксис языка <code class="docutils literal"><span class="pre">nix</span></code>.</p>
</li>
<li><p class="first"><a class="reference external" href="https://medium.com/@MrJamesFisher/nix-by-example-a0063a1a4c55">https://medium.com/@MrJamesFisher/nix-by-example-a0063a1a4c55</a> - еще про язык <code class="docutils literal"><span class="pre">nix</span></code>.</p>
</li>
<li><p class="first"><a class="reference external" href="http://nixpaste.lbr.uno/">http://nixpaste.lbr.uno/</a> - сервис на подобии <cite>pastebin</cite>, но есть подсветка
синтаксиса <code class="docutils literal"><span class="pre">nixexpr</span></code> и удобная утилита для командной строки.</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ <span class="nb">alias</span> <span class="nv">nixpaste</span><span class="o">=</span><span class="s2">"curl -F 'text=<-' http://nixpaste.lbr.uno"</span>
$ <span class="nb">command</span> <span class="p">|</span> nixpaste
$ nixpaste < ./myexpr.nix
</pre></div>
</div>
</li>
</ul>
</div>
<div class="section" id="id4">
<h2>Сообщество</h2>
<p>Перечислю источники по степени активности:</p>
<ul>
<li><p class="first">Форум <a class="reference external" href="https://discourse.nixos.org/">https://discourse.nixos.org/</a></p>
</li>
<li><p class="first"><code class="docutils literal"><span class="pre">#nixos</span></code> irc канал на freenode имеет очень высокую активность,
разработчики <a class="reference external" href="https://nixos.org/">NixOS</a> и все что с ней связанно в основном общаются здесь.</p>
<a class="reference external image-reference" href="https://webchat.freenode.net/?channels=nixos"><img alt="irc freenode" src="https://img.shields.io/badge/irc-freenode-blue.svg" /></a>
</li>
<li><p class="first">StackOverflow то же весьма активен, много людей из рассылки.</p>
<ul class="simple">
<li><a class="reference external" href="http://stackoverflow.com/questions/tagged/nix">http://stackoverflow.com/questions/tagged/nix</a></li>
<li><a class="reference external" href="http://stackoverflow.com/questions/tagged/nixos">http://stackoverflow.com/questions/tagged/nixos</a></li>
</ul>
</li>
<li><p class="first">Рассылки</p>
<ul class="simple">
<li><a class="reference external" href="https://twitter.com/nixos_org">https://twitter.com/nixos_org</a></li>
<li><a class="reference external" href="https://www.reddit.com/r/nixos">https://www.reddit.com/r/nixos</a></li>
<li><a class="reference external" href="https://groups.google.com/forum/#!forum/nix-devel">https://groups.google.com/forum/#!forum/nix-devel</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="id5">
<h2>Блоги</h2>
<p><a class="reference external" href="https://typing-nix.regnat.ovh/">https://typing-nix.regnat.ovh/</a></p>
</div>
</div>
gcc для C++11 из реп в CentOS6
http://uralbash.ru/articles/2016/centos6-gcc-cpp11/
2016-06-05T23:45:00Z
2016-06-05T23:45:00Z
Uralbash
<div class="section" id="gcc-c-11-centos6">
<p>C++11 в <a class="reference external" href="https://www.freebsd.org/cgi/man.cgi?query=gcc">gcc</a> появился, начиная с версии 4.7, но в CentOS6 естественно
более старая версия без С++11. Как вариант, можно собрать из исходников, но я
опишу способ установки из дополнительных реп.</p>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last"><a class="reference external" href="https://gcc.gnu.org/projects/cxx-status.html#cxx11">https://gcc.gnu.org/projects/cxx-status.html#cxx11</a></p>
</div>
<p>Добавляем репу:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo yum install centos-release-scl
</pre></div>
</div>
<p>Устанавливаем <code class="docutils literal"><span class="pre">devtoolset-3-toolchain</span></code>, который включает в себя <a class="reference external" href="https://www.freebsd.org/cgi/man.cgi?query=gcc">gcc</a>,
<a class="reference external" href="https://www.freebsd.org/cgi/man.cgi?query=gdb">gdb</a>, <a class="reference external" href="https://www.freebsd.org/cgi/man.cgi?query=binutils">binutils</a>, <a class="reference external" href="https://www.freebsd.org/cgi/man.cgi?query=elfutils">elfutils</a>, <a class="reference external" href="https://www.freebsd.org/cgi/man.cgi?query=dwz">dwz</a>, <a class="reference external" href="https://www.freebsd.org/cgi/man.cgi?query=memstomp">memstomp</a>,
<a class="reference external" href="https://www.freebsd.org/cgi/man.cgi?query=strace">strace</a>, <a class="reference external" href="https://www.freebsd.org/cgi/man.cgi?query=ltrace">ltrace</a>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo yum install devtoolset-3-toolchain
</pre></div>
</div>
<p>Прописываем <a class="reference external" href="https://www.freebsd.org/cgi/man.cgi?query=gcc">gcc</a> в окружение пользователя:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ scl <span class="nb">enable</span> devtoolset-3 bash
или
</pre></div>
</div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ <span class="nb">echo</span> <span class="s2">"source /opt/rh/devtoolset-3/enable"</span> >> ~/.bashrc
</pre></div>
</div>
<p>Профит!</p>
</div>
REST API в Pyramid
http://uralbash.ru/articles/2016/pyramid-restapi/
2016-05-31T14:49:00Z
2016-05-31T14:49:00Z
Uralbash
<div class="admonition note">
<p class="first admonition-title">Примечание</p>
<p class="last">Это статья из лекций
<a class="reference external" href="http://lectureswww.readthedocs.io/6.www.sync/3.framework/pyramid/5.1.rest.html">http://lectureswww.readthedocs.io/6.www.sync/3.framework/pyramid/5.1.rest.html</a></p>
</div>
<div class="section" id="rest-api-pyramid">
<div class="section" id="rest-api">
<h2>REST API</h2>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<ul class="last simple">
<li><a class="reference external" href="https://ru.wikipedia.org/wiki/REST">https://ru.wikipedia.org/wiki/REST</a></li>
<li><a class="reference external" href="http://blog.delaguardia.com.mx/pyramid-view-configuration-let-me-count-the-ways.html">Для тех кто в Djang’е
(http://blog.delaguardia.com.mx/pyramid-view-configuration-let-me-count-the-ways.html)</a></li>
<li><a class="reference external" href="http://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/testing/testing_post_curl.html">http://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/testing/testing_post_curl.html</a></li>
</ul>
</div>
<p><code class="docutils literal"><span class="pre">REST</span> <span class="pre">API</span></code> подразумевает под собой простые правила:</p>
<ul class="simple">
<li>Каждый URL является ресурсом</li>
<li>При обращении к ресурсу методом <code class="docutils literal"><span class="pre">GET</span></code> возвращается описание этого
ресурса</li>
<li>Метод <code class="docutils literal"><span class="pre">POST</span></code> добавляет новый ресурс</li>
<li>Метод <code class="docutils literal"><span class="pre">PUT</span></code> изменяет ресурс</li>
<li>Метод <code class="docutils literal"><span class="pre">DELETE</span></code> удаляет ресурс</li>
</ul>
<p>Эти правила предоставляют простой <code class="docutils literal"><span class="pre">CRUD</span></code> интерфейс для других приложений,
взаимодействие с которым происходит через протокол <code class="docutils literal"><span class="pre">HTTP</span></code>.</p>
<p>Соответствие <code class="docutils literal"><span class="pre">CRUD</span></code> операций и <code class="docutils literal"><span class="pre">HTTP</span></code> методов:</p>
<ul class="simple">
<li><strong>CREATE</strong> - <code class="docutils literal"><span class="pre">POST</span></code></li>
<li><strong>READ</strong> - <code class="docutils literal"><span class="pre">GET</span></code></li>
<li><strong>UPDATE</strong> - <code class="docutils literal"><span class="pre">PUT</span></code></li>
<li><strong>DELETE</strong> - <code class="docutils literal"><span class="pre">DELETE</span></code></li>
</ul>
<p><code class="docutils literal"><span class="pre">REST</span> <span class="pre">API</span></code> интерфейс очень удобен для межпрограммного взаимодействия,
например мобильное приложение может выступать в роли клиента, который
манипулирует данными посредством <code class="docutils literal"><span class="pre">REST</span></code>.</p>
<div class="section" id="pattern-matching">
<h3>Pattern matching</h3>
<p>Пример выше добавляет View с тремя методами, каждый из которых вызывается при
соответствующем <code class="docutils literal"><span class="pre">GET</span></code>, <code class="docutils literal"><span class="pre">POST</span></code>, <code class="docutils literal"><span class="pre">DELETE</span></code> запросе.
Ресурсом здесь является конкретный человек, получить которого можно по URL
<a class="reference external" href="http://localhost:8080/api/v1/people/123">http://localhost:8080/api/v1/people/123</a></p>
<p>Результатом запроса будет:</p>
<div class="highlight-json"><div class="highlight"><pre><span></span><span class="p">{</span><span class="nt">"get"</span><span class="p">:</span> <span class="p">{},</span> <span class="nt">"id"</span><span class="p">:</span> <span class="s2">"123"</span><span class="p">,</span> <span class="nt">"method"</span><span class="p">:</span> <span class="s2">"GET"</span><span class="p">}</span>
</pre></div>
</div>
<p>Для отправки <code class="docutils literal"><span class="pre">POST</span></code> запроса воспользуемся консольной утилитой <a class="reference external" href="https://www.freebsd.org/cgi/man.cgi?query=curl">curl</a>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ curl -X POST -d <span class="s1">'param1=value1&param2=value2'</span> http://localhost:8080/api/v1/people/1
</pre></div>
</div>
<p>Результат запроса:</p>
<div class="highlight-json"><div class="highlight"><pre><span></span><span class="p">{</span><span class="nt">"id"</span><span class="p">:</span> <span class="s2">"1"</span><span class="p">,</span> <span class="nt">"post"</span><span class="p">:</span> <span class="p">{</span><span class="nt">"param1"</span><span class="p">:</span> <span class="s2">"value1"</span><span class="p">,</span> <span class="nt">"param2"</span><span class="p">:</span> <span class="s2">"value2"</span><span class="p">},</span> <span class="nt">"method"</span><span class="p">:</span> <span class="s2">"POST"</span><span class="p">}</span>
</pre></div>
</div>
<p><code class="docutils literal"><span class="pre">DELETE</span></code> запрос выполняется по аналогии:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ curl -X DELETE http://localhost:8080/api/v1/people/1
</pre></div>
</div>
<p>Результат запроса:</p>
<div class="highlight-json"><div class="highlight"><pre><span></span><span class="p">{</span><span class="nt">"status"</span><span class="p">:</span> <span class="s2">"success"</span><span class="p">}</span>
</pre></div>
</div>
</div>
<div class="section" id="traversal">
<h3>Traversal</h3>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last">Метод URL диспетчеризации <a class="reference internal" href="../articles/2016/pyramid-traversal/#traversal-routing"><span class="std std-ref">Traversal</span></a></p>
</div>
<p>В предыдущем примере показан только один ресурс - конкретный человек и
в принципе все выглядит неплохо, пока не появится другой смежный ресурс,
например список всех людей по адресу <a class="reference external" href="http://localhost:8080/api/v1/people">http://localhost:8080/api/v1/people</a></p>
<p>В этом случае, придется добавлять новый путь (rout), привязывать его к
представлению (View) и самое неприятное менять само представление, или еще
хуже писать новое. Таким образом с увеличением ресурсов, сложность REST API
растет не пропорционально и в какой то момент код становится не читаемым
из-за больших размеров и постоянно меняющейся логики во View.</p>
<p>Выход из данной ситуации - отделить ресурсы от представлений, тем самым
вынести часть логики и сделать представления более универсальными.</p>
<div class="section" id="id1">
<h4>Ресурсы</h4>
<p>Ресурсы могут выглядеть так:</p>
<p><code class="docutils literal"><span class="pre">PeopleResource</span></code> представляет список всех людей и будет доступен по
адресу <a class="reference external" href="http://localhost:8080/api/v1/people">http://localhost:8080/api/v1/people</a>.
<code class="docutils literal"><span class="pre">PeopleResource</span></code> имеет метод <code class="docutils literal"><span class="pre">__getitem__</span></code>, что делает его похожим на
словарь. При обращении к объекту ресурса как к словарю, он вызовет
эту функцию и передаст ключ в параметр <code class="docutils literal"><span class="pre">people_id</span></code>, например:</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="n">foo</span> <span class="o">=</span> <span class="n">PeopleResource</span><span class="p">()</span>
<span class="n">bar</span> <span class="o">=</span> <span class="n">foo</span><span class="p">[</span><span class="mi">123</span><span class="p">]</span> <span class="c1"># Вернет объект PersonResource(123)</span>
</pre></div>
</div>
<p>Метод <code class="docutils literal"><span class="pre">__json__</span></code> определяет каким образом преобразовывать ресурс в json.</p>
<p><code class="docutils literal"><span class="pre">PersonResource</span></code> представляет конкретного человека и будет доступен по
адресу <a class="reference external" href="http://localhost:8080/api/v1/people/{id}">http://localhost:8080/api/v1/people/{id}</a>. Здесь отличительной
особенностью является то, что метод <code class="docutils literal"><span class="pre">__json__</span></code> наследует часть словаря из
класса <code class="docutils literal"><span class="pre">PeopleResource</span></code>, при помощи конструкции <code class="docutils literal"><span class="pre">super</span></code>:</p>
</div>
<div class="section" id="view">
<h4>View</h4>
<p>Перепишем View таким образом, что бы она возвращала только ресурс, а так-как
ресурс уже содержит в себе информацию как отдавать json, то это представление
будет универсальным как для <code class="docutils literal"><span class="pre">PeopleResource</span></code>, так и для <code class="docutils literal"><span class="pre">PersonResource</span></code>
и возможно подойдет другим ресурсам которые мы будем писать в будущем.</p>
<p>Рендерер <code class="docutils literal"><span class="pre">json</span></code> по умолчанию ищет метод <code class="docutils literal"><span class="pre">__json__</span></code> и если он есть то
возвращает его результат вызова.</p>
</div>
<div class="section" id="route">
<h4>Route</h4>
<p>Путь, в нашем случае, будет один, так-как вся структура вынесена в ресурсы
(метод <code class="docutils literal"><span class="pre">__getitem__</span></code>).</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">config</span><span class="o">.</span><span class="n">add_route</span><span class="p">(</span><span class="s1">'rest_api'</span><span class="p">,</span> <span class="s1">'/api/v1/*traverse'</span><span class="p">,</span> <span class="n">factory</span><span class="o">=</span><span class="n">rest_factory</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="id2">
<h4>Полный пример</h4>
</div>
</div>
</div>
</div>
Traversal роутинг в Pyramid
http://uralbash.ru/articles/2016/pyramid-traversal/
2016-05-30T14:49:00Z
2016-05-30T14:49:00Z
Uralbash
<div class="admonition note">
<p class="first admonition-title">Примечание</p>
<p class="last">Это статья из лекций
<a class="reference external" href="http://lectureswww.readthedocs.io/6.www.sync/3.framework/pyramid/5.urldispatch.html">http://lectureswww.readthedocs.io/6.www.sync/3.framework/pyramid/5.urldispatch.html</a></p>
</div>
<div class="section" id="traversal-pyramid">
<div class="section" id="url">
<h2>Диспетчеризация URL</h2>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<ul class="last simple">
<li><a class="reference external" href="http://docs.pylonsproject.org/projects/pyramid/en/1.6-branch/narr/urldispatch.html">http://docs.pylonsproject.org/projects/pyramid/en/1.6-branch/narr/urldispatch.html</a></li>
<li><a class="reference external" href="http://pyramid-cookbook.readthedocs.org/en/latest/routing/index.html">http://pyramid-cookbook.readthedocs.org/en/latest/routing/index.html</a></li>
<li><a class="reference external" href="http://blog.delaguardia.com.mx/pyramid-view-configuration-let-me-count-the-ways.html">Для тех кто в Djang’е
(http://blog.delaguardia.com.mx/pyramid-view-configuration-let-me-count-the-ways.html)</a></li>
</ul>
</div>
<p>Каждый поступающий на сервер приложений Pyramid запрос (<strong>request</strong>) должен
найти вид (<strong>view</strong>), который и будет его обрабатывать.</p>
<p>В Pyramid имеется два базовых подхода к поиску нужного вида для обрабатываемого
запроса: на основе сопоставления (<strong>matching</strong>), как в большинстве подобных
фреймворков, и обхода (<strong>traversal</strong>), как в <a class="reference external" href="http://www.zope.org/">Zope</a>. Кроме того, в одном
приложении можно с успехом сочетать оба подхода.</p>
<div class="section" id="pattern-matching">
<h3>Pattern Matching</h3>
<p>Простейший пример с заданием маршрута (заимствован из документации):</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1"># Здесь config - экземпляр pyramid.config.Configurator</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_route</span><span class="p">(</span><span class="s1">'idea'</span><span class="p">,</span> <span class="s1">'site/{id}'</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_view</span><span class="p">(</span><span class="s1">'mypackage.views.site_view'</span><span class="p">,</span> <span class="n">route_name</span><span class="o">=</span><span class="s1">'idea'</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="traversal">
<span id="traversal-routing"></span><h3>Traversal</h3>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<ul class="last simple">
<li><a class="reference external" href="http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/traversal.html">http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/traversal.html</a></li>
</ul>
</div>
<p>Использование обхода лучше проиллюстрировать на небольшом примере:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">wsgiref.simple_server</span> <span class="kn">import</span> <span class="n">make_server</span>
<span class="kn">from</span> <span class="nn">pyramid.config</span> <span class="kn">import</span> <span class="n">Configurator</span>
<span class="kn">from</span> <span class="nn">pyramid.response</span> <span class="kn">import</span> <span class="n">Response</span>
<span class="c1"># Класс некоторого ресурса</span>
<span class="k">class</span> <span class="nc">Resource</span><span class="p">(</span><span class="nb">dict</span><span class="p">):</span>
<span class="k">pass</span>
<span class="c1"># Дерево ресурсов (жёстко закодированное) в фабрике корня</span>
<span class="k">def</span> <span class="nf">get_root</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="k">return</span> <span class="n">Resource</span><span class="p">({</span><span class="s1">'a'</span><span class="p">:</span> <span class="n">Resource</span><span class="p">({</span><span class="s1">'b'</span><span class="p">:</span> <span class="n">Resource</span><span class="p">({</span><span class="s1">'c'</span><span class="p">:</span> <span class="n">Resource</span><span class="p">()})})})</span>
<span class="c1"># Вид-для-вызова, который умеет показывать ресурс Resource (в context)</span>
<span class="k">def</span> <span class="nf">hello_world_of_resources</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">request</span><span class="p">):</span>
<span class="n">output</span> <span class="o">=</span> <span class="s2">"Ресурс и его дети: </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="n">context</span>
<span class="k">return</span> <span class="n">Response</span><span class="p">(</span><span class="n">output</span><span class="p">)</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="n">config</span> <span class="o">=</span> <span class="n">Configurator</span><span class="p">(</span><span class="n">root_factory</span><span class="o">=</span><span class="n">get_root</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_view</span><span class="p">(</span><span class="n">hello_world_of_resources</span><span class="p">,</span> <span class="n">context</span><span class="o">=</span><span class="n">Resource</span><span class="p">)</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">make_wsgi_app</span><span class="p">()</span>
<span class="n">server</span> <span class="o">=</span> <span class="n">make_server</span><span class="p">(</span><span class="s1">'0.0.0.0'</span><span class="p">,</span> <span class="mi">8080</span><span class="p">,</span> <span class="n">app</span><span class="p">)</span>
<span class="n">server</span><span class="o">.</span><span class="n">serve_forever</span><span class="p">()</span>
</pre></div>
</div>
<p>В этом примере иерархия для обхода жестко задана в методе <code class="docutils literal"><span class="pre">get_root</span></code> с
помощью вложенных словарей, тогда как реальные приложения должны сами
определять необходимый доступ по ключам (метод <code class="docutils literal"><span class="pre">__getitem__</span></code> помогает
организовать такой доступ). В коде также присутствует корневая фабрика, с
которой собственно и начинается обход узлов (node) дерева ресурсов.
Вид-для-вызова (<a class="reference external" href="https://docs.pylonsproject.org/projects/pyramid/en/latest/glossary.html#term-view-callable" title="(в The Pyramid Web Framework v2.0)"><span class="xref std std-term">view callable</span></a>) представлен функцией
<code class="docutils literal"><span class="pre">hello_world_of_resources</span></code>. Говоря несколько упрощённо, на основе URL запроса
в результате обхода иерархии Pyramid находит ресурс и применяет к нему
«наилучший» вид-для-вызова (в нашем примере — он единственный).</p>
<div class="section" id="id1">
<h4>Обход словаря</h4>
<div class="admonition warning">
<p class="first admonition-title">Предупреждение</p>
<p class="last">В примерах используется Python3</p>
</div>
<p>Метод обхода дерева (traversal), позволяет находить ресурсы во вложенных структурах.
Такой механизм хорошо применим для некоторых практических задач, например
список всех URL маршрутов сайта является деревом, в котором каждый конечный URL
это отдельная ветка дерева. Поэтому всю структуру сайта можно поместить в словарь.</p>
<p>К примеру, известно, что смерь сказочного персонажа “кащея” находится в яйце,
которое в свою очередь в утке, которая в зайце и т.д. В сумме получается
вложенная структура, которую можно описать так:</p>
<p><code class="docutils literal"><span class="pre">остров</span> <span class="pre">-></span> <span class="pre">дуб</span> <span class="pre">-></span> <span class="pre">сундук</span> <span class="pre">-></span> <span class="pre">заяц</span> <span class="pre">-></span> <span class="pre">утка</span> <span class="pre">-></span> <span class="pre">яйцо</span> <span class="pre">-></span> <span class="pre">игла</span> <span class="pre">-></span> <span class="pre">СмертьКощея</span></code></p>
<p>Мы можем такую, плоскую, вложенную структуру легко представить в виде URL:</p>
<p><code class="docutils literal"><span class="pre">http://localhost:8080/mytraversal/остров/дуб/сундук/заяц/утка/яйцо/игла</span></code></p>
<p>А так-как любой URL является веткой дерева, то несложно описать это в Python:</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="p">{</span>
<span class="s1">'остров'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'дуб'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'сундук'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'заяц'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'утка'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'яйцо'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'игла'</span><span class="p">:</span> <span class="n">СмертьКощея</span><span class="p">()</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p><code class="docutils literal"><span class="pre">СмертьКощея()</span></code> - это объект класса <code class="docutils literal"><span class="pre">СмертьКощея</span></code>, который может выглядеть к примеру так:</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">СмертьКощея</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">__json__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">):</span>
<span class="k">return</span> <span class="p">{</span>
<span class="s1">'имя'</span><span class="p">:</span> <span class="s1">'кощей'</span><span class="p">,</span>
<span class="s1">'статус'</span><span class="p">:</span> <span class="n">request</span><span class="o">.</span><span class="n">context</span> <span class="o">==</span> <span class="bp">self</span> <span class="ow">and</span> <span class="s1">'мертв'</span> <span class="ow">or</span> <span class="s1">'жив ещё'</span><span class="p">,</span>
<span class="p">}</span>
</pre></div>
</div>
<p>В принципе, этого достаточно что бы наш сайт-убийца “кощея” заработал.
Осталось лишь прописать пути и добавить представление (view).</p>
<p>View будет просто возвращать объект, например, если мы ввели:</p>
<div class="highlight-text"><div class="highlight"><pre><span></span>URL: 'остров'
объект: {'дуб': {
'сундук': {
'заяц': {
'утка': {
'яйцо': {
'игла': СмертьКощея()
}
}
}
}
}}
</pre></div>
</div>
<div class="highlight-text"><div class="highlight"><pre><span></span>URL: 'остров/дуб'
объект: {'сундук': {
'заяц': {
'утка': {
'яйцо': {
'игла': СмертьКощея()
}
}
}
}}
</pre></div>
</div>
<div class="highlight-text"><div class="highlight"><pre><span></span>URL: 'остров/дуб/сундук'
объект: {'заяц': {
'утка': {
'яйцо': {
'игла': СмертьКощея()
}
}
}}
</pre></div>
</div>
<div class="highlight-text"><div class="highlight"><pre><span></span>URL: 'остров/дуб/сундук/заяц'
объект: {'утка': {
'яйцо': {
'игла': СмертьКощея()
}
}}
</pre></div>
</div>
<div class="highlight-text"><div class="highlight"><pre><span></span>URL: 'остров/дуб/сундук/заяц/утка'
объект: {'яйцо': {
'игла': СмертьКощея()
}}
</pre></div>
</div>
<div class="highlight-text"><div class="highlight"><pre><span></span>URL: 'остров/дуб/сундук/заяц/утка/яйцо'
объект: {'игла': СмертьКощея()}
</pre></div>
</div>
<div class="highlight-text"><div class="highlight"><pre><span></span>URL: 'остров/дуб/сундук/заяц/утка/яйцо/игла'
объект: СмертьКощея()
</pre></div>
</div>
<p>Такие функции-представления (View) должны принимать 2 параметра, где первый
параметр будет являться объектом, обычно именуемым <code class="docutils literal"><span class="pre">context</span></code>, а второй
параметр <code class="docutils literal"><span class="pre">request</span></code>:</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">traverse_koshey</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">request</span><span class="p">):</span>
<span class="k">return</span> <span class="n">context</span> <span class="c1"># Наш объект</span>
</pre></div>
</div>
<p>Роуты создаются почти так же как в <code class="docutils literal"><span class="pre">pattern</span> <span class="pre">matching</span></code>, за исключением того,
что структура путей передается в виде “фабрики”, которая возвращает словарь или
ему подобный (dict-like) объект. Путь указывается в виде статической и
динамической части, например <code class="docutils literal"><span class="pre">/fixedpath/*traverse</span></code>:</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="n">config</span><span class="o">.</span><span class="n">add_route</span><span class="p">(</span><span class="s1">'koshey'</span><span class="p">,</span> <span class="s1">'/mytraversal/*traverse'</span><span class="p">,</span> <span class="n">factory</span><span class="o">=</span><span class="n">my_factory</span><span class="p">)</span>
</pre></div>
</div>
<p>Фабрика, которая возвращает структуру сайта:</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">my_factory</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="k">return</span> <span class="p">{</span>
<span class="s1">'остров'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'дуб'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'сундук'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'заяц'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'утка'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'яйцо'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'игла'</span><span class="p">:</span> <span class="n">СмертьКощея</span><span class="p">()</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>View добавляется стандартно:</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="n">config</span><span class="o">.</span><span class="n">add_view</span><span class="p">(</span><span class="n">traverse_koshey</span><span class="p">,</span> <span class="n">route_name</span><span class="o">=</span><span class="s1">'koshey'</span><span class="p">,</span> <span class="n">renderer</span><span class="o">=</span><span class="s1">'json'</span><span class="p">)</span>
</pre></div>
</div>
<p>Все готово, можно перемещаться по объектам:</p>
<ul class="simple">
<li><a class="reference external" href="http://localhost:8080/mytraversal/">http://localhost:8080/mytraversal/</a></li>
<li><a class="reference external" href="http://localhost:8080/mytraversal/остров">http://localhost:8080/mytraversal/остров</a></li>
<li><a class="reference external" href="http://localhost:8080/mytraversal/остров/дуб">http://localhost:8080/mytraversal/остров/дуб</a></li>
<li><a class="reference external" href="http://localhost:8080/mytraversal/остров/дуб/сундук">http://localhost:8080/mytraversal/остров/дуб/сундук</a></li>
<li><a class="reference external" href="http://localhost:8080/mytraversal/остров/дуб/сундук/заяц">http://localhost:8080/mytraversal/остров/дуб/сундук/заяц</a></li>
<li><a class="reference external" href="http://localhost:8080/mytraversal/остров/дуб/сундук/заяц/утка">http://localhost:8080/mytraversal/остров/дуб/сундук/заяц/утка</a></li>
<li><a class="reference external" href="http://localhost:8080/mytraversal/остров/дуб/сундук/заяц/утка/яйцо">http://localhost:8080/mytraversal/остров/дуб/сундук/заяц/утка/яйцо</a></li>
<li><a class="reference external" href="http://localhost:8080/mytraversal/остров/дуб/сундук/заяц/утка/яйцо/игла">http://localhost:8080/mytraversal/остров/дуб/сундук/заяц/утка/яйцо/игла</a></li>
</ul>
<p>Полный пример:</p>
<p>Есть один нюанс, json renderer, по умолчанию, все не латинские символы отображает
как UTF коды <code class="docutils literal"><span class="pre">\uxxxx</span></code>, поэтому мы увидим следующий вывод:</p>
<div class="highlight-json"><div class="highlight"><pre><span></span><span class="p">{</span><span class="nt">"\u043e\u0441\u0442\u0440\u043e\u0432"</span><span class="p">:</span> <span class="p">{</span><span class="nt">"\u0434\u0443\u0431"</span><span class="p">:</span> <span class="p">{</span><span class="nt">"\u0441\u0443\u043d\u0434\u0443\u043a"</span><span class="p">:</span> <span class="p">{</span><span class="nt">"\u0437\u0430\u044f\u0446"</span><span class="p">:</span> <span class="p">{</span><span class="nt">"\u0443\u0442\u043a\u0430"</span><span class="p">:</span> <span class="p">{</span><span class="nt">"\u044f\u0439\u0446\u043e"</span><span class="p">:</span> <span class="p">{</span><span class="nt">"\u0438\u0433\u043b\u0430"</span><span class="p">:</span> <span class="p">{</span><span class="nt">"\u0441\u0442\u0430\u0442\u0443\u0441"</span><span class="p">:</span> <span class="s2">"\u0436\u0438\u0432 \u0435\u0449\u0451"</span><span class="p">,</span> <span class="nt">"\u0438\u043c\u044f"</span><span class="p">:</span> <span class="s2">"\u043a\u043e\u0449\u0435\u0439"</span><span class="p">}}}}}}}}</span>
</pre></div>
</div>
<p>Но можно изменить его поведение следующим образом:</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">pyramid.renderers</span> <span class="k">import</span> <span class="n">JSON</span>
<span class="o">...</span>
<span class="hll"> <span class="n">config</span><span class="o">.</span><span class="n">add_renderer</span><span class="p">(</span><span class="s1">'myjson'</span><span class="p">,</span> <span class="n">JSON</span><span class="p">(</span><span class="n">indent</span><span class="o">=</span><span class="mi">4</span><span class="p">,</span> <span class="n">ensure_ascii</span><span class="o">=</span><span class="kc">False</span><span class="p">))</span>
</span> <span class="n">config</span><span class="o">.</span><span class="n">add_view</span><span class="p">(</span><span class="n">traverse_koshey</span><span class="p">,</span> <span class="n">route_name</span><span class="o">=</span><span class="s1">'koshey'</span><span class="p">,</span> <span class="n">renderer</span><span class="o">=</span><span class="s1">'myjson'</span><span class="p">)</span>
</pre></div>
</div>
<p>Результат:</p>
<p><a class="reference external" href="http://localhost:8080/mytraversal/">http://localhost:8080/mytraversal/</a></p>
<div class="highlight-json"><div class="highlight"><pre><span></span><span class="p">{</span>
<span class="nt">"остров"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"дуб"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"сундук"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"заяц"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"утка"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"яйцо"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"игла"</span><span class="p">:</span> <span class="p">{</span>
<span class="nt">"имя"</span><span class="p">:</span> <span class="s2">"кощей"</span><span class="p">,</span>
<span class="nt">"статус"</span><span class="p">:</span> <span class="s2">"жив ещё"</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p><a class="reference external" href="http://localhost:8080/mytraversal/остров/дуб/сундук/заяц/утка/яйцо/игла">http://localhost:8080/mytraversal/остров/дуб/сундук/заяц/утка/яйцо/игла</a></p>
<div class="highlight-json"><div class="highlight"><pre><span></span><span class="p">{</span>
<span class="nt">"имя"</span><span class="p">:</span> <span class="s2">"кощей"</span><span class="p">,</span>
<span class="nt">"статус"</span><span class="p">:</span> <span class="s2">"мертв"</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Полный код:</p>
</div>
<div class="section" id="view">
<h4>Привязка View к ресурсам</h4>
<p>В Пирамиде объект (context) который передается во вью, именуют еще как “ресурс”.
Есть возможность жестко привязать View к типу ресурса. Например, наше
представление <code class="docutils literal"><span class="pre">traverse_koshey</span></code> должно вызываться, только когда пришел объект
класса <code class="docutils literal"><span class="pre">СмертьКощея</span></code>:</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="n">config</span><span class="o">.</span><span class="n">add_view</span><span class="p">(</span><span class="n">traverse_koshey</span><span class="p">,</span> <span class="n">route_name</span><span class="o">=</span><span class="s1">'koshey_context'</span><span class="p">,</span>
<span class="n">renderer</span><span class="o">=</span><span class="s1">'myjson'</span><span class="p">,</span>
<span class="hll"> <span class="n">context</span><span class="o">=</span><span class="n">СмертьКощея</span><span class="p">)</span>
</span></pre></div>
</div>
<p>Параметр <code class="docutils literal"><span class="pre">context</span></code> указывает на то, что это View принадлежит ТОЛЬКО объектам
класса <code class="docutils literal"><span class="pre">СмертьКащея</span></code>.</p>
<p>Все пути, кроме полного (который возвращает нужный объект), вернут 404 код ответа.
Полный путь <a class="reference external" href="http://localhost:8080/mytraversal/остров/дуб/сундук/заяц/утка/яйцо/игла">http://localhost:8080/mytraversal/остров/дуб/сундук/заяц/утка/яйцо/игла</a>.</p>
<p>Добавим в нашу структуру еще ресурсов:</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">my_factory</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="k">return</span> <span class="p">{</span>
<span class="s1">'превед'</span><span class="p">:</span> <span class="n">Человек</span><span class="p">(),</span>
<span class="s1">'остров'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'ясень'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'что то здесь'</span><span class="p">:</span> <span class="s1">'не так!'</span>
<span class="p">},</span>
<span class="s1">'дуб'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'сундук'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'заяц'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'утка'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'яйцо'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'игла'</span><span class="p">:</span> <span class="n">СмертьКощея</span><span class="p">()</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Здесь <code class="docutils literal"><span class="pre">Человек()</span></code> это новый тип ресурса, который имеет метод <code class="docutils literal"><span class="pre">__getitem__</span></code>
как у словаря и при обращении по ключу возвращает другой ресурс:</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Человек</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="n">name</span> <span class="o">=</span> <span class="s1">'Человек'</span>
<span class="k">def</span> <span class="nf">__getitem__</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="k">return</span> <span class="n">Имя</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Имя</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="n">__parent__</span> <span class="o">=</span> <span class="n">Человек</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
</pre></div>
</div>
<p>Например мы обращаемся по URL <a class="reference external" href="http://localhost:8080/mytraversal/превед/Пирамид">http://localhost:8080/mytraversal/превед/Пирамид</a>.
<code class="docutils literal"><span class="pre">превед</span></code> вернет ресурс <code class="docutils literal"><span class="pre">Человек</span></code>, а <code class="docutils literal"><span class="pre">Пирамид</span></code> вызовет метод
<code class="docutils literal"><span class="pre">__getitem__</span></code>, который вернет ресурс <code class="docutils literal"><span class="pre">Имя('Пирамид')</span></code>. Таким образом мы
можем строить дерево динамически при помощи dict-like объектов.</p>
<p>Для ресурса <code class="docutils literal"><span class="pre">Имя</span></code> мы можем создать отдельное представление и жестко привязать
его к этому типу.</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">traverse_hello</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">request</span><span class="p">):</span>
<span class="sd">"""</span>
<span class="sd"> http://localhost:8080/mytraversal/первед/Пирамид</span>
<span class="sd"> """</span>
<span class="k">return</span> <span class="n">Response</span><span class="p">(</span><span class="s1">'Превед '</span> <span class="o">+</span> <span class="n">context</span><span class="o">.</span><span class="n">__parent__</span><span class="o">.</span><span class="n">name</span> <span class="o">+</span> <span class="s1">' '</span> <span class="o">+</span> <span class="n">context</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
<span class="o">...</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_view</span><span class="p">(</span><span class="n">traverse_hello</span><span class="p">,</span> <span class="n">route_name</span><span class="o">=</span><span class="s1">'koshey_context'</span><span class="p">,</span>
<span class="n">renderer</span><span class="o">=</span><span class="s1">'text'</span><span class="p">,</span>
<span class="n">context</span><span class="o">=</span><span class="n">Имя</span><span class="p">)</span>
</pre></div>
</div>
<p>Результат вывода по адресу
<a class="reference external" href="http://localhost:8080/mytraversal/превед/Пирамид">http://localhost:8080/mytraversal/превед/Пирамид</a>, будет обычный текст
(<code class="docutils literal"><span class="pre">Content-Type:</span> <span class="pre">plain/text</span></code>):</p>
<div class="highlight-text"><div class="highlight"><pre><span></span>Превед Человек Пирамид
</pre></div>
</div>
<p>Полный пример:</p>
</div>
</div>
<div class="section" id="id14">
<h3>Комбинация обоих методов</h3>
<p>Фреймворк <code class="docutils literal"><span class="pre">Pyramid</span></code> позволяет использовать оба способа URL маршрутизации
одновременно.</p>
<p>Добавим к примеру с “кащеем” hello world с использованием pattern matching:</p>
<div class="highlight-python3"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">hello_world</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="k">return</span> <span class="n">Response</span><span class="p">(</span><span class="s1">'Hello </span><span class="si">%(name)s</span><span class="s1">!'</span> <span class="o">%</span> <span class="n">request</span><span class="o">.</span><span class="n">matchdict</span><span class="p">)</span>
<span class="o">...</span>
<span class="c1"># Pattern matching routes</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_route</span><span class="p">(</span><span class="s1">'hello'</span><span class="p">,</span> <span class="s1">'/hello/</span><span class="si">{name}</span><span class="s1">'</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_view</span><span class="p">(</span><span class="n">hello_world</span><span class="p">,</span> <span class="n">route_name</span><span class="o">=</span><span class="s1">'hello'</span><span class="p">)</span>
</pre></div>
</div>
<p>Полный пример:</p>
</div>
</div>
</div>
Pyramid фреймворк
http://uralbash.ru/pages/pyramid/
2015-11-21T18:06:00Z
2015-11-21T18:06:00Z
Uralbash
<div class="section" id="pyramid">
<p>Здесь я буду собирать разные полезные ресурсы по фреймворку <a class="reference external" href="http://pylonsproject.org/">Pyramid</a>. Если
вы что то не нашли, пишите в комментах.</p>
<div class="section" id="id1">
<h2>Оф. ресурсы</h2>
<ul class="simple">
<li>Официальный сайт фреймворка Pyramid <a class="reference external" href="http://trypyramid.com">http://trypyramid.com</a></li>
<li>Официальный сайт сообщества Pylons <a class="reference external" href="http://www.pylonsproject.org/">http://www.pylonsproject.org/</a></li>
<li>Документация <a class="reference external" href="http://docs.pylonsproject.org/en/latest/docs/pyramid.html">http://docs.pylonsproject.org/en/latest/docs/pyramid.html</a></li>
<li>Список туториалов <a class="reference external" href="http://docs.pylonsproject.org/projects/pyramid-tutorials/en/latest/index.html">http://docs.pylonsproject.org/projects/pyramid-tutorials/en/latest/index.html</a></li>
<li>Рецепты <a class="reference external" href="http://docs.pylonsproject.org/projects/pyramid-cookbook/en/latest/index.html">http://docs.pylonsproject.org/projects/pyramid-cookbook/en/latest/index.html</a></li>
<li>Код <a class="reference external" href="https://github.com/Pylons">https://github.com/Pylons</a></li>
<li>Донэйт <a class="reference external" href="https://gratipay.com/pylonsproject/">https://gratipay.com/pylonsproject/</a></li>
</ul>
</div>
<div class="section" id="id2">
<h2>Полезные ссылки</h2>
<ul class="simple">
<li><a class="reference external" href="https://github.com/uralbash/awesome-pyramid">Awesome список батареек на гитхабе</a></li>
</ul>
</div>
<div class="section" id="id3">
<h2>Сообщество</h2>
<p>Перечислю источники по степени активности:</p>
<ul>
<li><p class="first"><code class="docutils literal"><span class="pre">#pyramid</span></code> irc канал на freenode имеет очень высокую активность,
разработчики фреймворка и все что с ним связанно не брезгают отвечать на
вопросы новичков.</p>
<a class="reference external image-reference" href="https://webchat.freenode.net/?channels=pyramid"><img alt="irc freenode" src="https://img.shields.io/badge/irc-freenode-blue.svg" /></a>
</li>
<li><p class="first">Гугл группы, если хочется сформулировать вопрос/предложение или попиариться
не в чате.</p>
<ul class="simple">
<li><a class="reference external" href="https://groups.google.com/forum/#!forum/pylons-discuss">https://groups.google.com/forum/#!forum/pylons-discuss</a></li>
<li><a class="reference external" href="https://groups.google.com/forum/#!forum/pylons-devel">https://groups.google.com/forum/#!forum/pylons-devel</a></li>
</ul>
</li>
<li><p class="first">StackOverflow то же весьма активен, много людей из рассылки.</p>
<ul class="simple">
<li><a class="reference external" href="http://stackoverflow.com/questions/tagged/pyramid">http://stackoverflow.com/questions/tagged/pyramid</a></li>
</ul>
</li>
<li><p class="first">Reddit, полумертвый источник, но разработчики на него подписанны.</p>
<ul class="simple">
<li><a class="reference external" href="https://www.reddit.com/r/Pyramid/">https://www.reddit.com/r/Pyramid/</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="id4">
<h2>На русском</h2>
<ul>
<li><p class="first">Попытка создать тоже самое на русском <a class="reference external" href="https://groups.google.com/forum/#!forum/pyramid-ru">https://groups.google.com/forum/#!forum/pyramid-ru</a></p>
</li>
<li><p class="first"><code class="docutils literal"><span class="pre">#pyramid-ru</span></code> irc канал на freenode.</p>
<a class="reference external image-reference" href="https://webchat.freenode.net/?channels=pyramid-ru"><img alt="irc freenode" src="https://img.shields.io/badge/irc-freenode-blue.svg" /></a>
</li>
<li><p class="first">StackOverflow <a class="reference external" href="http://ru.stackoverflow.com/questions/tagged/pyramid">http://ru.stackoverflow.com/questions/tagged/pyramid</a></p>
</li>
<li><p class="first"><a class="reference external" href="http://lectureswww.readthedocs.io/6.www.sync/3.framework/pyramid/index.html">Лекции Python/Pyramid</a></p>
</li>
<li><p class="first">Wikipedia <a class="reference external" href="https://ru.wikipedia.org/wiki/Pyramid_(программный_каркас)">https://ru.wikipedia.org/wiki/Pyramid_(программный_каркас)</a></p>
</li>
</ul>
</div>
<div class="section" id="id5">
<h2>Блоги на русском</h2>
<ul class="simple">
<li><a class="reference external" href="http://faq1c.gorbunov.ru/node/85">http://faq1c.gorbunov.ru/node/85</a></li>
</ul>
</div>
</div>
Декораторы для корутин в asyncio
http://uralbash.ru/articles/2015/asyncio-decorator/
2015-10-15T14:49:00Z
2015-10-15T14:49:00Z
Uralbash
<div class="admonition note">
<p class="first admonition-title">Примечание</p>
<p class="last">Это статья из лекций
<a class="reference external" href="http://lectureswww.readthedocs.io/999.additions/python/asyncio-decorator.html">http://lectureswww.readthedocs.io/999.additions/python/asyncio-decorator.html</a></p>
</div>
<div class="section" id="asyncio">
<p>Декораторы для асинхронных функций пишутся как и для обычных только возвращать
нужно корутину, а не функцию.</p>
<p>Для примера обычная функция:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">plusplus</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">wrapped</span><span class="p">():</span>
<span class="k">return</span> <span class="n">func</span><span class="p">()</span> <span class="o">+</span> <span class="mi">1</span>
<span class="k">return</span> <span class="n">wrapped</span>
<span class="nd">@plusplus</span>
<span class="k">def</span> <span class="nf">one</span><span class="p">():</span>
<span class="k">return</span> <span class="mi">1</span>
<span class="k">print</span><span class="p">(</span><span class="n">one</span><span class="p">())</span> <span class="c1"># return 2</span>
<span class="nd">@plusplus</span>
<span class="nd">@plusplus</span>
<span class="nd">@plusplus</span>
<span class="nd">@plusplus</span>
<span class="k">def</span> <span class="nf">one</span><span class="p">():</span>
<span class="k">return</span> <span class="mi">1</span>
<span class="k">print</span><span class="p">(</span><span class="n">one</span><span class="p">())</span> <span class="c1"># now return 5</span>
</pre></div>
</div>
<p>В декораторе наша обертка над функцией (<code class="docutils literal"><span class="pre">wrapped</span></code>) стала корутиной:</p>
<div class="highlight-python"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">timeit</span>
<span class="kn">import</span> <span class="nn">asyncio</span>
<span class="k">def</span> <span class="nf">plusplus</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
<span class="hll"> <span class="n">async</span> <span class="k">def</span> <span class="nf">wrapped</span><span class="p">():</span>
</span><span class="hll"> <span class="n">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span><span class="hll"> <span class="k">return</span> <span class="n">await</span> <span class="n">func</span><span class="p">()</span> <span class="o">+</span> <span class="mi">1</span>
</span> <span class="k">return</span> <span class="n">wrapped</span>
<span class="nd">@plusplus</span>
<span class="hll"><span class="n">async</span> <span class="k">def</span> <span class="nf">one</span><span class="p">():</span>
</span><span class="hll"> <span class="n">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
</span> <span class="k">return</span> <span class="mi">1</span>
<span class="n">loop</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">get_event_loop</span><span class="p">()</span>
<span class="n">start</span> <span class="o">=</span> <span class="n">timeit</span><span class="o">.</span><span class="n">default_timer</span><span class="p">()</span>
<span class="k">print</span><span class="p">(</span><span class="n">loop</span><span class="o">.</span><span class="n">run_until_complete</span><span class="p">(</span><span class="n">one</span><span class="p">()))</span> <span class="c1"># return 2</span>
<span class="n">stop</span> <span class="o">=</span> <span class="n">timeit</span><span class="o">.</span><span class="n">default_timer</span><span class="p">()</span>
<span class="k">print</span><span class="p">(</span><span class="n">stop</span> <span class="o">-</span> <span class="n">start</span><span class="p">)</span> <span class="c1"># minimum 3 seconds</span>
<span class="nd">@plusplus</span>
<span class="nd">@plusplus</span>
<span class="nd">@plusplus</span>
<span class="nd">@plusplus</span>
<span class="hll"><span class="n">async</span> <span class="k">def</span> <span class="nf">one</span><span class="p">():</span>
</span><span class="hll"> <span class="n">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
</span> <span class="k">return</span> <span class="mi">1</span>
<span class="n">start</span> <span class="o">=</span> <span class="n">timeit</span><span class="o">.</span><span class="n">default_timer</span><span class="p">()</span>
<span class="k">print</span><span class="p">(</span><span class="n">loop</span><span class="o">.</span><span class="n">run_until_complete</span><span class="p">(</span><span class="n">one</span><span class="p">()))</span> <span class="c1"># return 5</span>
<span class="n">stop</span> <span class="o">=</span> <span class="n">timeit</span><span class="o">.</span><span class="n">default_timer</span><span class="p">()</span>
<span class="k">print</span><span class="p">(</span><span class="n">stop</span> <span class="o">-</span> <span class="n">start</span><span class="p">)</span> <span class="c1"># minimum 6 seconds</span>
</pre></div>
</td></tr></table></div>
<p>Более практичный пример это функция <code class="docutils literal"><span class="pre">json_response</span></code> для вьюх в
<a class="reference external" href="https://aiohttp.readthedocs.org/">aiohttp</a>. Идея взята из презентации
(<a class="reference external" href="http://igordavydenko.com/talks/lvivpy-4/#slide-31">http://igordavydenko.com/talks/lvivpy-4/#slide-31</a>).</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">ujson</span>
<span class="kn">import</span> <span class="nn">asyncio</span>
<span class="kn">from</span> <span class="nn">aiohttp</span> <span class="kn">import</span> <span class="n">web</span>
<span class="k">def</span> <span class="nf">json_response</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="n">kwargs</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="s1">'content_type'</span><span class="p">,</span> <span class="s1">'application/json'</span><span class="p">)</span>
<span class="k">return</span> <span class="n">web</span><span class="o">.</span><span class="n">Response</span><span class="p">(</span><span class="n">text</span><span class="o">=</span><span class="n">ujson</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">data</span><span class="p">),</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="n">async</span> <span class="k">def</span> <span class="nf">index</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="k">return</span> <span class="n">json_response</span><span class="p">({</span><span class="s2">"Hello"</span><span class="p">:</span> <span class="s2">"World"</span><span class="p">})</span>
</pre></div>
</div>
<p>Все хорошо но ретурнов во вьюхе может быть много и тогда оборачивать каждый в
<code class="docutils literal"><span class="pre">json_response</span></code> довольно неудобно. Что бы решить эту проблему создадим
декоратор <code class="docutils literal"><span class="pre">json_view</span></code>.</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">json_view</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
<span class="n">async</span> <span class="k">def</span> <span class="nf">wrapped</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="k">return</span> <span class="n">json_response</span><span class="p">(</span><span class="n">await</span> <span class="n">func</span><span class="p">(</span><span class="n">request</span><span class="p">))</span>
<span class="k">return</span> <span class="n">wrapped</span>
</pre></div>
</div>
<p>Теперь можно писать так:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="nd">@json_view</span>
<span class="n">async</span> <span class="k">def</span> <span class="nf">index</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="k">if</span> <span class="n">somethink</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span><span class="s2">"Somethink"</span><span class="p">:</span> <span class="s2">"happens"</span><span class="p">}</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span><span class="s2">"else"</span><span class="p">:</span> <span class="s2">"happens"</span><span class="p">}</span>
<span class="k">return</span> <span class="p">{</span><span class="s2">"Hello"</span><span class="p">:</span> <span class="s2">"World"</span><span class="p">}</span>
</pre></div>
</div>
<p>Класс <a class="reference external" href="https://docs.aiohttp.org/en/stable/web_reference.html#aiohttp.web.Response" title="(в aiohttp v3.8)"><code class="xref py py-class docutils literal"><span class="pre">aiohttp.web.Response</span></code></a> позволяет задавать различные параметры типа
заголовков и статуса ответа. Перепишем наш декоратор таким образом что бы он
умел принимать эти параметры:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">json_view_arg</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">wrap</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
<span class="n">async</span> <span class="k">def</span> <span class="nf">wrapped</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="k">return</span> <span class="n">json_response</span><span class="p">(</span><span class="n">await</span> <span class="n">func</span><span class="p">(</span><span class="n">request</span><span class="p">),</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="k">return</span> <span class="n">wrapped</span>
<span class="k">return</span> <span class="n">wrap</span>
</pre></div>
</div>
<p>Теперь можно задать, например, кастомный заголовок ответа <code class="docutils literal"><span class="pre">Server</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="nd">@json_view_arg</span><span class="p">(</span><span class="n">headers</span><span class="o">=</span><span class="p">{</span><span class="s2">"Server"</span><span class="p">:</span> <span class="s2">"Nginx"</span><span class="p">})</span>
<span class="n">async</span> <span class="k">def</span> <span class="nf">index</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="k">return</span> <span class="p">{</span><span class="s2">"Hello"</span><span class="p">:</span> <span class="s2">"World"</span><span class="p">}</span>
</pre></div>
</div>
<img alt="_static/999.additions/python/header-server-nginx.png" class="align-center" src="_static/999.additions/python/header-server-nginx.png" />
<p>И в заключение то же в виде класса-декоратора:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">JsonView</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">kwargs</span> <span class="o">=</span> <span class="n">kwargs</span>
<span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">func</span><span class="p">):</span>
<span class="n">async</span> <span class="k">def</span> <span class="nf">wrapped</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="k">return</span> <span class="n">json_response</span><span class="p">(</span><span class="n">await</span> <span class="n">func</span><span class="p">(</span><span class="n">request</span><span class="p">),</span> <span class="o">**</span><span class="bp">self</span><span class="o">.</span><span class="n">kwargs</span><span class="p">)</span>
<span class="k">return</span> <span class="n">wrapped</span>
</pre></div>
</div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="nd">@JsonView</span><span class="p">(</span><span class="n">headers</span><span class="o">=</span><span class="p">{</span><span class="s2">"Server"</span><span class="p">:</span> <span class="s2">"Nginx"</span><span class="p">})</span>
<span class="n">async</span> <span class="k">def</span> <span class="nf">index</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="k">return</span> <span class="p">{</span><span class="s2">"Hello"</span><span class="p">:</span> <span class="s2">"World"</span><span class="p">}</span>
</pre></div>
</div>
</div>
Установка python 3.5 в virtualenv
http://uralbash.ru/articles/2015/python3.5-virtualenv/
2015-10-10T13:51:00Z
2015-10-10T13:51:00Z
Uralbash
<div class="section" id="python-3-5-virtualenv">
<p>Все уже слышали про новый pyhton версии 3.5
(<a class="reference external" href="https://docs.python.org/3/whatsnew/3.5.html">https://docs.python.org/3/whatsnew/3.5.html</a>). Я постараюсь описать как начать
им пользоваться в вашем виртуальном окружении.</p>
<div class="section" id="id1">
<h2>Скачиваем</h2>
<div class="admonition note">
<p class="first admonition-title">Примечание</p>
<p>В <a class="reference external" href="https://docs.python.org/devguide/setup.html#getting-the-source-code">оф. документации</a>
предлагают скачать ртутью с фирменного сайта:</p>
<div class="last highlight-bash"><div class="highlight"><pre><span></span>$ hg clone https://hg.python.org/cpython
$ hg update <span class="m">3</span>.5
</pre></div>
</div>
</div>
<p>Скачиваем с гитхаба <a class="reference external" href="https://github.com/python/cpython">python/cpython</a>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>git clone https://github.com/python/cpython.git
</pre></div>
</div>
<p>Выбираем ветку <code class="docutils literal"><span class="pre">3.5</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>git checkout <span class="m">3</span>.5
</pre></div>
</div>
</div>
<div class="section" id="id3">
<h2>Собираем</h2>
<p>Укажем локальную директорию для сборки:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>./configure --prefix<span class="o">=</span><span class="nv">$HOME</span>/Projects/bin/python3.5
</pre></div>
</div>
<p>Скомпилируем:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>make <span class="o">&&</span> make install
</pre></div>
</div>
<p>Теперь можно запускать:</p>
<div class="highlight-ipython"><div class="highlight"><pre><span></span>$ $HOME/Projects/bin/python3.5/bin/python3
Python 3.5.0+ (default, Oct 10 2015, 13:35:25)
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
</pre></div>
</div>
<div class="highlight-ipython"><div class="highlight"><pre><span></span>>>> {*range(4), 4, *(5, 6, 7)}
{0, 1, 2, 3, 4, 5, 6, 7}
>>> import asyncio
>>> async def foo(bar): await asyncio.sleep(42)
</pre></div>
</div>
</div>
<div class="section" id="virtualenv">
<h2>virtualenv</h2>
<p>Укажем виртуальному окружению где находится интерпретатор cpython:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ mkvirtualenv --python<span class="o">=</span><span class="nv">$HOME</span>/Projects/bin/python3.5/bin/python3 python35_env
Running virtualenv with interpreter /home/uralbash/Projects/bin/python3.5/bin/python3
Using base prefix <span class="s1">'/home/uralbash/Projects/bin/python3.5'</span>
New python executable in aiohttp/bin/python3
Also creating executable in aiohttp/bin/python
Installing setuptools, pip, wheel...done.
</pre></div>
</div>
</div>
</div>
Обновление до Go1.5
http://uralbash.ru/articles/2015/go1.5/
2015-08-20T10:59:00Z
2015-08-20T10:59:00Z
Uralbash
<div class="section" id="go1-5">
<p>Для управления версиями я пользуюсь <a class="reference external" href="https://github.com/moovweb/gvm">moovweb/gvm</a>.</p>
<div class="section" id="gvm">
<h2>Установка gvm</h2>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ bash < <<span class="o">(</span>curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer<span class="o">)</span>
</pre></div>
</div>
</div>
<div class="section" id="go-1-4">
<h2>Установка Go 1.4</h2>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ gvm install go1.4
$ gvm use go1.4
</pre></div>
</div>
</div>
<div class="section" id="go-1-5">
<h2>Установка Go 1.5</h2>
<p>Теперь компилим <code class="docutils literal"><span class="pre">Go</span></code> при помощи <code class="docutils literal"><span class="pre">Go</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ <span class="nv">GOROOT_BOOTSTRAP</span><span class="o">=</span>~/.gvm/gos/go1.4 gvm install go1.5
Installing go1.5...
+ Compiling...
</pre></div>
</div>
<p>Выберем новую версию:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ gvm use go1.5
Now using version go1.5
$ go version
go version go1.5 linux/amd64
</pre></div>
</div>
<p>Убедимся в ее наличии:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ gvm list --all
gvm gos <span class="o">(</span>installed<span class="o">)</span>
go1.4
<span class="o">=</span>> go1.5
system
</pre></div>
</div>
</div>
</div>
Vim (и не только) для reStructuredText
http://uralbash.ru/articles/2015/rstcheck/
2015-08-13T17:24:00Z
2015-08-13T17:24:00Z
Uralbash
<div class="section" id="vim-restructuredtext">
<p><a class="reference external" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> - очень удобная разметка, которая используется при
написании документации (<a class="reference external" href="https://pypi.python.org/pypi/sphinx">sphinx</a>), README для гитхаба, битбакета, PyPi и
всего прочего вплоть до научных статей (<a class="reference external" href="http://hplgit.github.io/teamods/writing_reports/_static/report_solarized2_dark.html">пример</a>)
или же статей для <a class="reference internal" href="../articles/2015/ablog/#ablog"><span class="std std-ref">блога</span></a> :)</p>
<p>Так-как документация отымает бОльшую часть времени от разработки, то хорошо бы
настроить окружение под нее. В конечном счете это сэкономит кучу времени.</p>
<div class="section" id="tagbar">
<h2>TagBar</h2>
<p><a class="reference external" href="https://github.com/majutsushi/tagbar">majutsushi/tagbar</a> - это плагин который показывает тэги документа в
отдельном окне. Для настройки нам понадобится добавить его в <a class="reference external" href="http://www.vim.org">Vim</a> и
установить клавишу вызова (например <code class="kbd docutils literal"><span class="pre">F8</span></code>).</p>
<div class="literal-block-wrapper docutils container" id="id7">
<div class="code-block-caption"><span class="caption-text">.vimrc добавляем tagbar</span></div>
<div class="highlight-vim"><div class="highlight"><pre><span></span>Plug <span class="s1">'majutsushi/tagbar'</span>
nmap <span class="p"><</span>F8<span class="p">></span> :TagbarToggle<span class="p"><</span>CR<span class="p">></span>
</pre></div>
</div>
</div>
<p>Все что <code class="docutils literal"><span class="pre">tagbar</span></code> не умеет делать “из коробки” можно подключить в виде
отдельных расширений (<a class="reference external" href="https://github.com/majutsushi/tagbar/wiki">полный список тут</a>) или написать свое.</p>
<p>Для <a class="reference external" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> есть <a class="reference external" href="https://github.com/jszakmeister/rst2ctags">jszakmeister/rst2ctags</a>. Подключается
он довольно просто:</p>
<ul class="simple">
<li>клонируем <code class="docutils literal"><span class="pre">git</span></code> репу в локальную папку</li>
<li>и указываем путь до нее в <code class="docutils literal"><span class="pre">.vimrc</span></code></li>
</ul>
<div class="literal-block-wrapper docutils container" id="id8">
<div class="code-block-caption"><span class="caption-text">.vimrc конфиг rst2ctags</span></div>
<div class="highlight-vim"><div class="highlight"><pre><span></span><span class="k">let</span> <span class="k">g</span>:tagbar_type_rst <span class="p">=</span> {
\ <span class="s1">'ctagstype'</span>: <span class="s1">'rst'</span><span class="p">,</span>
<span class="hll"> \ <span class="s1">'ctagsbin'</span> : <span class="s1">'/home/uralbash/.vim/config/common/rst2ctags/rst2ctags.py'</span><span class="p">,</span>
</span> \ <span class="s1">'ctagsargs'</span> : <span class="s1">'-f - --sort=yes'</span><span class="p">,</span>
\ <span class="s1">'kinds'</span> : [
\ <span class="s1">'s:sections'</span><span class="p">,</span>
\ <span class="s1">'i:images'</span>
\ ]<span class="p">,</span>
\ <span class="s1">'sro'</span> : <span class="s1">'|'</span><span class="p">,</span>
\ <span class="s1">'kind2scope'</span> : {
\ <span class="s1">'s'</span> : <span class="s1">'section'</span><span class="p">,</span>
\ }<span class="p">,</span>
\ <span class="s1">'sort'</span>: <span class="m">0</span><span class="p">,</span>
\ }
</pre></div>
</div>
</div>
<p>После этого по нажатию <code class="kbd docutils literal"><span class="pre">F8</span></code> будет открываться “содержание” вашего
документа, как показано на рисунках ниже.</p>
<div class="figure align-center" id="id9">
<img alt="_static/2015/rst2ctags.png" src="_static/2015/rst2ctags.png" />
<p class="caption"><span class="caption-text">Пример <a class="reference external" href="https://github.com/jszakmeister/rst2ctags">jszakmeister/rst2ctags</a> в <a class="reference external" href="http://www.vim.org">Vim</a></span></p>
</div>
<div class="figure align-center" id="id10">
<img alt="_static/2015/rst2ctags2.png" src="_static/2015/rst2ctags2.png" />
<p class="caption"><span class="caption-text">Пример <a class="reference external" href="https://github.com/jszakmeister/rst2ctags">jszakmeister/rst2ctags</a> в <a class="reference external" href="http://www.vim.org">Vim</a> с более простой структурой
разделов</span></p>
</div>
<p>Таким образом упрощается навигация по документу и структурирование разделов.</p>
</div>
<div class="section" id="riv-vim">
<h2>Riv.vim</h2>
<p><a class="reference external" href="https://github.com/Rykka/riv.vim">Rykka/riv.vim</a> - это что то на подобии <code class="docutils literal"><span class="pre">python-mode</span></code> для
<a class="reference external" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a>. Всякие ништяки для rST.</p>
<div class="literal-block-wrapper docutils container" id="id11">
<div class="code-block-caption"><span class="caption-text">Добавляем <a class="reference external" href="https://github.com/Rykka/riv.vim">Rykka/riv.vim</a> в <a class="reference external" href="http://www.vim.org">Vim</a></span></div>
<div class="highlight-vim"><div class="highlight"><pre><span></span>Plug <span class="s1">'Rykka/riv.vim'</span><span class="p">,</span> { <span class="s1">'for'</span>: <span class="s1">'rst'</span> }
</pre></div>
</div>
</div>
<p>В командном режиме появятся следующие функции:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>Riv2BuildPath RivCreateHyperLink RivHelpTodo
RivListType2 RivShiftRight RivTitle2
Riv2HtmlAndBrowse RivCreateInterpreted RivInstruction
RivListType3 RivSpecification RivTitle3
Riv2HtmlFile RivCreateLink RivIntro
RivListType4 RivSuperCEnter RivTitle4
Riv2HtmlProject RivCreateLiteralBlock RivItemClick
RivNormEqual RivSuperEnter RivTitle5
Riv2Latex RivCreateLiteralInline RivItemToggle
RivNormLeft RivSuperMEnter RivTitle6
Riv2Odt RivCreateStrong RivLinkNext
RivNormRight RivSuperSEnter RivTodoAsk
Riv2Pdf RivCreateTime RivLinkOpen
RivPrimer RivTableCreate RivTodoDate
Riv2S5 RivCreateTransition RivLinkPrev
RivProjectHtmlIndex RivTableFormat RivTodoDel
Riv2Xml RivDeleteFile RivLinkShow
RivProjectIndex RivTableNextCell RivTodoPrior
RivCheatSheet RivDirectives RivListDelete
RivProjectList RivTablePrevCell RivTodoToggle
RivCreateContent RivFoldAll RivListNew
RivQuickStart RivTestFold0 RivTodoType1
RivCreateDate RivFoldToggle RivListSub
RivReload RivTestFold1 RivTodoType2
RivCreateEmphasis RivFoldUpdate RivListSup
RivScratchCreate RivTestObj RivTodoType3
RivCreateExplicitMark RivGetLatest RivListToggle
RivScratchView RivTestTest RivTodoType4
RivCreateFoot RivHelpFile RivListType0
RivShiftEqual RivTitle0 RivTodoUpdateCache
RivCreateGitLink RivHelpSection RivListType1
RivShiftLeft RivTitle1 RivVimTest
</pre></div>
</div>
<p>Плагин имеет множество разных функций которые лучше
изучить при помощи команды <code class="docutils literal"><span class="pre">:RivQuickStart</span></code>.</p>
<p>Например команда <code class="docutils literal"><span class="pre">:Riv2HtmlAndBrowse</span></code> рендерит текущий документ и открывает
его в браузере. А сочетание клавиш <code class="kbd docutils literal"><span class="pre">Ctrl+e</span></code> <code class="kbd docutils literal"><span class="pre">s</span></code> <code class="kbd docutils literal"><span class="pre">1</span></code> делает
текущую строку заголовком 1-го уровня, т.е. выполняет функцию <code class="docutils literal"><span class="pre">RivTitle1</span></code>.</p>
</div>
<div class="section" id="rstcheck">
<h2>rstcheck</h2>
<p><a class="reference external" href="https://github.com/myint/rstcheck">myint/rstcheck</a> - это отличный линтер для разметки
<a class="reference external" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a>, также помимо <code class="docutils literal"><span class="pre">docutils</span></code> он понимает <a class="reference external" href="http://sphinx-doc.org/">sphinx-doc</a>
директивы и роли.</p>
<div class="section" id="id3">
<h3>Установка</h3>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ pip install --upgrade rstcheck
</pre></div>
</div>
</div>
<div class="section" id="code-block">
<h3>Проверка синтаксиса в директиве <code class="docutils literal"><span class="pre">code-block</span></code></h3>
<p><code class="docutils literal"><span class="pre">rstcheck</span></code> умеет проверять синтаксис следующих языков в директиве <code class="docutils literal"><span class="pre">..</span>
<span class="pre">code-block::</span></code>:</p>
<ul class="simple">
<li>Bash</li>
<li>Doctest</li>
<li>C (C99)</li>
<li>C++ (C++11)</li>
<li>JSON</li>
<li>Python</li>
<li>reStructuredText</li>
</ul>
<p>Например я допустил ошибку в коде на <a class="reference external" href="http://www.python.org/">Python</a>:</p>
<div class="highlight-rst"><div class="highlight"><pre><span></span><span class="gh">====</span>
<span class="gh">Test</span>
<span class="gh">====</span>
<span class="p">..</span> <span class="ow">code-block</span><span class="p">::</span> python
print(
</pre></div>
</div>
<p>В этом случае линтер ее обнаружит:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ rstcheck bad_python.rst
bad_python.rst:7: <span class="o">(</span>ERROR/3<span class="o">)</span> <span class="o">(</span>python<span class="o">)</span> unexpected EOF <span class="k">while</span> parsing
</pre></div>
</div>
<p>Еще пример с <code class="docutils literal"><span class="pre">C++</span></code>:</p>
<div class="highlight-rst"><div class="highlight"><pre><span></span><span class="gh">====</span>
<span class="gh">Test</span>
<span class="gh">====</span>
<span class="p">..</span> <span class="ow">code-block</span><span class="p">::</span> <span class="k">cpp</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">return</span> <span class="n">x</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ rstcheck bad_cpp.rst
bad_cpp.rst:9: <span class="o">(</span>ERROR/3<span class="o">)</span> <span class="o">(</span>cpp<span class="o">)</span> error: <span class="s1">'x'</span> was not declared in this scope
</pre></div>
</div>
<p>И пример с опечаткой в rST:</p>
<div class="highlight-rst"><div class="highlight"><pre><span></span>====
<span class="gh">Test</span>
<span class="gh">===</span>
</pre></div>
</div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ rstcheck bad_rst.rst
bad_rst.rst:1: <span class="o">(</span>SEVERE/4<span class="o">)</span> Title overline <span class="p">&</span> underline mismatch.
</pre></div>
</div>
<p>Я добавляю <code class="docutils literal"><span class="pre">rstcheck</span></code> в <code class="docutils literal"><span class="pre">travis-ci</span></code> и после каждого коммита проверяю
документацию на наличие ошибок. Пример можно посмотреть <a class="reference external" href="https://github.com/ustu/lectures.www/blob/master/test.sh">здесь</a>.</p>
</div>
<div class="section" id="id5">
<h3>Конфиг</h3>
<p>Про некоторые кастомные роли и директивы <code class="docutils literal"><span class="pre">rstcheck</span></code> ничего не знает, что бы
они не попадали в поток ошибок их можно заигнорировать при помощи конфига. Файл
конфига с именем <code class="docutils literal"><span class="pre">.rstcheck.cfg</span></code> должен располагаться в текущей директории,
например так:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>docs
├── foo
│ └── bar.rst
├── index.rst
└── .rstcheck.cfg
</pre></div>
</div>
<p>Можно указать какие игнорировать директивы или роли, например для блога я
использую некоторые кастомные вещи из модуля расширения
<a class="reference external" href="https://github.com/ITCase/sphinx-links">ITCase/sphinx-links</a> и <a class="reference external" href="https://github.com/abakan/ablog">ABlog</a>:</p>
<div class="highlight-ini"><div class="highlight"><pre><span></span><span class="k">[rstcheck]</span>
<span class="na">ignore_directives</span><span class="o">=</span><span class="s">post,postlist</span>
<span class="na">ignore_roles</span><span class="o">=</span><span class="s">github,l,man,pypi</span>
</pre></div>
</div>
</div>
<div class="section" id="python">
<h3>Модуль для Python</h3>
<p>Т.к. <a class="reference external" href="https://pypi.python.org/pypi/rstcheck">rstcheck</a> это <a class="reference external" href="http://www.python.org/">Python</a> модуль, его можно использовать в своих
скриптах:</p>
<div class="highlight-ipython"><div class="highlight"><pre><span></span>>>> import rstcheck
>>> list(rstcheck.check('Example\n==='))
[(2, '(INFO/1) Possible title underline, too short for the title.')]
</pre></div>
</div>
</div>
<div class="section" id="vim">
<h3>Vim</h3>
<p>Для вима используйте <a class="reference external" href="https://github.com/scrooloose/syntastic">scrooloose/syntastic</a>:</p>
<div class="highlight-vim"><div class="highlight"><pre><span></span><span class="k">let</span> <span class="k">g</span>:syntastic_rst_checkers <span class="p">=</span> [<span class="s1">'rstcheck'</span>]
</pre></div>
</div>
<img alt="_static/2015/rstcheck_vim.png" class="align-center" src="_static/2015/rstcheck_vim.png" />
</div>
</div>
<div class="section" id="id6">
<h2>Итог</h2>
<p>Пишите документацию в целом и пишите больше в <a class="reference external" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> он
прекрасен.</p>
</div>
</div>
Блог в reStructuredText разметке
http://uralbash.ru/articles/2015/ablog/
2015-08-12T12:06:00Z
2015-08-12T12:06:00Z
Uralbash
<div class="section" id="restructuredtext">
<span id="ablog"></span>
<img alt="_static/2015/uralbash.ru.png" class="align-left" src="_static/2015/uralbash.ru.png" style="width: 500px;" />
<p>Перевел тут блог с <a class="reference external" href="https://www.blogger.com/">https://www.blogger.com/</a> на <a class="reference external" href="https://github.com/abakan/ablog">abakan/ablog</a>. Блоггер
это конечно хорошо, но у него крайне ограниченный WYSIWYG, тем более только из
браузера. <a class="reference external" href="https://github.com/abakan/ablog">Ablog</a> по сути это <a class="reference external" href="https://pypi.python.org/pypi/sphinx">sphinx</a> движок заточенный на блог со
всеми плюшками, rST разметкой, RSS и disqus комментами.</p>
<br clear="both"/>
<test/><div class="section" id="id1">
<h2>Профит</h2>
<ul class="simple">
<li><a class="reference external" href="https://pypi.python.org/pypi/Sphinx">Sphinx</a> позволяет автоматизировать многие вещи</li>
<li><code class="docutils literal"><span class="pre">reStructuredText</span></code> позволяет точно и красиво оформлять статьи, это как
писать “курсач” в LaTeX заместо MS Office</li>
<li>писать в <a class="reference external" href="http://www.vim.org">Vim</a> :)</li>
<li>хоститься где угодно и хранить информацию у себя локально</li>
</ul>
</div>
<div class="section" id="id2">
<h2>Установка</h2>
<div class="literal-block-wrapper docutils container" id="id10">
<div class="code-block-caption"><span class="caption-text">Стабильная версия с PyPi</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ pip install ablog
</pre></div>
</div>
</div>
<div class="literal-block-wrapper docutils container" id="id11">
<div class="code-block-caption"><span class="caption-text">Свежая версия из мастера</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ pip install git+https://github.com/abakan/ablog
</pre></div>
</div>
</div>
</div>
<div class="section" id="id3">
<h2>Инициализация нового проекта</h2>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last"><a class="reference external" href="http://ablog.readthedocs.org/manual/ablog-quick-start/">http://ablog.readthedocs.org/manual/ablog-quick-start/</a></p>
</div>
<p>Можно добавить настройки в <code class="docutils literal"><span class="pre">conf.py</span></code> уже существующего проекта:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1"># 1. Add 'ablog' to list of extensions</span>
<span class="n">extensions</span> <span class="o">=</span> <span class="p">[</span>
<span class="s1">'...'</span><span class="p">,</span>
<span class="s1">'ablog'</span>
<span class="p">]</span>
<span class="c1"># 2. Add ablog templates path</span>
<span class="kn">import</span> <span class="nn">ablog</span>
<span class="c1"># 2a. if `templates_path` is not defined</span>
<span class="n">templates_path</span> <span class="o">=</span> <span class="p">[</span><span class="n">ablog</span><span class="o">.</span><span class="n">get_html_templates_path</span><span class="p">()]</span>
<span class="c1"># 2b. if `templates_path` is defined</span>
<span class="n">templates_path</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ablog</span><span class="o">.</span><span class="n">get_html_templates_path</span><span class="p">())</span>
</pre></div>
</div>
<p>Или создать новый проект:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ ablog start
</pre></div>
</div>
</div>
<div class="section" id="id4">
<h2>Сборка и запуск</h2>
<p>Что бы собрать блог нужно выполнить:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ ablog build
</pre></div>
</div>
<p>HTML страницы создаются в папке <code class="docutils literal"><span class="pre">_website</span></code></p>
<p>Что запустить блог достаточно выполнить:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ ablog serve
</pre></div>
</div>
<p>теперь он доступен по адресу <a class="reference external" href="http://127:0.0.1:8000/">http://127:0.0.1:8000/</a></p>
</div>
<div class="section" id="id5">
<h2>Статьи</h2>
<p>Главная страница блога это <code class="docutils literal"><span class="pre">index.rst</span></code>. У меня она выглядит так:</p>
<div class="literal-block-wrapper docutils container" id="id12">
<div class="code-block-caption"><span class="caption-text">index.rst</span></div>
<div class="highlight-rst"><div class="highlight"><pre><span></span><span class="p">..</span> <span class="ow">postlist</span><span class="p">::</span> 100500
<span class="nc">:excerpts:</span>
<span class="nc">:date:</span> <span class="nf">%d-%m-%Y</span>
<span class="nc">:format:</span> <span class="nf">{date} | {title}</span>
</pre></div>
</div>
</div>
<p>Статьи могут находится в любом месте проекта, <a class="reference external" href="https://github.com/abakan/ablog">Ablog</a> их находит
автоматически. Я отвожу для этого отдельную папку:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>articles/
├── <span class="m">2011</span>
│ ├── breadcrumbs.rst
│ ├── capslock.rst
│ ├── content_assigment.rst
│ ├── couchdb.rst
│ ├── demo.rst
│ ├── fa_keyerror.rst
│ ├── fa_rest_controller.rst
│ ├── formalchemy.rst
│ ├── java_iceweasel.rst
│ ├── js_rrd.rst
│ ├── peyote.rst
│ ├── psycopg2.rst
│ ├── pylons_backslash.rst
│ ├── pylons_jscss_minificator.rst
│ ├── repoze.what.rst
│ ├── rrd_cut2.rst
│ ├── rrd_cut.rst
│ ├── rrdtool_ds18b20.rst
│ ├── snmp.rst
│ ├── sqlalchemy_mixin.rst
│ ├── sqlalchemy_trigger.rst
│ ├── sqlalchemy_uml.rst
│ ├── sqlalchemy_why_postgres.rst
│ ├── thinkpad_trackpoint.rst
│ ├── wtforms.rst
│ ├── wtform_validation.rst
│ ├── xfce_button.rst
│ └── xfce_display.rst
├── <span class="m">2012</span>
│ ├── 3com.rst
│ ├── ajax_triple_select.rst
│ ├── arch_book.rst
│ ├── boyan.rst
│ ├── cms_pyramid2.rst
│ ├── cms_pyramid.rst
│ ├── debian_bc.rst
│ ├── fortune.rst
│ ├── http_header_pyramid.rst
│ ├── jinja_pylons_i18n.rst
│ ├── jinja_pyramid_i18n.rst
│ ├── jinja_silent_none.rst
│ ├── lisp_book.rst
│ ├── lisp.rst
│ ├── matplotlib_numpy_and_virtualenv.rst
│ ├── osm_example.rst
│ ├── osm_geotagging.rst
│ ├── paramiko.rst
│ ├── penguin_troll.rst
│ ├── penguin_vs_leo.rst
│ ├── pg_book.rst
│ ├── proxmox.rst
│ ├── proxy_apt.rst
│ ├── pycrypto_virtualenv.rst
│ ├── pylons_console.rst
│ ├── pylons_csv.rst
│ ├── pylons_yapsy.rst
│ ├── pypi.rst
│ ├── pyramid_as_django.rst
│ ├── pyramid_blog.rst
│ ├── pyramid_formalchemy.rst
│ ├── python_labirint.rst
│ ├── python_snmp.rst
│ ├── pyyandexmap.rst
│ ├── qtile.rst
│ ├── redactor-js.rst
│ ├── rrd_faketime.rst
│ ├── rrdtool.rst
│ ├── sa_big_table.rst
│ ├── shared_net.rst
│ ├── sphinx_github.rst
│ ├── sran.rst
│ ├── vi_book.rst
│ └── x220t_buttons.rst
├── <span class="m">2013</span>
│ ├── car_differ.rst
│ ├── dbsession_includeme.rst
│ ├── flag_jinja2.rst
│ ├── hdaps_music.rst
│ ├── hstore_plpython.rst
│ ├── jinja2_lorem_ipsum.rst
│ ├── linux_attack.rst
│ ├── matrix.rst
│ ├── penguin.rst
│ ├── python_vim.rst
│ ├── reason_names_of.rst
│ ├── sacrud_alfa_0_1_0.rst
│ ├── sacrud_demo.rst
│ ├── sacrud_howto.rst
│ ├── sacrud_release_0_0_3.rst
│ ├── sacrud_release_0_1_0.rst
│ ├── sacrud.rst
│ ├── vi_book.rst
│ ├── vim_book.rst
│ ├── wat.rst
│ └── where_to_start.rst
├── <span class="m">2014</span>
│ ├── alembic_pyramid.rst
│ ├── chameleon_deform.rst
│ ├── ci.rst
│ ├── cornice.rst
│ ├── django-hyango.rst
│ ├── go.rst
│ ├── ia32-libs-multiarch:i386.rst
│ ├── king_penguin.rst
│ ├── man_month_book.rst
│ ├── panel_pyramid_dt.rst
│ ├── sacrud_release_0.1.1.rst
│ ├── sacrud_release_0.1.2.rst
│ ├── scrum.rst
│ ├── sphinx.rst
│ ├── sqlalchemy_mptt_0_0_5.rst
│ ├── sqlalchemy_mptt.rst
│ └── sqlite_to_pg.rst
└── <span class="m">2015</span>
└── ablog.rst
<span class="m">5</span> directories, <span class="m">111</span> files
</pre></div>
</div>
<p>Что бы файл <code class="docutils literal"><span class="pre">*.rst</span></code> стал статьей в нем должна находится директива <code class="docutils literal"><span class="pre">post</span></code>.
Например:</p>
<div class="literal-block-wrapper docutils container" id="id13">
<div class="code-block-caption"><span class="caption-text">foo.rst</span></div>
<div class="highlight-rst"><div class="highlight"><pre><span></span><span class="p">..</span> <span class="ow">post</span><span class="p">::</span> 15 Apr, 2013
<span class="nc">:tags:</span> <span class="nf">tips, ablog, directive</span>
<span class="nc">:category:</span> <span class="nf">Example, How To</span>
<span class="nc">:author:</span> <span class="nf">Ahmet, Durden</span>
<span class="nc">:location:</span> <span class="nf">Pittsburgh, SF</span>
<span class="nc">:redirect:</span> <span class="nf">blog/old-page-name-for-the-post</span>
<span class="nc">:excerpt:</span> <span class="nf">2</span>
<span class="nc">:image:</span> <span class="nf">1</span>
</pre></div>
</div>
</div>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last"><a class="reference external" href="http://ablog.readthedocs.org/manual/posting-and-listing/#directive-post">http://ablog.readthedocs.org/manual/posting-and-listing/#directive-post</a></p>
</div>
<p>Пример кода этой статьи:</p>
<div class="literal-block-wrapper docutils container" id="id14">
<div class="code-block-caption"><span class="caption-text">articles/2015/ablog.rst</span></div>
<div class="highlight-rst"><div class="highlight"><pre><span></span><span class="p">..</span> <span class="ow">post</span><span class="p">::</span> 12 Aug, 2015 12:06
<span class="nc">:tags:</span> <span class="nf">Python, reStructuredText, Sphinx</span>
<span class="nc">:category:</span> <span class="nf">Python</span>
<span class="nc">:author:</span> <span class="nf">Uralbash</span>
<span class="nc">:language:</span> <span class="nf">ru</span>
<span class="p">..</span> <span class="nt">_ablog:</span>
<span class="gh">Блог в reStructuredText разметке</span>
<span class="gh">================================</span>
<span class="p">..</span> <span class="ow">image</span><span class="p">::</span> /_static/2015/uralbash.ru.png
<span class="nc">:align:</span> <span class="nf">left</span>
<span class="nc">:width:</span> <span class="nf">500px</span>
Перевел тут блог с https://www.blogger.com/ на <span class="na">:github:</span><span class="nv">`abakan/ablog`</span>. Блоггер
это конечно хорошо, но у него крайне ограниченный WYSIWYG, тем более только из
браузера. <span class="na">:l:</span><span class="nv">`Ablog`</span> по сути это <span class="na">:pypi:</span><span class="nv">`sphinx`</span> движок заточенный на блог со
всеми плюшками, rST разметкой, RSS и disqus комментами.
<span class="p">..</span> <span class="ow">raw</span><span class="p">::</span> html
<br clear="both"/>
<test/>
<span class="gh">Профит</span>
<span class="gh">------</span>
<span class="m">*</span> <span class="na">:pypi:</span><span class="nv">`Sphinx`</span> позволяет автоматизировать многие вещи
<span class="m">*</span> <span class="s">``reStructuredText``</span> позволяет точно и красиво оформлять статьи, это как
писать "курсач" в LaTeX заместо MS Office
<span class="m">*</span> писать в <span class="na">:l:</span><span class="nv">`Vim`</span> :)
<span class="m">*</span> хоститься где угодно и хранить информацию у себя локально
<span class="gh">Установка</span>
<span class="gh">---------</span>
<span class="p">..</span> <span class="ow">code-block</span><span class="p">::</span> bash
<span class="nc">:caption:</span> <span class="nf">Стабильная версия с PyPi</span>
$ pip install ablog
<span class="p">..</span> <span class="ow">code-block</span><span class="p">::</span> bash
<span class="nc">:caption:</span> <span class="nf">Свежая версия из мастера</span>
$ pip install git+https://github.com/abakan/ablog
<span class="gh">Инициализация нового проекта</span>
<span class="gh">----------------------------</span>
<span class="p">..</span> <span class="ow">seealso</span><span class="p">::</span>
http://ablog.readthedocs.org/manual/ablog-quick-start/
Можно добавить настройки в <span class="s">``conf.py``</span> уже существующего проекта:
<span class="p">..</span> <span class="ow">code-block</span><span class="p">::</span> <span class="k">python</span>
<span class="c1"># 1. Add 'ablog' to list of extensions</span>
<span class="n">extensions</span> <span class="o">=</span> <span class="p">[</span>
<span class="s1">'...'</span><span class="p">,</span>
<span class="s1">'ablog'</span>
<span class="p">]</span>
<span class="c1"># 2. Add ablog templates path</span>
<span class="kn">import</span> <span class="nn">ablog</span>
<span class="c1"># 2a. if `templates_path` is not defined</span>
<span class="n">templates_path</span> <span class="o">=</span> <span class="p">[</span><span class="n">ablog</span><span class="o">.</span><span class="n">get_html_templates_path</span><span class="p">()]</span>
<span class="c1"># 2b. if `templates_path` is defined</span>
<span class="n">templates_path</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ablog</span><span class="o">.</span><span class="n">get_html_templates_path</span><span class="p">())</span>
Или создать новый проект:
<span class="p">..</span> <span class="ow">code-block</span><span class="p">::</span> <span class="k">bash</span>
$ ablog start
<span class="gh">Сборка и запуск</span>
<span class="gh">---------------</span>
Что бы собрать блог нужно выполнить:
<span class="p">..</span> <span class="ow">code-block</span><span class="p">::</span> <span class="k">bash</span>
$ ablog build
HTML страницы создаются в папке <span class="s">``_website``</span>
Что запустить блог достаточно выполнить:
<span class="p">..</span> <span class="ow">code-block</span><span class="p">::</span> <span class="k">bash</span>
$ ablog serve
теперь он доступен по адресу http://127:0.0.1:8000/
<span class="gh">Статьи</span>
<span class="gh">------</span>
Главная страница блога это <span class="s">``index.rst``</span>. У меня она выглядит так:
<span class="p">..</span> <span class="ow">code-block</span><span class="p">::</span> rst
<span class="nc">:caption:</span> <span class="nf">index.rst</span>
<span class="p"> ..</span> <span class="ow">postlist</span><span class="p">::</span> 100500
<span class="nc">:excerpts:</span>
<span class="nc">:date:</span> <span class="nf">%d-%m-%Y</span>
<span class="nc">:format:</span> <span class="nf">{date} | {title}</span>
Статьи могут находится в любом месте проекта, <span class="na">:l:</span><span class="nv">`Ablog`</span> их находит
автоматически. Я отвожу для этого отдельную папку:
<span class="p">..</span> <span class="ow">code-block</span><span class="p">::</span> <span class="k">bash</span>
articles/
├── <span class="m">2011</span>
│ ├── breadcrumbs.rst
│ ├── capslock.rst
│ ├── content_assigment.rst
│ ├── couchdb.rst
│ ├── demo.rst
│ ├── fa_keyerror.rst
│ ├── fa_rest_controller.rst
│ ├── formalchemy.rst
│ ├── java_iceweasel.rst
│ ├── js_rrd.rst
│ ├── peyote.rst
│ ├── psycopg2.rst
│ ├── pylons_backslash.rst
│ ├── pylons_jscss_minificator.rst
│ ├── repoze.what.rst
│ ├── rrd_cut2.rst
│ ├── rrd_cut.rst
│ ├── rrdtool_ds18b20.rst
│ ├── snmp.rst
│ ├── sqlalchemy_mixin.rst
│ ├── sqlalchemy_trigger.rst
│ ├── sqlalchemy_uml.rst
│ ├── sqlalchemy_why_postgres.rst
│ ├── thinkpad_trackpoint.rst
│ ├── wtforms.rst
│ ├── wtform_validation.rst
│ ├── xfce_button.rst
│ └── xfce_display.rst
├── <span class="m">2012</span>
│ ├── 3com.rst
│ ├── ajax_triple_select.rst
│ ├── arch_book.rst
│ ├── boyan.rst
│ ├── cms_pyramid2.rst
│ ├── cms_pyramid.rst
│ ├── debian_bc.rst
│ ├── fortune.rst
│ ├── http_header_pyramid.rst
│ ├── jinja_pylons_i18n.rst
│ ├── jinja_pyramid_i18n.rst
│ ├── jinja_silent_none.rst
│ ├── lisp_book.rst
│ ├── lisp.rst
│ ├── matplotlib_numpy_and_virtualenv.rst
│ ├── osm_example.rst
│ ├── osm_geotagging.rst
│ ├── paramiko.rst
│ ├── penguin_troll.rst
│ ├── penguin_vs_leo.rst
│ ├── pg_book.rst
│ ├── proxmox.rst
│ ├── proxy_apt.rst
│ ├── pycrypto_virtualenv.rst
│ ├── pylons_console.rst
│ ├── pylons_csv.rst
│ ├── pylons_yapsy.rst
│ ├── pypi.rst
│ ├── pyramid_as_django.rst
│ ├── pyramid_blog.rst
│ ├── pyramid_formalchemy.rst
│ ├── python_labirint.rst
│ ├── python_snmp.rst
│ ├── pyyandexmap.rst
│ ├── qtile.rst
│ ├── redactor-js.rst
│ ├── rrd_faketime.rst
│ ├── rrdtool.rst
│ ├── sa_big_table.rst
│ ├── shared_net.rst
│ ├── sphinx_github.rst
│ ├── sran.rst
│ ├── vi_book.rst
│ └── x220t_buttons.rst
├── <span class="m">2013</span>
│ ├── car_differ.rst
│ ├── dbsession_includeme.rst
│ ├── flag_jinja2.rst
│ ├── hdaps_music.rst
│ ├── hstore_plpython.rst
│ ├── jinja2_lorem_ipsum.rst
│ ├── linux_attack.rst
│ ├── matrix.rst
│ ├── penguin.rst
│ ├── python_vim.rst
│ ├── reason_names_of.rst
│ ├── sacrud_alfa_0_1_0.rst
│ ├── sacrud_demo.rst
│ ├── sacrud_howto.rst
│ ├── sacrud_release_0_0_3.rst
│ ├── sacrud_release_0_1_0.rst
│ ├── sacrud.rst
│ ├── vi_book.rst
│ ├── vim_book.rst
│ ├── wat.rst
│ └── where_to_start.rst
├── <span class="m">2014</span>
│ ├── alembic_pyramid.rst
│ ├── chameleon_deform.rst
│ ├── ci.rst
│ ├── cornice.rst
│ ├── django-hyango.rst
│ ├── go.rst
│ ├── ia32-libs-multiarch:i386.rst
│ ├── king_penguin.rst
│ ├── man_month_book.rst
│ ├── panel_pyramid_dt.rst
│ ├── sacrud_release_0.1.1.rst
│ ├── sacrud_release_0.1.2.rst
│ ├── scrum.rst
│ ├── sphinx.rst
│ ├── sqlalchemy_mptt_0_0_5.rst
│ ├── sqlalchemy_mptt.rst
│ └── sqlite_to_pg.rst
└── <span class="m">2015</span>
└── ablog.rst
<span class="m">5</span> directories, <span class="m">111</span> files
Что бы файл <span class="s">``*.rst``</span> стал статьей в нем должна находится директива <span class="s">``post``</span>.
Например:
<span class="p">..</span> <span class="ow">code-block</span><span class="p">::</span> rst
<span class="nc">:caption:</span> <span class="nf">foo.rst</span>
<span class="p"> ..</span> <span class="ow">post</span><span class="p">::</span> 15 Apr, 2013
<span class="nc">:tags:</span> <span class="nf">tips, ablog, directive</span>
<span class="nc">:category:</span> <span class="nf">Example, How To</span>
<span class="nc">:author:</span> <span class="nf">Ahmet, Durden</span>
<span class="nc">:location:</span> <span class="nf">Pittsburgh, SF</span>
<span class="nc">:redirect:</span> <span class="nf">blog/old-page-name-for-the-post</span>
<span class="nc">:excerpt:</span> <span class="nf">2</span>
<span class="nc">:image:</span> <span class="nf">1</span>
<span class="p">..</span> <span class="ow">seealso</span><span class="p">::</span>
http://ablog.readthedocs.org/manual/posting-and-listing/#directive-post
Пример кода этой статьи:
<span class="p">..</span> <span class="ow">literalinclude</span><span class="p">::</span> /articles/2015/ablog.rst
<span class="nc">:language:</span> <span class="nf">rst</span>
<span class="nc">:caption:</span> <span class="nf">articles/2015/ablog.rst</span>
<span class="gh">Тема</span>
<span class="gh">----</span>
Тема по умолчанию <span class="s">`Alabaster </span><span class="si"><https://github.com/bitprophet/alabaster></span><span class="s">`_</span>, но
можно поменять стандартными способами в <span class="s">``conf.py``</span>:
<span class="p">..</span> <span class="ow">no-code-block</span><span class="p">::</span> python
<span class="nc">:caption:</span> <span class="nf">conf.py установка темы</span>
import itcase_sphinx_theme
<span class="cp"> ...</span>
<span class="cp"> # -- Options for HTML output ----------------------------------------------</span>
<span class="cp"> # The theme to use for HTML and HTML Help pages. See the documentation for</span>
<span class="cp"> # a list of builtin themes.</span>
<span class="cp"> html_theme = 'itcase'</span>
<span class="cp"> # Theme options are theme-specific and customize the look and feel of a theme</span>
<span class="cp"> # further. For a list of options available for each theme, see the</span>
<span class="cp"> # documentation.</span>
<span class="cp"> html_theme_options = {</span>
<span class="cp"> 'github_button': False,</span>
<span class="cp"> }</span>
<span class="cp"> # Add any paths that contain custom themes here, relative to this directory.</span>
<span class="cp"> html_theme_path = [itcase_sphinx_theme.get_html_themes_path()]</span>
<span class="cp"> # The name for this set of Sphinx documents. If None, it defaults to</span>
<span class="cp"> # "<project> v<release> documentation".</span>
<span class="cp"> html_title = "Ural penguins"</span>
Я использую <span class="na">:github:</span><span class="nv">`ITCase/itcase_sphinx_theme`</span> с переопределенными шаблонами.
Для этого нужно указать где искать шаблоны и в каком порядке:
<span class="p">..</span> <span class="ow">code-block</span><span class="p">::</span> python
<span class="nc">:caption:</span> <span class="nf">conf.py указание пути по шаблонов темы</span>
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates', ablog.get_html_templates_path()]
Добавляем в папку <span class="s">``_templates``</span> нашего проекта шаблон <span class="s">``layout.html``</span>:
<span class="p">..</span> <span class="ow">literalinclude</span><span class="p">::</span> /_templates/layout.html
<span class="nc">:language:</span> <span class="nf">html+jinja</span>
<span class="nc">:caption:</span> <span class="nf">_templates/layout.html</span>
<span class="gh">Комменты</span>
<span class="gh">--------</span>
<span class="p">..</span> <span class="ow">seealso</span><span class="p">::</span>
http://ablog.readthedocs.org/manual/ablog-configuration-options/#disqus-integration
DISQUS ставится просто:
<span class="p">..</span> <span class="ow">code-block</span><span class="p">::</span> python
<span class="nc">:caption:</span> <span class="nf">настройки DISQUS</span>
# -- disqus integration -------------------------------------------------------
# you can enable disqus_ by setting <span class="s">``disqus_shortname``</span> variable.
# disqus_ short name for the blog.
disqus_shortname = "uralbash"
Правда у меня завелось только после переопределения шаблона <span class="s">``page.html``</span>:
<span class="p">..</span> <span class="ow">literalinclude</span><span class="p">::</span> /_templates/page.html
<span class="nc">:language:</span> <span class="nf">html+jinja</span>
<span class="nc">:caption:</span> <span class="nf">_templates/page.html</span>
<span class="nc">:emphasize-lines:</span> <span class="nf">37</span>
<span class="gh">Деплой</span>
<span class="gh">------</span>
<span class="p">..</span> <span class="ow">note</span><span class="p">::</span>
http://ablog.readthedocs.org/manual/deploy-to-github-pages/
<span class="m">#.</span> Создать репу с именем <span class="s">``<username>.github.io``</span>
<span class="m">#.</span> Добавить имя в настройки, например:
<span class="p"> ..</span> <span class="ow">code-block</span><span class="p">::</span> python
<span class="nc">:caption:</span> <span class="nf">conf.py настройки github pages</span>
github_pages = "uralbash"
<span class="m">#.</span> Сбилдить проект:
<span class="p"> ..</span> <span class="ow">code-block</span><span class="p">::</span> bash
$ ablog build
<span class="m">#.</span> Выложить на гитхаб:
<span class="p"> ..</span> <span class="ow">code-block</span><span class="p">::</span> bash
$ ablog deploy
<span class="gh">Итог</span>
<span class="gh">----</span>
На мой взгляд лучшее решения для <span class="s">``reStructuredText``</span> блога, местами сырой, но
активно развивается.
</pre></div>
</div>
</div>
</div>
<div class="section" id="id6">
<h2>Тема</h2>
<p>Тема по умолчанию <a class="reference external" href="https://github.com/bitprophet/alabaster">Alabaster</a>, но
можно поменять стандартными способами в <code class="docutils literal"><span class="pre">conf.py</span></code>:</p>
<div class="literal-block-wrapper docutils container" id="id15">
<div class="code-block-caption"><span class="caption-text">conf.py установка темы</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">itcase_sphinx_theme</span>
<span class="o">...</span>
<span class="c1"># -- Options for HTML output ----------------------------------------------</span>
<span class="c1"># The theme to use for HTML and HTML Help pages. See the documentation for</span>
<span class="c1"># a list of builtin themes.</span>
<span class="n">html_theme</span> <span class="o">=</span> <span class="s1">'itcase'</span>
<span class="c1"># Theme options are theme-specific and customize the look and feel of a theme</span>
<span class="c1"># further. For a list of options available for each theme, see the</span>
<span class="c1"># documentation.</span>
<span class="n">html_theme_options</span> <span class="o">=</span> <span class="p">{</span>
<span class="s1">'github_button'</span><span class="p">:</span> <span class="bp">False</span><span class="p">,</span>
<span class="p">}</span>
<span class="c1"># Add any paths that contain custom themes here, relative to this directory.</span>
<span class="n">html_theme_path</span> <span class="o">=</span> <span class="p">[</span><span class="n">itcase_sphinx_theme</span><span class="o">.</span><span class="n">get_html_themes_path</span><span class="p">()]</span>
<span class="c1"># The name for this set of Sphinx documents. If None, it defaults to</span>
<span class="c1"># "<project> v<release> documentation".</span>
<span class="n">html_title</span> <span class="o">=</span> <span class="s2">"Ural penguins"</span>
</pre></div>
</div>
</div>
<p>Я использую <a class="reference external" href="https://github.com/ITCase/itcase_sphinx_theme">ITCase/itcase_sphinx_theme</a> с переопределенными шаблонами.
Для этого нужно указать где искать шаблоны и в каком порядке:</p>
<div class="literal-block-wrapper docutils container" id="id16">
<div class="code-block-caption"><span class="caption-text">conf.py указание пути по шаблонов темы</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1"># Add any paths that contain templates here, relative to this directory.</span>
<span class="n">templates_path</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'_templates'</span><span class="p">,</span> <span class="n">ablog</span><span class="o">.</span><span class="n">get_html_templates_path</span><span class="p">()]</span>
</pre></div>
</div>
</div>
<p>Добавляем в папку <code class="docutils literal"><span class="pre">_templates</span></code> нашего проекта шаблон <code class="docutils literal"><span class="pre">layout.html</span></code>:</p>
<div class="literal-block-wrapper docutils container" id="id17">
<div class="code-block-caption"><span class="caption-text">_templates/layout.html</span></div>
<div class="highlight-html+jinja"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">"base.html"</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">breadcrumbs</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"head"</span> <span class="na">style</span><span class="o">=</span><span class="s">"background-image: url('/_static/bg.jpg');</span>
<span class="s"> background-size: 100%;</span>
<span class="s"> background-repeat: no-repeat;</span>
<span class="s"> height: 200px"</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"/"</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">style</span><span class="o">=</span><span class="s">"width:100%; height: 75%"</span><span class="p">></span>
<span class="p"><</span><span class="nt">h1</span> <span class="na">style</span><span class="o">=</span><span class="s">"padding-top:15px;padding-left:15px;font-size:60px"</span><span class="p">></span>Ural penguins<span class="p"></</span><span class="nt">h1</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"></</span><span class="nt">a</span><span class="p">></span>
<span class="p"><</span><span class="nt">table</span> <span class="na">style</span><span class="o">=</span><span class="s">"</span>
<span class="s"> border-collapse: unset !important;</span>
<span class="s"> border-spacing: 1 !important;"</span><span class="p">></span>
<span class="p"><</span><span class="nt">tr</span><span class="p">></span>
<span class="p"><</span><span class="nt">td</span> <span class="na">style</span><span class="o">=</span><span class="s">"padding-right: 2px"</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"/pages/pyramid/index.html"</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">style</span><span class="o">=</span><span class="s">"background: white;width:100px;height:50px;line-height:50px;text-align:center;"</span>
<span class="na">onmouseover</span><span class="o">=</span><span class="s">"this.style.background='lightgrey';"</span> <span class="na">onmouseout</span><span class="o">=</span><span class="s">"this.style.background='white';"</span><span class="p">></span>
Pyramid
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"></</span><span class="nt">a</span><span class="p">></span>
<span class="p"></</span><span class="nt">td</span><span class="p">></span>
<span class="p"><</span><span class="nt">td</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"/pages/nixos/index.html"</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">style</span><span class="o">=</span><span class="s">"background: white;width:100px;height:50px;line-height:50px;text-align:center;"</span>
<span class="na">onmouseover</span><span class="o">=</span><span class="s">"this.style.background='lightgrey';"</span> <span class="na">onmouseout</span><span class="o">=</span><span class="s">"this.style.background='white';"</span><span class="p">></span>
NixOS
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"></</span><span class="nt">a</span><span class="p">></span>
<span class="p"></</span><span class="nt">td</span><span class="p">></span>
<span class="p"></</span><span class="nt">tr</span><span class="p">></span>
<span class="p"></</span><span class="nt">table</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">async</span> <span class="na">src</span><span class="o">=</span><span class="s">"//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"badge"</span> <span class="na">style</span><span class="o">=</span><span class="s">"width:100%;height:80px"</span><span class="p">></span>
<span class="c"><!-- uralbash.ru --></span>
<span class="p"><</span><span class="nt">ins</span> <span class="na">class</span><span class="o">=</span><span class="s">"adsbygoogle"</span>
<span class="na">style</span><span class="o">=</span><span class="s">"display:block"</span>
<span class="na">data-ad-client</span><span class="o">=</span><span class="s">"ca-pub-2884502571619359"</span>
<span class="na">data-ad-slot</span><span class="o">=</span><span class="s">"9876011339"</span>
<span class="na">data-ad-format</span><span class="o">=</span><span class="s">"auto"</span><span class="p">></</span><span class="nt">ins</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span><span class="p">></span>
<span class="p">(</span><span class="nx">adsbygoogle</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">adsbygoogle</span> <span class="o">||</span> <span class="p">[]).</span><span class="nx">push</span><span class="p">({});</span>
<span class="p"></</span><span class="nt">script</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">extrahead</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">style</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/css"</span><span class="p">></span>
<span class="nt">html</span><span class="o">,</span> <span class="nt">body</span> <span class="p">{</span>
<span class="k">background</span><span class="p">:</span> <span class="mh">#545d5c</span> <span class="cp">!important</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">.</span><span class="nc">page__left</span> <span class="p">.</span><span class="nc">menu</span> <span class="p">{</span>
<span class="k">width</span><span class="p">:</span> <span class="mi">0</span><span class="kt">px</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">.</span><span class="nc">page__right</span> <span class="p">{</span>
<span class="k">background-color</span><span class="p">:</span> <span class="mh">#e7e7e7</span><span class="p">;</span>
<span class="k">margin</span><span class="p">:</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">30</span><span class="kt">px</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">.</span><span class="nc">rst-content</span> <span class="p">{</span>
<span class="k">padding</span><span class="p">:</span> <span class="mi">13</span><span class="kt">px</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">.</span><span class="nc">footer</span> <span class="p">{</span>
<span class="k">padding</span><span class="p">:</span> <span class="mi">13</span><span class="kt">px</span><span class="p">;</span>
<span class="p">}</span>
<span class="c">/* unvisited link */</span>
<span class="nt">ul</span><span class="p">.</span><span class="nc">postlist-style-none</span> <span class="nt">a</span><span class="p">:</span><span class="nd">link</span><span class="o">,</span> <span class="p">.</span><span class="nc">head</span> <span class="nt">a</span><span class="p">:</span><span class="nd">link</span> <span class="p">{</span>
<span class="k">color</span><span class="p">:</span> <span class="mh">#222</span><span class="p">;</span>
<span class="k">text-decoration</span><span class="p">:</span> <span class="kc">none</span><span class="p">;</span>
<span class="p">}</span>
<span class="c">/* visited link */</span>
<span class="nt">ul</span><span class="p">.</span><span class="nc">postlist-style-none</span> <span class="nt">a</span><span class="p">:</span><span class="nd">visited</span><span class="o">,</span> <span class="p">.</span><span class="nc">head</span> <span class="nt">a</span><span class="p">:</span><span class="nd">visited</span> <span class="p">{</span>
<span class="k">color</span><span class="p">:</span> <span class="mh">#222</span><span class="p">;</span>
<span class="k">text-decoration</span><span class="p">:</span> <span class="kc">none</span><span class="p">;</span>
<span class="p">}</span>
<span class="c">/* mouse over link */</span>
<span class="nt">ul</span><span class="p">.</span><span class="nc">postlist-style-none</span> <span class="nt">a</span><span class="p">:</span><span class="nd">hover</span><span class="o">,</span> <span class="p">.</span><span class="nc">head</span> <span class="nt">a</span><span class="p">:</span><span class="nd">hover</span> <span class="p">{</span>
<span class="k">color</span><span class="p">:</span> <span class="mh">#222</span><span class="p">;</span>
<span class="k">text-decoration</span><span class="p">:</span> <span class="kc">none</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">ul</span><span class="p">.</span><span class="nc">postlist-style-none</span> <span class="nt">a</span><span class="p">:</span><span class="nd">active</span><span class="o">,</span> <span class="p">.</span><span class="nc">head</span> <span class="nt">a</span><span class="p">:</span><span class="nd">active</span> <span class="p">{</span>
<span class="k">color</span><span class="p">:</span> <span class="mh">#222</span><span class="p">;</span>
<span class="k">text-decoration</span><span class="p">:</span> <span class="kc">none</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">ul</span><span class="p">.</span><span class="nc">postlist-style-none</span> <span class="nt">li</span> <span class="p">{</span>
<span class="k">list-style-type</span><span class="p">:</span> <span class="kc">none</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">ul</span><span class="p">.</span><span class="nc">postlist-style-none</span> <span class="nt">li</span> <span class="nt">p</span><span class="p">.</span><span class="nc">first</span> <span class="p">{</span>
<span class="k">color</span><span class="p">:</span> <span class="kc">red</span> <span class="cp">!important</span><span class="p">;</span>
<span class="k">font</span><span class="p">:</span> <span class="mf">1.8</span><span class="kt">em</span> <span class="s2">"Open Sans"</span><span class="p">,</span><span class="n">Arial</span><span class="p">,</span><span class="kc">sans-serif</span> <span class="cp">!important</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">.</span><span class="nc">first</span> <span class="nt">a</span> <span class="p">{</span>
<span class="k">font-weight</span><span class="p">:</span> <span class="kc">bold</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">.</span><span class="nc">first</span> <span class="nt">em</span> <span class="p">{</span>
<span class="k">font-style</span><span class="p">:</span> <span class="kc">normal</span> <span class="cp">!important</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">.</span><span class="nc">wrapper__inner</span> <span class="p">{</span>
<span class="k">padding</span><span class="p">:</span> <span class="mi">0</span><span class="kt">px</span> <span class="mi">30</span><span class="kt">px</span> <span class="mi">0</span> <span class="mi">0</span> <span class="cp">!important</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">.</span><span class="nc">strike</span> <span class="p">{</span>
<span class="k">text-decoration</span><span class="p">:</span> <span class="kc">line-through</span><span class="p">;</span>
<span class="p">}</span>
<span class="p"></</span><span class="nt">style</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">footer</span> <span class="cp">%}</span>
<span class="cp">{{</span> <span class="nb">super</span><span class="o">()</span> <span class="cp">}}</span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"footer__theme"</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"https://github.com/sunpy/ablog"</span> <span class="na">class</span><span class="o">=</span><span class="s">"footer__theme-link"</span><span class="p">></span>
Ablog powered.
<span class="p"></</span><span class="nt">a</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"footer__theme"</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"http://uralbash.ru/blog/atom.xml"</span> <span class="na">class</span><span class="o">=</span><span class="s">"footer__theme-link"</span><span class="p">></span>
RSS/Atom
<span class="p"></</span><span class="nt">a</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"footer__theme"</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"https://uralbash.blogspot.com"</span> <span class="na">class</span><span class="o">=</span><span class="s">"footer__theme-link"</span><span class="p">></span>
Старый блог
<span class="p"></</span><span class="nt">a</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
</pre></div>
</div>
</div>
</div>
<div class="section" id="id7">
<h2>Комменты</h2>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last"><a class="reference external" href="http://ablog.readthedocs.org/manual/ablog-configuration-options/#disqus-integration">http://ablog.readthedocs.org/manual/ablog-configuration-options/#disqus-integration</a></p>
</div>
<p>DISQUS ставится просто:</p>
<div class="literal-block-wrapper docutils container" id="id18">
<div class="code-block-caption"><span class="caption-text">настройки DISQUS</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1"># -- disqus integration -------------------------------------------------------</span>
<span class="c1"># you can enable disqus_ by setting ``disqus_shortname`` variable.</span>
<span class="c1"># disqus_ short name for the blog.</span>
<span class="n">disqus_shortname</span> <span class="o">=</span> <span class="s2">"uralbash"</span>
</pre></div>
</div>
</div>
<p>Правда у меня завелось только после переопределения шаблона <code class="docutils literal"><span class="pre">page.html</span></code>:</p>
<div class="literal-block-wrapper docutils container" id="id19">
<div class="code-block-caption"><span class="caption-text">_templates/page.html</span></div>
<div class="highlight-html+jinja"><div class="highlight"><pre><span></span><span class="cp">{%</span>- <span class="k">extends</span> <span class="s2">"layout.html"</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">set</span> <span class="nv">fa</span> <span class="o">=</span> <span class="nv">ablog.fontawesome</span> <span class="cp">%}</span>
<span class="cp">{%</span>- <span class="k">block</span> <span class="nv">extrahead</span> <span class="cp">%}</span>
<span class="cp">{{</span> <span class="nb">super</span><span class="o">()</span> <span class="cp">}}</span>
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">atom_feed</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">"alternate"</span> <span class="na">type</span><span class="o">=</span><span class="s">"application/atom+xml"</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">pathto</span><span class="o">(</span><span class="nv">feed_path</span><span class="o">,</span> <span class="m">1</span><span class="o">)</span> <span class="cp">}}</span><span class="s">/atom.xml"</span> <span class="na">title</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">ablog.blog_title</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">ablog.fontawesome_link_cdn</span><span class="cp">%}</span>
<span class="p"><</span><span class="nt">link</span> <span class="na">href</span><span class="o">=</span><span class="s">"http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css"</span> <span class="na">rel</span><span class="o">=</span><span class="s">"stylesheet"</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">elif</span> <span class="nv">ablog.fontawesome_css_file</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">"stylesheet"</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">pathto</span><span class="o">(</span><span class="s1">'_static/'</span> <span class="o">+</span> <span class="nv">ablog.fontawesome_css_file</span><span class="o">,</span> <span class="m">1</span><span class="o">)</span> <span class="cp">}}</span><span class="s">"</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/css"</span> <span class="p">/></span>
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">style</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/css"</span><span class="p">></span>
<span class="nt">ul</span><span class="p">.</span><span class="nc">ablog-archive</span> <span class="p">{</span><span class="k">list-style</span><span class="p">:</span> <span class="kc">none</span><span class="p">;</span> <span class="k">overflow</span><span class="p">:</span> <span class="kc">auto</span><span class="p">;</span> <span class="k">margin-left</span><span class="p">:</span> <span class="mi">0</span><span class="kt">px</span><span class="p">}</span>
<span class="nt">ul</span><span class="p">.</span><span class="nc">ablog-archive</span> <span class="nt">li</span> <span class="p">{</span><span class="k">float</span><span class="p">:</span> <span class="kc">left</span><span class="p">;</span> <span class="k">margin-right</span><span class="p">:</span> <span class="mi">5</span><span class="kt">px</span><span class="p">;</span> <span class="k">font-size</span><span class="p">:</span> <span class="mi">80</span><span class="kt">%</span><span class="p">}</span>
<span class="nt">ul</span><span class="p">.</span><span class="nc">post-list-style-disc</span> <span class="p">{</span><span class="k">list-style-type</span><span class="p">:</span> <span class="kc">disc</span><span class="p">;}</span>
<span class="nt">ul</span><span class="p">.</span><span class="nc">post-list-style-none</span> <span class="p">{</span><span class="k">list-style-type</span><span class="p">:</span> <span class="kc">none</span><span class="p">;}</span>
<span class="nt">ul</span><span class="p">.</span><span class="nc">post-list-style-circle</span> <span class="p">{</span><span class="k">list-style-type</span><span class="p">:</span> <span class="kc">circle</span><span class="p">;}</span>
<span class="p"></</span><span class="nt">style</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">body</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/javascript"</span> <span class="na">src</span><span class="o">=</span><span class="s">"//yastatic.net/share/share.js"</span> <span class="na">charset</span><span class="o">=</span><span class="s">"utf-8"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">table</span><span class="p">></span>
<span class="p"><</span><span class="nt">tr</span><span class="p">></span>
<span class="p"><</span><span class="nt">td</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"yashare-auto-init"</span> <span class="na">data-yashareL10n</span><span class="o">=</span><span class="s">"ru"</span>
<span class="na">data-yashareType</span><span class="o">=</span><span class="s">"medium"</span>
<span class="na">data-yashareQuickServices</span><span class="o">=</span><span class="s">"vkontakte,facebook,twitter,odnoklassniki,moimir,gplus"</span>
<span class="na">data-yashareTheme</span><span class="o">=</span><span class="s">"counter"</span><span class="p">></</span><span class="nt">div</span><span class="p">></span>
<span class="p"></</span><span class="nt">td</span><span class="p">></span>
<span class="p"><</span><span class="nt">td</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">include</span> <span class="s2">"my_postcard.html"</span> <span class="cp">%}</span>
<span class="p"></</span><span class="nt">td</span><span class="p">></span>
<span class="p"></</span><span class="nt">tr</span><span class="p">></span>
<span class="p"></</span><span class="nt">table</span><span class="p">></span>
<span class="hll"> <span class="cp">{{</span> <span class="nv">body</span> <span class="cp">}}</span>
</span> <span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"section"</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">pagename</span> <span class="k">in</span> <span class="nv">ablog</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">include</span> <span class="s2">"postnavy.html"</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
<span class="cp">{%</span>- <span class="k">if</span> <span class="k">not</span> <span class="nv">internal_build</span> <span class="k">and</span> <span class="o">(</span><span class="nv">pagename</span> <span class="p">!</span><span class="o">=</span> <span class="s1">'index'</span><span class="o">)</span> <span class="cp">%}</span>
<span class="c">{# {% if ablog.disqus_shortname and ablog.blog_baseurl and ((pagename in ablog and (ablog[pagename].published or ablog.disqus_drafts)) or (not pagename in ablog and ablog.disqus_pages)) %} #}</span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"section"</span><span class="p">></span>
<span class="p"><</span><span class="nt">br</span> <span class="p">/></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/javascript"</span> <span class="na">src</span><span class="o">=</span><span class="s">"//yastatic.net/share/share.js"</span> <span class="na">charset</span><span class="o">=</span><span class="s">"utf-8"</span><span class="p">></</span><span class="nt">script</span><span class="p">><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"yashare-auto-init"</span> <span class="na">data-yashareL10n</span><span class="o">=</span><span class="s">"ru"</span> <span class="na">data-yashareType</span><span class="o">=</span><span class="s">"medium"</span> <span class="na">data-yashareQuickServices</span><span class="o">=</span><span class="s">"vkontakte,facebook,twitter,odnoklassniki,moimir,gplus"</span> <span class="na">data-yashareTheme</span><span class="o">=</span><span class="s">"counter"</span><span class="p">></</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">h2</span><span class="p">></span>Comments<span class="p"></</span><span class="nt">h2</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">"disqus_thread"</span><span class="p">></</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/javascript"</span><span class="p">></span>
<span class="cm">/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */</span>
<span class="kd">var</span> <span class="nx">disqus_shortname</span> <span class="o">=</span> <span class="s1">'</span><span class="cp">{{</span> <span class="nv">ablog.disqus_shortname</span> <span class="cp">}}</span><span class="s1">'</span><span class="p">;</span> <span class="c1">// required: replace example with your forum shortname</span>
<span class="kd">var</span> <span class="nx">disqus_identifier</span> <span class="o">=</span> <span class="s1">'</span><span class="cp">{{</span><span class="nv">ablog.page_id</span><span class="o">(</span><span class="nv">pagename</span><span class="o">)</span><span class="cp">}}</span><span class="s1">'</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">disqus_title</span> <span class="o">=</span> <span class="s1">'</span><span class="cp">{{</span><span class="nv">title</span><span class="o">|</span><span class="nf">e</span><span class="cp">}}</span><span class="s1">'</span><span class="p">;</span>
<span class="c">{# var disqus_url = '{{ablog.page_url(pagename)}}'; #}</span>
<span class="cm">/* * * DON'T EDIT BELOW THIS LINE * * */</span>
<span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">dsq</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s1">'script'</span><span class="p">);</span> <span class="nx">dsq</span><span class="p">.</span><span class="nx">type</span> <span class="o">=</span> <span class="s1">'text/javascript'</span><span class="p">;</span> <span class="nx">dsq</span><span class="p">.</span><span class="nx">async</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
<span class="nx">dsq</span><span class="p">.</span><span class="nx">src</span> <span class="o">=</span> <span class="s1">'//'</span> <span class="o">+</span> <span class="nx">disqus_shortname</span> <span class="o">+</span> <span class="s1">'.disqus.com/embed.js'</span><span class="p">;</span>
<span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByTagName</span><span class="p">(</span><span class="s1">'head'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="o">||</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByTagName</span><span class="p">(</span><span class="s1">'body'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]).</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">dsq</span><span class="p">);</span>
<span class="p">})();</span>
<span class="p"></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">noscript</span><span class="p">></span>Please enable JavaScript to view the <span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"http://disqus.com/?ref_noscript"</span><span class="p">></span>comments powered by Disqus.<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">noscript</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"http://disqus.com"</span> <span class="na">class</span><span class="o">=</span><span class="s">"dsq-brlink"</span><span class="p">></span>comments powered by <span class="p"><</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">"logo-disqus"</span><span class="p">></span>Disqus<span class="p"></</span><span class="nt">span</span><span class="p">></</span><span class="nt">a</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
</pre></div>
</div>
</div>
</div>
<div class="section" id="id8">
<h2>Деплой</h2>
<div class="admonition note">
<p class="first admonition-title">Примечание</p>
<p class="last"><a class="reference external" href="http://ablog.readthedocs.org/manual/deploy-to-github-pages/">http://ablog.readthedocs.org/manual/deploy-to-github-pages/</a></p>
</div>
<ol class="arabic">
<li><p class="first">Создать репу с именем <code class="docutils literal"><span class="pre"><username>.github.io</span></code></p>
</li>
<li><p class="first">Добавить имя в настройки, например:</p>
<div class="literal-block-wrapper docutils container" id="id20">
<div class="code-block-caption"><span class="caption-text">conf.py настройки github pages</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">github_pages</span> <span class="o">=</span> <span class="s2">"uralbash"</span>
</pre></div>
</div>
</div>
</li>
<li><p class="first">Сбилдить проект:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ ablog build
</pre></div>
</div>
</li>
<li><p class="first">Выложить на гитхаб:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ ablog deploy
</pre></div>
</div>
</li>
</ol>
</div>
<div class="section" id="id9">
<h2>Итог</h2>
<p>На мой взгляд лучшее решения для <code class="docutils literal"><span class="pre">reStructuredText</span></code> блога, местами сырой, но
активно развивается.</p>
</div>
</div>
Королевский пингвин - круче только ты один!
http://uralbash.ru/articles/2014/king_penguin/
2014-10-04T00:00:00Z
2014-10-04T00:00:00Z
Uralbash
<div class="section" id="id1">
<img alt="_static/2014/penguin.jpg" class="align-center" src="_static/2014/penguin.jpg" />
</div>
Документация python проекта на практике
http://uralbash.ru/articles/2014/sphinx/
2014-09-22T15:15:00Z
2014-09-22T15:15:00Z
Uralbash
<div class="section" id="python">
<p>Документация в <a class="reference external" href="http://www.python.org/">python</a> проектах пишется при помощи <a class="reference external" href="https://pypi.python.org/pypi/sphinx">sphinx</a>, он умеет
используя расширение <code class="docutils literal"><span class="pre">automodule</span></code> читать докстринги и формировать
документацию из кода.</p>
<p>Создать проект можно ответив на вопросы через <code class="docutils literal"><span class="pre">sphinx-quickstart</span></code> или
использовать уже подготовленный шаблон который генерит дополнительно API
пакета:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sphinx-apidoc -F -o docs sacrud
Creating file docs/sacrud_deform.rst.
Creating file docs/sacrud_deform.tests.rst.
Creating file docs/conf.py.
Creating file docs/index.rst.
Creating file docs/Makefile.
Creating file docs/make.bat.
</pre></div>
</div>
<p>Автогенератор API обычно создает много лишнего и далеко не идеально генерит
названия, поэтому удалим API тестов и попереимеуем все остальное.</p>
<img alt="_static/2014/sphinx.png" class="align-center" src="_static/2014/sphinx.png" />
<p>Для сборки доков нужно в папке docs выполнить make html. Ниже структура
получившихся файлов:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>.
├── _build
│ ├── doctrees
│ │ ├── environment.pickle
│ │ ├── index.doctree
│ │ ├── readme.doctree
│ │ ├── sacrud_deform.doctree
│ │ └── sacrud_deform.tests.doctree
│ └── html
│ ├── genindex.html
│ ├── index.html
│ ├── _modules
│ │ ├── index.html
│ │ ├── sacrud_deform
│ │ │ ├── tests
│ │ │ │ └── test_form.html
│ │ │ └── widgets.html
│ │ └── sacrud_deform.html
│ ├── objects.inv
│ ├── py-modindex.html
│ ├── readme.html
│ ├── sacrud_deform.html
│ ├── sacrud_deform.tests.html
│ ├── search.html
│ ├── searchindex.js
│ ├── _sources
│ │ ├── index.txt
│ │ ├── readme.txt
│ │ ├── sacrud_deform.tests.txt
│ │ └── sacrud_deform.txt
│ └── _static
│ ├── ajax-loader.gif
│ ├── basic.css
│ ├── comment-bright.png
│ ├── comment-close.png
│ ├── comment.png
│ ├── default.css
│ ├── doctools.js
│ ├── down.png
│ ├── down-pressed.png
│ ├── file.png
│ ├── jquery.js
│ ├── minus.png
│ ├── plus.png
│ ├── pygments.css
│ ├── searchtools.js
│ ├── sidebar.js
│ ├── underscore.js
│ ├── up.png
│ ├── up-pressed.png
│ └── websupport.js
├── conf.py
├── index.rst
├── make.bat
├── Makefile
├── readme.rst
├── sacrud_deform.rst
├── _static
└── _templates
</pre></div>
</div>
<p>В директории <code class="docutils literal"><span class="pre">build/html</span></code> находится наша готовая документация в формате html.
Добавим описание проекта на основную страницу. Для этого создаем <code class="docutils literal"><span class="pre">readme.rst</span></code>
в директории <code class="docutils literal"><span class="pre">docs</span></code> и включаем его в <code class="docutils literal"><span class="pre">index.rst</span></code>, а в дальнейшем этот же
<code class="docutils literal"><span class="pre">readme.rst</span></code> будет использоваться в <code class="docutils literal"><span class="pre">README.rst</span></code> в корне проекта для
<a class="reference external" href="https://github.com/">github</a> и <a class="reference external" href="https://pypi.python.org/">PyPi</a>.</p>
<div class="literal-block-wrapper docutils container" id="id1">
<div class="code-block-caption"><span class="caption-text">readme.rst</span></div>
<div class="highlight-rst"><div class="highlight"><pre><span></span>|Build Status| |Coverage Status| |Stories in Progress| |PyPI|
<span class="p">..</span> <span class="nt">|Build Status|</span> <span class="ow">image</span><span class="p">::</span> https://travis-ci.org/ITCase/sacrud_deform.svg?branch=master
<span class="nc">:target:</span> <span class="nf">https://travis-ci.org/ITCase/sacrud_deform</span>
<span class="p">..</span> <span class="nt">|Coverage Status|</span> <span class="ow">image</span><span class="p">::</span> https://coveralls.io/repos/ITCase/sacrud_deform/badge.png?branch=master
<span class="nc">:target:</span> <span class="nf">https://coveralls.io/r/ITCase/sacrud_deform?branch=master</span>
<span class="p">..</span> <span class="nt">|Stories in Progress|</span> <span class="ow">image</span><span class="p">::</span> https://badge.waffle.io/ITCase/sacrud_deform.png?label=in%20progress&title=In%20Progress
<span class="nc">:target:</span> <span class="nf">http://waffle.io/ITCase/sacrud_defrom</span>
<span class="p">..</span> <span class="nt">|PyPI|</span> <span class="ow">image</span><span class="p">::</span> http://img.shields.io/pypi/dm/sacrud_deform.svg
<span class="nc">:target:</span> <span class="nf">https://pypi.python.org/pypi/sacrud_deform/</span>
<span class="gh">sacrud_deform</span>
<span class="gh">==============</span>
Form generotor for SQLAlchemy models.
<span class="gh">Install</span>
<span class="gh">=======</span>
develop version from source
<span class="p">..</span> <span class="ow">code-block</span><span class="p">::</span> <span class="k">bash</span>
pip install git+git://github.com/ITCase/sacrud_deform@develop
from pypi
<span class="p">..</span> <span class="ow">code-block</span><span class="p">::</span> <span class="k">bash</span>
pip install sacrud_deform
<span class="gh">Use</span>
<span class="gh">===</span>
<span class="p">..</span> <span class="ow">code-block</span><span class="p">::</span> <span class="k">python</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">form_generator</span><span class="p">(</span><span class="n">dbsession</span><span class="o">=</span><span class="n">DBSession</span><span class="p">,</span>
<span class="n">obj</span><span class="o">=</span><span class="n">obj_of_model</span><span class="p">,</span> <span class="n">table</span><span class="o">=</span><span class="n">MyModel</span><span class="p">,</span>
<span class="n">columns</span><span class="o">=</span><span class="n">columns_of_model</span><span class="p">)</span>
<span class="n">form</span><span class="p">,</span> <span class="n">js_list</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">render</span><span class="p">()</span>
</pre></div>
</div>
</div>
<p>Здесь вроде все понятно, но есть нюансы, если например в директиве <code class="docutils literal"><span class="pre">..</span>
<span class="pre">code-block</span></code> не указать язык или не дописывать “=” в заголовках то документация
будет нормально генериться, но <a class="reference external" href="https://pypi.python.org/">PyPi</a> её не поймет и выведет что-то типа
этого:</p>
<img alt="_static/2014/sphinx2.png" class="align-center" src="_static/2014/sphinx2.png" />
<p>Нужно быть внимательным и проверять как <a class="reference external" href="https://pypi.python.org/">PyPi</a> подхватил <code class="docutils literal"><span class="pre">README.rst</span></code>.
Дальше в наш <code class="docutils literal"><span class="pre">index.rst</span></code> добавим <code class="docutils literal"><span class="pre">readme.rst</span></code> что бы он был по презентабельнее.</p>
<div class="literal-block-wrapper docutils container" id="id2">
<div class="code-block-caption"><span class="caption-text">index.rst</span></div>
<div class="highlight-rst"><div class="highlight"><pre><span></span><span class="gh">Welcome to sacrud_deform's documentation!</span>
<span class="gh">=========================================</span>
<span class="p">..</span> <span class="ow">include</span><span class="p">::</span> readme.rst
Contents:
<span class="p">..</span> <span class="ow">toctree</span><span class="p">::</span>
<span class="nc">:maxdepth:</span> <span class="nf">4</span>
sacrud_deform
<span class="gh">Indices and tables</span>
<span class="gh">==================</span>
<span class="m">+</span> <span class="na">:ref:</span><span class="nv">`genindex`</span>
<span class="m">+</span> <span class="na">:ref:</span><span class="nv">`modindex`</span>
<span class="m">+</span> <span class="na">:ref:</span><span class="nv">`search`</span>
</pre></div>
</div>
</div>
<p>Теперь главная страница документации выглядит так:</p>
<img alt="_static/2014/sphinx3.png" class="align-center" src="_static/2014/sphinx3.png" />
<p>В принципе уже хорошо, добавим это описание ещё для <a class="reference external" href="https://github.com/">github</a> и <a class="reference external" href="https://pypi.python.org/">PyPi</a>.
Они по умолчанию берут файл <code class="docutils literal"><span class="pre">README.rst</span></code> из корня проекта и ничего про папку
<code class="docutils literal"><span class="pre">docs</span></code> не знают. Можно было бы заинклудить <code class="docutils literal"><span class="pre">readme.rst</span></code> в корневой
<code class="docutils literal"><span class="pre">README.rst</span></code> (<code class="docutils literal"><span class="pre">..include::</span> <span class="pre">docs/readme.rst</span></code>), но <a class="reference external" href="https://github.com/">github</a> и <a class="reference external" href="https://pypi.python.org/">PyPi</a>
инклуды не понимают, поэтому придется писать свой велосипед для копирования.
Либо тупо делать это вручную. Я написал на коленке простой скрипт который это
делает и заменяет директивы <code class="docutils literal"><span class="pre">include</span></code> содержанием их файлов.</p>
<div class="literal-block-wrapper docutils container" id="id3">
<div class="code-block-caption"><span class="caption-text">make_README.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">fileinput</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">from</span> <span class="nn">shutil</span> <span class="kn">import</span> <span class="n">copyfile</span>
<span class="n">src</span> <span class="o">=</span> <span class="s2">"readme.rst"</span>
<span class="n">src_path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</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">realpath</span><span class="p">(</span><span class="n">src</span><span class="p">))</span>
<span class="n">dst</span> <span class="o">=</span> <span class="s2">"../README.rst"</span>
<span class="n">copyfile</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="n">dst</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">read_file</span><span class="p">(</span><span class="n">path</span><span class="p">):</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="s1">'r'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="k">return</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">fileinput</span><span class="o">.</span><span class="n">input</span><span class="p">(</span><span class="n">dst</span><span class="p">,</span> <span class="n">inplace</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span>
<span class="n">splitted</span> <span class="o">=</span> <span class="n">line</span><span class="o">.</span><span class="n">rstrip</span><span class="p">()</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'.. include:: '</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">splitted</span><span class="p">)</span> <span class="o">==</span> <span class="mi">2</span><span class="p">:</span>
<span class="n">line</span> <span class="o">=</span> <span class="n">read_file</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">src_path</span><span class="p">,</span> <span class="n">splitted</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span>
<span class="k">print</span> <span class="n">line</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">print</span> <span class="n">line</span><span class="o">.</span><span class="n">rstrip</span><span class="p">()</span>
</pre></div>
</div>
</div>
<p>Теперь если запустить из папки <code class="docutils literal"><span class="pre">docs</span></code> команду <code class="docutils literal"><span class="pre">python</span> <span class="pre">make_README.py</span></code>, то в
корне проекта появится или перезапишется файл <code class="docutils literal"><span class="pre">README.rst</span></code>.</p>
<p>Что бы это делалось автоматически при каждой сборке документации добавим в
<code class="docutils literal"><span class="pre">Makefile</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>...
readme:
python make_README.py
readme_html: html readme
</pre></div>
</div>
<p>При вызове <code class="docutils literal"><span class="pre">make</span> <span class="pre">readme_html</span></code> у нас будет собираться документация html и
копипаститься <code class="docutils literal"><span class="pre">readme</span></code>.</p>
<p>Конфиг для <code class="docutils literal"><span class="pre">sphinx</span></code> лежит в папке документации с названием <code class="docutils literal"><span class="pre">conf.py</span></code>. В нем
можно настраивать документацию как угодно, к примеру оформим тему как у проекта
<a class="reference external" href="http://pylonsproject.org/">Pyramid</a>.</p>
<p>Добавим в <code class="docutils literal"><span class="pre">conf.py</span></code>:</p>
<div class="literal-block-wrapper docutils container" id="id4">
<div class="code-block-caption"><span class="caption-text">conf.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="c1"># Add and use Pylons theme</span>
<span class="k">if</span> <span class="s1">'sphinx-build'</span> <span class="ow">in</span> <span class="s1">' '</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="c1"># protect against dumb importers</span>
<span class="kn">from</span> <span class="nn">subprocess</span> <span class="kn">import</span> <span class="n">call</span><span class="p">,</span> <span class="n">Popen</span><span class="p">,</span> <span class="n">PIPE</span>
<span class="n">p</span> <span class="o">=</span> <span class="n">Popen</span><span class="p">(</span><span class="s1">'which git'</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">stdout</span><span class="o">=</span><span class="n">PIPE</span><span class="p">)</span>
<span class="n">git</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">read</span><span class="p">()</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
<span class="n">cwd</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">getcwd</span><span class="p">()</span>
<span class="n">_themes</span> <span class="o">=</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">cwd</span><span class="p">,</span> <span class="s1">'_themes'</span><span class="p">)</span>
<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">isdir</span><span class="p">(</span><span class="n">_themes</span><span class="p">):</span>
<span class="n">call</span><span class="p">([</span><span class="n">git</span><span class="p">,</span> <span class="s1">'clone'</span><span class="p">,</span> <span class="s1">'git://github.com/Pylons/pylons_sphinx_theme.git'</span><span class="p">,</span>
<span class="s1">'_themes'</span><span class="p">])</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">os</span><span class="o">.</span><span class="n">chdir</span><span class="p">(</span><span class="n">_themes</span><span class="p">)</span>
<span class="n">call</span><span class="p">([</span><span class="n">git</span><span class="p">,</span> <span class="s1">'checkout'</span><span class="p">,</span> <span class="s1">'master'</span><span class="p">])</span>
<span class="n">call</span><span class="p">([</span><span class="n">git</span><span class="p">,</span> <span class="s1">'pull'</span><span class="p">])</span>
<span class="n">os</span><span class="o">.</span><span class="n">chdir</span><span class="p">(</span><span class="n">cwd</span><span class="p">)</span>
<span class="n">sys</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">append</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">abspath</span><span class="p">(</span><span class="s1">'_themes'</span><span class="p">))</span>
<span class="n">parent</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</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">dirname</span><span class="p">(</span><span class="vm">__file__</span><span class="p">))</span>
<span class="n">sys</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">append</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">abspath</span><span class="p">(</span><span class="n">parent</span><span class="p">))</span>
<span class="n">wd</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">getcwd</span><span class="p">()</span>
<span class="n">os</span><span class="o">.</span><span class="n">chdir</span><span class="p">(</span><span class="n">parent</span><span class="p">)</span>
<span class="n">os</span><span class="o">.</span><span class="n">chdir</span><span class="p">(</span><span class="n">wd</span><span class="p">)</span>
<span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="n">parent</span><span class="p">):</span>
<span class="k">if</span> <span class="n">item</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s1">'.egg'</span><span class="p">):</span>
<span class="n">sys</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">append</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">parent</span><span class="p">,</span> <span class="n">item</span><span class="p">))</span>
</pre></div>
</div>
</div>
<p>Этот код я скопировал из проекта <a class="reference external" href="http://pylonsproject.org/">Pyramid</a>, он просто выкачивает их тему с
<a class="reference external" href="https://github.com/">github</a> в директорию <code class="docutils literal"><span class="pre">_themes</span></code>. Далее укажем в конфиге название темы и где их искать.</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1"># -- Options for HTML output ----------------------------------------------</span>
<span class="c1"># The theme to use for HTML and HTML Help pages. See the documentation for</span>
<span class="c1"># a list of builtin themes.</span>
<span class="n">html_theme</span> <span class="o">=</span> <span class="s1">'pyramid'</span>
<span class="c1"># Add any paths that contain custom themes here, relative to this directory.</span>
<span class="n">html_theme_path</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'_themes'</span><span class="p">]</span>
</pre></div>
</div>
<p>После сборки проект будет выглядеть так:</p>
<img alt="_static/2014/sphinx4.png" class="align-center" src="_static/2014/sphinx4.png" />
<p>Вообщем конфиг умеет много чего, есть еще много разных расширений, можно писать
свои, либо переопределять/добавлять директивы итд. Вот например как вставлять
ссылки на сторонние проекты:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1"># Add any Sphinx extension module names here, as strings. They can be</span>
<span class="c1"># extensions coming with Sphinx (named 'sphinx.ext.*') or your custom</span>
<span class="c1"># ones.</span>
<span class="n">extensions</span> <span class="o">+=</span> <span class="p">[</span>
<span class="s1">'sphinx.ext.intersphinx'</span>
<span class="p">]</span>
<span class="n">intersphinx_mapping</span> <span class="o">=</span> <span class="p">{</span>
<span class="s1">'sacrud'</span><span class="p">:</span> <span class="p">(</span><span class="s1">'http://sacrud.readthedocs.org/en/latest/'</span><span class="p">,</span> <span class="bp">None</span><span class="p">),</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Теперь можно писать так:</p>
<div class="highlight-rst"><div class="highlight"><pre><span></span>Use <span class="na">:py:class:</span><span class="nv">`sacrud.common.TableProperty`</span> decorator.
</pre></div>
</div>
<p>И наверно последний этап это добавление документации на readthedocs. Сложностей
там особо нету, регаешься, добавляешь гитхаб профиль, синхронизируешь репы и
выбираешь нужные. Хук на коммиты в таком случае вешается автоматически,
единственное что нужно отметить что если в документации используется automodule
нужно ставить галку virtualenv (в настройках readthedocs) иначе он просто будет
пустым.</p>
<img alt="_static/2014/sphinx5.png" class="align-center" src="_static/2014/sphinx5.png" />
<p>Готовый пример можно посмотреть здесь
<a class="reference external" href="http://sacrud-deform.readthedocs.org/en/develop/">http://sacrud-deform.readthedocs.org/en/develop/</a></p>
</div>
REST API для Pyramid при помощи Cornice и SACRUD
http://uralbash.ru/articles/2014/cornice/
2014-09-05T16:33:00Z
2014-09-05T16:33:00Z
Uralbash
<div class="section" id="rest-api-pyramid-cornice-sacrud">
<p><a class="reference external" href="https://github.com/Mozilla">Mozilla</a> использует в своих проектах <a class="reference external" href="http://pylonsproject.org/">Pyramid</a> и у них есть
отличный модуль для создания <code class="docutils literal"><span class="pre">REST</span> <span class="pre">API</span></code>
<a class="reference external" href="https://cornice.readthedocs.org/en/latest/">https://cornice.readthedocs.org/en/latest/</a></p>
<p><code class="docutils literal"><span class="pre">REST</span> <span class="pre">API</span></code> обычно меняет, создает и удаляет записи, которые хранятся в БД.
Что бы не писать много кода на <a class="reference external" href="http://sqlalchemy.org/">SQLAlchemy</a> я использую заготовленные
функции из <a class="reference external" href="https://pypi.python.org/pypi/sacrud">sacrud</a>.</p>
<p>Итак поехали, представим сервис <code class="docutils literal"><span class="pre">REST</span> <span class="pre">API</span></code> для платежных карт с моделью типа:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Card</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'card'</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">number</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">BigInteger</span><span class="p">,</span> <span class="n">nullable</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">unique</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">uid</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">BYTEA</span><span class="p">,</span> <span class="n">nullable</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">unique</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">balance</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Numeric</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="n">nullable</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
<span class="n">preference</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">GUID</span><span class="p">())</span>
<span class="k">def</span> <span class="nf">__json__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'id'</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">id</span><span class="p">,</span>
<span class="s1">'number'</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">number</span><span class="p">,</span>
<span class="s1">'uid'</span><span class="p">:</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">uid</span><span class="p">),</span>
<span class="s1">'balance'</span><span class="p">:</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">balance</span><span class="p">)</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Создадим отдельную папку в <a class="reference external" href="http://pylonsproject.org/">pyramid</a> проекте с названием <code class="docutils literal"><span class="pre">rest</span></code>, где будут
храниться функции api, и пропишем это в основном конфиге.</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1"># REST API</span>
<span class="n">config</span><span class="o">.</span><span class="n">include</span><span class="p">(</span><span class="s2">"cornice"</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">include</span><span class="p">(</span><span class="s2">"myapp.rest"</span><span class="p">,</span> <span class="n">route_prefix</span><span class="o">=</span><span class="s2">"/api"</span><span class="p">)</span>
</pre></div>
</div>
<p>В pyramid’е есть такая штука как <code class="docutils literal"><span class="pre">config.scan()</span></code> она смотрит все файлы в
проекте с расширением <code class="docutils literal"><span class="pre">*.py</span></code> (от текущей директории) и ищет вьюхи обернутые
декоратором <code class="docutils literal"><span class="pre">@view_config</span></code>. Я предпочитаю включать в основной конфиг папочки
через инклуд как в примере выше, а локально в каждой папке уже вызывать
<code class="docutils literal"><span class="pre">config.scan()</span></code>.</p>
<p>Структура папки <code class="docutils literal"><span class="pre">rest</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>rest/
├── card.py
├── __init__.py
└── validators.py
</pre></div>
</div>
<p>Файл <code class="docutils literal"><span class="pre">__init__.py</span></code>:</p>
<div class="literal-block-wrapper docutils container" id="id1">
<div class="code-block-caption"><span class="caption-text">__init__.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">includeme</span><span class="p">(</span><span class="n">config</span><span class="p">):</span>
<span class="n">config</span><span class="o">.</span><span class="n">scan</span><span class="p">()</span>
</pre></div>
</div>
</div>
<p>В <code class="docutils literal"><span class="pre">card.py</span></code> сама реализация <code class="docutils literal"><span class="pre">REST</span> <span class="pre">API</span></code>:</p>
<div class="section" id="get">
<h2>GET</h2>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">json</span>
<span class="kn">from</span> <span class="nn">cornice</span> <span class="kn">import</span> <span class="n">Service</span>
<span class="kn">from</span> <span class="nn">myapp.models</span> <span class="kn">import</span> <span class="n">DBSession</span>
<span class="kn">from</span> <span class="nn">myapp.models</span> <span class="kn">import</span> <span class="n">Card</span>
<span class="kn">from</span> <span class="nn">myapp.rest.validators</span> <span class="kn">import</span> <span class="n">_400</span><span class="p">,</span> <span class="n">_404</span><span class="p">,</span> <span class="n">valid_hex</span>
<span class="kn">from</span> <span class="nn">sacrud.action</span> <span class="kn">import</span> <span class="n">CRUD</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.exc</span> <span class="kn">import</span> <span class="n">DataError</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.orm.exc</span> <span class="kn">import</span> <span class="n">NoResultFound</span>
<span class="n">card_api</span> <span class="o">=</span> <span class="n">Service</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">'card'</span><span class="p">,</span> <span class="n">path</span><span class="o">=</span><span class="s1">'/card/{UID}'</span><span class="p">,</span>
<span class="n">description</span><span class="o">=</span><span class="s2">"REST API for card"</span><span class="p">)</span>
<span class="nd">@card_api.get</span><span class="p">(</span><span class="n">validators</span><span class="o">=</span><span class="n">valid_hex</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">get_card</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="sd">"""``GET``: возвращает данные о карте.</span>
<span class="sd"> .. code-block:: bash</span>
<span class="sd"> $ curl -D - http://0.0.0.0:6543/api/card/07a8e29d</span>
<span class="sd"> HTTP/1.1 200 OK</span>
<span class="sd"> Content-Length: 69</span>
<span class="sd"> Content-Type: application/json; charset=UTF-8</span>
<span class="sd"> Date: Sat, 02 Aug 2014 11:22:52 GMT</span>
<span class="sd"> Server: waitress</span>
<span class="sd"> {"uid": "07a8e29d", "balance": 507.05, "id": 3, "number": 8224548674}</span>
<span class="sd"> """</span>
<span class="n">key</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">validated</span><span class="p">[</span><span class="s1">'UID'</span><span class="p">]</span>
<span class="n">card</span> <span class="o">=</span> <span class="n">DBSession</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">Card</span><span class="p">)</span>
<span class="k">if</span> <span class="n">key</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">card</span> <span class="o">=</span> <span class="n">card</span><span class="o">.</span><span class="n">filter_by</span><span class="p">(</span><span class="n">uid</span><span class="o">=</span><span class="n">key</span><span class="p">)</span><span class="o">.</span><span class="n">one</span><span class="p">()</span>
<span class="k">except</span> <span class="n">NoResultFound</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">_404</span><span class="p">()</span>
<span class="k">except</span> <span class="n">DataError</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">_400</span><span class="p">()</span>
<span class="k">return</span> <span class="n">card</span><span class="o">.</span><span class="n">__json__</span><span class="p">()</span>
</pre></div>
</div>
<p>Декоратор <code class="docutils literal"><span class="pre">card_api</span></code> превращает функцию <code class="docutils literal"><span class="pre">get_card</span></code> во вьюху, ожидающею HTTP
метод GET, и <code class="docutils literal"><span class="pre">config.scan()</span></code> её автоматически подхватит. Внутри можно
реализовывать все что угодно. Про метод validated ниже.</p>
</div>
<div class="section" id="post">
<h2>POST</h2>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="nd">@card_api.post</span><span class="p">(</span><span class="n">validators</span><span class="o">=</span><span class="n">valid_hex</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">set_card</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="sd">"""``POST``: передает параметры для редактирования карты.</span>
<span class="sd"> .. code-block:: bash</span>
<span class="sd"> $ curl -H 'Accept: application/json'\\</span>
<span class="sd"> -H 'Content-Type: application/json'\\</span>
<span class="sd"> http://0.0.0.0:6543/api/card/07a8e29d\\</span>
<span class="sd"> -d '{"number": "8224548674", "balance": "507.05"}'</span>
<span class="sd"> {"uid": "07a8e29d", "balance": 507.05, "id": 3, "number": 8224548674}</span>
<span class="sd"> Если карты нету, то создается новая</span>
<span class="sd"> .. code-block:: bash</span>
<span class="sd"> $ curl -H 'Accept: application/json'\\</span>
<span class="sd"> -H 'Content-Type: application/json'\\</span>
<span class="sd"> http://0.0.0.0:6543/api/card/550e8400\\</span>
<span class="sd"> -d '{"balance": "100.11", "preference": "956bfc40"}'</span>
<span class="sd"> {"uid": "550e8400", "balance": 100.11, "id": 7, "number": 91328937986}</span>
<span class="sd"> """</span>
<span class="n">key</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">validated</span><span class="p">[</span><span class="s1">'UID'</span><span class="p">]</span>
<span class="n">data</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'request'</span><span class="p">:</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">body</span><span class="p">)}</span>
<span class="n">card</span> <span class="o">=</span> <span class="n">DBSession</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">Card</span><span class="p">)</span><span class="o">.</span><span class="n">filter_by</span><span class="p">(</span><span class="n">uid</span><span class="o">=</span><span class="n">key</span><span class="p">)</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
<span class="k">if</span> <span class="n">card</span><span class="p">:</span>
<span class="n">data</span><span class="p">[</span><span class="s1">'pk'</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'id'</span><span class="p">:</span> <span class="n">card</span><span class="o">.</span><span class="n">id</span><span class="p">}</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">data</span><span class="p">[</span><span class="s1">'request'</span><span class="p">][</span><span class="s1">'uid'</span><span class="p">]</span> <span class="o">=</span> <span class="n">key</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">CRUD</span><span class="p">(</span><span class="n">DBSession</span><span class="p">,</span> <span class="n">Card</span><span class="p">,</span> <span class="o">**</span><span class="n">data</span><span class="p">)</span><span class="o">.</span><span class="n">add</span><span class="p">()</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">_400</span><span class="p">(</span><span class="n">msg</span><span class="o">=</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">message</span><span class="p">))</span>
<span class="n">card</span> <span class="o">=</span> <span class="n">DBSession</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">Card</span><span class="p">)</span><span class="o">.</span><span class="n">filter_by</span><span class="p">(</span><span class="n">uid</span><span class="o">=</span><span class="n">key</span><span class="p">)</span><span class="o">.</span><span class="n">one</span><span class="p">()</span>
<span class="k">return</span> <span class="n">card</span><span class="o">.</span><span class="n">__json__</span><span class="p">()</span>
</pre></div>
</div>
<p>Метод POST меняет параметры карты или создает новую если такой нету. Карта
создается при помощи мега модуля <a class="reference external" href="https://pypi.python.org/pypi/sacrud">sacrud</a>. Подробнее о создании записей
через <a class="reference external" href="https://pypi.python.org/pypi/sacrud">sacrud</a> здесь
<a class="reference external" href="http://sacrud.readthedocs.org/en/latest/plain_usage.html#create-action">http://sacrud.readthedocs.org/en/latest/plain_usage.html#create-action</a></p>
</div>
<div class="section" id="delete">
<h2>DELETE</h2>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="nd">@card_api.delete</span><span class="p">(</span><span class="n">validators</span><span class="o">=</span><span class="n">valid_hex</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">del_card</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="sd">"""``DELETE``: удаляет карту по UID</span>
<span class="sd"> .. code-block:: bash</span>
<span class="sd"> $ curl -H 'Accept: application/json'\\</span>
<span class="sd"> -H 'Content-Type: application/json'\\</span>
<span class="sd"> http://0.0.0.0:6543/api/card/550e8400 -X DELETE</span>
<span class="sd"> {"Goodbye": "550e8400"}</span>
<span class="sd"> """</span>
<span class="n">key</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">validated</span><span class="p">[</span><span class="s1">'UID'</span><span class="p">]</span>
<span class="n">card</span> <span class="o">=</span> <span class="n">DBSession</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">Card</span><span class="p">)</span><span class="o">.</span><span class="n">filter_by</span><span class="p">(</span><span class="n">uid</span><span class="o">=</span><span class="n">key</span><span class="p">)</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">card</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">_404</span><span class="p">()</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">CRUD</span><span class="p">(</span><span class="n">DBSession</span><span class="p">,</span> <span class="n">Card</span><span class="p">,</span> <span class="n">pk</span><span class="o">=</span><span class="p">{</span><span class="s1">'id'</span><span class="p">:</span> <span class="n">card</span><span class="o">.</span><span class="n">id</span><span class="p">})</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
<span class="k">except</span> <span class="n">DataError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">_400</span><span class="p">(</span><span class="n">msg</span><span class="o">=</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">message</span><span class="p">))</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'Goodbye'</span><span class="p">:</span> <span class="n">key</span><span class="p">}</span>
</pre></div>
</div>
<p>Удаление происходит при вызове HTTP метода DELETE. <a class="reference external" href="https://pypi.python.org/pypi/sacrud">sacrud</a> опять же
несколько упрощает эту операцию
<a class="reference external" href="http://sacrud.readthedocs.org/en/latest/plain_usage.html#delete-action">http://sacrud.readthedocs.org/en/latest/plain_usage.html#delete-action</a></p>
<p>В файле <code class="docutils literal"><span class="pre">validators.py</span></code> хранятся всякие исключения и сами проверки. Если в
декораторе card_api указан валидатор, то валидные данные нужно будет выбирать
не через <code class="docutils literal"><span class="pre">request.matchdict</span></code> а через <code class="docutils literal"><span class="pre">request.validated</span></code>.</p>
<p>Пример файла <code class="docutils literal"><span class="pre">validators.py</span></code></p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">string</span>
<span class="kn">from</span> <span class="nn">webob</span> <span class="kn">import</span> <span class="n">exc</span><span class="p">,</span> <span class="n">Response</span>
<span class="k">class</span> <span class="nc">_404</span><span class="p">(</span><span class="n">exc</span><span class="o">.</span><span class="n">HTTPError</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">msg</span><span class="o">=</span><span class="s1">'Not Found'</span><span class="p">):</span>
<span class="n">body</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'status'</span><span class="p">:</span> <span class="mi">404</span><span class="p">,</span> <span class="s1">'message'</span><span class="p">:</span> <span class="n">msg</span><span class="p">}</span>
<span class="n">Response</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">body</span><span class="p">))</span>
<span class="bp">self</span><span class="o">.</span><span class="n">status</span> <span class="o">=</span> <span class="mi">404</span>
<span class="bp">self</span><span class="o">.</span><span class="n">content_type</span> <span class="o">=</span> <span class="s1">'application/json'</span>
<span class="k">class</span> <span class="nc">_400</span><span class="p">(</span><span class="n">exc</span><span class="o">.</span><span class="n">HTTPError</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">msg</span><span class="o">=</span><span class="s1">'Bad Request'</span><span class="p">):</span>
<span class="n">body</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'status'</span><span class="p">:</span> <span class="mi">400</span><span class="p">,</span> <span class="s1">'message'</span><span class="p">:</span> <span class="n">msg</span><span class="p">}</span>
<span class="n">Response</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">body</span><span class="p">))</span>
<span class="bp">self</span><span class="o">.</span><span class="n">status</span> <span class="o">=</span> <span class="mi">400</span>
<span class="bp">self</span><span class="o">.</span><span class="n">content_type</span> <span class="o">=</span> <span class="s1">'application/json'</span>
<span class="k">def</span> <span class="nf">valid_hex</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="n">key</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">matchdict</span><span class="p">[</span><span class="s1">'UID'</span><span class="p">]</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">all</span><span class="p">(</span><span class="n">c</span> <span class="ow">in</span> <span class="n">string</span><span class="o">.</span><span class="n">hexdigits</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">key</span><span class="p">):</span>
<span class="k">raise</span> <span class="n">_400</span><span class="p">(</span><span class="n">msg</span><span class="o">=</span><span class="s2">"Not valid UID '</span><span class="si">%s</span><span class="s2">'"</span> <span class="o">%</span> <span class="n">key</span><span class="p">)</span>
<span class="n">request</span><span class="o">.</span><span class="n">validated</span><span class="p">[</span><span class="s1">'UID'</span><span class="p">]</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
</pre></div>
</div>
<p>Таким образом можно довольно просто создать API для вашего проекта на пирамиде.
Cornice делает много за вас, создает вьюхи, пути, валидацию, может генерить
автоматически <a class="reference external" href="https://pypi.python.org/pypi/Sphinx">Sphinx</a> документацию, а <a class="reference external" href="https://pypi.python.org/pypi/SACRUD">SACRUD</a> упрощает работу с БД.</p>
</div>
</div>
Chameleon, deform и маленькая хитрость
http://uralbash.ru/articles/2014/chameleon_deform/
2014-08-19T19:29:00Z
2014-08-19T19:29:00Z
Uralbash
<div class="section" id="chameleon-deform">
<p><a class="reference external" href="https://pypi.python.org/pypi/Deform">Deform</a> - это такая штука которая генерит формы, а шаблоны для виджетов
в нем написаны в формате Chameleon шаблонизатора.</p>
<p>Простой пример формы (<a class="reference external" href="http://deformdemo.xo7.de/nonrequiredfields/">http://deformdemo.xo7.de/nonrequiredfields/</a>):</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Schema</span><span class="p">(</span><span class="n">colander</span><span class="o">.</span><span class="n">Schema</span><span class="p">):</span>
<span class="n">required</span> <span class="o">=</span> <span class="n">colander</span><span class="o">.</span><span class="n">SchemaNode</span><span class="p">(</span>
<span class="n">colander</span><span class="o">.</span><span class="n">String</span><span class="p">(),</span>
<span class="n">description</span><span class="o">=</span><span class="s1">'Required Field'</span>
<span class="p">)</span>
<span class="n">notrequired</span> <span class="o">=</span> <span class="n">colander</span><span class="o">.</span><span class="n">SchemaNode</span><span class="p">(</span>
<span class="n">colander</span><span class="o">.</span><span class="n">String</span><span class="p">(),</span>
<span class="n">missing</span><span class="o">=</span><span class="nb">unicode</span><span class="p">(</span><span class="s1">''</span><span class="p">),</span>
<span class="n">description</span><span class="o">=</span><span class="s1">'Unrequired Field'</span><span class="p">)</span>
<span class="n">schema</span> <span class="o">=</span> <span class="n">Schema</span><span class="p">()</span>
<span class="n">form</span> <span class="o">=</span> <span class="n">deform</span><span class="o">.</span><span class="n">Form</span><span class="p">(</span><span class="n">schema</span><span class="p">,</span> <span class="n">buttons</span><span class="o">=</span><span class="p">(</span><span class="s1">'submit'</span><span class="p">,))</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">render_form</span><span class="p">(</span><span class="n">form</span><span class="p">)</span>
</pre></div>
</div>
<img alt="_static/2014/chameleon_deform.png" src="_static/2014/chameleon_deform.png" />
<p>К полям можно добавлять описание, но если вставить html то он
заэскапируется
(<a class="reference external" href="https://github.com/Pylons/deform/blob/bb4fc86913884deafa9350de86d87fb5232263fa/deform/templates/form.pt#L42">https://github.com/Pylons/deform/blob/bb4fc86913884deafa9350de86d87fb5232263fa/deform/templates/form.pt#L42</a>).
Можно воспользоваться хитрой возможностью <a class="reference external" href="https://pypi.python.org/pypi/Chameleon">Chameleon</a>‘а что бы вывести html.</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">HTMLText</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">text</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">text</span> <span class="o">=</span> <span class="n">text</span>
<span class="k">def</span> <span class="nf">__html__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">unicode</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
<span class="n">notrequired</span> <span class="o">=</span> <span class="n">colander</span><span class="o">.</span><span class="n">SchemaNode</span><span class="p">(</span>
<span class="n">colander</span><span class="o">.</span><span class="n">String</span><span class="p">(),</span>
<span class="n">missing</span><span class="o">=</span><span class="nb">unicode</span><span class="p">(</span><span class="s1">''</span><span class="p">),</span>
<span class="n">description</span><span class="o">=</span><span class="n">HTMLText</span><span class="p">(</span><span class="s1">'Hello <hr color="red" /> World!!! <hr />'</span><span class="p">))</span>
</pre></div>
</div>
<p><a class="reference external" href="https://pypi.python.org/pypi/Chameleon">Chameleon</a> по умолчанию ищет метод <code class="docutils literal"><span class="pre">__html__</span></code> у объектов и если он
есть то выводит его результат в чистом виде. Вот.</p>
</div>
sqlalchemy_mptt v0.0.5
http://uralbash.ru/articles/2014/sqlalchemy_mptt_0_0_5/
2014-06-26T17:27:00Z
2014-06-26T17:27:00Z
Uralbash
<div class="section" id="sqlalchemy-mptt-v0-0-5">
<p>В новом релизе:</p>
<ul class="simple">
<li>устранены некоторые баги</li>
<li>написана документация <a class="reference external" href="http://sqlalchemy-mptt.readthedocs.org/">http://sqlalchemy-mptt.readthedocs.org/</a></li>
</ul>
</div>
Scrum и XP: заметки с передовой
http://uralbash.ru/articles/2014/scrum/
2014-06-06T22:44:00Z
2014-06-06T22:44:00Z
Uralbash
<div class="section" id="scrum-xp">
<img alt="_static/2014/scrum.png" class="align-left" src="_static/2014/scrum.png" />
<p>Старая, но очень полезная книга по <code class="docutils literal"><span class="pre">Agile</span></code>. Довольно редкий случай когда вся
книга описывает рабочие процессы реальной организации, никакой воды, никакой
зауми и вялой теории. Очень рекомендую. Тем более книга в свободном доступе и
переведена на русский язык (лучи добра и счастья переводчикам).</p>
<p><a class="reference external" href="http://scrum.org.ua/wp-content/uploads/2008/12/scrum_xp-from-the-trenches-rus-final.pdf">http://scrum.org.ua/wp-content/uploads/2008/12/scrum_xp-from-the-trenches-rus-final.pdf</a></p>
<p>Дальше несколько интересных цитат из книги:</p>
<p>По правде говоря, у системы с высоким внутренним качеством иногда может быть
довольно низкое внешнее. Но наоборот бывает крайне редко. Сложно построить
что-то хорошее на прогнившем фундаменте.</p>
<p>По моему личному опыту, жертвовать внутренним качеством – это практически
всегда очень и очень плохая идея. Сэкономленное время ничтожно мало по
сравнению с той ценой, которую вам придётся заплатить как в ближайшем будущем,
так и в перспективе. Как только
качество вашего кода ухудшится, восстановить его будет очень тяжело.</p>
<p>Учитесь оставаться в рамках установленного времени, учитесь давать реалистичные
оценки. Это касается как продолжительности встреч, так и продолжительности
спринта.</p>
<p>А различие очень простое: истории это нечто, что можно продемонстрировать, что
представляет ценность для product owner’а, а задачи либо нельзя
продемонстрировать, либо они не представляют ценности для product owner’a.</p>
<p>Пример разбиения истории на более мелкие:</p>
<img alt="_static/2014/scrum2.png" src="_static/2014/scrum2.png" />
<p>Пример разбиения истории на задачи:</p>
<img alt="_static/2014/scrum3.png" src="_static/2014/scrum3.png" />
<p>Мы попробовали различные варианты работы с техническими историями. Мы пробовали
считать их самыми обычными user story. Это была неудачная идея: для product
owner’а приоритезировать их в product backlog’е было всё равно, что сравнить
тёплое с мягким. По очевидным причинам технические истории получали самый
низкий приоритет с объяснением: “Да, ребята, несомненно, ваш сервер непрерывной
интеграции – очень важная штука, но давайте сперва реализуем кое-какие
прибыльные функции? После этого вы можете прикрутить вашу техническую конфетку,
окей?”</p>
<img alt="_static/2014/scrum4.png" src="_static/2014/scrum4.png" />
<p>если вы пользуетесь стикерами для задач, не забудьте прикрепить их скотчем, или
же в один “прекрасный” день вы найдете их аккуратной кучкой на полу.</p>
<img alt="_static/2014/scrum5.png" src="_static/2014/scrum5.png" />
<p>Как быть с опоздавшими?</p>
<p>Некоторые команды заводят специальную копилку. Если вы опоздали, даже на
минуту, вы кидаете в копилку определённую сумму. Без вариантов. Даже если вы
позвонили перед началом ежедневного Scrum’а и предупредили, заплатить всё равно
придётся :o)</p>
<p>Деньги из копилки используются на общественные нужды. Например, на них можно заказать пиццу</p>
<img alt="_static/2014/scrum6.png" src="_static/2014/scrum6.png" />
<p>Если вы действительно хотите разобраться, как планировать релиз, советую
пропустить эту главу и купить книгу Майка Кона “Agile Estimating and Planning”.
Эх, прочитать бы мне эту книгу раньше... (она попалась мне уже после того, как
мы на собственном опыте поняли, что к чему...). Мой способ планирования
простой, как угол дома, но может послужить вам хорошей отправной точкой.</p>
<a class="reference external image-reference" href="http://www.books.ru/books/scrum-gibkaya-razrabotka-po-signature-series-3643772/?show=1&bkrand=1ncaafgaia8ck1qvpo5u9nklk0/?partner=490327"><img alt="_static/2014/scrum_book.jpg" class="align-left" src="_static/2014/scrum_book.jpg" /></a>
<p>Вот эта книга, кстати тоже переведена на русский</p>
<br clear="both"/><p>Scrum решает вопросы управления и организации, тогда как XP специализируется на
инженерных практиках. Вот почему эти две технологии хорошо работают вместе,
дополняя друг друга.</p>
<p>Работка через тестирование (TDD)</p>
<p>Наконец-то! Разработка через тестирование для меня важнее, чем Scrum и XP
вместе взятые. Можете отнять у меня дом, телевизор, собаку, но только
попробуйте запретить использование TDD! Если вам не нравится TDD, тогда просто
не подпускайте меня близко, иначе я всё равно привнесу его в проект втихую :)</p>
<p>Мы столкнулись с ситуацией, когда было невозможно внедрить Scrum в большом
проекте из-за того, что его команда постоянно тушила пожары, т.е. в панике
устраняла дефекты преждевременно выпущенной системы. Это был порочный круг:
из-за того, что всё время уходило на постоянную борьбу с пожарами, не было
времени на их предотвращение (т.е. на улучшение архитектуры, внедрение
автоматического тестирования, создание систем мониторинга и оповещения, и т.п.)</p>
</div>
ia32-libs-multiarch:i386 : Зависит: libsane:i386 но он не установлен
http://uralbash.ru/articles/2014/ia32-libs-multiarch:i386/
2014-05-22T18:30:00Z
2014-05-22T18:30:00Z
Uralbash
<div class="section" id="ia32-libs-multiarch-i386-libsane-i386">
<p>Что бы удалить поломанный пакет типа такого:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo apt-get upgrade
Чтение списков пакетов… Готово
Построение дерева зависимостей
Чтение информации о состоянии… Готово
Возможно, для исправления этих ошибок вы захотите воспользоваться «apt-get -f install».
Пакеты, имеющие неудовлетворённые зависимости:
ia32-libs-multiarch:i386 : Зависит: libsane:i386 но он не установлен
E: Неудовлетворённые зависимости. Попытайтесь использовать -f.
</pre></div>
</div>
<p>Выполняем то что он просит:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo apt-get -f install
Чтение списков пакетов… Готово
Построение дерева зависимостей
Чтение информации о состоянии… Готово
Исправление зависимостей… Готово
Будут установлены следующие дополнительные пакеты:
libsane:i386
Предлагаемые пакеты:
hpoj:i386 hplip:i386 libsane-extras:i386 sane-utils:i386
НОВЫЕ пакеты, которые будут установлены:
libsane:i386
обновлено <span class="m">0</span>, установлено <span class="m">1</span> новых пакетов, для удаления отмечено <span class="m">0</span> пакетов, и <span class="m">1</span> пакетов не обновлено.
не установлено до конца или удалено <span class="m">120</span> пакетов.
Необходимо скачать <span class="m">0</span> B/3 <span class="m">734</span> kB архивов.
После данной операции, объём занятого дискового пространства возрастёт на <span class="m">8</span> <span class="m">970</span> kB.
Хотите продолжить <span class="o">[</span>Д/н<span class="o">]</span>? y
<span class="o">(</span>Чтение базы данных … на данный момент установлено <span class="m">577328</span> файлов и каталогов.<span class="o">)</span>
Распаковывается пакет libsane:i386 <span class="o">(</span>из файла …/libsane_1.0.23-0ubuntu1_i386.deb<span class="o">)</span> …
dpkg: ошибка при обработке параметра /var/cache/apt/archives/libsane_1.0.23-0ubuntu1_i386.deb <span class="o">(</span>--unpack<span class="o">)</span>:
попытка перезаписать общий «/etc/sane.d/dc240.conf», который отличается от других экземпляров пакета libsane:i386
Отчёты apport не записаны, так достигнут MaxReports
При обработке следующих пакетов произошли ошибки:
/var/cache/apt/archives/libsane_1.0.23-0ubuntu1_i386.deb
E: Sub-process /usr/bin/dpkg returned an error code <span class="o">(</span><span class="m">1</span><span class="o">)</span>
</pre></div>
</div>
<p>Удаляем сломанный пакет через <a class="reference external" href="https://www.freebsd.org/cgi/man.cgi?query=dpkg">dpkg</a>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo dpkg -r libsane
dpkg: предупреждение: игнорируется запрос на удаление пакета libsane:amd64, от которого
сохранились только файлы настройки<span class="p">;</span> чтобы удалить и файлы
настройки, используйте --purge
</pre></div>
</div>
<p>Удаляем конфиги пакета:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo dpkg --purge libsane
<span class="o">(</span>Чтение базы данных … на данный момент установлено <span class="m">577328</span> файлов и каталогов.<span class="o">)</span>
Удаляется пакет libsane:amd64 …
Вычищаются файлы настройки пакета libsane:amd64 …
Removing directory /etc/sane.d/ ...
</pre></div>
</div>
</div>
MPTT для SQLAlchemy
http://uralbash.ru/articles/2014/sqlalchemy_mptt/
2014-05-12T18:30:00Z
2014-05-12T18:30:00Z
Uralbash
<div class="section" id="mptt-sqlalchemy">
<p>Запилил я тут для своих нужд небольшое приложение (<a class="reference external" href="https://pypi.python.org/pypi/sqlalchemy_mptt">sqlalchemy_mptt</a>)
которое добавляет в модель поля и функционал необходимый для <code class="docutils literal"><span class="pre">Nested</span> <span class="pre">sets</span></code>.
По аналогии с <a class="reference external" href="https://pypi.python.org/pypi/django-mptt">django-mptt</a>. Грубо говоря в модель добавляются поля
<code class="docutils literal"><span class="pre">left</span></code> и <code class="docutils literal"><span class="pre">right</span></code> которые при помощи системы эвентов самостоятельно
пересчитываются при изменении дерева. Ниже пример обхода дерева:</p>
<img alt="_static/2014/2_sqlalchemy_mptt_traversal.png" class="align-center" src="_static/2014/2_sqlalchemy_mptt_traversal.png" style="width: 600px;" />
<p>Простой пример:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">Column</span><span class="p">,</span> <span class="n">Integer</span><span class="p">,</span> <span class="n">Boolean</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.ext.declarative</span> <span class="kn">import</span> <span class="n">declarative_base</span>
<span class="kn">from</span> <span class="nn">sqlalchemy_mptt.mixins</span> <span class="kn">import</span> <span class="n">BaseNestedSets</span>
<span class="n">Base</span> <span class="o">=</span> <span class="n">declarative_base</span><span class="p">()</span>
<span class="k">class</span> <span class="nc">Tree</span><span class="p">(</span><span class="n">Base</span><span class="p">,</span> <span class="n">BaseNestedSets</span><span class="p">):</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s2">"tree"</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">visible</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Boolean</span><span class="p">)</span> <span class="c1"># Наше кастомное поле</span>
<span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="s2">"<node s="">"</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">id</span>
<span class="n">Tree</span><span class="o">.</span><span class="n">register_tree</span><span class="p">()</span> <span class="c1"># Регистрирует event'ы</span>
</pre></div>
</div>
<div class="section" id="id1">
<h2>Добавление</h2>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">node</span> <span class="o">=</span> <span class="n">Tree</span><span class="p">(</span><span class="n">parent_id</span><span class="o">=</span><span class="mi">6</span><span class="p">)</span>
<span class="n">session</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
</pre></div>
</div>
<p>получим:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>level Nested sets example
<span class="m">1</span> <span class="m">1</span><span class="o">(</span><span class="m">1</span><span class="o">)</span><span class="m">22</span>
_______________<span class="p">|</span>___________________
<span class="p">|</span> <span class="p">|</span> <span class="p">|</span>
<span class="m">2</span> <span class="m">2</span><span class="o">(</span><span class="m">2</span><span class="o">)</span><span class="m">5</span> <span class="m">6</span><span class="o">(</span><span class="m">4</span><span class="o">)</span><span class="m">11</span> <span class="m">12</span><span class="o">(</span><span class="m">7</span><span class="o">)</span><span class="m">21</span>
<span class="p">|</span> ^ ^
<span class="m">3</span> <span class="m">3</span><span class="o">(</span><span class="m">3</span><span class="o">)</span><span class="m">4</span> <span class="m">7</span><span class="o">(</span><span class="m">5</span><span class="o">)</span><span class="m">8</span> <span class="m">9</span><span class="o">(</span><span class="m">6</span><span class="o">)</span><span class="m">10</span> <span class="m">13</span><span class="o">(</span><span class="m">8</span><span class="o">)</span><span class="m">16</span> <span class="m">17</span><span class="o">(</span><span class="m">10</span><span class="o">)</span><span class="m">20</span>
<span class="p">|</span> <span class="p">|</span>
<span class="m">4</span> <span class="m">14</span><span class="o">(</span><span class="m">9</span><span class="o">)</span><span class="m">15</span> <span class="m">18</span><span class="o">(</span><span class="m">11</span><span class="o">)</span><span class="m">19</span>
level Insert node with <span class="nv">parent_id</span> <span class="o">==</span> <span class="m">6</span>
<span class="m">1</span> <span class="m">1</span><span class="o">(</span><span class="m">1</span><span class="o">)</span><span class="m">24</span>
_______________<span class="p">|</span>_________________
<span class="p">|</span> <span class="p">|</span> <span class="p">|</span>
<span class="m">2</span> <span class="m">2</span><span class="o">(</span><span class="m">2</span><span class="o">)</span><span class="m">5</span> <span class="m">6</span><span class="o">(</span><span class="m">4</span><span class="o">)</span><span class="m">13</span> <span class="m">14</span><span class="o">(</span><span class="m">7</span><span class="o">)</span><span class="m">23</span>
<span class="p">|</span> ____<span class="p">|</span>____ ___<span class="p">|</span>____
<span class="p">|</span> <span class="p">|</span> <span class="p">|</span> <span class="p">|</span> <span class="p">|</span>
<span class="m">3</span> <span class="m">3</span><span class="o">(</span><span class="m">3</span><span class="o">)</span><span class="m">4</span> <span class="m">7</span><span class="o">(</span><span class="m">5</span><span class="o">)</span><span class="m">8</span> <span class="m">9</span><span class="o">(</span><span class="m">6</span><span class="o">)</span><span class="m">12</span> <span class="m">15</span><span class="o">(</span><span class="m">8</span><span class="o">)</span><span class="m">18</span> <span class="m">19</span><span class="o">(</span><span class="m">10</span><span class="o">)</span><span class="m">22</span>
<span class="p">|</span> <span class="p">|</span> <span class="p">|</span>
<span class="m">4</span> <span class="m">10</span><span class="o">(</span><span class="m">23</span><span class="o">)</span><span class="m">11</span> <span class="m">16</span><span class="o">(</span><span class="m">9</span><span class="o">)</span><span class="m">17</span> <span class="m">20</span><span class="o">(</span><span class="m">11</span><span class="o">)</span><span class="m">21</span>
</pre></div>
</div>
</div>
<div class="section" id="id2">
<h2>Удаление</h2>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">node</span> <span class="o">=</span> <span class="n">session</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">Tree</span><span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">Tree</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="mi">4</span><span class="p">)</span><span class="o">.</span><span class="n">one</span><span class="p">()</span>
<span class="n">session</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
</pre></div>
</div>
<p>получим:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>level Nested sets example
<span class="m">1</span> <span class="m">1</span><span class="o">(</span><span class="m">1</span><span class="o">)</span><span class="m">22</span>
_______________<span class="p">|</span>___________________
<span class="p">|</span> <span class="p">|</span> <span class="p">|</span>
<span class="m">2</span> <span class="m">2</span><span class="o">(</span><span class="m">2</span><span class="o">)</span><span class="m">5</span> <span class="m">6</span><span class="o">(</span><span class="m">4</span><span class="o">)</span><span class="m">11</span> <span class="m">12</span><span class="o">(</span><span class="m">7</span><span class="o">)</span><span class="m">21</span>
<span class="p">|</span> ^ ^
<span class="m">3</span> <span class="m">3</span><span class="o">(</span><span class="m">3</span><span class="o">)</span><span class="m">4</span> <span class="m">7</span><span class="o">(</span><span class="m">5</span><span class="o">)</span><span class="m">8</span> <span class="m">9</span><span class="o">(</span><span class="m">6</span><span class="o">)</span><span class="m">10</span> <span class="m">13</span><span class="o">(</span><span class="m">8</span><span class="o">)</span><span class="m">16</span> <span class="m">17</span><span class="o">(</span><span class="m">10</span><span class="o">)</span><span class="m">20</span>
<span class="p">|</span> <span class="p">|</span>
<span class="m">4</span> <span class="m">14</span><span class="o">(</span><span class="m">9</span><span class="o">)</span><span class="m">15</span> <span class="m">18</span><span class="o">(</span><span class="m">11</span><span class="o">)</span><span class="m">19</span>
level Delete <span class="nv">node</span> <span class="o">==</span> <span class="m">4</span>
<span class="m">1</span> <span class="m">1</span><span class="o">(</span><span class="m">1</span><span class="o">)</span><span class="m">16</span>
_______________<span class="p">|</span>_____
<span class="p">|</span> <span class="p">|</span>
<span class="m">2</span> <span class="m">2</span><span class="o">(</span><span class="m">2</span><span class="o">)</span><span class="m">5</span> <span class="m">6</span><span class="o">(</span><span class="m">7</span><span class="o">)</span><span class="m">15</span>
<span class="p">|</span> ^
<span class="m">3</span> <span class="m">3</span><span class="o">(</span><span class="m">3</span><span class="o">)</span><span class="m">4</span> <span class="m">7</span><span class="o">(</span><span class="m">8</span><span class="o">)</span><span class="m">10</span> <span class="m">11</span><span class="o">(</span><span class="m">10</span><span class="o">)</span><span class="m">14</span>
<span class="p">|</span> <span class="p">|</span>
<span class="m">4</span> <span class="m">8</span><span class="o">(</span><span class="m">9</span><span class="o">)</span><span class="m">9</span> <span class="m">12</span><span class="o">(</span><span class="m">11</span><span class="o">)</span><span class="m">13</span>
</pre></div>
</div>
</div>
<div class="section" id="id3">
<h2>Обновление</h2>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">node</span> <span class="o">=</span> <span class="n">session</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">Tree</span><span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">Tree</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="mi">8</span><span class="p">)</span><span class="o">.</span><span class="n">one</span><span class="p">()</span>
<span class="n">node</span><span class="o">.</span><span class="n">parent_id</span> <span class="o">=</span> <span class="mi">5</span>
<span class="n">session</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
</pre></div>
</div>
<p>получим</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>level Nested sets example
<span class="m">1</span> <span class="m">1</span><span class="o">(</span><span class="m">1</span><span class="o">)</span><span class="m">22</span>
_______________<span class="p">|</span>___________________
<span class="p">|</span> <span class="p">|</span> <span class="p">|</span>
<span class="m">2</span> <span class="m">2</span><span class="o">(</span><span class="m">2</span><span class="o">)</span><span class="m">5</span> <span class="m">6</span><span class="o">(</span><span class="m">4</span><span class="o">)</span><span class="m">11</span> <span class="m">12</span><span class="o">(</span><span class="m">7</span><span class="o">)</span><span class="m">21</span>
<span class="p">|</span> ^ ^
<span class="m">3</span> <span class="m">3</span><span class="o">(</span><span class="m">3</span><span class="o">)</span><span class="m">4</span> <span class="m">7</span><span class="o">(</span><span class="m">5</span><span class="o">)</span><span class="m">8</span> <span class="m">9</span><span class="o">(</span><span class="m">6</span><span class="o">)</span><span class="m">10</span> <span class="m">13</span><span class="o">(</span><span class="m">8</span><span class="o">)</span><span class="m">16</span> <span class="m">17</span><span class="o">(</span><span class="m">10</span><span class="o">)</span><span class="m">20</span>
<span class="p">|</span> <span class="p">|</span>
<span class="m">4</span> <span class="m">14</span><span class="o">(</span><span class="m">9</span><span class="o">)</span><span class="m">15</span> <span class="m">18</span><span class="o">(</span><span class="m">11</span><span class="o">)</span><span class="m">19</span>
level Move <span class="m">8</span> - > <span class="m">5</span>
<span class="m">1</span> <span class="m">1</span><span class="o">(</span><span class="m">1</span><span class="o">)</span><span class="m">22</span>
_______________<span class="p">|</span>__________________
<span class="p">|</span> <span class="p">|</span> <span class="p">|</span>
<span class="m">2</span> <span class="m">2</span><span class="o">(</span><span class="m">2</span><span class="o">)</span><span class="m">5</span> <span class="m">6</span><span class="o">(</span><span class="m">4</span><span class="o">)</span><span class="m">15</span> <span class="m">16</span><span class="o">(</span><span class="m">7</span><span class="o">)</span><span class="m">21</span>
<span class="p">|</span> ^ <span class="p">|</span>
<span class="m">3</span> <span class="m">3</span><span class="o">(</span><span class="m">3</span><span class="o">)</span><span class="m">4</span> <span class="m">7</span><span class="o">(</span><span class="m">5</span><span class="o">)</span><span class="m">12</span> <span class="m">13</span><span class="o">(</span><span class="m">6</span><span class="o">)</span><span class="m">14</span> <span class="m">17</span><span class="o">(</span><span class="m">10</span><span class="o">)</span><span class="m">20</span>
<span class="p">|</span> <span class="p">|</span>
<span class="m">4</span> <span class="m">8</span><span class="o">(</span><span class="m">8</span><span class="o">)</span><span class="m">11</span> <span class="m">18</span><span class="o">(</span><span class="m">11</span><span class="o">)</span><span class="m">19</span>
<span class="p">|</span>
<span class="m">5</span> <span class="m">9</span><span class="o">(</span><span class="m">9</span><span class="o">)</span><span class="m">10</span>
</pre></div>
</div>
</div>
<div class="section" id="id4">
<h2>Перенос ноды по дереву или между деревьев</h2>
<img alt="_static/2014/3_sqlalchemy_mptt_multitree.png" class="align-center" src="_static/2014/3_sqlalchemy_mptt_multitree.png" style="width: 600px;" />
</div>
<div class="section" id="move-inside">
<h2>Move inside (перемещает ноду на первое место от родителя)</h2>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">node</span> <span class="o">=</span> <span class="n">session</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">Tree</span><span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">Tree</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="mi">8</span><span class="p">)</span><span class="o">.</span><span class="n">one</span><span class="p">()</span>
<span class="n">node</span> <span class="o">=</span> <span class="n">session</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">Tree</span><span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">Tree</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="mi">4</span><span class="p">)</span><span class="o">.</span><span class="n">one</span><span class="p">()</span>
<span class="n">node</span><span class="o">.</span><span class="n">move_inside</span><span class="p">(</span><span class="s2">"15"</span><span class="p">)</span>
</pre></div>
</div>
<p>получим:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span> <span class="m">4</span> -> <span class="m">15</span>
level Nested sets tree1
<span class="m">1</span> <span class="m">1</span><span class="o">(</span><span class="m">1</span><span class="o">)</span><span class="m">16</span>
_______________<span class="p">|</span>_____________________
<span class="p">|</span> <span class="p">|</span>
<span class="m">2</span> <span class="m">2</span><span class="o">(</span><span class="m">2</span><span class="o">)</span><span class="m">5</span> <span class="m">6</span><span class="o">(</span><span class="m">7</span><span class="o">)</span><span class="m">15</span>
<span class="p">|</span> ^
<span class="m">3</span> <span class="m">3</span><span class="o">(</span><span class="m">3</span><span class="o">)</span><span class="m">4</span> <span class="m">7</span><span class="o">(</span><span class="m">8</span><span class="o">)</span><span class="m">10</span> <span class="m">11</span><span class="o">(</span><span class="m">10</span><span class="o">)</span><span class="m">14</span>
<span class="p">|</span> <span class="p">|</span>
<span class="m">4</span> <span class="m">8</span><span class="o">(</span><span class="m">9</span><span class="o">)</span><span class="m">9</span> <span class="m">12</span><span class="o">(</span><span class="m">11</span><span class="o">)</span><span class="m">13</span>
level Nested sets tree2
<span class="m">1</span> <span class="m">1</span><span class="o">(</span><span class="m">12</span><span class="o">)</span><span class="m">28</span>
________________<span class="p">|</span>_______________________
<span class="p">|</span> <span class="p">|</span> <span class="p">|</span>
<span class="m">2</span> <span class="m">2</span><span class="o">(</span><span class="m">13</span><span class="o">)</span><span class="m">5</span> <span class="m">6</span><span class="o">(</span><span class="m">15</span><span class="o">)</span><span class="m">17</span> <span class="m">18</span><span class="o">(</span><span class="m">18</span><span class="o">)</span><span class="m">27</span>
<span class="p">|</span> ^ ^
<span class="m">3</span> <span class="m">3</span><span class="o">(</span><span class="m">14</span><span class="o">)</span><span class="m">4</span> <span class="m">7</span><span class="o">(</span><span class="m">4</span><span class="o">)</span><span class="m">12</span> <span class="m">13</span><span class="o">(</span><span class="m">16</span><span class="o">)</span><span class="m">14</span> <span class="m">15</span><span class="o">(</span><span class="m">17</span><span class="o">)</span><span class="m">16</span> <span class="m">19</span><span class="o">(</span><span class="m">19</span><span class="o">)</span><span class="m">22</span> <span class="m">23</span><span class="o">(</span><span class="m">21</span><span class="o">)</span><span class="m">26</span>
^ <span class="p">|</span> <span class="p">|</span>
<span class="m">4</span> <span class="m">8</span><span class="o">(</span><span class="m">5</span><span class="o">)</span><span class="m">9</span> <span class="m">10</span><span class="o">(</span><span class="m">6</span><span class="o">)</span><span class="m">11</span> <span class="m">20</span><span class="o">(</span><span class="m">20</span><span class="o">)</span><span class="m">21</span> <span class="m">24</span><span class="o">(</span><span class="m">22</span><span class="o">)</span><span class="m">25</span>
</pre></div>
</div>
</div>
<div class="section" id="move-after">
<h2>Move after (перемещает ноду после текущей ноды)</h2>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">node</span> <span class="o">=</span> <span class="n">session</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">Tree</span><span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">Tree</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="mi">8</span><span class="p">)</span><span class="o">.</span><span class="n">one</span><span class="p">()</span>
<span class="n">node</span> <span class="o">=</span> <span class="n">session</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">Tree</span><span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">Tree</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="mi">8</span><span class="p">)</span><span class="o">.</span><span class="n">one</span><span class="p">()</span>
<span class="n">node</span><span class="o">.</span><span class="n">move_after</span><span class="p">(</span><span class="s2">"5"</span><span class="p">)</span>
</pre></div>
</div>
<p>получим:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>level Nested sets example
<span class="m">1</span> <span class="m">1</span><span class="o">(</span><span class="m">1</span><span class="o">)</span><span class="m">22</span>
_______________<span class="p">|</span>___________________
<span class="p">|</span> <span class="p">|</span> <span class="p">|</span>
<span class="m">2</span> <span class="m">2</span><span class="o">(</span><span class="m">2</span><span class="o">)</span><span class="m">5</span> <span class="m">6</span><span class="o">(</span><span class="m">4</span><span class="o">)</span><span class="m">11</span> <span class="m">12</span><span class="o">(</span><span class="m">7</span><span class="o">)</span><span class="m">21</span>
<span class="p">|</span> ^ ^
<span class="m">3</span> <span class="m">3</span><span class="o">(</span><span class="m">3</span><span class="o">)</span><span class="m">4</span> <span class="m">7</span><span class="o">(</span><span class="m">5</span><span class="o">)</span><span class="m">8</span> <span class="m">9</span><span class="o">(</span><span class="m">6</span><span class="o">)</span><span class="m">10</span> <span class="m">13</span><span class="o">(</span><span class="m">8</span><span class="o">)</span><span class="m">16</span> <span class="m">17</span><span class="o">(</span><span class="m">10</span><span class="o">)</span><span class="m">20</span>
<span class="p">|</span> <span class="p">|</span>
<span class="m">4</span> <span class="m">14</span><span class="o">(</span><span class="m">9</span><span class="o">)</span><span class="m">15</span> <span class="m">18</span><span class="o">(</span><span class="m">11</span><span class="o">)</span><span class="m">19</span>
level Move <span class="m">8</span> after <span class="m">5</span>
<span class="m">1</span> <span class="m">1</span><span class="o">(</span><span class="m">1</span><span class="o">)</span><span class="m">22</span>
_______________<span class="p">|</span>__________________
<span class="p">|</span> <span class="p">|</span> <span class="p">|</span>
<span class="m">2</span> <span class="m">2</span><span class="o">(</span><span class="m">2</span><span class="o">)</span><span class="m">5</span> <span class="m">6</span><span class="o">(</span><span class="m">4</span><span class="o">)</span><span class="m">15</span> <span class="m">16</span><span class="o">(</span><span class="m">7</span><span class="o">)</span><span class="m">21</span>
<span class="p">|</span> ^ <span class="p">|</span>
<span class="m">3</span> <span class="m">3</span><span class="o">(</span><span class="m">3</span><span class="o">)</span><span class="m">4</span> <span class="m">7</span><span class="o">(</span><span class="m">5</span><span class="o">)</span><span class="m">8</span> <span class="m">9</span><span class="o">(</span><span class="m">8</span><span class="o">)</span><span class="m">12</span> <span class="m">13</span><span class="o">(</span><span class="m">6</span><span class="o">)</span><span class="m">14</span> <span class="m">17</span><span class="o">(</span><span class="m">10</span><span class="o">)</span><span class="m">20</span>
<span class="p">|</span> <span class="p">|</span>
<span class="m">4</span> <span class="m">10</span><span class="o">(</span><span class="m">9</span><span class="o">)</span><span class="m">11</span> <span class="m">18</span><span class="o">(</span><span class="m">11</span><span class="o">)</span><span class="m">19</span>
</pre></div>
</div>
</div>
<div class="section" id="move-to-top-level">
<h2>Move to top level (выделение ноды в самостоятельное дерево)</h2>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">node</span> <span class="o">=</span> <span class="n">session</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">Tree</span><span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">Tree</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="mi">8</span><span class="p">)</span><span class="o">.</span><span class="n">one</span><span class="p">()</span>
<span class="n">node</span> <span class="o">=</span> <span class="n">session</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">Tree</span><span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">Tree</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="mi">15</span><span class="p">)</span><span class="o">.</span><span class="n">one</span><span class="p">()</span>
<span class="n">node</span><span class="o">.</span><span class="n">move_after</span><span class="p">(</span><span class="s2">"1"</span><span class="p">)</span>
</pre></div>
</div>
<p>получим:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>level <span class="nv">tree_id</span> <span class="o">=</span> <span class="m">1</span>
<span class="m">1</span> <span class="m">1</span><span class="o">(</span><span class="m">1</span><span class="o">)</span><span class="m">22</span>
_______________<span class="p">|</span>___________________
<span class="p">|</span> <span class="p">|</span> <span class="p">|</span>
<span class="m">2</span> <span class="m">2</span><span class="o">(</span><span class="m">2</span><span class="o">)</span><span class="m">5</span> <span class="m">6</span><span class="o">(</span><span class="m">4</span><span class="o">)</span><span class="m">11</span> <span class="m">12</span><span class="o">(</span><span class="m">7</span><span class="o">)</span><span class="m">21</span>
<span class="p">|</span> ^ ^
<span class="m">3</span> <span class="m">3</span><span class="o">(</span><span class="m">3</span><span class="o">)</span><span class="m">4</span> <span class="m">7</span><span class="o">(</span><span class="m">5</span><span class="o">)</span><span class="m">8</span> <span class="m">9</span><span class="o">(</span><span class="m">6</span><span class="o">)</span><span class="m">10</span> <span class="m">13</span><span class="o">(</span><span class="m">8</span><span class="o">)</span><span class="m">16</span> <span class="m">17</span><span class="o">(</span><span class="m">10</span><span class="o">)</span><span class="m">20</span>
<span class="p">|</span> <span class="p">|</span>
<span class="m">4</span> <span class="m">14</span><span class="o">(</span><span class="m">9</span><span class="o">)</span><span class="m">15</span> <span class="m">18</span><span class="o">(</span><span class="m">11</span><span class="o">)</span><span class="m">19</span>
level <span class="nv">tree_id</span> <span class="o">=</span> <span class="m">2</span>
<span class="m">1</span> <span class="m">1</span><span class="o">(</span><span class="m">15</span><span class="o">)</span><span class="m">6</span>
^
<span class="m">2</span> <span class="m">2</span><span class="o">(</span><span class="m">16</span><span class="o">)</span><span class="m">3</span> <span class="m">4</span><span class="o">(</span><span class="m">17</span><span class="o">)</span><span class="m">5</span>
level <span class="nv">tree_id</span> <span class="o">=</span> <span class="m">3</span>
<span class="m">1</span> <span class="m">1</span><span class="o">(</span><span class="m">12</span><span class="o">)</span><span class="m">16</span>
_______________<span class="p">|</span>
<span class="p">|</span> <span class="p">|</span>
<span class="m">2</span> <span class="m">2</span><span class="o">(</span><span class="m">13</span><span class="o">)</span><span class="m">5</span> <span class="m">6</span><span class="o">(</span><span class="m">18</span><span class="o">)</span><span class="m">15</span>
<span class="p">|</span> ^
<span class="m">3</span> <span class="m">3</span><span class="o">(</span><span class="m">14</span><span class="o">)</span><span class="m">4</span> <span class="m">7</span><span class="o">(</span><span class="m">19</span><span class="o">)</span><span class="m">10</span> <span class="m">11</span><span class="o">(</span><span class="m">21</span><span class="o">)</span><span class="m">14</span>
<span class="p">|</span> <span class="p">|</span>
<span class="m">4</span> <span class="m">8</span><span class="o">(</span><span class="m">20</span><span class="o">)</span><span class="m">9</span> <span class="m">12</span><span class="o">(</span><span class="m">22</span><span class="o">)</span><span class="m">13</span>
</pre></div>
</div>
<p>За основу был взят пример <code class="docutils literal"><span class="pre">Mike</span> <span class="pre">Bayer</span></code>, впринципе в тестах можно посмотреть
больше примеров. Ссылка на github: <a class="reference external" href="https://github.com/ITCase/sqlalchemy_mptt">https://github.com/ITCase/sqlalchemy_mptt</a></p>
</div>
</div>
Локальный Continuous Integration сервер
http://uralbash.ru/articles/2014/ci/
2014-04-13T04:40:00Z
2014-04-13T04:40:00Z
Uralbash
<div class="section" id="continuous-integration">
<img alt="_static/2014/ci1.jpg" class="align-center" src="_static/2014/ci1.jpg" style="width: 400px;" />
<p>Идея непрерывной интеграции заключается в том, что при любом изменении проекта
он пересобирается в условиях приближенных к реальной эксплуатации и каждый раз
запускает тесты. Это позволяет моментально отловить баги и исправить их не
отходя от кассы, пока ещё помнишь что понаписал.</p>
<blockquote>
<div>Принцип работы у всех примерно один:</div></blockquote>
<ul class="simple">
<li>скачать код</li>
<li>создать окружение</li>
<li>установить (собрать) код</li>
<li>запустить и протестировать</li>
<li>отправить уведомление</li>
</ul>
<p>Это можно сделать самостоятельно, например при помощи <code class="docutils literal"><span class="pre">fabric</span></code>, <a class="reference external" href="https://www.freebsd.org/cgi/man.cgi?query=cron">cron</a>,
<a class="reference external" href="https://www.freebsd.org/cgi/man.cgi?query=chroot">chroot</a> или <a class="reference external" href="http://docker.io/">docker</a> или при помощи готовых <code class="docutils literal"><span class="pre">CI</span></code> серверов:</p>
<ul class="simple">
<li><a class="reference external" href="http://jenkins-ci.org/">jenkins</a></li>
<li><a class="reference external" href="http://buildbot.net/">buildbot</a></li>
<li><a class="reference external" href="https://travis-ci.org/">travis-ci</a></li>
<li><a class="reference external" href="http://stridercd.com/">StriderCD</a></li>
<li><a class="reference external" href="https://github.com/drone/drone">drone</a></li>
</ul>
<p>Облачные <code class="docutils literal"><span class="pre">CI</span></code> сервера:</p>
<ul class="simple">
<li><a class="reference external" href="https://travis-ci.org/">https://travis-ci.org/</a></li>
<li><a class="reference external" href="https://drone.io">https://drone.io</a></li>
</ul>
<p>Облачный <code class="docutils literal"><span class="pre">CI</span></code> отлично подойдет для <code class="docutils literal"><span class="pre">OpenSource</span></code> проектов, а остальное можно
тестировать на локальном сервере.</p>
<p>Посмотрим как это работает на примере python + pyramid приложения.</p>
<img alt="_static/2014/ci2.JPG" class="align-center" src="_static/2014/ci2.JPG" style="width: 400px;" />
<div class="section" id="id1">
<h2>Начнём с Travis-ci</h2>
<a class="reference external image-reference" href="https://travis-ci.org/"><img alt="_static/2014/travis.png" class="align-left" src="_static/2014/travis.png" /></a>
<p>Следит за вашими репозитариями на <a class="reference external" href="https://github.com/">github</a>, выкачивает при каждом коммите,
собирает окружение в индивидуальном контейнере каждый раз, имеет простой
конфиг. Работает только с <a class="reference external" href="https://github.com/">github</a>, закрытые репы за деньги.</p>
<br clear="both"/><p>Авторизация через гитхаб аккаунт, дальше указываем что будем тестировать</p>
<img alt="_static/2014/travis1.png" src="_static/2014/travis1.png" />
<p>Теперь положим в корень репы на гитхабе файл с настройками <code class="docutils literal"><span class="pre">.travis.yml</span></code></p>
<img alt="_static/2014/travis3.png" src="_static/2014/travis3.png" />
<p>В этом файле находятся инструкции, какое окружение нужно для вашего проекта,
как его собирать, запускать тесты и куда слать уведомления.</p>
<div class="literal-block-wrapper docutils container" id="id3">
<div class="code-block-caption"><span class="caption-text">.travis.yml</span></div>
<div class="highlight-yaml"><div class="highlight"><pre><span></span><span class="l l-Scalar l-Scalar-Plain">language</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">python</span>
<span class="l l-Scalar l-Scalar-Plain">notifications</span><span class="p p-Indicator">:</span>
<span class="l l-Scalar l-Scalar-Plain">email</span><span class="p p-Indicator">:</span> <span class="s">"sacrud@uralbash.ru"</span>
<span class="l l-Scalar l-Scalar-Plain">email</span><span class="p p-Indicator">:</span> <span class="s">"arkadiy@bk.ru"</span>
<span class="l l-Scalar l-Scalar-Plain">python</span><span class="p p-Indicator">:</span>
<span class="l l-Scalar l-Scalar-Plain">1. "2.7"</span>
<span class="l l-Scalar l-Scalar-Plain">2. "2.6"</span>
<span class="l l-Scalar l-Scalar-Plain">install</span><span class="p p-Indicator">:</span>
<span class="l l-Scalar l-Scalar-Plain">1. pip install nose coverage coveralls</span>
<span class="l l-Scalar l-Scalar-Plain">2. pip install pyramid pyramid_jinja2 pyramid_beaker</span>
<span class="l l-Scalar l-Scalar-Plain">3. pip install -r requirements.txt</span>
<span class="l l-Scalar l-Scalar-Plain">script</span><span class="p p-Indicator">:</span>
<span class="l l-Scalar l-Scalar-Plain">1. nosetests --with-coverage --cover-package sacrud --cover-erase --with-doctest</span>
<span class="l l-Scalar l-Scalar-Plain">after_success</span><span class="p p-Indicator">:</span>
<span class="l l-Scalar l-Scalar-Plain">coveralls</span>
</pre></div>
</div>
</div>
<p>Здесь я думаю и так все понятно. <a class="reference external" href="https://pypi.python.org/pypi/coveralls">coveralls</a> нужен для сервиса
<a class="reference external" href="https://coveralls.io/">https://coveralls.io/</a> (про него ниже).</p>
<p>После каждого коммита создается задание в трависе которое заканчивается
примерно таким выводом <a class="reference external" href="https://travis-ci.org/ITCase/sacrud/jobs/22811094">https://travis-ci.org/ITCase/sacrud/jobs/22811094</a></p>
<p>Иногда СЕОшники всё портят как здесь
<a class="reference external" href="https://travis-ci.org/ITCase/sacrud/jobs/22688250">https://travis-ci.org/ITCase/sacrud/jobs/22688250</a> т.к. не умеют запускать
тесты, но благодаря <code class="docutils literal"><span class="pre">CI</span></code> эти проблемы сразу обнаруживаются.
Более сложный конфиг с установкой postgres
<a class="reference external" href="https://github.com/ITCase/pyramid_sacrud_example/blob/master/.travis.yml">https://github.com/ITCase/pyramid_sacrud_example/blob/master/.travis.yml</a></p>
</div>
<div class="section" id="drone-io">
<h2>drone.io</h2>
<img alt="_static/2014/drone.io.png" class="align-center" src="_static/2014/drone.io.png" />
<p><code class="docutils literal"><span class="pre">Drone</span></code> похож на <code class="docutils literal"><span class="pre">travis-ci</span></code> но он дешевле, умеет <code class="docutils literal"><span class="pre">bitbucket</span></code> и исходный
код <a class="reference external" href="https://github.com/drone/drone">https://github.com/drone/drone</a>. Очень удобно <code class="docutils literal"><span class="pre">OpenSource</span></code> в облаке,
приватные репы на локальном сервере и все это имеет одинаковый конфиг. Конфиг
<code class="docutils literal"><span class="pre">.drone.yml</span></code>, формат очень похож на <code class="docutils literal"><span class="pre">travis</span></code>.</p>
<div class="literal-block-wrapper docutils container" id="id4">
<div class="code-block-caption"><span class="caption-text">.drone.yml</span></div>
<div class="highlight-yaml"><div class="highlight"><pre><span></span><span class="l l-Scalar l-Scalar-Plain">image</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">python2.7</span>
<span class="l l-Scalar l-Scalar-Plain">script</span><span class="p p-Indicator">:</span>
<span class="l l-Scalar l-Scalar-Plain">1. pip install nose coverage pyramid pyramid_jinja2 pyramid_beaker</span>
<span class="l l-Scalar l-Scalar-Plain">2. pip install -r requirements.txt</span>
<span class="l l-Scalar l-Scalar-Plain">3. nosetests --cover-package=sacrud --cover-erase --with-coverage --with-doctest</span>
<span class="l l-Scalar l-Scalar-Plain">notify</span><span class="p p-Indicator">:</span>
<span class="l l-Scalar l-Scalar-Plain">email</span><span class="p p-Indicator">:</span>
<span class="l l-Scalar l-Scalar-Plain">recipients</span><span class="p p-Indicator">:</span>
<span class="l l-Scalar l-Scalar-Plain">1. sacrud@uralbash.ru</span>
</pre></div>
</div>
</div>
<p>С облаком всё понятно, установим <code class="docutils literal"><span class="pre">drone</span></code> локально. В качестве платформы
используется VM с Ubuntu server 12.04 с одним ядром и 2Гб ОЗУ, что вполне
достаточно для небольшой команды программистов.</p>
<p>Т.к. drone собирает проекты в легковесных контенерах при помощи <a class="reference external" href="http://docker.io/">Docker</a>
вначале установим его
<a class="reference external" href="http://docs.docker.io/en/latest/installation/ubuntulinux/#ubuntu-precise">http://docs.docker.io/en/latest/installation/ubuntulinux/#ubuntu-precise</a></p>
<p>Сам drone устанавливается очень просто через <code class="docutils literal"><span class="pre">deb</span></code> пакет
<a class="reference external" href="http://drone.readthedocs.org/en/latest/install.html">http://drone.readthedocs.org/en/latest/install.html</a>, теперь он у вас висит на
80 порту или на том который вы указали. Запускается и конфигурируется через
upstart (<code class="docutils literal"><span class="pre">sudo</span> <span class="pre">start</span> <span class="pre">drone</span></code>, <code class="docutils literal"><span class="pre">sudo</span> <span class="pre">stop</span> <span class="pre">drone</span></code>). Можно проверить локально,
если перейти в репозитарий проекта с файлом <code class="docutils literal"><span class="pre">.drone.yml</span></code> и запустить <code class="docutils literal"><span class="pre">drone</span>
<span class="pre">build</span></code>.</p>
<p>Для того что бы github или bitbucket слал уведомление вашему drone серверу
нужен статический IP. Пробросим порты к виртуалке на роутере :) и укажем IP в
настройках:</p>
<img alt="_static/2014/drone1.png" class="align-center" src="_static/2014/drone1.png" />
<p>добавим репу:</p>
<img alt="_static/2014/drone2.png" class="align-center" src="_static/2014/drone2.png" />
<p>После добавления в гитхаб появится новый аппликайшин:</p>
<img alt="_static/2014/drone3.png" class="align-center" src="_static/2014/drone3.png" />
<p><code class="docutils literal"><span class="pre">Client</span> <span class="pre">ID</span></code> и <code class="docutils literal"><span class="pre">Client</span> <span class="pre">Secret</span></code> нужно указать в настройках drone. Теперь
комитим и чиним.</p>
<img alt="_static/2014/drone4.png" class="align-center" src="_static/2014/drone4.png" />
<p>Для приватных реп drone автоматически прописывает RSA ключ. Его можно
посмотреть в настройках репы и скопировать вручную например или поменять.</p>
<p>Вывод похож на travis:</p>
<img alt="_static/2014/drone5.png" class="align-center" src="_static/2014/drone5.png" />
<p>Пару слов почему не другие системы. Во первых <code class="docutils literal"><span class="pre">drone</span></code> это и облако и локалхост,
дальше bitbucket+github, контейнеры docker из коробки, иконка-статус сборки в
Markdown, написан на Go как и Docker. Из недостатков пока мало свистелок и
перделок, первое что бросается в глаза отсутствие кнопки REBUILD (пересобрать
вручную). Но т.к. проект молодой то всё обещают запилить в следующей версии,
судя по issue на github’е.</p>
<p><code class="docutils literal"><span class="pre">Jenkins</span></code> страшный, сложный, всё пилить руками, докера нет, написан на Java.</p>
<p><code class="docutils literal"><span class="pre">Buildbot</span></code> написан на python, хорошая архитектура master-slave, можно запилить
slave в контейнеры, но написан на старой версии twisted и sqlalchemy аж 0.7
версии, код ужасен, инструкции из документации устаревшие, нужно додумывать,
конфиг сложный, будущего у системы нет.</p>
<p><code class="docutils literal"><span class="pre">StriderCD</span></code> написан на nodejs, много чего есть из коробки, принцип плагинов
через npm, docker пилить самому, глючный :( хотя выглядит неплохо.</p>
<p>Есть ещё альтернативы типа gitlab-ci и наверняка ещё что-то, но я их не смотрел.</p>
</div>
<div class="section" id="coveralls">
<h2>Coveralls</h2>
<div class="figure align-center" id="id5">
<img alt="_static/2014/coverrals1.png" src="_static/2014/coverrals1.png" />
<p class="caption"><span class="caption-text"><a class="reference external" href="https://coveralls.io/r/ITCase/sacrud">https://coveralls.io/r/ITCase/sacrud</a></span></p>
</div>
<div class="figure align-center">
<img alt="_static/2014/coverrals2.png" src="_static/2014/coverrals2.png" />
</div>
<p>Coveralls отличное дополнение, в котором можно визуально отследить что ещё не
покрыто тестами. Из минусов, нет bitbucket, мне показался он дороговатым для
приватных реп и ещё лежит отдавая 503 на момент написания этой статьи, но
локальных альтернатив я не нашёл, к сожалению.</p>
</div>
<div class="section" id="anykey">
<h2>AnyKey</h2>
<div class="line-block">
<div class="line"><a class="reference external" href="http://jmcvetta.github.io/blog/2013/08/30/continuous-integration-for-go-code/">http://jmcvetta.github.io/blog/2013/08/30/continuous-integration-for-go-code/</a></div>
<div class="line"><a class="reference external" href="http://lucapette.com/go/go-docker-and-a-ci-server/">http://lucapette.com/go/go-docker-and-a-ci-server/</a></div>
</div>
</div>
<div class="section" id="id2">
<h2>И напоследок...</h2>
<p>В этом обзоре показан простой пример как можно настроить непрерывную интеграцию
проекта на python и pyramid. Но по аналогии можно поднять любой другой проект.
Думаю вам эта статья поможет, хотя бы начать писать тесты :)</p>
<img alt="_static/2014/ci_end.jpg" class="align-center" src="_static/2014/ci_end.jpg" />
</div>
</div>
Пишем на Go (Golang)
http://uralbash.ru/articles/2014/go/
2014-04-06T00:58:00Z
2014-04-06T00:58:00Z
Uralbash
<div class="section" id="go-golang">
<img alt="_static/2014/go.png" class="align-left" src="_static/2014/go.png" />
<p>Go замечательный язык программирования, который можно компилировать,
компилировать под разные платформы (<code class="docutils literal"><span class="pre">ARM</span></code>, <code class="docutils literal"><span class="pre">x86</span></code>), распараллеливать. Он
проще <code class="docutils literal"><span class="pre">C/C++</span></code> и уже сформировавшийся язык в отличии от <code class="docutils literal"><span class="pre">Rust</span></code> который
ломает программы с каждым обновлением. Область применения самая разная начиная
от консольных утилит, всяких парсеров, системного, сетевого ПО, связи с
физическими устройствами и заканчивая веб приложениями, <span class="strike">разве что пока нету
реализаций под смартфоны</span> (<a class="reference external" href="https://docs.google.com/document/d/1N3XyVkAP8nmWjASz8L_OjjnjVKxgeVBjIsTr5qIUcA4/edit">android</a>).</p>
<br clear="both"/><p>На Go уже написаны:</p>
<ul class="simple">
<li><a class="reference external" href="http://docker.io/">Docker</a> - система легковесных контейнеров (переписан с <a class="reference external" href="http://www.python.org/">python</a>)</li>
<li><a class="reference external" href="http://drone.io">http://drone.io</a> - система непрерывного тестирования, поддерживающая
<a class="reference external" href="http://docker.io/">Docker</a> (о ней я напишу отдельно скорее всего) и огромное количество
других проектов, что удивительно ведь <a class="reference external" href="https://golang.org/">go</a> очень молодой проект, а ещё гугл</li>
</ul>
<p>Здесь я опишу процесс одной из возможных реализаций установки <a class="reference external" href="https://golang.org/">Go</a> под
<a class="reference external" href="https://www.kernel.org/">Linux</a>.</p>
<div class="section" id="id1">
<h2>УСТАНОВКА</h2>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<p class="last">Более простой способ <a class="reference external" href="https://github.com/moovweb/gvm">moovweb/gvm</a></p>
</div>
<div class="line-block">
<div class="line">описано подробно в оф. документации <a class="reference external" href="http://golang.org/doc/install">http://golang.org/doc/install</a></div>
<div class="line"><a class="reference external" href="http://code.google.com/p/go/downloads/list?q=OpSys-FreeBSD+OR+OpSys-Linux+OR+OpSys-OSX+Type-Archive">Скачать архив</a> и распаковать в <code class="docutils literal"><span class="pre">~/golang</span></code> например:</div>
</div>
<br><div class="highlight-bash"><div class="highlight"><pre><span></span>$ tar -C ~/golang -xzf go1.2.1.linux-amd64.tar.gz
</pre></div>
</div>
<p>Добавляем в <code class="docutils literal"><span class="pre">~/.bashrc</span></code>:</p>
<div class="literal-block-wrapper docutils container" id="id5">
<div class="code-block-caption"><span class="caption-text">~/.bashrc</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># Go lang</span>
<span class="nb">export</span> <span class="nv">GOROOT</span><span class="o">=</span><span class="nv">$HOME</span>/golang
<span class="nb">export</span> <span class="nv">PATH</span><span class="o">=</span><span class="nv">$PATH</span>:<span class="nv">$GOROOT</span>/bin
</pre></div>
</div>
</div>
<p>создаем файл <code class="docutils literal"><span class="pre">hello.go</span></code>:</p>
<div class="literal-block-wrapper docutils container" id="id6">
<div class="code-block-caption"><span class="caption-text">hello.go</span></div>
<div class="highlight-go"><div class="highlight"><pre><span></span><span class="kn">package</span> <span class="nx">main</span>
<span class="kn">import</span> <span class="s">"fmt"</span>
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"hello, world\n"</span><span class="p">)</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
<p>и выполняем так:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ go run hello.go
hello, world
</pre></div>
</div>
<p>или компилируем:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ go build hello.go
$ ./hello
hello, world
</pre></div>
</div>
<p>теперь у нас установлен <a class="reference external" href="https://golang.org/">go</a> в системе. Если вам нужно свои пакеты хранить в
другой директории (не <code class="docutils literal"><span class="pre">$HOME/golang</span></code>), но при этом что бы они находились в
общем окружении, то можно задать переменную окружения <code class="docutils literal"><span class="pre">GOPATH</span></code>. У меня всё
вместе выглядит так:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># Go lang</span>
<span class="nb">export</span> <span class="nv">GOPATH</span><span class="o">=</span><span class="nv">$HOME</span>/Projects/go
<span class="nb">export</span> <span class="nv">GOROOT</span><span class="o">=</span><span class="nv">$HOME</span>/golang
<span class="nb">export</span> <span class="nv">PATH</span><span class="o">=</span><span class="nv">$PATH</span>:<span class="nv">$GOROOT</span>/bin:<span class="nv">$GOPATH</span>/bin
</pre></div>
</div>
</div>
<div class="section" id="vim">
<h2>VIM</h2>
<p>есть много дополнений для go но самая крутое из них это <a class="reference external" href="https://github.com/fatih/vim-go">https://github.com/fatih/vim-go</a>
пример <code class="docutils literal"><span class="pre">.vimrc</span></code>:</p>
<div class="highlight-vim"><div class="highlight"><pre><span></span><span class="k">au</span> <span class="nb">BufNewFile</span><span class="p">,</span><span class="nb">BufRead</span> *.<span class="k">go</span> <span class="k">set</span> <span class="nb">ft</span><span class="p">=</span><span class="k">go</span> <span class="k">nu</span>
<span class="k">au</span> <span class="nb">FileType</span> <span class="k">go</span> map <span class="p"><</span>leader<span class="p">></span><span class="k">r</span> :<span class="p">!</span><span class="k">go</span> run %<span class="p"><</span>CR<span class="p">></span>
Bundle <span class="s2">"fatih/vim-go"</span>
</pre></div>
</div>
<p><code class="docutils literal"><span class="pre">vim-go</span></code> умеет:</p>
<ul class="simple">
<li>подсветка синтаксиса</li>
<li>автодополнение кода gocode</li>
<li>автоформатирование кода через gofmt</li>
<li>автоимпорт недостающих библиотек goimports</li>
<li>проверять код на наличие ошибок с помощью golint</li>
<li>поддерживает снипеты ultisnips or neosnippet</li>
<li>и многое другое</li>
</ul>
<iframe width="420" height="315"
src="https://www.youtube.com/embed/rD11pEx5h8c" frameborder="0"
allowfullscreen></iframe></div>
<div class="section" id="id3">
<h2>КНИГИ</h2>
<p>книг много, но на великом только одна от издательства ДМК пресс, к счастью есть
эл.вариант книги хоть и в pdf.</p>
<a class="reference external image-reference" href="http://dmkpress.com/catalog/computer/programming/978-5-94074-854-0/"><img alt="_static/2014/go_book.jpg" class="align-center" src="_static/2014/go_book.jpg" /></a>
</div>
<div class="section" id="id4">
<h2>Ресурсы</h2>
<div class="line-block">
<div class="line"><a class="reference external" href="http://4gophers.com/">http://4gophers.com/</a> (ru)</div>
<div class="line">#go-nuts in the irc.freenode.org network.</div>
<div class="line"><a class="reference external" href="http://blog.golang.org/">http://blog.golang.org/</a></div>
<div class="line">google group</div>
<div class="line">reddit</div>
</div>
</div>
<div class="section" id="anykey">
<h2>AnyKey</h2>
<div class="line-block">
<div class="line">Использование Си в Гоу</div>
<div class="line"><a class="reference external" href="http://zacg.github.io/blog/2013/06/06/calling-c-plus-plus-code-from-go-with-swig/">http://zacg.github.io/blog/2013/06/06/calling-c-plus-plus-code-from-go-with-swig/</a></div>
<div class="line"><br /></div>
<div class="line">ORM</div>
<div class="line"><a class="reference external" href="https://github.com/eaigner/hood">https://github.com/eaigner/hood</a></div>
<div class="line"><a class="reference external" href="https://github.com/jinzhu/gorm">https://github.com/jinzhu/gorm</a></div>
<div class="line"><br /></div>
<div class="line">Web</div>
<div class="line">Revel</div>
<div class="line">Gorilla</div>
<div class="line">net/http</div>
<div class="line"><br /></div>
<div class="line">Список пакетов</div>
<div class="line"><a class="reference external" href="https://code.google.com/p/go-wiki/wiki/Projects">https://code.google.com/p/go-wiki/wiki/Projects</a></div>
<div class="line"><br /></div>
<div class="line">Go для программистов C++</div>
<div class="line"><a class="reference external" href="http://netsago.org/ru/docs/1/16/">http://netsago.org/ru/docs/1/16/</a></div>
<div class="line"><a class="reference external" href="http://eao197.narod.ru/desc/short_effective_go.html">http://eao197.narod.ru/desc/short_effective_go.html</a></div>
<div class="line"><br /></div>
<div class="line"><br /></div>
<div class="line">Calling Go from Python via JSON-RPC</div>
<div class="line">www.artima.com/weblogs/viewpost.jsp?thread=333589</div>
<div class="line"><br /></div>
<div class="line">Go для Python программистов</div>
<div class="line"><a class="reference external" href="http://www.slideshare.net/kcherkasoff/go-for">http://www.slideshare.net/kcherkasoff/go-for</a>-pythonistas#</div>
<div class="line"><br /></div>
<div class="line">Тесты</div>
<div class="line"><a class="reference external" href="http://smartystreets.github.io/goconvey/">http://smartystreets.github.io/goconvey/</a></div>
<div class="line"><br /></div>
<div class="line">Примеры</div>
<div class="line"><a class="reference external" href="https://gobyexample.com/">https://gobyexample.com/</a></div>
<div class="line"><br /></div>
<div class="line">CI</div>
<div class="line"><a class="reference external" href="https://github.com/drone/drone">https://github.com/drone/drone</a></div>
<div class="line"><br /></div>
<div class="line">Хайлод++</div>
<div class="line"><a class="reference external" href="http://www.youtube.com/watch?v=bqtN6XViejE">http://www.youtube.com/watch?v=bqtN6XViejE</a></div>
<div class="line"><br /></div>
<div class="line">Туториал</div>
<div class="line"><a class="reference external" href="http://tour.golang.org/">http://tour.golang.org/</a></div>
<div class="line"><br /></div>
</div>
<img alt="_static/2014/gopher.png" class="align-center" src="_static/2014/gopher.png" />
</div>
</div>
Перенос БД с sqlite на postgres
http://uralbash.ru/articles/2014/sqlite_to_pg/
2014-03-15T17:53:00Z
2014-03-15T17:53:00Z
Uralbash
<div class="section" id="sqlite-postgres">
<p><code class="docutils literal"><span class="pre">ORM</span></code> позволяет быстро переключатся между БД не учитывая их диалект
(практически). Но данные хранятся физически в разных местах и естественно их
надо переносить, например при переключении с <a class="reference external" href="http://sqlite.org/">sqlite</a> на <a class="reference external" href="http://postgresql.org">PostgreSQL</a>. В
<a class="reference external" href="https://www.djangoproject.com/">Django</a> есть встроенный функционал в виде:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># Выгрузка в JSON</span>
$ python manage.py dumpdata myapp.A > a.json
<span class="c1"># Загрузка из JSON</span>
$ python manage.py loaddata a.json
</pre></div>
</div>
<p>Т.е. мы выгружаем данные из <a class="reference external" href="http://sqlite.org/">sqlite</a> в <code class="docutils literal"><span class="pre">JSON</span></code> формат, затем меняем строку
подключения на <a class="reference external" href="http://postgresql.org">postgres</a> и выполняем загрузку из <code class="docutils literal"><span class="pre">JSON</span></code>. Очень удобно, но
почему то этот метод не работает, либо работает только при переносе из <code class="docutils literal"><span class="pre">sqlite</span>
<span class="pre">-></span> <span class="pre">sqlite</span></code>, что в принципе не очень интересно, точнее бессмысленно. Есть какие
то решений с бубном как это вот:</p>
<div class="line-block">
<div class="line"><a class="reference external" href="http://macrotoma.blogspot.ru/2012/10/solved-move-django-from-sqlite-to-mysql.html">http://macrotoma.blogspot.ru/2012/10/solved-move-django-from-sqlite-to-mysql.html</a>,</div>
<div class="line"><a class="reference external" href="http://blog.abourget.net/2009/7/7/exporting-sql-schemas-from-sqlalchemy-table-definitions/">http://blog.abourget.net/2009/7/7/exporting-sql-schemas-from-sqlalchemy-table-definitions/</a>.</div>
</div>
<p>Эти методы не универсальны, потому что имеют привязку к моделям (ORM), требуют
для переноса проект на <a class="reference external" href="https://www.djangoproject.com/">Django</a> и ручные действия вроде создания схемы и
выполнения миграций (далеко не всегда миграции созданы правильно).</p>
<p>Я написал небольшой пример как можно перевести данные не имея фреймворков, не
привязываясь к моделям, указав только две строки подключения откуда переносить
и куда (вроде было что то похожее на руби). За основы взят пример из этой статьи
<a class="reference external" href="http://www.tylerlesmann.com/2009/apr/27/copying-databases-across-platforms-sqlalchemy/">http://www.tylerlesmann.com/2009/apr/27/copying-databases-across-platforms-sqlalchemy/</a>.
Где предлагается указать дополнительно названия таблиц.</p>
<p>В <a class="reference external" href="http://sqlalchemy.org/">sqlalchemy</a> с весии 9.1 появилась встроенная возможность автоматического
определения схемы БД
<a class="reference external" href="http://docs.sqlalchemy.org/en/rel_0_9/orm/extensions/automap.html">http://docs.sqlalchemy.org/en/rel_0_9/orm/extensions/automap.html</a>. Правда
намного раньше появились сторонние решения:</p>
<ul class="simple">
<li><a class="reference external" href="http://turbogears.org/2.1/docs/main/Utilities/sqlautocode.html">http://turbogears.org/2.1/docs/main/Utilities/sqlautocode.html</a></li>
<li><a class="reference external" href="https://sqlsoup.readthedocs.org/en/latest/">https://sqlsoup.readthedocs.org/en/latest/</a>.</li>
</ul>
<p>Первое что мы сделаем, это получим схему БД:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">sqlalchemy.ext.automap</span> <span class="kn">import</span> <span class="n">automap_base</span>
<span class="k">def</span> <span class="nf">get_metadata</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">engine</span><span class="p">):</span>
<span class="c1"># produce our own MetaData object</span>
<span class="n">metadata</span> <span class="o">=</span> <span class="n">MetaData</span><span class="p">()</span>
<span class="c1"># we can reflect it ourselves from a database, using options</span>
<span class="c1"># such as 'only' to limit what tables we look at...</span>
<span class="c1"># only = ['news_news', 'pages_page']</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">only</span><span class="p">:</span>
<span class="n">metadata</span><span class="o">.</span><span class="n">reflect</span><span class="p">(</span><span class="n">engine</span><span class="p">,</span> <span class="n">only</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">only</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">metadata</span><span class="o">.</span><span class="n">reflect</span><span class="p">(</span><span class="n">engine</span><span class="p">)</span>
<span class="c1"># we can then produce a set of mappings from this MetaData.</span>
<span class="n">Base</span> <span class="o">=</span> <span class="n">automap_base</span><span class="p">(</span><span class="n">metadata</span><span class="o">=</span><span class="n">metadata</span><span class="p">)</span>
<span class="c1"># calling prepare() just sets up mapped classes and relationships.</span>
<span class="n">Base</span><span class="o">.</span><span class="n">prepare</span><span class="p">()</span>
<span class="k">return</span> <span class="n">metadata</span><span class="p">,</span> <span class="n">Base</span>
</pre></div>
</div>
<p>Дальше получаем все таблицы:</p>
<p><code class="docutils literal"><span class="pre">tables</span> <span class="pre">=</span> <span class="pre">Base.classes</span></code></p>
<p>Создаем такую же структуру БД в <a class="reference external" href="http://postgresql.org">postgres</a>:</p>
<p><code class="docutils literal"><span class="pre">metadata.create_all(self.engine_dst)</span></code></p>
<p>По очереди проходим каждую таблицу и переносим из нее данные в новую БД:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">table</span> <span class="ow">in</span> <span class="n">tables</span><span class="p">:</span>
<span class="n">columns</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="n">__table__</span><span class="o">.</span><span class="n">c</span><span class="o">.</span><span class="n">keys</span><span class="p">()</span>
<span class="k">print</span> <span class="s1">'Transferring records to </span><span class="si">%s</span><span class="s1">'</span> <span class="o">%</span> <span class="n">table</span><span class="o">.</span><span class="n">__table__</span><span class="o">.</span><span class="n">name</span>
<span class="k">for</span> <span class="n">record</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">table</span><span class="p">)</span><span class="o">.</span><span class="n">all</span><span class="p">():</span>
<span class="n">data</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span>
<span class="p">[(</span><span class="nb">str</span><span class="p">(</span><span class="n">column</span><span class="p">),</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">record</span><span class="p">,</span> <span class="n">column</span><span class="p">))</span> <span class="k">for</span> <span class="n">column</span> <span class="ow">in</span> <span class="n">columns</span><span class="p">]</span>
<span class="p">)</span>
<span class="n">NewRecord</span> <span class="o">=</span> <span class="n">quick_mapper</span><span class="p">(</span><span class="n">table</span><span class="o">.</span><span class="n">__table__</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">session_dst</span><span class="o">.</span><span class="n">merge</span><span class="p">(</span><span class="n">NewRecord</span><span class="p">(</span><span class="o">**</span><span class="n">data</span><span class="p">))</span>
<span class="bp">self</span><span class="o">.</span><span class="n">session_dst</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
</pre></div>
</div>
<p>Если возникли конфликты можно их решить переопределением типов полей. Например
при переносе из <a class="reference external" href="http://sqlite.org/">sqlite</a> в <a class="reference external" href="http://postgresql.org">postgres</a> тип полей <code class="docutils literal"><span class="pre">DATETIME</span></code> нужно
заменить на <code class="docutils literal"><span class="pre">DateTime</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">dialect</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">engine</span><span class="o">.</span><span class="n">dialect</span><span class="o">.</span><span class="n">name</span>
<span class="n">dialect_dst</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">engine_dst</span><span class="o">.</span><span class="n">dialect</span><span class="o">.</span><span class="n">name</span>
<span class="k">if</span> <span class="n">dialect</span> <span class="o">==</span> <span class="n">dialect_dst</span><span class="p">:</span>
<span class="k">return</span>
<span class="k">for</span> <span class="n">table</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">tables</span><span class="p">:</span>
<span class="n">columns</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="n">__table__</span><span class="o">.</span><span class="n">c</span>
<span class="k">for</span> <span class="n">column</span> <span class="ow">in</span> <span class="n">columns</span><span class="p">:</span>
<span class="k">if</span> <span class="n">dialect_dst</span> <span class="o">==</span> <span class="s1">'postgresql'</span><span class="p">:</span>
<span class="c1"># DATETIME->DateTime</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">column</span><span class="o">.</span><span class="n">type</span><span class="p">,</span> <span class="n">DATETIME</span><span class="p">):</span>
<span class="n">column</span><span class="o">.</span><span class="n">type</span> <span class="o">=</span> <span class="n">DateTime</span><span class="p">()</span>
</pre></div>
</div>
<p>Пример запуска:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ python convertdbdata.py -f <span class="s2">"sqlite:///fromMydb.sqlite"</span> -t <span class="s2">"postgresql://postgres:postgres@localhost/toMydb"</span> -i <span class="s2">"auth_user,news_news"</span>
</pre></div>
</div>
<p><code class="docutils literal"><span class="pre">-i</span></code> параметр указывает какие таблицы нужно запускать первыми, например в такой ситуации:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>DETAIL: Ключ <span class="o">(</span>user_id<span class="o">)=(</span><span class="m">1</span><span class="o">)</span> отсутствует в таблице <span class="s2">"auth_user"</span>.
<span class="s1">'INSERT INTO django_admin_log (id, action_time, user_id, content_type_id, object_id, object_repr, action_flag,</span>
<span class="s1"> change_message) VALUES (%(id)s, %(action_time)s, %(user_id)s, %(content_type_id)s, %(object_id)s, %(object_repr)s,</span>
<span class="s1"> %(action_flag)s, %(change_message)s)'</span> <span class="o">{</span><span class="s1">'action_flag'</span>: <span class="m">1</span>, <span class="s1">'action_time'</span>: datetime.datetime<span class="o">(</span><span class="m">2014</span>, <span class="m">2</span>, <span class="m">5</span>, <span class="m">13</span>, <span class="m">15</span>, <span class="m">27</span>, <span class="m">948000</span><span class="o">)</span>,
<span class="s1">'user_id'</span>: <span class="m">1</span>, <span class="s1">'content_type_id'</span>: <span class="m">39</span>, <span class="s1">'object_repr'</span>: u<span class="s1">'dfgsdfg'</span>, <span class="s1">'object_id'</span>: u<span class="s1">'1'</span>, <span class="s1">'change_message'</span>: u<span class="s1">''</span>, <span class="s1">'id'</span>: <span class="m">1</span><span class="o">}</span>
</pre></div>
</div>
<p>Код полностью <a class="reference external" href="https://github.com/ITCase/convertdbdata">https://github.com/ITCase/convertdbdata</a></p>
<p>Сейчас скрипт не рассчитан на большие объемы данных и учитывает только разницу
в <code class="docutils literal"><span class="pre">DateTime</span></code> поле, но думаю это легко исправить по мере поступления задач.</p>
</div>
Обновление sacrud. Версия 0.1.2
http://uralbash.ru/articles/2014/sacrud_release_0.1.2/
2014-03-10T14:34:00Z
2014-03-10T14:34:00Z
Uralbash
<div class="section" id="sacrud-0-1-2">
<img alt="_static/2014/sacrud_0_1_2.png" class="align-left" src="_static/2014/sacrud_0_1_2.png" />
<div class="line-block">
<div class="line">Код: <a class="reference external" href="https://github.com/uralbash/sacrud">https://github.com/uralbash/sacrud</a></div>
<div class="line">Описание: <a class="reference external" href="http://sacrud.readthedocs.org/">http://sacrud.readthedocs.org/</a></div>
</div>
<p>В этой версии делался упор на кастомизацию интерфейса.</p>
<p>Что нового?</p>
<ul class="simple">
<li>добавлена пагинация</li>
<li>теперь pk показывается по умолчанию в форме создания/редактирования</li>
<li>новая опция <code class="docutils literal"><span class="pre">sacrud_detail_col</span></code> где можно задать отображаемые поля в форме редактирования</li>
<li>новая опция <code class="docutils literal"><span class="pre">sacrud_list_col</span></code> где можно задать отображаемые поля в списке записей</li>
<li>новая опция <code class="docutils literal"><span class="pre">verbose_name</span></code> для полей и таблиц</li>
<li>опция <code class="docutils literal"><span class="pre">sacrud_css_class</span></code>, назначает <code class="docutils literal"><span class="pre">CSS</span></code> стили полям</li>
<li>новый атрибут колонки <code class="docutils literal"><span class="pre">sacrud_position</span></code>: “inline” (см. реализацию <code class="docutils literal"><span class="pre">horizontal_fields</span></code>)</li>
<li>новая функция <code class="docutils literal"><span class="pre">horizontal_fields</span></code></li>
<li>новый тип <code class="docutils literal"><span class="pre">exttype.GUID</span></code></li>
<li>для переопределения <code class="docutils literal"><span class="pre">base.html</span></code> создан шаблон <code class="docutils literal"><span class="pre">redefineme.html</span></code></li>
<li>вывод флеш уведомлений если задана <code class="docutils literal"><span class="pre">sesion_factory</span></code></li>
<li>исправлены названия классов в шаблонах у полей</li>
<li>исправлен шаблон <code class="docutils literal"><span class="pre">ForeignKey.jinja2</span></code></li>
<li><code class="docutils literal"><span class="pre">sa_create</span></code>, <code class="docutils literal"><span class="pre">sa_read</span></code>, <code class="docutils literal"><span class="pre">sa_update</span></code>, <code class="docutils literal"><span class="pre">sa_delete</span></code> view вынесены в общий класс <code class="docutils literal"><span class="pre">CRUD</span></code></li>
<li>в example добавлены <a class="reference external" href="https://pypi.python.org/pypi/pyramid_beaker">pyramid_beaker</a>, примеры с кастомизацией, FileField и все
остальные поля которые есть в sacrud/templates/sacrud/types.</li>
</ul>
<p>Пример кастомизации:</p>
<div class="literal-block-wrapper docutils container" id="id1">
<div class="code-block-caption"><span class="caption-text">models.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">TestCustomizing</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s2">"test_customizing"</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">name</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">)</span>
<span class="n">date</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Date</span><span class="p">,</span> <span class="n">info</span><span class="o">=</span><span class="p">{</span><span class="s2">"verbose_name"</span><span class="p">:</span> <span class="s1">'date JQuery-ui'</span><span class="p">})</span>
<span class="n">name_ru</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">,</span> <span class="n">info</span><span class="o">=</span><span class="p">{</span><span class="s2">"verbose_name"</span><span class="p">:</span> <span class="sa">u</span><span class="s1">'Название'</span><span class="p">,</span> <span class="p">})</span>
<span class="n">name_fr</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">,</span> <span class="n">info</span><span class="o">=</span><span class="p">{</span><span class="s2">"verbose_name"</span><span class="p">:</span> <span class="sa">u</span><span class="s1">'nom'</span><span class="p">,</span> <span class="p">})</span>
<span class="n">name_bg</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">,</span> <span class="n">info</span><span class="o">=</span><span class="p">{</span><span class="s2">"verbose_name"</span><span class="p">:</span> <span class="sa">u</span><span class="s1">'Име'</span><span class="p">,</span> <span class="p">})</span>
<span class="n">name_cze</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">,</span> <span class="n">info</span><span class="o">=</span><span class="p">{</span><span class="s2">"verbose_name"</span><span class="p">:</span> <span class="sa">u</span><span class="s1">'název'</span><span class="p">,</span> <span class="p">})</span>
<span class="n">description</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Text</span><span class="p">)</span>
<span class="n">description2</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Text</span><span class="p">)</span>
<span class="n">visible</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Boolean</span><span class="p">)</span>
<span class="n">in_menu</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Boolean</span><span class="p">,</span> <span class="n">info</span><span class="o">=</span><span class="p">{</span><span class="s2">"verbose_name"</span><span class="p">:</span> <span class="sa">u</span><span class="s1">'menu?'</span><span class="p">,</span> <span class="p">})</span>
<span class="n">in_banner</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Boolean</span><span class="p">,</span> <span class="n">info</span><span class="o">=</span><span class="p">{</span><span class="s2">"verbose_name"</span><span class="p">:</span> <span class="sa">u</span><span class="s1">'on banner?'</span><span class="p">,</span> <span class="p">})</span>
<span class="c1"># SACRUD</span>
<span class="n">verbose_name</span> <span class="o">=</span> <span class="sa">u</span><span class="s1">'Customizing table'</span>
<span class="n">sacrud_css_class</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'tinymce'</span><span class="p">:</span> <span class="p">[</span><span class="n">description</span><span class="p">,</span> <span class="n">description2</span><span class="p">],</span>
<span class="s1">'content'</span><span class="p">:</span> <span class="p">[</span><span class="n">description</span><span class="p">],</span>
<span class="s1">'name'</span><span class="p">:</span> <span class="p">[</span><span class="n">name</span><span class="p">],</span> <span class="s1">'Date'</span><span class="p">:</span> <span class="p">[</span><span class="n">date</span><span class="p">]}</span>
<span class="n">sacrud_list_col</span> <span class="o">=</span> <span class="p">[</span><span class="n">name</span><span class="p">,</span> <span class="n">name_ru</span><span class="p">,</span> <span class="n">name_cze</span><span class="p">]</span>
<span class="n">sacrud_detail_col</span> <span class="o">=</span> <span class="p">[</span><span class="n">name</span><span class="p">,</span>
<span class="n">hosrizontal_field</span><span class="p">(</span><span class="n">name_ru</span><span class="p">,</span> <span class="n">name_bg</span><span class="p">,</span> <span class="n">name_fr</span><span class="p">,</span> <span class="n">name_cze</span><span class="p">,</span>
<span class="n">sacrud_name</span><span class="o">=</span><span class="sa">u</span><span class="s2">"i18n names"</span><span class="p">),</span>
<span class="n">description</span><span class="p">,</span> <span class="n">date</span><span class="p">,</span>
<span class="n">hosrizontal_field</span><span class="p">(</span><span class="n">in_menu</span><span class="p">,</span> <span class="n">visible</span><span class="p">,</span> <span class="n">in_banner</span><span class="p">,</span>
<span class="n">sacrud_name</span><span class="o">=</span><span class="sa">u</span><span class="s2">"Расположение"</span><span class="p">),</span>
<span class="n">description2</span><span class="p">]</span>
</pre></div>
</div>
</div>
<div class="literal-block-wrapper docutils container" id="id2">
<div class="code-block-caption"><span class="caption-text">templates/sacrud/redefineme.jinja2</span></div>
<div class="highlight-html+jinja"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">"sacrud/base.jinja2"</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">userspace</span> <span class="cp">%}</span>
<span class="cp">{{</span> <span class="nb">super</span><span class="o">()</span> <span class="cp">}}</span>
<span class="c"><!-- Date field --></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">"http://code.jquery.com/jquery-1.10.2.js"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">"http://code.jquery.com/ui/1.10.4/jquery-ui.js"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">link</span> <span class="na">href</span><span class="o">=</span><span class="s">"//code.jquery.com/ui/1.10.4/themes/smoothness/jquery-ui.css"</span> <span class="na">rel</span><span class="o">=</span><span class="s">"stylesheet"</span><span class="p">></</span><span class="nt">link</span><span class="p">></span>
<span class="p"><</span><span class="nt">style</span><span class="p">></span>
<span class="p">.</span><span class="nc">content</span> <span class="p">{</span>
<span class="k">height</span><span class="p">:</span> <span class="mi">550</span><span class="kt">px</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">.</span><span class="nc">name</span> <span class="p">{</span>
<span class="k">width</span><span class="p">:</span> <span class="mi">400</span><span class="kt">px</span><span class="p">;</span>
<span class="p">}</span>
<span class="p"></</span><span class="nt">style</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span><span class="p">></span>
<span class="nx">$</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">$</span><span class="p">(</span><span class="s2">".Date"</span><span class="p">).</span><span class="nx">datepicker</span><span class="p">({</span> <span class="nx">dateFormat</span><span class="o">:</span> <span class="s1">'yy-mm-dd'</span> <span class="p">});</span>
<span class="p">});</span>
<span class="p"></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">"//tinymce.cachefly.net/4.0/tinymce.min.js"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span><span class="p">></span>
<span class="nx">tinymce</span><span class="p">.</span><span class="nx">init</span><span class="p">({</span>
<span class="nx">selector</span><span class="o">:</span><span class="s1">'textarea.tinymce'</span><span class="p">,</span>
<span class="nx">plugins</span><span class="o">:</span> <span class="s2">"image link"</span><span class="p">,</span>
<span class="nx">file_browser_callback</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">field_name</span><span class="p">,</span> <span class="nx">url</span><span class="p">,</span> <span class="nx">type</span><span class="p">,</span> <span class="nx">win</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">tinymce</span><span class="p">.</span><span class="nx">activeEditor</span><span class="p">.</span><span class="nx">windowManager</span><span class="p">.</span><span class="nx">open</span><span class="p">({</span>
<span class="nx">title</span><span class="o">:</span> <span class="s2">"SACRUD file browser"</span><span class="p">,</span>
<span class="nx">url</span><span class="o">:</span> <span class="s2">"/image/filebrowser"</span><span class="p">,</span>
<span class="nx">width</span><span class="o">:</span> <span class="mi">600</span><span class="p">,</span>
<span class="nx">height</span><span class="o">:</span> <span class="mi">400</span><span class="p">,</span>
<span class="p">},</span> <span class="p">{</span>
<span class="nx">oninsert</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">url</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">win</span><span class="p">.</span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="nx">field_name</span><span class="p">).</span><span class="nx">value</span> <span class="o">=</span> <span class="nx">url</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">},</span>
<span class="p">});</span>
<span class="p"></</span><span class="nt">script</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">sa_body</span> <span class="cp">%}</span>
<span class="cp">{{</span> <span class="nb">super</span><span class="o">()</span> <span class="cp">}}</span>
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
</pre></div>
</div>
</div>
<p>Результат:</p>
<div class="figure align-center" id="id3">
<img alt="_static/2014/sacrud_0.1.2_example.png" src="_static/2014/sacrud_0.1.2_example.png" />
<p class="caption"><span class="caption-text">Пример кастомного CRUD интерфейса для SQLAlchemy</span></p>
</div>
<p>Демо приложение: <a class="reference external" href="https://github.com/uralbash/pyramid_sacrud_example">https://github.com/uralbash/pyramid_sacrud_example</a></p>
</div>
Своя панель в pyramid_debugtoolbar
http://uralbash.ru/articles/2014/panel_pyramid_dt/
2014-02-28T22:03:00Z
2014-02-28T22:03:00Z
Uralbash
<div class="section" id="pyramid-debugtoolbar">
<div class="line-block">
<div class="line">В <a class="reference external" href="https://pypi.python.org/pypi/pyramid_debugtoolbar">pyramid_debugtoolbar</a> можно создавать панели для своих нужд.</div>
<div class="line">Документация здесь: <a class="reference external" href="http://docs.pylonsproject.org/projects/pyramid_debugtoolbar/en/latest/#adding-custom-panels">http://docs.pylonsproject.org/projects/pyramid_debugtoolbar/en/latest/#adding-custom-panels</a></div>
</div>
<p>Я создал небольшой пример, как это сделать на примере <a class="reference external" href="https://pypi.python.org/pypi/sadisplay">sadisplay</a>.
<a class="reference external" href="https://pypi.python.org/pypi/sadisplay">sadisplay</a> - это модуль который отображает модели <a class="reference external" href="http://sqlalchemy.org/">SQLAlchemy</a> в виде
<code class="docutils literal"><span class="pre">UML</span></code> диаграммы.</p>
<img alt="_static/2014/sadisplay.png" class="align-center" src="_static/2014/sadisplay.png" />
<p>Было бы удобно видеть схему БД проекта в дебаг панеле. Для этого создадим папку
проекта <code class="docutils literal"><span class="pre">pyramid_debugtoolbar_sadisplay</span></code> со структурой:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>├── __init__.py
├── panel.py
└── templates
└── base.dbtmako
</pre></div>
</div>
<div class="literal-block-wrapper docutils container" id="id1">
<div class="code-block-caption"><span class="caption-text">panel.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="ch">#! /usr/bin/env python</span>
<span class="c1"># -*- coding: utf-8 -*-</span>
<span class="c1"># vim:fenc=utf-8</span>
<span class="c1">#</span>
<span class="c1"># Copyright © 2014 uralbash <root uralbash.ru=""></span>
<span class="c1">#</span>
<span class="c1"># Distributed under terms of the MIT license.</span>
<span class="sd">"""</span>
<span class="sd">sadisplay in pyramid_debugtoolbar</span>
<span class="sd">"""</span>
<span class="kn">import</span> <span class="nn">pydot</span>
<span class="kn">import</span> <span class="nn">sadisplay</span>
<span class="kn">import</span> <span class="nn">sqlalchemy</span>
<span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">engine_from_config</span>
<span class="kn">from</span> <span class="nn">pyramid_debugtoolbar.panels</span> <span class="kn">import</span> <span class="n">DebugPanel</span>
<span class="n">_</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span>
<span class="k">def</span> <span class="nf">get_sa_base</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">settings</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
<span class="k">if</span> <span class="n">settings</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
<span class="n">settings</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">registry</span><span class="o">.</span><span class="n">settings</span>
<span class="n">engine</span> <span class="o">=</span> <span class="n">engine_from_config</span><span class="p">(</span><span class="n">settings</span><span class="p">,</span> <span class="s1">'sqlalchemy.'</span><span class="p">)</span>
<span class="n">sabase</span> <span class="o">=</span> <span class="n">sqlalchemy</span><span class="o">.</span><span class="n">ext</span><span class="o">.</span><span class="n">declarative</span><span class="o">.</span><span class="n">declarative_base</span><span class="p">()</span>
<span class="n">sabase</span><span class="o">.</span><span class="n">metadata</span><span class="o">.</span><span class="n">reflect</span><span class="p">(</span><span class="n">engine</span><span class="p">)</span>
<span class="k">return</span> <span class="n">sabase</span>
<span class="k">class</span> <span class="nc">SadisplayDebugPanel</span><span class="p">(</span><span class="n">DebugPanel</span><span class="p">):</span>
<span class="sd">"""</span>
<span class="sd">debug panel</span>
<span class="sd">"""</span>
<span class="n">name</span> <span class="o">=</span> <span class="s1">'SADisplay'</span>
<span class="n">has_content</span> <span class="o">=</span> <span class="bp">True</span>
<span class="n">template</span> <span class="o">=</span> <span class="s1">'pyramid_debugtoolbar_sadisplay:templates/base.dbtmako'</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">request</span> <span class="o">=</span> <span class="n">request</span>
<span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">=</span> <span class="p">{}</span>
<span class="bp">self</span><span class="o">.</span><span class="n">Base</span> <span class="o">=</span> <span class="n">get_sa_base</span><span class="p">(</span><span class="n">request</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">nav_title</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="n">_</span><span class="p">(</span><span class="s1">'SADisplay'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">url</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="s1">''</span>
<span class="k">def</span> <span class="nf">title</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="n">_</span><span class="p">(</span><span class="s1">'SADisplay'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">render_vars</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">):</span>
<span class="n">tables</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">Base</span><span class="o">.</span><span class="n">metadata</span><span class="o">.</span><span class="n">tables</span><span class="o">.</span><span class="n">values</span><span class="p">()</span>
<span class="n">desc</span> <span class="o">=</span> <span class="n">sadisplay</span><span class="o">.</span><span class="n">describe</span><span class="p">(</span><span class="n">tables</span><span class="p">)</span>
<span class="n">dot_data</span> <span class="o">=</span> <span class="n">sadisplay</span><span class="o">.</span><span class="n">dot</span><span class="p">(</span><span class="n">desc</span><span class="p">)</span>
<span class="n">graph</span> <span class="o">=</span> <span class="n">pydot</span><span class="o">.</span><span class="n">graph_from_dot_data</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">dot_data</span><span class="p">))</span>
<span class="n">svg_img</span> <span class="o">=</span> <span class="n">graph</span><span class="o">.</span><span class="n">create_svg</span><span class="p">()</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'svg_img'</span><span class="p">:</span> <span class="n">svg_img</span><span class="p">}</span>
<span class="k">def</span> <span class="nf">content</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="nb">vars</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">render_vars</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">request</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">render</span><span class="p">(</span>
<span class="s1">'pyramid_debugtoolbar_sadisplay:templates/base.dbtmako'</span><span class="p">,</span>
<span class="nb">vars</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">request</span><span class="p">)</span>
</pre></div>
</div>
</div>
<p>Функция <code class="docutils literal"><span class="pre">get_sa_base</span></code> создает <code class="docutils literal"><span class="pre">base</span></code> объект и заполняет его метаданными по
строке подключения к БД, в дальнейшем мы сможем получить все модели проекта.
Метод <code class="docutils literal"><span class="pre">render_vars</span></code> при помощи <a class="reference external" href="https://pypi.python.org/pypi/sadisplay">sadisplay</a> генерит текст формата
<code class="docutils literal"><span class="pre">dot</span></code> и при помощи <a class="reference external" href="https://pypi.python.org/pypi/pydot">pydot</a> конвертит его в <code class="docutils literal"><span class="pre">svg</span></code>.</p>
<p>В версии <a class="reference external" href="https://pypi.python.org/pypi/pyramid_debugtoolbar">pyramid_debugtoolbar</a> 1.0.* нужно рендерить шаблон в методе
content. В 2.0.* метод <code class="docutils literal"><span class="pre">content</span></code> не нужен, шаблон указывается в виде атрибута
<code class="docutils literal"><span class="pre">template</span></code>, а параметры отдаются в методе <code class="docutils literal"><span class="pre">render_vars</span></code>. В примере
используются оба метода, что бы работало во всех версиях.</p>
<p>шаблон <code class="docutils literal"><span class="pre">base.dbtmako</span></code>:</p>
<div class="literal-block-wrapper docutils container" id="id2">
<div class="code-block-caption"><span class="caption-text">base.dbtmako</span></div>
<div class="highlight-html+mako"><div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">h4</span><span class="p">></span>SQLAlchemy models preview<span class="p"></</span><span class="nt">h4</span><span class="p">></span>
<span class="cp">${</span> <span class="n">svg_img</span><span class="o">|</span><span class="n">n</span> <span class="cp">}</span>
link: <span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"https://github.com/uralbash/pyramid_debugtoolbar_sadisplay"</span> <span class="na">style</span><span class="o">=</span><span class="s">"color: blue;"</span><span class="p">></span>pyramid_debugtoolbar_sadisplay<span class="p"></</span><span class="nt">a</span><span class="p">></span>
</pre></div>
</div>
</div>
<p>Подключаем к приложению:</p>
<div class="literal-block-wrapper docutils container" id="id3">
<div class="code-block-caption"><span class="caption-text">__init__.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1"># SADisplay in pyramid_debugtoolbar</span>
<span class="kn">from</span> <span class="nn">pyramid_debugtoolbar_sadisplay.panel</span> <span class="kn">import</span> <span class="n">SadisplayDebugPanel</span>
<span class="n">config</span><span class="o">.</span><span class="n">registry</span><span class="o">.</span><span class="n">settings</span><span class="p">[</span><span class="s1">'debugtoolbar.panels'</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">SadisplayDebugPanel</span><span class="p">)</span>
</pre></div>
</div>
</div>
<p>Результат:</p>
<img alt="_static/2014/dt_sadisplay1.png" src="_static/2014/dt_sadisplay1.png" />
<img alt="_static/2014/dt_sadisplay2.png" src="_static/2014/dt_sadisplay2.png" />
<p>Код примера здесь: <a class="reference external" href="https://github.com/uralbash/pyramid_debugtoolbar_sadisplay">https://github.com/uralbash/pyramid_debugtoolbar_sadisplay</a></p>
</div>
Обновление sacrud. Версия 0.1.1
http://uralbash.ru/articles/2014/sacrud_release_0.1.1/
2014-02-23T18:02:00Z
2014-02-23T18:02:00Z
Uralbash
<div class="section" id="sacrud-0-1-1">
<img alt="_static/2014/sacrud_0_1_1.png" class="align-left" src="_static/2014/sacrud_0_1_1.png" />
<div class="line-block">
<div class="line">Код: <a class="reference external" href="https://github.com/uralbash/sacrud">https://github.com/uralbash/sacrud</a></div>
<div class="line">Описание: <a class="reference external" href="http://sacrud.readthedocs.org/">http://sacrud.readthedocs.org/</a></div>
</div>
<p>Что нового?</p>
<ul>
<li><p class="first">в расширении для pyramid параметр “sacrud_models” переименован в “sacrud.models”</p>
</li>
<li><p class="first">“sacrud.models” теперь словарь, а не список:</p>
<blockquote>
<div><div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">settings</span><span class="p">[</span><span class="s1">'sacrud.models'</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
<span class="s1">'Company'</span><span class="p">:</span> <span class="p">[</span><span class="n">Company</span><span class="p">,</span> <span class="n">User</span><span class="p">,</span> <span class="n">EmployeeType</span><span class="p">],</span>
<span class="s1">'Auth'</span><span class="p">:</span> <span class="p">[</span><span class="n">Group</span><span class="p">,</span> <span class="n">GroupPermission</span><span class="p">,</span> <span class="n">UserGroup</span><span class="p">,</span>
<span class="n">GroupResourcePermission</span><span class="p">,</span> <span class="n">Resource</span><span class="p">,</span> <span class="n">UserPermission</span><span class="p">,</span>
<span class="n">UserResourcePermission</span><span class="p">,</span> <span class="n">ExternalIdentity</span><span class="p">],</span>
<span class="s1">''</span><span class="p">:</span> <span class="p">[</span><span class="n">Company</span><span class="p">]</span>
<span class="p">}</span>
</pre></div>
</div>
</div></blockquote>
</li>
<li><p class="first">в словаре можно поделить модели на группы</p>
</li>
<li><p class="first">тесты исправлены для <a class="reference external" href="http://pylonsproject.org/">Pyramid</a> <code class="docutils literal"><span class="pre">1.5</span></code>:</p>
<div class="deprecated">
<p><span class="versionmodified">Не рекомендуется, начиная с версии pyramid: </span>1.5</p>
<p>Removed the ability to influence and query a pyramid.request.Request object as
if it were a dictionary. Previously it was possible to use methods like
__getitem__, get, items, and other dictlike methods to access values in the
WSGI environment. This behavior had been deprecated since Pyramid 1.1. Use
methods of request.environ (a real dictionary) instead.</p>
</div>
</li>
</ul>
</div>
Мифический человеко месяц
http://uralbash.ru/articles/2014/man_month_book/
2014-02-16T02:47:00Z
2014-02-16T02:47:00Z
Uralbash
<div class="section" id="id1">
<p>Я прочитал этот шедевр довольно давно, но всё же раз начал писать про книги,
то напишу отзыв. Книга просто необходима для прочтения, в первую очередь
руководителям и разработчикам с опытом решения разных проблем в области IT и
возможно HR в той же области. В этой книге главное осилить первую половину,
вторая читается на одном дыхании (а почему так это лучше узнать из контекста).
Брукс крут! <strong>Реально крут!</strong></p>
<a class="reference external image-reference" href="http://www.books.ru/books/mificheskii-cheloveko-mesyats-ili-kak-sozdayutsya-programmnye-sistemy-3626/?partner=490327"><img alt="_static/2014/bruks.jpg" class="align-center" src="_static/2014/bruks.jpg" style="width: 400px;" /></a>
</div>
миграции в Pyramid
http://uralbash.ru/articles/2014/alembic_pyramid/
2014-02-16T02:04:00Z
2014-02-16T02:04:00Z
Uralbash
<div class="section" id="pyramid">
<p>Пример миграций в пирамиде:</p>
<p>В <a class="reference external" href="https://www.djangoproject.com/">Django</a> <a class="reference external" href="https://pypi.python.org/pypi/south">south</a> в <a class="reference external" href="http://pylonsproject.org/">Pyramid</a> <a class="reference external" href="https://pypi.python.org/pypi/alembic">alembic</a>. Создаём файл
<code class="docutils literal"><span class="pre">alembic.ini</span></code> и указываем путь до настроек :, т.е. <code class="docutils literal"><span class="pre"><имя</span> <span class="pre">проекта>:<название</span>
<span class="pre">папки></span></code> например <code class="docutils literal"><span class="pre">hlp:alembic</span></code>:</p>
<div class="literal-block-wrapper docutils container" id="id1">
<div class="code-block-caption"><span class="caption-text">alembic.ini</span></div>
<div class="highlight-ini"><div class="highlight"><pre><span></span><span class="na">pyramid.includes</span> <span class="o">=</span><span class="s"></span>
<span class="s"> pyramid_debugtoolbar</span>
<span class="s"> pyramid_tm</span>
<span class="s"> ziggurat_foundations.ext.pyramid.sign_in</span>
<span class="na">ziggurat_foundations.model_locations.User</span> <span class="o">=</span> <span class="s">hlp.models.auth:User</span>
<span class="c1">#sqlalchemy.url = sqlite:///%(here)s/hlp.sqlite</span>
<span class="na">sqlalchemy.url</span> <span class="o">=</span> <span class="s">postgresql://postgres:postgres@localhost:5432/hlp</span>
<span class="c1"># By default, the toolbar only appears for clients from IP addresses</span>
<span class="c1"># '127.0.0.1' and '::1'.</span>
<span class="c1"># debugtoolbar.hosts = 127.0.0.1 ::1</span>
<span class="c1">###</span>
<span class="c1"># wsgi server configuration</span>
<span class="c1">###</span>
<span class="k">[server:main]</span>
<span class="na">use</span> <span class="o">=</span> <span class="s">egg:waitress#main</span>
<span class="na">host</span> <span class="o">=</span> <span class="s">0.0.0.0</span>
<span class="na">port</span> <span class="o">=</span> <span class="s">6543</span>
<span class="hll"><span class="k">[alembic]</span>
</span><span class="hll"><span class="c1"># path to migration scripts</span>
</span><span class="hll"><span class="na">script_location</span> <span class="o">=</span> <span class="s">hlp:alembic</span>
</span></pre></div>
</div>
</div>
<p>в проекте создаем папку <code class="docutils literal"><span class="pre">alembic</span></code> со следующей структурой:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span> alembic/$ tree
.
├── env.py
├── script.py.mako
└── versions
└── 29ac938c56f_starting.py
</pre></div>
</div>
<div class="literal-block-wrapper docutils container" id="id2">
<div class="code-block-caption"><span class="caption-text">env.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">with_statement</span>
<span class="kn">from</span> <span class="nn">alembic</span> <span class="kn">import</span> <span class="n">context</span>
<span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">engine_from_config</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.engine.base</span> <span class="kn">import</span> <span class="n">Engine</span>
<span class="kn">from</span> <span class="nn">pyramid.paster</span> <span class="kn">import</span> <span class="n">setup_logging</span>
<span class="c1"># this is the Alembic Config object, which provides</span>
<span class="c1"># access to the values within the .ini file in use.</span>
<span class="n">config</span> <span class="o">=</span> <span class="n">context</span><span class="o">.</span><span class="n">config</span>
<span class="kn">from</span> <span class="nn">hlp.models</span> <span class="kn">import</span> <span class="n">Base</span>
<span class="n">setup_logging</span><span class="p">(</span><span class="n">config</span><span class="o">.</span><span class="n">config_file_name</span><span class="p">)</span>
<span class="n">engine</span> <span class="o">=</span> <span class="n">engine_from_config</span><span class="p">(</span><span class="n">config</span><span class="o">.</span><span class="n">get_section</span><span class="p">(</span><span class="s1">'app:main'</span><span class="p">),</span> <span class="s1">'sqlalchemy.'</span><span class="p">)</span>
<span class="n">target_metadata</span> <span class="o">=</span> <span class="n">Base</span><span class="o">.</span><span class="n">metadata</span>
<span class="k">def</span> <span class="nf">run_migrations_offline</span><span class="p">():</span>
<span class="sd">"""Run migrations in 'offline' mode.</span>
<span class="sd"> This configures the context with just a URL</span>
<span class="sd"> and not an Engine, though an Engine is acceptable</span>
<span class="sd"> here as well. By skipping the Engine creation</span>
<span class="sd"> we don't even need a DBAPI to be available.</span>
<span class="sd"> Calls to context.execute() here emit the given string to the</span>
<span class="sd"> script output.</span>
<span class="sd"> """</span>
<span class="n">context</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span><span class="n">url</span><span class="o">=</span><span class="n">engine</span><span class="o">.</span><span class="n">url</span><span class="p">)</span>
<span class="k">with</span> <span class="n">context</span><span class="o">.</span><span class="n">begin_transaction</span><span class="p">():</span>
<span class="n">context</span><span class="o">.</span><span class="n">run_migrations</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">run_migrations_online</span><span class="p">():</span>
<span class="sd">"""Run migrations in 'online' mode.</span>
<span class="sd"> In this scenario we need to create an Engine</span>
<span class="sd"> and associate a connection with the context.</span>
<span class="sd"> """</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">engine</span><span class="p">,</span> <span class="n">Engine</span><span class="p">):</span>
<span class="n">connection</span> <span class="o">=</span> <span class="n">engine</span><span class="o">.</span><span class="n">connect</span><span class="p">()</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span>
<span class="s1">'Expected engine instance got </span><span class="si">%s</span><span class="s1"> instead'</span> <span class="o">%</span> <span class="nb">type</span><span class="p">(</span><span class="n">engine</span><span class="p">)</span>
<span class="p">)</span>
<span class="n">context</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span>
<span class="n">connection</span><span class="o">=</span><span class="n">connection</span><span class="p">,</span>
<span class="n">target_metadata</span><span class="o">=</span><span class="n">target_metadata</span>
<span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">with</span> <span class="n">context</span><span class="o">.</span><span class="n">begin_transaction</span><span class="p">():</span>
<span class="n">context</span><span class="o">.</span><span class="n">run_migrations</span><span class="p">()</span>
<span class="k">finally</span><span class="p">:</span>
<span class="n">connection</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">if</span> <span class="n">context</span><span class="o">.</span><span class="n">is_offline_mode</span><span class="p">():</span>
<span class="n">run_migrations_offline</span><span class="p">()</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">run_migrations_online</span><span class="p">()</span>
</pre></div>
</div>
</div>
<div class="literal-block-wrapper docutils container" id="id3">
<div class="code-block-caption"><span class="caption-text">script.py.mako</span></div>
<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">"""</span><span class="cp">${</span><span class="n">message</span><span class="cp">}</span><span class="x"></span>
<span class="x">Revision ID: </span><span class="cp">${</span><span class="n">up_revision</span><span class="cp">}</span><span class="x"></span>
<span class="x">Revises: </span><span class="cp">${</span><span class="n">down_revision</span><span class="cp">}</span><span class="x"></span>
<span class="x">Create Date: </span><span class="cp">${</span><span class="n">create_date</span><span class="cp">}</span><span class="x"></span>
<span class="x">"""</span>
<span class="x"># revision identifiers, used by Alembic.</span>
<span class="x">revision = </span><span class="cp">${</span><span class="nb">repr</span><span class="p">(</span><span class="n">up_revision</span><span class="p">)</span><span class="cp">}</span><span class="x"></span>
<span class="x">down_revision = </span><span class="cp">${</span><span class="nb">repr</span><span class="p">(</span><span class="n">down_revision</span><span class="p">)</span><span class="cp">}</span><span class="x"></span>
<span class="x">from alembic import op</span>
<span class="x">import sqlalchemy as sa</span>
<span class="cp">${</span><span class="n">imports</span> <span class="k">if</span> <span class="n">imports</span> <span class="k">else</span> <span class="s2">""</span><span class="cp">}</span><span class="x"></span>
<span class="x">def upgrade():</span>
<span class="cp">${</span><span class="n">upgrades</span> <span class="k">if</span> <span class="n">upgrades</span> <span class="k">else</span> <span class="s2">"pass"</span><span class="cp">}</span><span class="x"></span>
<span class="x">def downgrade():</span>
<span class="cp">${</span><span class="n">downgrades</span> <span class="k">if</span> <span class="n">downgrades</span> <span class="k">else</span> <span class="s2">"pass"</span><span class="cp">}</span><span class="x"></span>
</pre></div>
</div>
</div>
<p>Создаем первую миграцию:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ alembic revision --autogenerate -m <span class="s2">"create table"</span>
</pre></div>
</div>
<p>переходим к последней миграции:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ alembic upgrade head
</pre></div>
</div>
<p>Есть ешё ништиковые команды типа:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ alembic upgrade +2
$ alembic downgrade -1
$ alembic upgrade 29ac
$ alembic <span class="nb">history</span>
$ alembic current
</pre></div>
</div>
<div class="line-block">
<div class="line">пример исключения таблиц из миграций <a class="reference external" href="http://blog.utek.pl/2013/ignoring-tables-in-alembic/">http://blog.utek.pl/2013/ignoring-tables-in-alembic/</a></div>
<div class="line">подробнее здесь <a class="reference external" href="https://alembic.readthedocs.org/en/latest/tutorial.html">https://alembic.readthedocs.org/en/latest/tutorial.html</a></div>
</div>
</div>
Django - кот в мешке.
http://uralbash.ru/articles/2014/django-hyango/
2014-02-02T20:43:00Z
2014-02-02T20:43:00Z
Uralbash
<div class="section" id="django">
<img alt="_static/2014/wat.jpg" class="align-right" src="_static/2014/wat.jpg" style="width: 420px;" />
<p><a class="reference external" href="https://www.djangoproject.com/">Django</a> это фреймворк, при помощи которого быстро пишутся сайты. Так ли это?</p>
<p>Фичи джанги:</p>
<ul class="simple">
<li>Админка</li>
<li>куча аппликэйшинов</li>
<li>Шаблоны</li>
<li>ORM</li>
<li>DebugToolbar</li>
</ul>
<br clear="both"/><div class="section" id="id1">
<h2>Админка</h2>
<p>Из коробки у вас есть админка. Для простых сайтов её нужно кастомайзить долго и
упорно, правда, обычно, это делается один раз. В сайте среднего уровня
жангоадминка уже не прокатит. Вывод админка даёт профит в простых сайтах.</p>
</div>
<div class="section" id="id2">
<h2>Аппликашины</h2>
<p>Обычно очень посредственного качества и не совместимы друг с другом, поэтому
танцы с бубном и велосипеды наше всё + <code class="docutils literal"><span class="pre">djangosnippets</span></code>.</p>
</div>
<div class="section" id="id3">
<h2>Шаблоны</h2>
<ul>
<li><p class="first">нету break, continue
<code class="docutils literal"><span class="pre">jinja2.ext.loopcontrols</span> <span class="pre">This</span> <span class="pre">extension</span> <span class="pre">adds</span> <span class="pre">support</span> <span class="pre">for</span> <span class="pre">break</span> <span class="pre">and</span> <span class="pre">continue</span> <span class="pre">in</span> <span class="pre">loops.</span></code></p>
</li>
<li><p class="first">рекурсия Jinja</p>
<div class="highlight-html+jinja"><div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"sitemap"</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">item</span> <span class="k">in</span> <span class="nv">sitemap</span> <span class="k">recursive</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">item.href</span><span class="o">|</span><span class="nf">e</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">item.title</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">a</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">item.children</span> -<span class="cp">%}</span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"submenu"</span><span class="p">></span><span class="cp">{{</span> <span class="nb">loop</span><span class="o">(</span><span class="nv">item.children</span><span class="o">)</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">ul</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span><span class="p"></</span><span class="nt">li</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
</pre></div>
</div>
<p>а в джанге это видимо не нужно</p>
</li>
<li><p class="first">не работает вызов функций типа <code class="docutils literal"><span class="pre">item()</span></code> (лолшто?)</p>
</li>
<li><p class="first"><code class="docutils literal"><span class="pre">[:-1]</span></code> не работает, нужно писать <code class="docutils literal"><span class="pre">|latest</span></code></p>
</li>
<li><p class="first"><span class="strike">для js выражение типа:</span></p>
<p><span class="strike">var foo = [{% for item in items %}{{ item.paren }}{% endfor %}]</span>
<span class="strike">не работает, потому что js выполняется до рендеринга таких {%%} конструкций.</span></p>
</li>
<li><p class="first">коменты <code class="docutils literal"><span class="pre">{#</span> <span class="pre">#}</span></code> неработают в несколько строк</p>
</li>
<li><p class="first">вместо <code class="docutils literal"><span class="pre">{{</span> <span class="pre">list[5]</span> <span class="pre">}}</span></code> -> <code class="docutils literal"><span class="pre">{{</span> <span class="pre">arr.5</span> <span class="pre">}}</span></code></p>
</li>
<li><p class="first">для словарей <code class="docutils literal"><span class="pre">{{</span> <span class="pre">dict.foo</span> <span class="pre">}}</span></code> не работает, да здравствует <code class="docutils literal"><span class="pre">template</span> <span class="pre">tag</span></code></p>
</li>
<li><p class="first">для <code class="xref py py-mod docutils literal"><span class="pre">itertools.chain</span></code> можно сосать лапу с таким фокусом <code class="docutils literal"><span class="pre">{{</span> <span class="pre">list[5]</span> <span class="pre">}}</span></code></p>
</li>
<li><p class="first">о джанга ты прекрасна <code class="docutils literal"><span class="pre">{{</span> <span class="pre">myval|add:"-5"</span> <span class="pre">}}</span></code> вместо уродского <code class="docutils literal"><span class="pre">{{</span> <span class="pre">myval</span> <span class="pre">-</span> <span class="pre">5</span> <span class="pre">}}</span></code></p>
</li>
<li><p class="first">нельзя сделать так <code class="docutils literal"><span class="pre">{{</span> <span class="pre">dir(foo)</span> <span class="pre">}}</span></code></p>
</li>
<li><p class="first">как узнать длину <a class="reference external" href="https://docs.python.org/3/library/itertools.html#module-itertools" title="(в Python v3.10)"><code class="xref py py-mod docutils literal"><span class="pre">itertools</span></code></a>? в <a class="reference external" href="http://jinja.pocoo.org/">jinja</a> делается так <code class="docutils literal"><span class="pre">{{</span> <span class="pre">list(foo).length</span> <span class="pre">}}</span></code></p>
</li>
</ul>
</div>
<div class="section" id="orm">
<h2>ORM</h2>
<ul class="simple">
<li><code class="docutils literal"><span class="pre">Page.objects.filter(parent__in=objects)</span></code> вместо <code class="docutils literal"><span class="pre">DBSession.query(Page).filter(parent</span> <span class="pre">in</span> <span class="pre">objects)</span></code></li>
<li>великолепный <code class="docutils literal"><span class="pre">foomodel_set__barmodel__name</span></code> лолшто?!</li>
<li><code class="docutils literal"><span class="pre">Entry.objects.all()[:1].get()</span></code> вместо <code class="docutils literal"><span class="pre">DBSession.query(Entry).first()</span></code> или <code class="docutils literal"><span class="pre">one()</span></code></li>
<li>добавляем в модель: <code class="docutils literal"><span class="pre">class</span> <span class="pre">Meta:</span> <span class="pre">app_label</span> <span class="pre">=</span> <span class="pre">'asdasda'</span></code> и переходим к разделу дебаг!</li>
</ul>
</div>
<div class="section" id="debug">
<h2>Debug</h2>
<style>
.red {
color: red;
font-weight: bold;
}
.red-white {
background-color: red;
font-weight: bold;
color: white;
</style><p><span class="red-white">Дебаг джанго кормит вас!</span> Потому что вы <a class="reference external" href="https://www.djangoproject.com/">Django</a> программист и
половину рабочего времени пытаетесь понять что за !@#$% произошла, получая за
это зарплату.</p>
<p><code class="docutils literal"><span class="pre">class</span> <span class="pre">Meta:</span> <span class="pre">app_label</span> <span class="pre">=</span> <span class="pre">'asdasda'</span></code> генерит трейс:</p>
<p><span class="red">django.core.management.base.CommandError: One or more models did not validate:
gallery.galleryimage: ‘gallery’ has a relation with model <class
‘gallery.models.Gallery’>, which has either not been installed or is abstract.</span></p>
<p>Шыкарные красные ошибки джанги. Очень информативно, ищется аникейством и
вспоминанием чё правил.</p>
<p>Я запилил <a class="reference external" href="https://github.com/uralbash/django-hyango">небольшой пример</a> что
бы вы могли поднять его и посмотреть на эту магию.</p>
</div>
<div class="section" id="id5">
<h2>Квик старт</h2>
<ol class="arabic">
<li><p class="first">Установка по <code class="docutils literal"><span class="pre">pip</span> <span class="pre">install</span> <span class="pre">-r</span> <span class="pre">requirements.txt</span></code></p>
</li>
<li><p class="first">Далее введим <code class="docutils literal"><span class="pre">python</span> <span class="pre">manage.py</span> <span class="pre">syncdb</span></code> и видим <span class="red">ImportError: cannot import name SEOModel</span> Супер информативный вывод, все сразу стало понятно.</p>
<blockquote>
<div><p>2.1 Прошел все модели в проекте, <code class="docutils literal"><span class="pre">SEOModel</span></code> не нашел, при учете что у меня <code class="docutils literal"><span class="pre">gallery</span></code> стоит в <a class="reference external" href="https://pypi.python.org/pypi/virtualenv">virtualenv</a></p>
<p>2.2 может во вью? Во вью то же нету</p>
<p>2.3 ищем по проекту тупо по всем файлам, нету.</p>
<p>2.4 идем в <code class="docutils literal"><span class="pre">settings/apps.py</span></code> и смотрим какое г может это содержать (так на угад), смотрим <code class="docutils literal"><span class="pre">common</span></code> опа вот он в моделях, осталось найти где он импортируется неправильно.</p>
<p>2.5 ради интереса запускаю сервер <code class="docutils literal"><span class="pre">python</span> <span class="pre">manage.py</span> <span class="pre">runserver</span></code> и получаю:</p>
<blockquote>
<div><p><span class="red">File ”.../local/lib/python2.7/site-packages/gallery/models.py”, line 12, in <module> from website.models import SEOModel, VisibleModel ImportError: cannot import name SEOModel</span></p>
</div></blockquote>
</div></blockquote>
</li>
</ol>
<p>т.е. в некоторых случаях джангу надо дебажить runserver’ом</p>
</div>
<div class="section" id="pages">
<h2>Pages</h2>
<ul class="simple">
<li>захожу в pages в админке</li>
<li>добавляю дерево</li>
<li>тыкаю по дереву (вложенность 2го уровня) что бы развернуть список и получаю:</li>
</ul>
<p><code class="docutils literal"><span class="pre">Error</span> <span class="pre">while</span> <span class="pre">loading</span> <span class="pre">the</span> <span class="pre">data</span> <span class="pre">from</span> <span class="pre">the</span> <span class="pre">server.</span></code></p>
<img alt="_static/2014/pages_tree.png" src="_static/2014/pages_tree.png" />
<p>и трэйс:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>Internal Server Error: /admin/pages/page/tree_json/
Traceback <span class="o">(</span>most recent call last<span class="o">)</span>:
File <span class="s2">"/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django/core/handlers/base.py"</span>, line <span class="m">115</span>, in get_response
<span class="nv">response</span> <span class="o">=</span> callback<span class="o">(</span>request, *callback_args, **callback_kwargs<span class="o">)</span>
File <span class="s2">"/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django_mptt_admin/admin.py"</span>, line <span class="m">50</span>, in wrapper
<span class="k">return</span> self.admin_site.admin_view<span class="o">(</span>view<span class="o">)(</span>*args, **kwargs<span class="o">)</span>
File <span class="s2">"/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django/utils/decorators.py"</span>, line <span class="m">91</span>, in _wrapped_view
<span class="nv">response</span> <span class="o">=</span> view_func<span class="o">(</span>request, *args, **kwargs<span class="o">)</span>
File <span class="s2">"/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django/views/decorators/cache.py"</span>, line <span class="m">89</span>, in _wrapped_view_func
<span class="nv">response</span> <span class="o">=</span> view_func<span class="o">(</span>request, *args, **kwargs<span class="o">)</span>
File <span class="s2">"/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django/contrib/admin/sites.py"</span>, line <span class="m">202</span>, in inner
<span class="k">return</span> view<span class="o">(</span>request, *args, **kwargs<span class="o">)</span>
File <span class="s2">"/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django_mptt_admin/admin.py"</span>, line <span class="m">157</span>, in tree_json_view
<span class="nv">node</span> <span class="o">=</span> self.model.objects.get<span class="o">(</span><span class="nv">id</span><span class="o">=</span>node_id<span class="o">)</span>
File <span class="s2">"/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django/db/models/manager.py"</span>, line <span class="m">143</span>, in get
<span class="k">return</span> self.get_query_set<span class="o">()</span>.get<span class="o">(</span>*args, **kwargs<span class="o">)</span>
File <span class="s2">"/home/uralbash/.virtualenvs/django-hyango/local/lib/python2.7/site-packages/django/db/models/query.py"</span>, line <span class="m">404</span>, in get
self.model._meta.object_name<span class="o">)</span>
DoesNotExist: Page matching query does not exist.
<span class="o">[</span><span class="m">16</span>/Dec/2013 <span class="m">23</span>:42:28<span class="o">]</span> <span class="s2">"GET /admin/pages/page/tree_json/?node=5&_=1387215746550 HTTP/1.1"</span> <span class="m">500</span> <span class="m">22668</span>
</pre></div>
</div>
<div class="line-block">
<div class="line">бесполезный трейс и непонятная ошибка КРУТО!</div>
<div class="line">Если я зайду на адрес <code class="docutils literal"><span class="pre">/admin/pages/page/tree_json/?node=5&_=1387215746550</span></code></div>
</div>
<p>то получу статический trace и хер знает куда bp вставить что бы хоть за че-то
зацепиться.</p>
<p>Ставлю <a class="reference external" href="https://pypi.python.org/pypi/django-extensions">django-extensions</a> через <a class="reference external" href="https://pypi.python.org/pypi/pip">pip</a> и <a class="reference external" href="https://pypi.python.org/pypi/Werkzeug">Werkzeug</a> что бы
получить хоть какой то интерактив на том же трэйсе.</p>
<p>Запускаю командой <code class="docutils literal"><span class="pre">python</span> <span class="pre">manage.py</span> <span class="pre">runserver_plus</span></code>, отваливается
<code class="docutils literal"><span class="pre">debug_toolbar</span></code>. Но и интерактивный трейс мало чем помогает в этом случае.
Джанга каким то чудом обходит то место которое все ломает, ГРЕБАННЫЙ СТЫД!
Ошибка ищется тупым эникейством. Предполагая что <a class="reference external" href="https://www.djangoproject.com/">django</a> идеальна и в ней
нет ошибок, <a class="reference external" href="https://pypi.python.org/pypi/django_mptt_admin">django_mptt_admin</a> на <code class="docutils literal"><span class="pre">example</span></code> работает хорошо, может
быть что то в Pages??? Ад же какойто?</p>
</div>
</div>
Причины названий python, django и pyramid
http://uralbash.ru/articles/2013/reason_names_of/
2013-12-22T16:34:00Z
2013-12-22T16:34:00Z
Uralbash
<div class="section" id="python-django-pyramid">
<div class="section" id="python">
<h2>Python</h2>
<img alt="_static/2013/200px-Monty_Python's_Flying_Circus.jpg" class="align-left" src="_static/2013/200px-Monty_Python's_Flying_Circus.jpg" />
<p>Название языка произошло вовсе не от вида пресмыкающихся. Автор назвал язык в
честь популярного британского комедийного телешоу 70x «<a class="reference external" href="http://ru.wikipedia.org/wiki/%D0%9B%D0%B5%D1%82%D0%B0%D1%8E%D1%89%D0%B8%D0%B9_%D1%86%D0%B8%D1%80%D0%BA_%D0%9C%D0%BE%D0%BD%D1%82%D0%B8_%D0%9F%D0%B0%D0%B9%D1%82%D0%BE%D0%BD%D0%B0">Летающий цирк Монти
Пайтона</a>».
Но потом все стали его ассоциировать со змеей, ибо змея она и в
африке змея.</p>
<br clear="both"/></div>
<div class="section" id="django">
<h2>Django</h2>
<img alt="_static/2013/220px-Django_Reinhardt_(Gottlieb_07301).jpg" class="align-left" src="_static/2013/220px-Django_Reinhardt_(Gottlieb_07301).jpg" />
<p><a class="reference external" href="http://ru.wikipedia.org/wiki/%D0%A0%D0%B5%D0%B9%D0%BD%D1%85%D0%B0%D1%80%D0%B4%D1%82,_%D0%96%D0%B0%D0%BD_%D0%91%D0%B0%D1%82%D0%B8%D1%81%D1%82">Джанго Рейнхардт</a>
— музыкант, в честь которого получил название фреймворк</p>
<br clear="both"/></div>
<div class="section" id="pyramid">
<h2>Pyramid</h2>
<img alt="_static/2013/venus-shpinx-pyramid-vegas2.jpg" class="align-left" src="_static/2013/venus-shpinx-pyramid-vegas2.jpg" style="width: 300px;" />
<p><a class="reference external" href="https://github.com/stevepiercy">stevepiercy</a> ответил так :)</p>
<div class="line-block">
<div class="line"><a class="reference external" href="https://github.com/stevepiercy">stevepiercy</a>: because we have pointy heads</div>
<div class="line"><code class="docutils literal"><span class="pre">Потому</span> <span class="pre">что</span> <span class="pre">у</span> <span class="pre">нас</span> <span class="pre">такие</span> <span class="pre">же</span> <span class="pre">острые</span> <span class="pre">умы.</span></code></div>
</div>
<p><a class="reference external" href="https://github.com/stevepiercy">stevepiercy</a>: but seriously, the decision to merge web app frameworks
into one was made at the Luxor in Las Vegas, which is a hotel shaped like a
pyramid, and the name starts with “Py”, so....</p>
<p>Но если серьезно, то решение об объединении фреймворков в один, было принято
в отеле Luxor в Лас-Вегасе, который имеет форму пирамиды и название начинается
с “Py”...</p>
<br clear="both"/></div>
</div>
Python'им в Vim
http://uralbash.ru/articles/2013/python_vim/
2013-11-23T02:20:00Z
2013-11-23T02:20:00Z
Uralbash
<div class="section" id="python-vim">
<img alt="_static/2013/vim-cheat-sheet-en.png" class="align-center" src="_static/2013/vim-cheat-sheet-en.png" />
<p>В продолжение статьи о рабочем окружении (<a class="reference internal" href="../articles/2013/where_to_start/#were-to-start"><span class="std std-ref">С чего начать?©</span></a>), по просьбам
трудящихся и во благо партии пишу о текстовом редакторе <a class="reference external" href="http://www.vim.org">Vim</a>.</p>
<p>Думаю в лишнем представлении <a class="reference external" href="http://www.vim.org">Vim</a> не нуждается, это очень популярный
редактор, которым пользуется огромное количество программистов. Посмотрим, чем
он так хорош:</p>
<div class="section" id="id1">
<h2>Консоль</h2>
<p>Реально же круто писать код в консоле, не отвлекаясь на X окна!? Пишешь код,
тут же смотришь логи сервера, тут же запускаешь тесты, дебажишь, комитишь, ну и
т.д. Что бы бысто выйти в консоль из <a class="reference external" href="http://www.vim.org">vim</a> можно нажать <code class="docutils literal"><span class="pre">Ctr^z</span></code>, вернуться
выполнив команду <a class="reference external" href="https://www.freebsd.org/cgi/man.cgi?query=fg">fg</a>. Или можно ввести команду <code class="docutils literal"><span class="pre">:sh</span></code> в <a class="reference external" href="http://www.vim.org">Vim</a>, что бы
вернуться просто закрыть консоль командой <a class="reference external" href="https://www.freebsd.org/cgi/man.cgi?query=exit">exit</a>. Для бОльших благ есть
<a class="reference external" href="https://tmux.github.io/">tmux</a>.</p>
</div>
<div class="section" id="id2">
<h2>Основные настройки</h2>
<p>В <a class="reference external" href="http://www.vim.org">Vim</a> настройки хранятся в файле <code class="docutils literal"><span class="pre">~/.vimrc</span></code>, а плагины в директории
<code class="docutils literal"><span class="pre">~/.vim</span></code>. Для начальных настроек добавьте в ваш <code class="docutils literal"><span class="pre">~/.vimrc</span></code>:</p>
<div class="highlight-vim"><div class="highlight"><pre><span></span><span class="c">""""</span>
<span class="c">" Other settings</span>
<span class="c">"</span>
<span class="c"> " подстройка под разные типы файлов</span>
<span class="k">filetype</span> plugin indent <span class="k">on</span>
<span class="c"> " Use <leader>l to toggle display of whitespace</span>
nmap <span class="p"><</span>leader<span class="p">></span><span class="k">l</span> :<span class="k">set</span> <span class="nb">list</span><span class="p">!<</span>CR<span class="p">></span>
<span class="c"> " And set some nice chars to do it with</span>
<span class="k">set</span> <span class="nb">listchars</span><span class="p">=</span><span class="k">tab</span>:»\ <span class="p">,</span><span class="nb">eol</span>:¬
<span class="c"> " automatically change window's cwd to file's dir</span>
<span class="k">set</span> <span class="nb">autochdir</span>
<span class="c"> " I'm prefer spaces to tabs</span>
<span class="k">set</span> <span class="nb">tabstop</span><span class="p">=</span><span class="m">4</span>
<span class="k">set</span> <span class="nb">shiftwidth</span><span class="p">=</span><span class="m">4</span>
<span class="k">set</span> <span class="nb">expandtab</span>
<span class="c"> " Backspace key won't move from current line</span>
<span class="k">set</span> <span class="nb">backspace</span><span class="p">=</span>indent<span class="p">,</span><span class="nb">eol</span><span class="p">,</span><span class="k">start</span>
<span class="c"> " folding</span>
<span class="k">set</span> <span class="nb">foldenable</span>
<span class="k">set</span> <span class="nb">foldmethod</span><span class="p">=</span>indent
<span class="k">set</span> <span class="nb">foldlevel</span><span class="p">=</span><span class="m">99</span>
<span class="c"> " disable F1</span>
imap <span class="p"><</span>F1<span class="p">></span> <span class="p"><</span>nop<span class="p">></span>
nmap <span class="p"><</span>F1<span class="p">></span> <span class="p"><</span>nop<span class="p">></span>
<span class="c"> " 256 colors</span>
<span class="nb">syntax</span> <span class="k">on</span>
<span class="k">if</span> $COLORTERM <span class="p">==</span> <span class="s1">'gnome-terminal'</span>
<span class="k">set</span> <span class="nb">t_Co</span><span class="p">=</span><span class="m">256</span>
<span class="k">endif</span>
<span class="c"> " Подсветка 80й колонки в *.py файлах</span>
autocmd <span class="nb">FileType</span> python <span class="k">setlocal</span> <span class="nb">colorcolumn</span><span class="p">=</span><span class="m">80</span>
<span class="c"> " отключаем режим совместимости с Vi</span>
<span class="k">set</span> <span class="nb">nocompatible</span>
<span class="k">filetype</span> off
<span class="k">set</span> <span class="nb">mousehide</span> <span class="c">"Спрятать курсор мыши когда набираем текст</span>
<span class="k">set</span> <span class="nb">mouse</span><span class="p">=</span><span class="k">a</span> <span class="c">"Включить поддержку мыши</span>
<span class="k">set</span> <span class="nb">termencoding</span><span class="p">=</span>utf<span class="m">-8</span> <span class="c">"Кодировка терминала</span>
<span class="k">set</span> <span class="nb">novisualbell</span> <span class="c">"Не мигать</span>
<span class="k">set</span> <span class="nb">t_vb</span><span class="p">=</span> <span class="c">"Не пищать! (Опции 'не портить текст', к сожалению, нету)</span>
<span class="c"> " Курсор</span>
<span class="k">set</span> <span class="nb">cuc</span> <span class="nb">cul</span>
<span class="nb">highlight</span> CursorLine cterm<span class="p">=</span>none ctermbg<span class="p">=</span><span class="m">235</span>
<span class="nb">highlight</span> CursorColumn cterm<span class="p">=</span>none ctermbg<span class="p">=</span><span class="m">235</span>
</pre></div>
</div>
<p>Здесь думаю все понятно, объясню разве что фолдинг. Он у меня включен, но по
умолчанию все развернуто. Что бы сфолдить/разфолдить я иногда пользуюсь
командой <code class="docutils literal"><span class="pre">za</span></code>.</p>
</div>
<div class="section" id="id3">
<h2>Пакетный менеджер</h2>
<p><a class="reference external" href="http://www.vim.org">vim</a> имеет множество дополнений, раньше приходилось их скачивать и
рассовывать файлы по папкам вручную, сейчас есть <a class="reference external" href="https://github.com/VundleVim/Vundle.vim">VundleVim/Vundle.vim</a>
(а ещё лучше <a class="reference external" href="https://github.com/junegunn/vim-plug">junegunn/vim-plug</a>) пакетный менеджер который делает это
за вас, аля <a class="reference external" href="https://www.freebsd.org/cgi/man.cgi?query=apt-get">apt-get</a> (для любителей экзотики <a class="reference external" href="https://github.com/egalpin/apt-vim">egalpin/apt-vim</a>).</p>
<p>Установка:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ git clone https://github.com/gmarik/vundle.git ~/.vim/bundle/vundle
</pre></div>
</div>
<p>Настройка (<code class="docutils literal"><span class="pre">~/.vimrc</span></code>):</p>
<div class="highlight-vim"><div class="highlight"><pre><span></span><span class="c">""""</span>
<span class="c">" Vundle - packages control</span>
<span class="c">"</span>
<span class="k">set</span> <span class="nb">rtp</span><span class="p">+=~</span><span class="sr">/.vim/</span>bundle<span class="sr">/vundle/</span>
<span class="k">call</span> vundle#rc<span class="p">()</span>
<span class="c"> " let Vundle manage Vundle</span>
<span class="c"> " required!</span>
Bundle <span class="s1">'gmarik/vundle'</span>
</pre></div>
</div>
<p>Теперь посмотрим в действии, перезагрузим конфиг открытого <a class="reference external" href="http://www.vim.org">vim</a>:</p>
<p><code class="docutils literal"><span class="pre">:source</span> <span class="pre">$MYVIMRC</span></code></p>
<p>Установим все пакеты:</p>
<p><code class="docutils literal"><span class="pre">:BundleInstall</span></code></p>
<p>Обновим пакеты:</p>
<p><code class="docutils literal"><span class="pre">:BundleUpdate</span></code></p>
<p>Через директиву <code class="docutils literal"><span class="pre">Bundle</span></code> добавляются пакеты, причем ищутся они автоматически
на <a class="reference external" href="https://github.com/">github</a> или <code class="docutils literal"><span class="pre">vimscripts</span></code>.</p>
</div>
<div class="section" id="vimcommander">
<h2>VimCommander</h2>
<p>для перемещения, удаления файлов и директорий я использую
<a class="reference external" href="https://github.com/lpenz/VimCommander">lpenz/VimCommander</a>, это аналог <code class="docutils literal"><span class="pre">MidnightCommander</span></code>. Мне удобнее
прямо в <a class="reference external" href="http://www.vim.org">vim</a> нажать <code class="docutils literal"><span class="pre"><F9></span></code> (открыть <code class="docutils literal"><span class="pre">VimComander</span></code>), выделить файлы и
нажать <code class="docutils literal"><span class="pre"><F5></span></code> или <code class="docutils literal"><span class="pre"><F8></span></code>, чем переключаться в другое окно и запускать
<a class="reference external" href="https://www.freebsd.org/cgi/man.cgi?query=mc">mc</a>.</p>
<div class="figure align-center" id="id15">
<img alt="_static/2013/vimcommander.png" src="_static/2013/vimcommander.png" />
<p class="caption"><span class="caption-text">VimCommander</span></p>
</div>
<p>Конфиг:</p>
<div class="highlight-vim"><div class="highlight"><pre><span></span><span class="c">""""</span>
<span class="c">" VimCommander</span>
<span class="c">"</span>
Bundle <span class="s1">'lpenz/vimcommander'</span>
<span class="nb">noremap</span> <span class="p"><</span><span class="k">silent</span><span class="p">></span> <span class="p"><</span>F9<span class="p">></span> :<span class="k">cal</span> VimCommanderToggle<span class="p">()<</span>CR<span class="p">></span>
</pre></div>
</div>
<p>Установка:</p>
<p><code class="docutils literal"><span class="pre">:BundleInstall</span></code></p>
</div>
<div class="section" id="nerdtree">
<h2>NERDTree</h2>
<p>Левое окошко на картинке выше это <a class="reference external" href="https://github.com/scrooloose/NERDTree">scrooloose/NERDTree</a>, в нем можно
перемещаться по каталогам, открывать файлы в текущем буфере или в виде вкладки
итд. Вкладки и файлы можно тыкать мышью. Что бы открыть файл в текущем окне,
просто кликните по нему мышью или нажмите <code class="docutils literal"><span class="pre"><ENTER></span></code> или <code class="docutils literal"><span class="pre">o</span></code>. Для открытия в
новой вкладке нажмите <code class="docutils literal"><span class="pre">t</span></code>. Для отображения скрытых файлов (начинаются с
точки), нажмите <code class="docutils literal"><span class="pre">Shift+i</span></code>. Для доп. информации <code class="docutils literal"><span class="pre">?</span></code>.</p>
<p>Конфиг:</p>
<div class="highlight-vim"><div class="highlight"><pre><span></span><span class="c">""""</span>
<span class="c">" NerdTree</span>
<span class="c">"</span>
Bundle <span class="s1">'scrooloose/nerdtree'</span>
<span class="c"> "map <F2> :NERDTreeToggle<CR></span>
<span class="c"> " Автоматическое закрытие с последним окном</span>
autocmd bufenter * <span class="k">if</span> <span class="p">(</span>winnr<span class="p">(</span><span class="s2">"$"</span><span class="p">)</span> <span class="p">==</span> <span class="m">1</span> && exists<span class="p">(</span><span class="s2">"b:NERDTreeType"</span><span class="p">)</span> && <span class="k">b</span>:NERDTreeType <span class="p">==</span> <span class="s2">"primary"</span><span class="p">)</span> <span class="p">|</span> <span class="k">q</span> <span class="p">|</span> <span class="k">endif</span>
<span class="c"> " Убираем в табах путь у файлу (только название файла)</span>
<span class="k">set</span> <span class="nb">tabline</span><span class="p">=</span>%<span class="p">!</span>MyTabLine<span class="p">()</span>
<span class="k">function</span><span class="p">!</span> MyTabLine<span class="p">()</span>
<span class="k">let</span> s <span class="p">=</span> <span class="s1">''</span>
<span class="k">for</span> <span class="k">i</span> <span class="k">in</span> range<span class="p">(</span>tabpagenr<span class="p">(</span><span class="s1">'$'</span><span class="p">))</span>
<span class="c"> " select the highlighting</span>
<span class="k">if</span> <span class="k">i</span> <span class="p">+</span> <span class="m">1</span> <span class="p">==</span> tabpagenr<span class="p">()</span>
<span class="k">let</span> s .<span class="p">=</span> <span class="s1">'%#TabLineSel#'</span>
<span class="k">else</span>
<span class="k">let</span> s .<span class="p">=</span> <span class="s1">'%#TabLine#'</span>
<span class="k">endif</span>
<span class="c"> " set the tab page number (for mouse clicks)</span>
<span class="k">let</span> s .<span class="p">=</span> <span class="s1">'%'</span> . <span class="p">(</span><span class="k">i</span> <span class="p">+</span> <span class="m">1</span><span class="p">)</span> . <span class="s1">'T'</span>
<span class="c"> " the label is made by MyTabLabel()</span>
<span class="k">let</span> s .<span class="p">=</span> <span class="s1">' %{MyTabLabel('</span> . <span class="p">(</span><span class="k">i</span> <span class="p">+</span> <span class="m">1</span><span class="p">)</span> . <span class="s1">')} |'</span>
<span class="k">endfor</span>
<span class="c"> " after the last tab fill with TabLineFill and reset tab page nr</span>
<span class="k">let</span> s .<span class="p">=</span> <span class="s1">'%#TabLineFill#%T'</span>
<span class="c">"""""""" " right-align the label to close the current tab page</span>
<span class="k">if</span> tabpagenr<span class="p">(</span><span class="s1">'$'</span><span class="p">)</span> <span class="p">></span> <span class="m">1</span>
<span class="k">let</span> s .<span class="p">=</span> <span class="s1">'%=%#TabLine#%999X X'</span>
<span class="k">endif</span>
<span class="c"> "echomsg 's:' . s</span>
<span class="k">return</span> s
<span class="k">endfunction</span>
<span class="k">function</span><span class="p">!</span> MyTabLabel<span class="p">(</span><span class="k">n</span><span class="p">)</span>
<span class="k">let</span> buflist <span class="p">=</span> tabpagebuflist<span class="p">(</span><span class="k">a</span>:<span class="k">n</span><span class="p">)</span>
<span class="k">let</span> winnr <span class="p">=</span> tabpagewinnr<span class="p">(</span><span class="k">a</span>:<span class="k">n</span><span class="p">)</span>
<span class="k">let</span> numtabs <span class="p">=</span> tabpagenr<span class="p">(</span><span class="s1">'$'</span><span class="p">)</span>
<span class="c"> " account for space padding between tabs, and the "close" button</span>
<span class="k">let</span> maxlen <span class="p">=</span> <span class="p">(</span> &<span class="nb">columns</span> <span class="p">-</span> <span class="p">(</span> numtabs * <span class="m">2</span> <span class="p">)</span> <span class="p">-</span> <span class="m">4</span> <span class="p">)</span> / numtabs
<span class="k">let</span> tablabel <span class="p">=</span> bufname<span class="p">(</span>buflist[winnr <span class="p">-</span> <span class="m">1</span>]<span class="p">)</span>
<span class="k">while</span> strlen<span class="p">(</span> tablabel <span class="p">)</span> <span class="p"><</span> <span class="m">4</span>
<span class="k">let</span> tablabel <span class="p">=</span> tablabel . <span class="s2">" "</span>
<span class="k">endwhile</span>
<span class="k">let</span> tablabel <span class="p">=</span> fnamemodify<span class="p">(</span> tablabel<span class="p">,</span> <span class="s1">':t'</span> <span class="p">)</span>
<span class="k">let</span> tablabel <span class="p">=</span> strpart<span class="p">(</span> tablabel<span class="p">,</span> <span class="m">0</span><span class="p">,</span> maxlen <span class="p">)</span>
<span class="k">return</span> tablabel
<span class="k">endfunction</span>
<span class="c">""""</span>
<span class="c">" NerdTree-Tabs</span>
<span class="c">"</span>
Bundle <span class="s1">'jistr/vim-nerdtree-tabs'</span>
map <span class="p"><</span>F2<span class="p">></span> :NERDTreeTabsToggle<span class="p"><</span>CR<span class="p">></span>
<span class="k">let</span> NERDTreeIgnore <span class="p">=</span> [<span class="s1">'\.pyc$'</span>]
</pre></div>
</div>
<p><a class="reference external" href="https://github.com/jistr/vim-nerdtree-tabs">jistr/vim-nerdtree-tabs</a> нужен для зацикленного открытия/закрытия по
<code class="docutils literal"><span class="pre"><F2></span></code>.</p>
</div>
<div class="section" id="klen-python-mode">
<h2><a class="reference external" href="https://github.com/klen/python-mode">klen/python-mode</a></h2>
<p>отличная штука которая подсвечивает ошибки, следит за <span class="target" id="index-0"></span><a class="pep reference external" href="https://www.python.org/dev/peps/pep-0008"><strong>PEP 8</strong></a>, позволят делать
<code class="docutils literal"><span class="pre">breakpoint'ы</span></code> для дебага, ну и еще <a class="reference external" href="https://github.com/klen/python-mode">многое другое</a>.</p>
<p>Конфиг:</p>
<div class="highlight-vim"><div class="highlight"><pre><span></span><span class="c">""""</span>
<span class="c">" Python mode</span>
<span class="c">"</span>
Bundle <span class="s1">'klen/python-mode'</span>
<span class="c"> " Python-mode</span>
<span class="c"> " Activate rope</span>
<span class="c"> " Keys:</span>
<span class="c"> " K Show python docs</span>
<span class="c"> " <Ctrl-Space> Rope autocomplete</span>
<span class="c"> " <Ctrl-c>g Rope goto definition</span>
<span class="c"> " <Ctrl-c>d Rope show documentation</span>
<span class="c"> " <Ctrl-c>f Rope find occurrences</span>
<span class="c"> " <Leader>b Set, unset breakpoint (g:pymode_breakpoint enabled)</span>
<span class="c"> " [[ Jump on previous class or function (normal, visual, operator modes)</span>
<span class="c"> " ]] Jump on next class or function (normal, visual, operator modes)</span>
<span class="c"> " [M Jump on previous class or method (normal, visual, operator modes)</span>
<span class="c"> " ]M Jump on next class or method (normal, visual, operator modes)</span>
<span class="k">let</span> <span class="k">g</span>:pymode_rope <span class="p">=</span> <span class="m">0</span>
<span class="k">let</span> <span class="k">g</span>:pymode_lint_ignore <span class="p">=</span> <span class="s2">"E501,C0110,W0102,F0401,C0301"</span>
<span class="c"> " Documentation</span>
<span class="k">let</span> <span class="k">g</span>:pymode_doc <span class="p">=</span> <span class="m">1</span>
<span class="k">let</span> <span class="k">g</span>:pymode_doc_key <span class="p">=</span> <span class="s1">'<F1>'</span>
<span class="c"> "Linting</span>
<span class="k">let</span> <span class="k">g</span>:pymode_lint <span class="p">=</span> <span class="m">1</span>
<span class="k">let</span> <span class="k">g</span>:pymode_lint_checker <span class="p">=</span> <span class="s2">"pyflakes,pep8"</span>
<span class="c"> " Auto check on save</span>
<span class="k">let</span> <span class="k">g</span>:pymode_lint_write <span class="p">=</span> <span class="m">1</span>
<span class="c"> " Support virtualenv</span>
<span class="k">let</span> <span class="k">g</span>:pymode_virtualenv <span class="p">=</span> <span class="m">1</span>
<span class="c"> " Enable breakpoints plugin</span>
<span class="k">let</span> <span class="k">g</span>:pymode_breakpoint <span class="p">=</span> <span class="m">1</span>
<span class="k">let</span> <span class="k">g</span>:pymode_breakpoint_key <span class="p">=</span> <span class="s1">'<leader>b'</span>
<span class="c"> " syntax highlighting</span>
<span class="k">let</span> <span class="k">g</span>:pymode_syntax <span class="p">=</span> <span class="m">1</span>
<span class="k">let</span> <span class="k">g</span>:pymode_syntax_all <span class="p">=</span> <span class="m">1</span>
<span class="k">let</span> <span class="k">g</span>:pymode_syntax_indent_errors <span class="p">=</span> <span class="k">g</span>:pymode_syntax_all
<span class="k">let</span> <span class="k">g</span>:pymode_syntax_space_errors <span class="p">=</span> <span class="k">g</span>:pymode_syntax_all
<span class="c"> " Don't autofold code</span>
<span class="k">let</span> <span class="k">g</span>:pymode_folding <span class="p">=</span> <span class="m">0</span>
<span class="c"> " replace pdb to ipdb</span>
iab ipdb import ipdb; ipdb.set_trace<span class="p">()</span>
</pre></div>
</div>
<p>Для создания <code class="docutils literal"><span class="pre">breackpoint'а</span></code> нажимаем <code class="docutils literal"><span class="pre"><leader>b</span></code>, остальное думаю и так
понятно по коментам.</p>
</div>
<div class="section" id="id5">
<h2>Автодополнение кода</h2>
<p>для автодополнения я использую <a class="reference external" href="https://github.com/davidhalter/jedi-vim">davidhalter/jedi-vim</a> и
<a class="reference external" href="https://github.com/Valloric/YouCompleteMe">Valloric/YouCompleteMe</a>.</p>
<img alt="_static/2013/ycm.gif" class="align-center" src="_static/2013/ycm.gif" />
<p>Конфиг:</p>
<div class="highlight-vim"><div class="highlight"><pre><span></span><span class="c">" Jedi - autocomplete</span>
<span class="c">"</span>
Bundle <span class="s1">'davidhalter/jedi-vim'</span>
<span class="k">let</span> <span class="k">g</span>:jedi#show_call_signatures <span class="p">=</span> <span class="m">1</span>
<span class="c">""""</span>
<span class="c">" YouCompleteMe</span>
<span class="c">"</span>
Bundle <span class="s1">'Valloric/YouCompleteMe'</span>
<span class="c">""""</span>
<span class="c">" SuperTab</span>
<span class="c">"</span>
Bundle <span class="s1">'ervandew/supertab'</span>
</pre></div>
</div>
<p>Установка:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ pip install jedi
</pre></div>
</div>
<p><code class="docutils literal"><span class="pre">YoCompleteMe</span></code> требует минимум <code class="docutils literal"><span class="pre">7.3</span></code> версию <a class="reference external" href="http://www.vim.org">Vim</a>, поэтому его нужно
будет пересобрать. Это очень просто, <a class="reference external" href="https://github.com/Valloric/YouCompleteMe/wiki/Building-Vim-from-source">инструкция здесь</a>.</p>
<p><a class="reference external" href="https://github.com/ervandew/SuperTab">ervandew/SuperTab</a> включает дополнение по <code class="docutils literal"><span class="pre"><Tab></span></code>.</p>
</div>
<div class="section" id="tagbar">
<h2>TagBar</h2>
<p><a class="reference external" href="https://github.com/majutsushi/tagbar">majutsushi/tagbar</a> это правое окошко на рисунке:</p>
<img alt="_static/2013/tagbar.png" class="align-center" src="_static/2013/tagbar.png" />
<p>По сути это навигация по классам и функциям, очень удобно переходить к классу
просто по нему кликнув. На рисунке видно что он подсвечивает функцию в которой
я нахожусь.</p>
<p>Конфиг:</p>
<div class="highlight-vim"><div class="highlight"><pre><span></span><span class="c">""""</span>
<span class="c">" TagBar</span>
<span class="c">"</span>
Bundle <span class="s1">'majutsushi/tagbar'</span>
nmap <span class="p"><</span>F8<span class="p">></span> :TagbarToggle<span class="p"><</span>CR<span class="p">></span>
</pre></div>
</div>
</div>
<div class="section" id="id7">
<h2>Подсветка синтаксиса</h2>
<div class="highlight-vim"><div class="highlight"><pre><span></span><span class="c">""""</span>
<span class="c">" Color</span>
<span class="c">"</span>
Bundle <span class="s1">'jonathanfilip/vim-lucius'</span>
<span class="k">color</span> lucius
map <span class="p"><</span>F5<span class="p">></span> :<span class="k">call</span> ToggleBg<span class="p">()<</span>CR<span class="p">></span>
<span class="k">set</span> <span class="nb">bg</span><span class="p">=</span><span class="nb">dark</span>
<span class="k">function</span><span class="p">!</span> ToggleBg<span class="p">()</span>
<span class="k">if</span> &<span class="nb">background</span> <span class="p">==</span> <span class="s1">'dark'</span>
<span class="k">set</span> <span class="nb">bg</span><span class="p">=</span><span class="nb">light</span>
<span class="k">else</span>
<span class="k">set</span> <span class="nb">bg</span><span class="p">=</span><span class="nb">dark</span>
<span class="k">endif</span>
endfunc
</pre></div>
</div>
<p>Тема <a class="reference external" href="https://github.com/jonathanfilip/vim-lucius">jonathanfilip/vim-lucius</a>. Можно по <code class="docutils literal"><span class="pre"><F5></span></code> переключаться с светлой, на
темную :)</p>
<p>Подсветка различных типов:</p>
<div class="highlight-vim"><div class="highlight"><pre><span></span><span class="c">""""</span>
<span class="c">" Syntax file</span>
<span class="c">"</span>
Bundle <span class="s1">'me-vlad/python-syntax.vim'</span>
<span class="c">""""</span>
<span class="c">" sophacles / vim-bundle-mako</span>
<span class="c">"</span>
Bundle <span class="s2">"sophacles/vim-bundle-mako"</span>
<span class="k">au</span> <span class="nb">BufNewFile</span><span class="p">,</span><span class="nb">BufRead</span> *.mako <span class="k">set</span> <span class="nb">ft</span><span class="p">=</span>mako
<span class="c">""""</span>
<span class="c">" tmux syntax</span>
<span class="c">"</span>
Bundle <span class="s2">"tejr/vim-tmux"</span>
<span class="c">""""</span>
<span class="c">" Vim-Jinja2</span>
<span class="c">"</span>
Bundle <span class="s1">'Glench/Vim-Jinja2-Syntax'</span>
<span class="k">au</span> <span class="nb">BufRead</span><span class="p">,</span><span class="nb">BufNewFile</span> *.jinja2 <span class="k">set</span> <span class="k">filetype</span><span class="p">=</span>jinja
<span class="c">""""</span>
<span class="c">" Jinja2</span>
<span class="c">"</span>
<span class="c"> " Works with http://www.vim.org/scripts/script.php?script_id=2075</span>
<span class="c"> " indent/htm.vim</span>
Bundle <span class="s2">"lepture/vim-jinja"</span>
<span class="k">au</span> <span class="nb">BufNewFile</span><span class="p">,</span><span class="nb">BufRead</span> *.html<span class="p">,</span>*.htm<span class="p">,</span>*.shtml<span class="p">,</span>*.stm<span class="p">,</span>*.jinja2 <span class="k">set</span> <span class="nb">ft</span><span class="p">=</span>jinja
<span class="k">au</span> <span class="nb">FileType</span> jinja <span class="k">setl</span> <span class="k">sw</span><span class="p">=</span><span class="m">2</span> <span class="k">ts</span><span class="p">=</span><span class="m">2</span> <span class="nb">et</span> <span class="k">nu</span>
<span class="k">au</span> <span class="nb">FileType</span> jinja <span class="k">hi</span> link htmlLink <span class="nb">NONE</span>
autocmd Filetype jinja :normal gg<span class="p">=</span>G
</pre></div>
</div>
<p>Подсветка для <a class="reference external" href="http://jinja.pocoo.org/">Jinja2</a> отлично подходит к <a class="reference external" href="https://www.djangoproject.com/">Django</a> шаблонам.</p>
</div>
<div class="section" id="id8">
<h2>Автосохранение</h2>
<p>я не использую <code class="docutils literal"><span class="pre">swp</span></code> файлы для восстановления файлов, вместо этого файл
автосохраняется каждую секунду.</p>
<p>Конфиг:</p>
<div class="highlight-vim"><div class="highlight"><pre><span></span><span class="c">""""</span>
<span class="c">" Autosave</span>
<span class="c">"</span>
Bundle <span class="s2">"vim-auto-save"</span>
<span class="k">let</span> <span class="k">g</span>:auto_save <span class="p">=</span> <span class="m">1</span> <span class="c">" enable AutoSave on Vim startup</span>
<span class="k">set</span> <span class="nb">noswapfile</span>
</pre></div>
</div>
</div>
<div class="section" id="id9">
<h2>Шаблоны</h2>
<p><a class="reference external" href="https://github.com/aperezdc/vim-template">aperezdc/vim-template</a> имеет заготовки для разных типов файлов.
Например для файлов <code class="docutils literal"><span class="pre">*.py</span></code>, <code class="docutils literal"><span class="pre">Makefile</span></code> и т.д. Если я создам новый файл
<code class="docutils literal"><span class="pre">my.py</span></code>, то у меня сразу появится следующий текст в нем:</p>
<div class="literal-block-wrapper docutils container" id="id16">
<div class="code-block-caption"><span class="caption-text">my.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="ch">#! /usr/bin/env python</span>
<span class="c1"># -*- coding: utf-8 -*-</span>
<span class="c1"># vim:fenc=utf-8</span>
<span class="c1">#</span>
<span class="c1"># Copyright © 2013 uralbash <root@uralbash.ru></span>
<span class="c1">#</span>
<span class="c1"># Distributed under terms of the MIT license.</span>
<span class="sd">"""</span>
<span class="sd">"""</span>
</pre></div>
</div>
</div>
<p>Или <code class="docutils literal"><span class="pre">Makefile</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1">#</span>
<span class="c1"># Makefile</span>
<span class="c1"># uralbash, 2013-11-23 01:01</span>
<span class="c1">#</span>
all:
@echo <span class="s2">"Makefile needs your attention"</span>
<span class="c1"># vim:ft=make</span>
<span class="c1">#</span>
</pre></div>
</div>
<p>Конфиг:</p>
<div class="highlight-vim"><div class="highlight"><pre><span></span><span class="c">""""</span>
<span class="c">" Template</span>
<span class="c">"</span>
Bundle <span class="s1">'aperezdc/vim-template'</span>
<span class="k">let</span> <span class="k">g</span>:email <span class="p">=</span> <span class="s1">'root@uralbash.ru'</span>
</pre></div>
</div>
<p>В непустой файл можно добавить шапку так:</p>
<p><code class="docutils literal"><span class="pre">:Template</span> <span class="pre">py</span></code></p>
</div>
<div class="section" id="powerline">
<h2>Powerline</h2>
<img alt="_static/2013/powerline.png" class="align-center" src="_static/2013/powerline.png" />
<p>Божественно красивая статусная строка, как установить <code class="docutils literal"><span class="pre">powerline</span></code> шыкарно
<a class="reference external" href="http://askubuntu.com/questions/283908/how-can-i-install-and-use-powerline-plugin">описано здесь</a>.
Но я рекомендую <a class="reference external" href="https://github.com/bling/vim-airline">bling/vim-airline</a>, в нем больше фич, в частности совместимость с
популярными плагинами.</p>
<p>Конфиг:</p>
<div class="highlight-vim"><div class="highlight"><pre><span></span><span class="c">""""</span>
<span class="c">" Powerline - status bar</span>
<span class="c">"</span>
<span class="c">" Bundle 'Lokaltog/powerline', {'rtp': 'powerline/bindings/vim/'}</span>
<span class="c"> " Powerline setup</span>
<span class="c"> " http://askubuntu.com/questions/283908/how-can-i-install-and-use-powerline-plugin</span>
<span class="c">" set encoding=utf-8 " Necessary to show Unicode glyphs</span>
<span class="c">" set rtp+=$HOME/.local/lib/python2.7/site-packages/powerline/bindings/vim/</span>
<span class="c"> " Always show statusline</span>
<span class="c">" set laststatus=2</span>
<span class="c">" set t_Co=256v</span>
<span class="c">" set guifont=DejaVu\ Sans\ Mono\ for\ Powerline\ 9</span>
<span class="c">" let g:Powerline_symbols = 'fancy'</span>
<span class="c">" set laststatus=2</span>
Bundle <span class="s1">'bling/vim-airline'</span>
<span class="k">let</span> <span class="k">g</span>:airline_theme<span class="p">=</span><span class="s1">'powerlineish'</span>
<span class="k">let</span> <span class="k">g</span>:airline_powerline_fonts
</pre></div>
</div>
</div>
<div class="section" id="git">
<h2>Git</h2>
<p><a class="reference external" href="https://github.com/airblade/vim-gitgutter">airblade/vim-gitgutter</a> отображает текущую ветку и показывает внесенные
изменения по сравнению с предыдущим коммитом.</p>
<img alt="_static/2013/vim_git1.png" class="align-center" src="_static/2013/vim_git1.png" />
<img alt="_static/2013/vim_git2.png" class="align-center" src="_static/2013/vim_git2.png" />
<p>Конфиг:</p>
<div class="highlight-vim"><div class="highlight"><pre><span></span><span class="c">""""</span>
<span class="c">" A Vim plugin which shows a git diff in the 'gutter' (sign column).</span>
<span class="c">"</span>
Bundle <span class="s1">'airblade/vim-gitgutter'</span>
</pre></div>
</div>
</div>
<div class="section" id="id11">
<h2>Что еще?</h2>
<p>Есть еще огромное количество плагинов, которые невозможно описать в одной
статье. Если вы настроите то что я описал, то вам не составит труда добавить
что то самостоятельно. Например мой <code class="docutils literal"><span class="pre">:BundleList</span></code>.</p>
<div class="highlight-vim"><div class="highlight"><pre><span></span><span class="c">" My Bundles</span>
Bundle <span class="s1">'gmarik/vundle'</span>
Bundle <span class="s1">'bling/vim-airline'</span>
Bundle <span class="s1">'airblade/vim-gitgutter'</span>
Bundle <span class="s1">'tpope/vim-fugitive'</span>
Bundle <span class="s1">'scrooloose/nerdtree'</span>
Bundle <span class="s1">'jistr/vim-nerdtree-tabs'</span>
Bundle <span class="s1">'klen/python-mode'</span>
Bundle <span class="s1">'davidhalter/jedi-vim'</span>
Bundle <span class="s1">'spf13/vim-colors'</span>
Bundle <span class="s1">'tpope/vim-vividchalk'</span>
Bundle <span class="s1">'morhetz/gruvbox'</span>
Bundle <span class="s1">'jonathanfilip/vim-lucius'</span>
Bundle <span class="s1">'flazz/vim-colorschemes'</span>
Bundle <span class="s1">'majutsushi/tagbar'</span>
Bundle <span class="s1">'aperezdc/vim-template'</span>
Bundle <span class="s1">'me-vlad/python-syntax.vim'</span>
Bundle <span class="s1">'ervandew/supertab'</span>
Bundle <span class="s1">'lpenz/vimcommander'</span>
Bundle <span class="s1">'Glench/Vim-Jinja2-Syntax'</span>
Bundle <span class="s1">'lepture/vim-jinja'</span>
Bundle <span class="s1">'vim-auto-save'</span>
Bundle <span class="s1">'sophacles/vim-bundle-mako'</span>
Bundle <span class="s1">'tejr/vim-tmux'</span>
Bundle <span class="s1">'lyokha/vim-xkbswitch'</span>
Bundle <span class="s1">'vim-scripts/vim-punto-switcher'</span>
</pre></div>
</div>
</div>
<div class="section" id="id12">
<h2>Книги</h2>
<p>В этом году вышли аж 2 книги на русском языке:</p>
<a class="reference external image-reference" href="http://www.books.ru/books/izuchaem-redaktory-vi-i-vim-7-e-izdanie-fail-3579382/?show=1&partner=490327"><img alt="_static/2012/vi_book.jpg" src="_static/2012/vi_book.jpg" style="width: 200px;" /></a>
<a class="reference external image-reference" href="http://www.дмк.рф/catalog/computer/programming/978-5-94074-972-1/"><img alt="_static/2013/vim.jpg" src="_static/2013/vim.jpg" style="width: 200px;" /></a>
</div>
<div class="section" id="anykey">
<h2>AnyKey</h2>
<p>для практики конечно же <code class="docutils literal"><span class="pre">vimtutor</span></code>, для фана следующие ресурсы:</p>
<ul class="simple">
<li><a class="reference external" href="http://www.openvim.com/tutorial.html">http://www.openvim.com/tutorial.html</a></li>
<li><a class="reference external" href="http://vim-adventures.com/">http://vim-adventures.com/</a></li>
<li><a class="reference external" href="http://ru.wikipedia.org/wiki/Vimperator">http://ru.wikipedia.org/wiki/Vimperator</a></li>
<li><a class="reference external" href="http://stackoverflow.com/questions/1218390/what-is-your-most-productive-shortcut-with-vim">http://stackoverflow.com/questions/1218390/what-is-your-most-productive-shortcut-with-vim</a></li>
</ul>
</div>
<div class="section" id="id13">
<h2>Другие статьи</h2>
<ul class="simple">
<li><a class="reference external" href="http://blog.sontek.net/blog/detail/turning-vim-into-a-modern-python-ide">http://blog.sontek.net/blog/detail/turning-vim-into-a-modern-python-ide</a></li>
<li><a class="reference external" href="http://unlogic.co.uk/posts/vim-python-ide.html">http://unlogic.co.uk/posts/vim-python-ide.html</a></li>
<li><a class="reference external" href="http://pep8.ru/blog/tag/vim">http://pep8.ru/blog/tag/vim</a></li>
<li>Супер инструкция <a class="reference external" href="https://github.com/joedicastro/dotfiles/tree/master/vim">https://github.com/joedicastro/dotfiles/tree/master/vim</a></li>
</ul>
</div>
<div class="section" id="id14">
<h2>Итого</h2>
<p>Таких заметок как эта несчетное множество и все равно они вызывают интерес,
потому что в мире нет двух одинаковых конфигов Vim. Вы можете подсмотреть здесь
какие-то идеи, но ваша конфигурация не будет один в один совпадать, у вас
наверняка есть разногласия со мной и вы захотите сделать Vim удобным для себя.
Тем самым конфиг Vim’а является отображением стиля программирования. По этой
причине я не выкладываю свой конфиг в чистом виде, для типовых вещей есть IDE -
это как костюм пошитый на заказ по вашим размерам и пеплос 52 размера купленный
на рынке.</p>
</div>
</div>
С чего начать?©
http://uralbash.ru/articles/2013/where_to_start/
2013-11-22T09:24:00Z
2013-11-22T09:24:00Z
Uralbash
<div class="section" id="were-to-start">
<span id="id1"></span>
<p>С чего начать программировать?</p>
<p>Элементарно же: написать ТЗ, выбрать фреймворк, спроектировать базу, написать
функцию, написать тест... Ну или какой-нибудь ваш ответ, здесь всё равно что то
тормозит, а именно окружение, именно про него все забывают. Попробую описать
один из возможных вариантов для <a class="reference external" href="http://www.python.org/">python</a>.</p>
<div class="section" id="virtualenv">
<h2><a class="reference external" href="https://pypi.python.org/pypi/Virtualenv">Virtualenv</a></h2>
<p>замечательная штука, позволяет под каждый проект создать свое окружение
пакетов, при чём избавляя основное окружение дистрибутива от захламления. Это
одна из самых крутых фич питона.</p>
<p>установка:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ pip install virtualenv
</pre></div>
</div>
</div>
<div class="section" id="virtualenvwrapper">
<h2><a class="reference external" href="https://pypi.python.org/pypi/Virtualenvwrapper">Virtualenvwrapper</a></h2>
<p>В чистом виде <a class="reference external" href="https://pypi.python.org/pypi/virtualenv">virtualenv</a> имеет множество команд для гибкой настройки
окружения, но каждый раз делать одни и те же действия не хорошо, по этому
придумали пакет <a class="reference external" href="https://pypi.python.org/pypi/virtualenvwrapper">virtualenvwrapper</a> облегчающий работу с
<a class="reference external" href="https://pypi.python.org/pypi/virtualenv">virtualenv</a> (люди не использующие его мне кажутся странными).</p>
<p>установка:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ pip install virtualenvwrapper
</pre></div>
</div>
<p>для того что бы в окружении консоли (вашего системного профиля) появились
команды <a class="reference external" href="https://pypi.python.org/pypi/virtualenvwrapper">virtualenvwrapper</a>, нужно выполнить команду:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ <span class="nb">source</span> /usr/local/bin/virtualenvwrapper.sh
</pre></div>
</div>
<p>что бы каждый раз после перезагрузки так не делать, добавьте эту строчку в
<code class="docutils literal"><span class="pre">~/.bashrc</span></code>.</p>
<div class="section" id="id2">
<h3>Как это работает</h3>
<p>создаем новое окружение:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ mkvirtualenv <span class="nb">test</span>
</pre></div>
</div>
<p>все мы в нем, в консоле должно появится название окружения:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>uralbash ⓔ <span class="nb">test</span> ~ Projects
</pre></div>
</div>
<p>Теперь все вызовы <a class="reference external" href="https://pypi.python.org/pypi/pip">pip</a> будут устанавливать пакеты в окружение <code class="docutils literal"><span class="pre">test</span></code>.
Что бы выйти из него нужно ввести:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ deactivate
</pre></div>
</div>
<p>Теперь если нужно зайти снова в окружение <code class="docutils literal"><span class="pre">test</span></code> выполняем команду:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ mkvirtualenv <span class="nb">test</span>
</pre></div>
</div>
<p>Команда такая же как и при создании, но если окружение уже существует, то оно
просто откроется. Если у вас много окружений и нужно между ними переключаться,
выполните команду:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ workon test2
</pre></div>
</div>
</div>
</div>
<div class="section" id="pip">
<h2>PIP</h2>
<p>думаю и так все понятно, оставлю здесь лишь пример установка из репозитария на
<a class="reference external" href="https://github.com/">github</a>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ pip install git+http://github.com/uralbash/sacrud.git
</pre></div>
</div>
</div>
<div class="section" id="github">
<h2>Разработка вашего приложения и github</h2>
<p>я пишу <a class="reference external" href="https://pypi.python.org/pypi/sacrud">sacrud</a> и использую его во многих моих проектах, что вызывает
некоторые неудобства если его обновлять через <a class="reference external" href="https://pypi.python.org/pypi/pip">pip</a>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ pip install git+http://github.com/uralbash/sacrud.git --upgrade
</pre></div>
</div>
<p>Это конечно работает, но представьте постоянно обновлять 10 окружений разных
проектов на своем компе, при том что новую версию <a class="reference external" href="https://pypi.python.org/pypi/sacrud">sacrud</a> прежде еще
нужно выложить на <a class="reference external" href="https://github.com/">github</a>. Для решения этой проблемы есть очень простой
способ. В папке с вашим проектом создаем символическую ссылку на локальное
размещение <a class="reference external" href="https://pypi.python.org/pypi/sacrud">sacrud</a>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>example/$ tree
.
├── example
├── Makefile
├── MANIFEST.in
├── production.ini
├── README.md
├── sacrud -> ../sacrud
├── setup.cfg
└── setup.py
</pre></div>
</div>
<p>Таким образом у нас всегда всё с пылу, с жару. Можно пилить <a class="reference external" href="https://pypi.python.org/pypi/sacrud">sacrud</a> и
тут же видеть изменения в ваших проектах.</p>
<div class="admonition note">
<p class="first admonition-title">Примечание</p>
<p>Более элегантный метод - это установить пакет через <a class="reference external" href="https://pypi.python.org/pypi/setuptools">setuptools</a> с
флагом для разработки:</p>
<div class="literal-block-wrapper docutils container" id="id6">
<div class="code-block-caption"><span class="caption-text">В директории пакета выполнить команду</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ python setup.py develop
</pre></div>
</div>
</div>
<p class="last">Он автоматически пропишет симлинк в окружении, что можно будет наблюдать
выполнив <code class="docutils literal"><span class="pre">pip</span> <span class="pre">list</span></code>.</p>
</div>
</div>
<div class="section" id="id3">
<h2>Текстовый редактор</h2>
<p>если кратко описать этот раздел, то он займет 80% этой статьи, посему мне
придется лишь дать наставление использовать продвинутый едитор с множеством
фич, например <code class="docutils literal"><span class="pre">vim</span></code>, <code class="docutils literal"><span class="pre">emacs</span></code>, <span class="strike">sublime text</span>. Плохая идея
использовать <code class="docutils literal"><span class="pre">gedit</span></code> или <code class="docutils literal"><span class="pre">ms</span> <span class="pre">notepad</span></code>. Мой выбор определен на <code class="docutils literal"><span class="pre">Vim</span></code>,
обязательно напишу про него отдельную заметку как использую с <a class="reference external" href="http://www.python.org/">Python</a>, а
пока скриншот:</p>
<div class="figure align-center" id="id7">
<img alt="_static/2013/vim.png" src="_static/2013/vim.png" />
<p class="caption"><span class="caption-text">Vim + Python</span></p>
</div>
<p>здесь видно что я могу перемещаться по файлам, видеть изменения по сравнению с
предыдущим комитом, интроспекция кода, ну и все прочие ништяки.</p>
</div>
<div class="section" id="ide">
<h2>IDE</h2>
<p>не нужны</p>
</div>
<div class="section" id="tmux">
<h2><a class="reference external" href="https://tmux.github.io/">Tmux</a></h2>
<p>это эмулятор терминалов, он позволяет в одной вкладке терминала запустить
несколько окон виртуальных терминалов.</p>
<div class="figure align-center" id="id8">
<img alt="_static/2013/tmux.png" src="_static/2013/tmux.png" />
<p class="caption"><span class="caption-text">tmux</span></p>
</div>
<p>Поверьте, это удобно.</p>
<div class="section" id="id4">
<h3>Пример использования</h3>
<p>в первом окне у меня запущен Веб сервер (<code class="docutils literal"><span class="pre">pserve</span></code> или <code class="docutils literal"><span class="pre">runserver</span></code>), во
втором редактор <code class="docutils literal"><span class="pre">Vim</span></code>, по необходимости я могу создать третье окно для
запуска тестов или <a class="reference external" href="https://pypi.python.org/pypi/ipython">ipython</a> или чего еще. Поехали:</p>
<p>для запуска <a class="reference external" href="https://tmux.github.io/">tmux</a> выполните:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ tmux
</pre></div>
</div>
<p>я обычно запускаю <a class="reference external" href="https://tmux.github.io/">tmux</a> так:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ tmux attach <span class="o">||</span> tmux new
</pre></div>
</div>
<p>здесь он присоединится к существующей сессии или откроет новую. Далее запустим
сервер <a class="reference external" href="http://pylonsproject.org/">Pyramid</a> (<a class="reference external" href="https://pypi.python.org/pypi/waitress">waitress</a>):</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ pserve development.ini.example start --reload
</pre></div>
</div>
<p>Это замечательный сервер, который умеет перезагружаться если вы внесли
изменения в код, но он упадет если в этих изменения есть ошибки. По этому что
бы не подымать его руками запустим сервер так:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ watch -n <span class="m">3</span> pserve development.ini.example start --reload
</pre></div>
</div>
<p><a class="reference external" href="https://www.freebsd.org/cgi/man.cgi?query=watch">watch</a> это утилита которая каждые 3 секунды пытается перезапустить
<code class="docutils literal"><span class="pre">pserve</span></code> (<a class="reference external" href="https://pypi.python.org/pypi/waitress">waitress</a>). Это не сильно нагружает систему зато очень
удобно!</p>
<p>Дальше создаем второе окно, нажимаем <code class="docutils literal"><span class="pre">Ctr^b+c</span></code> (<code class="docutils literal"><span class="pre">create</span></code>), попали в новое
окно пишем <a class="reference external" href="http://www.vim.org">vim</a> и начинаем писать. Если нужно переключиться обратно в 1
окно с сервером, нажимаем <code class="docutils literal"><span class="pre">Ctr^b+n</span></code> (<code class="docutils literal"><span class="pre">next</span></code>).</p>
<p>Если нужно <code class="docutils literal"><span class="pre">закрыть</span> <span class="pre">окно</span></code> просто выполните <a class="reference external" href="https://www.freebsd.org/cgi/man.cgi?query=exit">exit</a>, как если бы закрыли обычный терминал.</p>
<p>Допустим я не хочу создавать отдельное окно для тестов, мой экран позволяет <code class="docutils literal"><span class="pre">два</span>
<span class="pre">окна</span> <span class="pre">уместить</span> <span class="pre">рядом</span></code> и это будет очень удобно (писать код и выполнять тесты на
одном экране, широком правда). В текущем окне с <a class="reference external" href="http://www.vim.org">Vim</a>, нажмите <code class="docutils literal"><span class="pre">Ctr^b+"</span></code>
это <code class="docutils literal"><span class="pre">разделит</span> <span class="pre">экран</span> <span class="pre">по</span> <span class="pre">горизонтали</span></code> пополам.</p>
<div class="line-block">
<div class="line">Что бы <code class="docutils literal"><span class="pre">увеличить</span> <span class="pre">окно</span></code> нажмите <code class="docutils literal"><span class="pre">Ctr^b+Ctr^↑</span></code> или <code class="docutils literal"><span class="pre">Ctr^b+Ctr^↓</span></code>.</div>
<div class="line">Для <code class="docutils literal"><span class="pre">перемещения</span> <span class="pre">курсора</span> <span class="pre">на</span> <span class="pre">другой</span> <span class="pre">экран</span></code> <code class="docutils literal"><span class="pre">Ctr^b+↑</span></code> или <code class="docutils literal"><span class="pre">Ctr^b+↓</span></code>.</div>
<div class="line">Для <code class="docutils literal"><span class="pre">разделения</span> <span class="pre">экрана</span> <span class="pre">по</span> <span class="pre">вертикали</span></code> <code class="docutils literal"><span class="pre">Ctr^b+%</span></code> и стрелки вбок для изменения размеров, по аналогии.</div>
<div class="line"><code class="docutils literal"><span class="pre">Перемещаться</span></code> также можно при помощи <code class="docutils literal"><span class="pre">Ctr^b+o</span></code>, а <code class="docutils literal"><span class="pre">менять</span> <span class="pre">окна</span> <span class="pre">местами</span></code> <code class="docutils literal"><span class="pre">Ctr^b+O</span></code>.</div>
<div class="line">Комбинации легко запомнить, всегда! перед действием нажимай <code class="docutils literal"><span class="pre">Ctr^b</span></code>.</div>
</div>
<p>Гораздо веселее это все делать мышкой :) Для этого изменим конфиг:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ cat ~/.tmux.conf
<span class="nb">source</span> ~/.local/lib/python2.7/site-packages/powerline/bindings/tmux/powerline.conf
set-option -g default-terminal <span class="s2">"screen-256color"</span>
<span class="nb">set</span> -g status-interval <span class="m">15</span>
<span class="c1"># Mouse mode</span>
<span class="nb">set</span> -g mode-mouse on
<span class="nb">set</span> -g mouse-resize-pane on
<span class="nb">set</span> -g mouse-select-pane on
<span class="nb">set</span> -g mouse-select-window on
<span class="c1">##Toggle mouse on with m</span>
<span class="nb">bind</span> m <span class="se">\</span>
<span class="nb">set</span> -g mode-mouse on <span class="se">\;\</span>
<span class="nb">set</span> -g mouse-resize-pane on <span class="se">\;\</span>
<span class="nb">set</span> -g mouse-select-pane on <span class="se">\;\</span>
<span class="nb">set</span> -g mouse-select-window on <span class="se">\;\</span>
display <span class="s1">'Mouse: ON'</span>
<span class="c1">## Toggle mouse off with M</span>
<span class="nb">bind</span> M <span class="se">\</span>
<span class="nb">set</span> -g mode-mouse off <span class="se">\;\</span>
<span class="nb">set</span> -g mouse-resize-pane off <span class="se">\;\</span>
<span class="nb">set</span> -g mouse-select-pane off <span class="se">\;\</span>
<span class="nb">set</span> -g mouse-select-window off <span class="se">\;\</span>
display <span class="s1">'Mouse: OFF'</span>
<span class="c1">### End Mouse On/Off ### }}}</span>
</pre></div>
</div>
<p>Теперь двигай мышью! В режиме мыши нельзя скопировать текст из терминала. Что
бы этого избежать повешены два хоткея для включения <code class="docutils literal"><span class="pre">Ctr^b+m</span></code> и отключения
<code class="docutils literal"><span class="pre">Ctr^b+M</span></code> режима мыши.</p>
<p>Если не впечатлило, то есть один очень хороший стимул использовать <a class="reference external" href="https://tmux.github.io/">tmux</a>:
он поддерживает сколько угодно терминалов с одинаковым <a class="reference external" href="https://pypi.python.org/pypi/virtualenv">virtualenv</a>. К
примеру если я создам X вкладку <code class="docutils literal"><span class="pre">gnome-terminal</span></code> и активирую там окружение
<code class="docutils literal"><span class="pre">test</span></code>, то во второй X вкладке я получу вот такую ошибку:</p>
<p><code class="docutils literal"><span class="pre">IOError:</span> <span class="pre">[Errno</span> <span class="pre">26]</span> <span class="pre">Text</span> <span class="pre">file</span> <span class="pre">busy:</span> <span class="pre">'test/bin/python'</span></code></p>
<p><a class="reference external" href="https://tmux.github.io/">tmux</a> это решает очень просто, перед запуском активируйте <a class="reference external" href="https://pypi.python.org/pypi/virtualenv">virtualenv</a>,
а затем запустите <a class="reference external" href="https://tmux.github.io/">tmux</a>. Теперь все новые окна будут иметь это же
<a class="reference external" href="https://pypi.python.org/pypi/virtualenv">virtualenv</a> окружение.</p>
</div>
</div>
<div class="section" id="id5">
<h2><a class="reference external" href="https://powerline.readthedocs.org/en/latest/index.html">Powerline</a></h2>
<img alt="_static/2013/powerline.png" class="align-center" src="_static/2013/powerline.png" />
<p>На картинке с <a class="reference external" href="http://www.vim.org">Vim</a>, в левом нижнем углу, есть красивая панелька с погодой,
часами и <a class="reference external" href="https://tmux.github.io/">tmux</a> окнами. Слева есть запись <code class="docutils literal"><span class="pre">1>watch</span> <span class="pre">2>vim</span></code>, это означает
что в текущей сессии <a class="reference external" href="https://tmux.github.io/">tmux</a> в которой я нахожусь создано 2 окна, текущее
подсвечено синим цветом. Самое приятное что кликая по ним мышкой они
переключаются. Эта панель называется <code class="docutils literal"><span class="pre">powerline</span></code> она очень удобная и
красивая. <code class="docutils literal"><span class="pre">Powerline</span></code> можно поставить так же для <code class="docutils literal"><span class="pre">bash</span></code>, <code class="docutils literal"><span class="pre">zsh</span></code>,
<a class="reference external" href="https://pypi.python.org/pypi/ipython">ipython</a>, <a class="reference external" href="http://www.vim.org">vim</a>. Как это сделать, подробно описано здесь
<a class="reference external" href="http://askubuntu.com/questions/283908/how-can-i-install-and-use-powerline-plugin">http://askubuntu.com/questions/283908/how-can-i-install-and-use-powerline-plugin</a></p>
<p>Для vim я рекомендую <a class="reference external" href="https://github.com/bling/vim-airline">bling/vim-airline</a> вместо <code class="docutils literal"><span class="pre">powerline</span></code>.</p>
</div>
<div class="section" id="pgup-pgdown">
<h2>pgUp & pgDown</h2>
<p>Я ни когда не ищу команды, в консоле, которые уже вводил. Для этого набираю
начало команды и нажимаю <code class="docutils literal"><span class="pre">pgUp</span></code>. Например <code class="docutils literal"><span class="pre">pse+pgUp</span></code> выдаст <code class="docutils literal"><span class="pre">pserve</span>
<span class="pre">development.ini</span> <span class="pre">start</span> <span class="pre">--reload</span></code>.</p>
<p>Если вы хотите также, то добавьте в <code class="docutils literal"><span class="pre">~/.inputrc</span></code> следующие строки:</p>
<div class="literal-block-wrapper docutils container" id="id9">
<div class="code-block-caption"><span class="caption-text">.inputrc</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="s2">"\e[5~"</span>: history-search-backward
<span class="s2">"\e[6~"</span>: history-search-forward
</pre></div>
</div>
</div>
</div>
<div class="section" id="makefile">
<h2>Makefile</h2>
<p>в проекте можно создать <code class="docutils literal"><span class="pre">Makefile</span></code> файл, что бы выполнять скрипты одной
командой. Пример:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ cat ../sacrud/Makefile
all: <span class="nb">test</span>
setup_test:
python setup.py <span class="nb">test</span>
coverage:
nosetests --cover-package<span class="o">=</span>sacrud --cover-erase --with-coverage --with-doctest
test:
nosetests --cover-package<span class="o">=</span>sacrud --with-doctest
run:
pserve development.ini --reload
shell:
pshell development.ini
</pre></div>
</div>
<p>Теперь чтоб запустить тесты пишем просто <code class="docutils literal"><span class="pre">make</span> <span class="pre">all</span></code>.</p>
</div>
<div class="section" id="ipython-notebook">
<h2>ipython notebook</h2>
<p><code class="docutils literal"><span class="pre">notebook</span></code> запускает <a class="reference external" href="https://pypi.python.org/pypi/ipython">ipython</a> в браузере, это очень удобно
если вы работаете с графикой, <a class="reference external" href="https://pypi.python.org/pypi/matplotlib">matplotlib</a> например.</p>
<img alt="_static/2013/notebook_specgram.png" class="align-center" src="_static/2013/notebook_specgram.png" />
<p>Установка:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo apt-get install ipython-notebook
</pre></div>
</div>
<p>Запуск:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ ipython notebook --pylab
</pre></div>
</div>
<p>Причем фишечка! Свои творения можно расшарить в Интернете здесь <a class="reference external" href="http://nbviewer.ipython.org/">http://nbviewer.ipython.org/</a></p>
</div>
<div class="section" id="jsfiddle">
<h2>jsFiddle</h2>
<p>jsFiddle это такой сервис который позволяет нахаляву написать js код, тут же
его отладить, расшарить и дать кому-нибудь ссылку. Про него все знают и многие
пользуются. Но есть и для <a class="reference external" href="http://www.python.org/">Python</a> такой сервис, вот <a class="reference external" href="http://codebunk.com">http://codebunk.com</a>
Можно выбрать <code class="docutils literal"><span class="pre">python</span></code>, <code class="docutils literal"><span class="pre">js</span></code>, <code class="docutils literal"><span class="pre">ruby</span></code>, <code class="docutils literal"><span class="pre">perl</span></code>, <code class="docutils literal"><span class="pre">php</span></code>, <code class="docutils literal"><span class="pre">lua</span></code>, <code class="docutils literal"><span class="pre">C</span></code>,
<code class="docutils literal"><span class="pre">C++</span></code> разве что Лиспа нету, но все равно потрясает.</p>
<p>В заключение могу сказать что это только мое видение окружения, у других людей
оно может отличаться. Я надеюсь что эта заметка поможет вам выбрать правильное
начало.</p>
</div>
</div>
sacrud 0.1.0
http://uralbash.ru/articles/2013/sacrud_release_0_1_0/
2013-11-19T20:12:00Z
2013-11-19T20:12:00Z
Uralbash
<div class="section" id="sacrud-0-1-0">
<p>Обновил <a class="reference external" href="https://pypi.python.org/pypi/sacrud">sacrud</a> до <code class="docutils literal"><span class="pre">0.1.0</span></code>.</p>
<img alt="_static/2013/crud_java_servlet_freemarker_2.png" src="_static/2013/crud_java_servlet_freemarker_2.png" />
<p>Изменения:</p>
<ul class="simple">
<li>исправлено куча ошибок</li>
<li>добавлена документация</li>
</ul>
<p>В планах система расширения и кастомизации.</p>
</div>
Linux attack
http://uralbash.ru/articles/2013/linux_attack/
2013-11-07T07:15:00Z
2013-11-07T07:15:00Z
Uralbash
<div class="section" id="linux-attack">
<iframe width="420" height="315"
src="https://www.youtube.com/embed/6qNOIJNfICI" frameborder="0"
allowfullscreen></iframe></div>
Демо репозитарий Pyramid + sacrud
http://uralbash.ru/articles/2013/sacrud_demo/
2013-09-29T05:21:00Z
2013-09-29T05:21:00Z
Uralbash
<div class="section" id="pyramid-sacrud">
<p>pyramid_sacrud_example - пример работы <a class="reference external" href="https://pypi.python.org/pypi/sacrud">sacrud</a> в <a class="reference external" href="http://pylonsproject.org/">Pyramid</a> вместе с
<code class="docutils literal"><span class="pre">PostgreSQL</span></code>.</p>
<img alt="_static/2013/sacrud_demo.png" src="_static/2013/sacrud_demo.png" />
</div>
Практическое использование Vim
http://uralbash.ru/articles/2013/vim_book/
2013-09-07T14:02:00Z
2013-09-07T14:02:00Z
Uralbash
<div class="section" id="vim">
<p>Еще одна книга по <code class="docutils literal"><span class="pre">Vim</span></code> на русском языке готовится к выходу. ДМК - это всегда
прекрасный перевод тех. литературы, но ксожалению отсутствие эл.форматов.</p>
<a class="reference external image-reference" href="http://www.дмк.рф/catalog/computer/programming/978-5-94074-972-1/"><img alt="_static/2013/vim.jpg" class="align-center" src="_static/2013/vim.jpg" /></a>
</div>
Новое в sacrud 0.1.0a
http://uralbash.ru/articles/2013/sacrud_alfa_0_1_0/
2013-09-06T15:16:00Z
2013-09-06T15:16:00Z
Uralbash
<div class="section" id="sacrud-0-1-0a">
<p>Теперь <a class="reference external" href="https://pypi.python.org/pypi/sacrud">sacrud</a> 0.1.0a</p>
<p>Что нового:</p>
<ul class="simple">
<li>dnd через любое поле</li>
<li>объединение полей</li>
<li>js сортировка колонок</li>
</ul>
<p>Приложение для ознакомления pyramid_sacrud_example</p>
<p>В планах:</p>
<ul class="simple">
<li>yapsy плагины</li>
<li>mass delete</li>
<li>ImageField в pyramid_sacrud_example</li>
</ul>
</div>
Изучаем редакторы vi и Vim, epub + pdf
http://uralbash.ru/articles/2013/vi_book/
2013-09-05T19:32:00Z
2013-09-05T19:32:00Z
Uralbash
<div class="section" id="vi-vim-epub-pdf">
<p>Уже упоминал эту замечательную книгу (<a class="reference internal" href="../articles/2013/vi_book/#vi_book"><span class="std std-ref">Изучаем редакторы vi и Vim, epub + pdf</span></a>). Теперь в epub’е, вобщем зачёт.</p>
<a class="reference external image-reference" href="http://www.books.ru/books/izuchaem-redaktory-vi-i-vim-7-e-izdanie-fail-3579382/?show=1&partner=490327"><img alt="_static/2012/vi_book.jpg" class="align-center" src="_static/2012/vi_book.jpg" style="width: 400px;" /></a>
</div>
Запись в БД через sacrud используя SQLAlchemy session.
http://uralbash.ru/articles/2013/sacrud_howto/
2013-08-26T17:06:00Z
2013-08-26T17:06:00Z
Uralbash
<div class="section" id="sacrud-sqlalchemy-session">
<p>Для простых <code class="docutils literal"><span class="pre">CRUD</span></code> действий с БД, можно воспользоваться модулем
<a class="reference external" href="https://sacrud.readthedocs.io/en/master/api.html#module-sacrud.action" title="(в sacrud v)"><code class="xref py py-mod docutils literal"><span class="pre">action</span></code></a> из <a class="reference external" href="https://pypi.python.org/pypi/sacrud">sacrud</a>. Это немного сократит код и добавит
некоторой универсальности в ПО со сложной логикой.</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">sacrud</span> <span class="kn">import</span> <span class="n">action</span>
<span class="kn">from</span> <span class="nn">models</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">DBSession</span><span class="p">,</span>
<span class="n">TestTable</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">hstore_data</span> <span class="o">=</span> <span class="nb">str</span><span class="p">({</span><span class="s1">'param1'</span><span class="p">:</span> <span class="s1">'bla bla bla'</span><span class="p">,</span>
<span class="s1">'param2'</span><span class="p">:</span> <span class="s1">'bla bla bla2'</span><span class="p">,</span>
<span class="s1">'param3'</span><span class="p">:</span> <span class="s1">'7389a498-9347-48e3-835d-c3900dcd2566'</span><span class="p">,</span>
<span class="s1">'patam4'</span><span class="p">:</span> <span class="s1">'dddddddd'</span><span class="p">})</span>
<span class="n">param</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'value'</span><span class="p">:</span> <span class="p">(</span><span class="s1">'123'</span><span class="p">,),</span>
<span class="s1">'description'</span><span class="p">:</span> <span class="p">(</span><span class="s1">'test description'</span><span class="p">,),</span>
<span class="s1">'myhash'</span><span class="p">:</span> <span class="p">[</span><span class="n">hstore_data</span><span class="p">,</span> <span class="p">],</span>
<span class="p">}</span>
<span class="c1"># записывает транзакцию в БД</span>
<span class="n">action</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">DBSession</span><span class="p">,</span> <span class="n">TestTable</span><span class="p">,</span> <span class="n">param</span><span class="p">)</span>
</pre></div>
</div>
<p>параметры в виде списка сделаны для того что бы можно было принимать
множественные значения поля с HTML формы.</p>
<p>UPD: в новой версии можно делать так:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">param</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'value'</span><span class="p">:</span> <span class="s1">'123'</span><span class="p">,</span>
<span class="s1">'description'</span><span class="p">:</span> <span class="s1">'test description'</span><span class="p">,</span>
<span class="s1">'myhash'</span><span class="p">:</span> <span class="n">hstore_data</span><span class="p">,</span>
<span class="p">}</span>
<span class="c1"># записывает транзакцию в БД</span>
<span class="n">action</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">DBSession</span><span class="p">,</span> <span class="n">TestTable</span><span class="p">,</span> <span class="n">param</span><span class="p">)</span>
</pre></div>
</div>
</div>
Обновление sacrud и pyramid_ext
http://uralbash.ru/articles/2013/sacrud_release_0_0_3/
2013-08-26T16:24:00Z
2013-08-26T16:24:00Z
Uralbash
<div class="section" id="sacrud-pyramid-ext">
<p>Новая версия <a class="reference external" href="https://pypi.python.org/pypi/sacrud">sacrud</a> <code class="docutils literal"><span class="pre">0.0.3</span></code>. В ней поправлены некоторые баги,
добавлены <span class="strike">нескучные обои</span> элементы дизайна в расширении для
<code class="docutils literal"><span class="pre">Pyramid</span></code> и создан отдельный репозитарий с примерами работы разных типов
полей (pyramid_sacrud_example). Pyramid_sacrud_example работает только с
<a class="reference external" href="http://postgresql.org">Postgres</a> потому что включает в себя примеры полей специфичных именно для этой
БД (таких как <code class="docutils literal"><span class="pre">hstore</span></code>).</p>
<img alt="_static/2013/sacrud_0_0_3.png" class="align-center" src="_static/2013/sacrud_0_0_3.png" />
</div>
Опиум hstore в plpython
http://uralbash.ru/articles/2013/hstore_plpython/
2013-07-22T18:17:00Z
2013-07-22T18:17:00Z
Uralbash
<div class="section" id="hstore-plpython">
<p>Приведу просто пример триггера на <code class="docutils literal"><span class="pre">plpython</span></code> который использует данные из
поля <code class="docutils literal"><span class="pre">hstore</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="n">TD</span><span class="p">[</span><span class="s2">"event"</span><span class="p">]</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">"INSERT"</span><span class="p">,</span> <span class="s2">"UPDATE"</span><span class="p">):</span>
<span class="n">obj_id</span> <span class="o">=</span> <span class="n">TD</span><span class="p">[</span><span class="s2">"new"</span><span class="p">][</span><span class="s2">"id"</span><span class="p">]</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">TD</span><span class="p">[</span><span class="s2">"new"</span><span class="p">][</span><span class="s2">"data"</span><span class="p">]</span>
<span class="n">prepare_data</span> <span class="o">=</span> <span class="n">plpy</span><span class="o">.</span><span class="n">prepare</span><span class="p">(</span><span class="s2">"SELECT hstore($1)->$2 as val;"</span><span class="p">,</span> <span class="p">[</span><span class="s2">"character varying"</span><span class="p">,</span> <span class="s2">"character varying"</span><span class="p">])</span>
<span class="n">param1</span> <span class="o">=</span> <span class="n">plpy</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">prepare_data</span><span class="p">,</span> <span class="p">[</span><span class="n">data</span><span class="p">,</span> <span class="s2">"param1"</span><span class="p">])[</span><span class="mi">0</span><span class="p">][</span><span class="s1">'val'</span><span class="p">]</span>
<span class="n">param2</span> <span class="o">=</span> <span class="n">plpy</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">prepare_data</span><span class="p">,</span> <span class="p">[</span><span class="n">data</span><span class="p">,</span> <span class="s2">"param2"</span><span class="p">])[</span><span class="mi">0</span><span class="p">][</span><span class="s1">'val'</span><span class="p">]</span>
<span class="n">param3</span> <span class="o">=</span> <span class="n">plpy</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">prepare_data</span><span class="p">,</span> <span class="p">[</span><span class="n">data</span><span class="p">,</span> <span class="s2">"param3"</span><span class="p">])[</span><span class="mi">0</span><span class="p">][</span><span class="s1">'val'</span><span class="p">]</span>
<span class="n">param4</span> <span class="o">=</span> <span class="n">plpy</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">prepare_data</span><span class="p">,</span> <span class="p">[</span><span class="n">data</span><span class="p">,</span> <span class="s2">"param4"</span><span class="p">])[</span><span class="mi">0</span><span class="p">][</span><span class="s1">'val'</span><span class="p">]</span>
</pre></div>
</div>
<p>Вот так я получаю параметры из <code class="docutils literal"><span class="pre">hstore</span></code>, вместо
<code class="docutils literal"><span class="pre">TD["new"]["data"]["param1"]</span></code>. Может я что то делаю не так?</p>
</div>
CRUD интерфейс для SQLAlchemy и подключение к Pyramid
http://uralbash.ru/articles/2013/sacrud/
2013-03-09T02:55:00Z
2013-03-09T02:55:00Z
Uralbash
<div class="section" id="crud-sqlalchemy-pyramid">
<p>Запилил Yet another CRUD интерфейс для <a class="reference external" href="http://sqlalchemy.org/">SQLAlchemy</a>. По сути это аналог
<a class="reference external" href="https://www.djangoproject.com/">Django</a> админки или <a class="reference external" href="http://docs.formalchemy.org/">FormAlchemy</a>, но ОЧЕНЬ сильно упрощенный, ничего
лишнего. Есть поддержка большинства полей + кастомные поля типа файл (для
загрузки файлов, изображений) и <code class="docutils literal"><span class="pre">GUID</span></code>. Довольно просто подключить к
<a class="reference external" href="http://pylonsproject.org/">Pyramid</a> проекту и сразу начать работать по адресу
<a class="reference external" href="http://localhost:6543/sacrud">http://localhost:6543/sacrud</a></p>
<p>Проект доступен на github <a class="reference external" href="https://github.com/uralbash/sacrud">https://github.com/uralbash/sacrud</a></p>
<p>В след. релизах планирую добавить новые типы полей, кастомные поля типа
<code class="docutils literal"><span class="pre">tree</span></code> и <code class="docutils literal"><span class="pre">btree</span></code> с <code class="docutils literal"><span class="pre">AJAX</span></code> обработкой в интерфейсе, расширение для других
фреймворков (например <a class="reference external" href="http://flask.pocoo.org/">flask</a>), кастомные фильтры, пагинацию итд</p>
<div class="section" id="id1">
<h2>Установка</h2>
<div class="literal-block-wrapper docutils container" id="id3">
<div class="code-block-caption"><span class="caption-text">PyPi</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ pip install sacrud
</pre></div>
</div>
</div>
<div class="literal-block-wrapper docutils container" id="id4">
<div class="code-block-caption"><span class="caption-text">source</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ python setup.py install
</pre></div>
</div>
</div>
</div>
<div class="section" id="pyramid">
<h2>Пример использования в Pyramid</h2>
<p>Add to your project config:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1"># pyramid_jinja2 configuration</span>
<span class="n">config</span><span class="o">.</span><span class="n">include</span><span class="p">(</span><span class="s1">'pyramid_jinja2'</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_jinja2_search_path</span><span class="p">(</span><span class="s2">"myprojectname:templates"</span><span class="p">)</span>
<span class="kn">from</span> <span class="nn">.models</span> <span class="kn">import</span> <span class="p">(</span><span class="n">Model1</span><span class="p">,</span> <span class="n">Model2</span><span class="p">,</span> <span class="n">Model3</span><span class="p">,)</span>
<span class="c1"># add sacrud and project models</span>
<span class="n">config</span><span class="o">.</span><span class="n">include</span><span class="p">(</span><span class="s1">'sacrud.pyramid_ext'</span><span class="p">)</span>
<span class="n">settings</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">registry</span><span class="o">.</span><span class="n">settings</span>
<span class="n">settings</span><span class="p">[</span><span class="s1">'sacrud_models'</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">Model1</span><span class="p">,</span> <span class="n">Model2</span><span class="p">,</span> <span class="n">Model3</span><span class="p">)</span>
</pre></div>
</div>
<p>go to <a class="reference external" href="http://localhost:6543/sacrud">http://localhost:6543/sacrud</a></p>
</div>
<div class="section" id="id2">
<h2>Скриншоты</h2>
<div class="figure align-center" id="id5">
<img alt="_static/2013/sacrud_index.png" src="_static/2013/sacrud_index.png" />
<p class="caption"><span class="caption-text">список таблиц</span></p>
</div>
<div class="figure align-center" id="id6">
<img alt="_static/2013/sacrud_rows.png" src="_static/2013/sacrud_rows.png" />
<p class="caption"><span class="caption-text">список записей в таблице</span></p>
</div>
<div class="figure align-center" id="id7">
<img alt="_static/2013/sacrud_edit.png" src="_static/2013/sacrud_edit.png" />
<p class="caption"><span class="caption-text">редактирование записи</span></p>
</div>
</div>
</div>
Объявление флага в цикле Jinja2
http://uralbash.ru/articles/2013/flag_jinja2/
2013-02-28T22:49:00Z
2013-02-28T22:49:00Z
Uralbash
<div class="section" id="jinja2">
<p>Понадобилось мне тут создать флаг в цикле, который можно использовать где
нибудь потом в шаблоне. По логике все должно выглядеть примерно так:</p>
<div class="highlight-jinja"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">set</span> <span class="nv">exists</span> <span class="o">=</span> <span class="m">0</span> <span class="cp">%}</span><span class="x"></span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">i</span> <span class="k">in</span> <span class="nv">range</span><span class="o">(</span><span class="m">5</span><span class="o">)</span> <span class="cp">%}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{%</span> <span class="k">if</span> <span class="kp">True</span> <span class="cp">%}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{%</span> <span class="k">set</span> <span class="nv">exists</span> <span class="o">=</span> <span class="m">1</span> <span class="cp">%}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span><span class="x"></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span><span class="x"></span>
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">exists</span> <span class="cp">%}</span><span class="x"></span>
<span class="x"> <!-- exists is true --></span>
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
</div>
<p>Но такой код не фурычит! <code class="docutils literal"><span class="pre">exist</span></code> всегда будет <code class="docutils literal"><span class="pre">0</span></code>. Это особенность области
видимости переменных в <a class="reference external" href="http://jinja.pocoo.org/">Jinja</a> при присваивании.</p>
<p>Поэтому есть небольшой хак как это поправить:</p>
<div class="highlight-jinja"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">set</span> <span class="nv">exists</span> <span class="o">=</span> <span class="o">[]</span> <span class="cp">%}</span><span class="x"></span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">i</span> <span class="k">in</span> <span class="nv">range</span><span class="o">(</span><span class="m">5</span><span class="o">)</span> <span class="cp">%}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{%</span> <span class="k">if</span> <span class="kp">True</span> <span class="cp">%}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{%</span> <span class="k">do</span> <span class="nv">exists.append</span><span class="o">(</span><span class="m">1</span><span class="o">)</span> <span class="cp">%}</span><span class="x"></span>
<span class="x"> </span><span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span><span class="x"></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span><span class="x"></span>
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">exists</span> <span class="cp">%}</span><span class="x"></span>
<span class="x"> <!-- exists is true --></span>
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
</div>
<p>Решение взято от <a class="reference external" href="http://stackoverflow.com/questions/4870346/can-a-jinja-variables-scope-extend-beyond-in-an-inner-block">сюда</a>.</p>
</div>
Jinja2 Lorem ipsum dolor sit amet
http://uralbash.ru/articles/2013/jinja2_lorem_ipsum/
2013-02-19T03:12:00Z
2013-02-19T03:12:00Z
Uralbash
<div class="section" id="jinja2-lorem-ipsum-dolor-sit-amet">
<p>Иногда в шаблоне нужно зафигачить какую-нибудь рыбу типа <code class="docutils literal"><span class="pre">"Lorem</span> <span class="pre">ipsum</span> <span class="pre">dolor</span>
<span class="pre">sit</span> <span class="pre">amet"</span></code>, часто в цикле итд. Для этого существует функция <a class="reference external" href="http://jinja.pocoo.org/docs/dev/templates/#lipsum">lipsum()</a>.</p>
<p>Вот пример:</p>
<div class="highlight-html+jinja"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">for</span> <span class="nv">x</span> <span class="k">in</span> <span class="nv">range</span><span class="o">(</span><span class="m">5</span><span class="o">)</span> <span class="cp">%}</span>
<span class="cp">{{</span> <span class="nv">lipsum</span><span class="o">()|</span><span class="nf">truncate</span><span class="o">(</span><span class="m">150</span><span class="o">)|</span><span class="nf">safe</span> <span class="cp">}}</span>
<span class="p"><</span><span class="nt">hr</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
</pre></div>
</div>
<p>И результат:</p>
Justo aliquam faucibus lacus pulvinar commodo nisl, quisque est fusce venenatis mattis magnis arcu, hac felis parturient suspendisse a. Vitae ...
<hr>
Porta tellus turpis leo suspendisse rutrum metus blandit, montes dis lacinia felis non, vehicula vivamus condimentum luctus massa, vehicula ...
<hr>
Convallis molestie blandit viverra imperdiet eros dolor nam, ridiculus tortor duis blandit duis enim, cursus bibendum lobortis faucibus dui ...
<hr>
Diam placerat risus porta litora consequat vel, accumsan tempus ligula laoreet a mollis rutrum, aptent est tortor pulvinar senectus, litora etiam. ...
<hr>
Cursus non morbi non proin, porttitor consequat eget ac eget netus penatibus, egestas primis suspendisse ad, iaculis eu cursus urna blandit, leo. ...
<hr></div>
Использование SQLAlchemy в дополнениях к Pyramid
http://uralbash.ru/articles/2013/dbsession_includeme/
2013-02-17T17:43:00Z
2013-02-17T17:43:00Z
Uralbash
<div class="section" id="sqlalchemy-pyramid">
<p>У меня есть дополнение к pyramid которое я включаю почти в каждый проект при
помощи <code class="docutils literal"><span class="pre">includeme</span></code> (<a class="reference external" href="https://docs.pylonsproject.org/projects/pyramid/en/latest/api/config.html#pyramid.config.Configurator.include" title="(в The Pyramid Web Framework v2.0)"><code class="xref py py-meth docutils literal"><span class="pre">include()</span></code></a>). Приложение
это дает мне простой <code class="docutils literal"><span class="pre">CRUD</span></code> интерфейс с <a class="reference external" href="http://jinja.pocoo.org/">Jinja</a> шаблонами малой кровью.
Что позволяет избавиться от монстра <a class="reference external" href="http://docs.formalchemy.org/">FormAlchemy</a>. Естественно каждый
проект имеет свое название поэтому пришлось применить немного магии что бы
создать универсальный механизм получения <code class="docutils literal"><span class="pre">DBSession</span></code> в своем подключаемом
дополнении.</p>
<p>Примерная структура папок дополнения:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>pyramid_ext_plugin
<span class="p">|</span>-- __init__.py
<span class="sb">`</span>-- action.py
</pre></div>
</div>
<p>В <code class="docutils literal"><span class="pre">__init__.py</span></code> находятся все настройки <code class="docutils literal"><span class="pre">includeme</span></code>, а в <code class="docutils literal"><span class="pre">action.py</span></code>
действия с базой. Для получения <code class="docutils literal"><span class="pre">DBSession</span></code> в <code class="docutils literal"><span class="pre">action.py</span></code> исправим сначала
<code class="docutils literal"><span class="pre">__init__.py</span></code>:</p>
<div class="literal-block-wrapper docutils container" id="id1">
<div class="code-block-caption"><span class="caption-text">__init__.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">sqlalchemy</span>
<span class="kn">import</span> <span class="nn">sqlalchemy.orm</span> <span class="kn">as</span> <span class="nn">orm</span>
<span class="kn">from</span> <span class="nn">zope.sqlalchemy</span> <span class="kn">import</span> <span class="n">ZopeTransactionExtension</span>
<span class="n">DBSession</span> <span class="o">=</span> <span class="bp">None</span>
<span class="k">def</span> <span class="nf">includeme</span><span class="p">(</span><span class="n">config</span><span class="p">):</span>
<span class="k">global</span> <span class="n">DBSession</span>
<span class="n">engine</span> <span class="o">=</span> <span class="n">sqlalchemy</span><span class="o">.</span><span class="n">engine_from_config</span><span class="p">(</span><span class="n">config</span><span class="o">.</span><span class="n">registry</span><span class="o">.</span><span class="n">settings</span><span class="p">)</span>
<span class="k">if</span> <span class="n">DBSession</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
<span class="n">DBSession</span> <span class="o">=</span> <span class="n">orm</span><span class="o">.</span><span class="n">scoped_session</span><span class="p">(</span>
<span class="n">orm</span><span class="o">.</span><span class="n">sessionmaker</span><span class="p">(</span><span class="n">extension</span><span class="o">=</span><span class="n">ZopeTransactionExtension</span><span class="p">()))</span>
<span class="n">DBSession</span><span class="o">.</span><span class="n">remove</span><span class="p">()</span>
<span class="n">DBSession</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span><span class="n">bind</span><span class="o">=</span><span class="n">engine</span><span class="p">)</span>
</pre></div>
</div>
</div>
<p>Все Ж) теперь можно в <code class="docutils literal"><span class="pre">action.py</span></code> писать так:</p>
<div class="literal-block-wrapper docutils container" id="id2">
<div class="code-block-caption"><span class="caption-text">action.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pyramid_ext_pugin</span> <span class="kn">import</span> <span class="n">DBSession</span>
</pre></div>
</div>
</div>
</div>
ThinkPad управление музыкой с помощью HDAPS
http://uralbash.ru/articles/2013/hdaps_music/
2013-02-17T17:04:00Z
2013-02-17T17:04:00Z
Uralbash
<div class="section" id="thinkpad-hdaps">
<div class="line-block">
<div class="line">Хорошая статья из Ынтернета как управлять плеером cups наклоняя ноутбук.</div>
<div class="line"><a class="reference external" href="http://www.mhermans.net/dhaps-controlled-thinkpad.html">Ссылка на оригинал</a></div>
</div>
<p>Сначала установим HDAPS:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo apt-get install tp-smapi-dkms hdapsd
</pre></div>
</div>
<p>Затем проверим:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ cat /sys/devices/platform/hdaps/position
<span class="o">(</span><span class="m">471</span>,504<span class="o">)</span>
</pre></div>
</div>
<p>И запустим следующий скрипт на <a class="reference external" href="http://www.python.org/">Python</a>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">time</span><span class="o">,</span> <span class="nn">subprocess</span>
<span class="k">class</span> <span class="nc">Orientation</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">readfreq</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">x_init</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">y_init</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">x_hist</span> <span class="o">=</span> <span class="p">[]</span>
<span class="bp">self</span><span class="o">.</span><span class="n">y_hist</span> <span class="o">=</span> <span class="p">[]</span>
<span class="c1"># read in some values to smooth movement</span>
<span class="bp">self</span><span class="o">.</span><span class="n">collect</span><span class="p">()</span>
<span class="c1"># cooldown makes sure only a single command</span>
<span class="c1"># is executed in one movement</span>
<span class="bp">self</span><span class="o">.</span><span class="n">cooldown</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">def</span> <span class="nf">read</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">f</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s1">'/sys/bus/platform/devices/hdaps/position'</span><span class="p">)</span>
<span class="n">s</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
<span class="n">f</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">strip</span><span class="p">(</span><span class="s1">'()'</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">','</span><span class="p">)</span>
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">x</span><span class="p">),</span> <span class="nb">int</span><span class="p">(</span><span class="n">y</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">collect</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">n</span><span class="o">=</span><span class="mi">10</span><span class="p">):</span>
<span class="c1"># change n for smoothing over longer period</span>
<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">x_hist</span><span class="p">)</span> <span class="o"><</span> <span class="n">n</span><span class="o">+</span><span class="mi">1</span><span class="p">:</span>
<span class="n">coords</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">x_hist</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">coords</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="bp">self</span><span class="o">.</span><span class="n">y_hist</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">coords</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">x_avg</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">sum</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">x_hist</span><span class="p">)</span><span class="o">/</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">x_hist</span><span class="p">)</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">y_avg</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">sum</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">y_hist</span><span class="p">)</span><span class="o">/</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">y_hist</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">tick</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mf">0.1</span><span class="p">):</span>
<span class="c1"># timeout provides the period between "ticks", i.e.</span>
<span class="c1"># the frequency of reads and checks on thresholds</span>
<span class="bp">self</span><span class="o">.</span><span class="n">update</span><span class="p">()</span> <span class="c1"># read in and process new position</span>
<span class="c1"># if not in cooldown period, check if thresholds are</span>
<span class="c1"># triggerd, and possibly execute a command</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">cooldown</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">execute</span><span class="p">()</span>
<span class="k">else</span><span class="p">:</span> <span class="c1"># reduce cooldown periode every tick</span>
<span class="bp">self</span><span class="o">.</span><span class="n">cooldown</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cooldown</span> <span class="o">-</span> <span class="mi">1</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">timeout</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">update</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="c1"># position relative to the moving average position</span>
<span class="bp">self</span><span class="o">.</span><span class="n">x_rel</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">y_rel</span> <span class="o">=</span> <span class="n">o</span><span class="o">.</span><span class="n">x</span> <span class="o">-</span> <span class="n">o</span><span class="o">.</span><span class="n">x_avg</span><span class="p">,</span> <span class="n">o</span><span class="o">.</span><span class="n">y</span> <span class="o">-</span> <span class="n">o</span><span class="o">.</span><span class="n">y_avg</span>
<span class="c1"># keep a stack of n observations by popping the first</span>
<span class="c1"># and appending to the end</span>
<span class="bp">self</span><span class="o">.</span><span class="n">x_hist</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">x_hist</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">x</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">y_hist</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">y_hist</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">y</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">tresholds</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x_min</span><span class="o">=-</span><span class="mi">30</span><span class="p">,</span> <span class="n">x_max</span><span class="o">=</span><span class="mi">30</span><span class="p">,</span> <span class="n">y_min</span><span class="o">=-</span><span class="mi">30</span><span class="p">,</span> <span class="n">y_max</span><span class="o">=</span><span class="mi">30</span><span class="p">):</span>
<span class="c1"># check if thresholds are triggerd, turns a tuple with</span>
<span class="c1"># four True/False values</span>
<span class="n">triggered</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">x_rel</span> <span class="o"><</span> <span class="n">x_min</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">x_rel</span> <span class="o">></span> <span class="n">x_max</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">y_rel</span> <span class="o"><</span> <span class="n">y_min</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">y_rel</span> <span class="o">></span> <span class="n">y_max</span><span class="p">)</span>
<span class="k">return</span> <span class="n">triggered</span>
<span class="k">def</span> <span class="nf">execute</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">t</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">tresholds</span><span class="p">()</span>
<span class="k">if</span> <span class="n">t</span> <span class="o">==</span> <span class="p">(</span><span class="bp">True</span><span class="p">,</span> <span class="bp">False</span><span class="p">,</span> <span class="bp">False</span><span class="p">,</span> <span class="bp">False</span><span class="p">):</span>
<span class="k">print</span> <span class="s1">'Detected a forward tilt'</span>
<span class="n">subprocess</span><span class="o">.</span><span class="n">call</span><span class="p">([</span><span class="s1">'cmus-remote'</span><span class="p">,</span> <span class="s1">'-v'</span><span class="p">,</span> <span class="s1">'-10%'</span><span class="p">])</span>
<span class="bp">self</span><span class="o">.</span><span class="n">cooldown</span> <span class="o">=</span> <span class="mi">10</span>
<span class="k">if</span> <span class="n">t</span> <span class="o">==</span> <span class="p">(</span><span class="bp">False</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">False</span><span class="p">,</span> <span class="bp">False</span><span class="p">):</span>
<span class="k">print</span> <span class="s1">'Detected a backward tilt'</span>
<span class="n">subprocess</span><span class="o">.</span><span class="n">call</span><span class="p">([</span><span class="s1">'cmus-remote'</span><span class="p">,</span> <span class="s1">'-v'</span><span class="p">,</span> <span class="s1">'+10%'</span><span class="p">])</span>
<span class="bp">self</span><span class="o">.</span><span class="n">cooldown</span> <span class="o">=</span> <span class="mi">10</span>
<span class="k">if</span> <span class="n">t</span> <span class="o">==</span> <span class="p">(</span><span class="bp">False</span><span class="p">,</span> <span class="bp">False</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="bp">False</span><span class="p">):</span>
<span class="k">print</span> <span class="s1">'Detected a left tilt'</span>
<span class="n">subprocess</span><span class="o">.</span><span class="n">call</span><span class="p">([</span><span class="s1">'cmus-remote'</span><span class="p">,</span> <span class="s1">'-u'</span><span class="p">])</span>
<span class="bp">self</span><span class="o">.</span><span class="n">cooldown</span> <span class="o">=</span> <span class="mi">10</span>
<span class="k">if</span> <span class="n">t</span> <span class="o">==</span> <span class="p">(</span><span class="bp">False</span><span class="p">,</span> <span class="bp">False</span><span class="p">,</span> <span class="bp">False</span><span class="p">,</span> <span class="bp">True</span><span class="p">):</span>
<span class="k">print</span> <span class="s1">'Detected a right tilt'</span>
<span class="n">subprocess</span><span class="o">.</span><span class="n">call</span><span class="p">([</span><span class="s1">'cmus-remote'</span><span class="p">,</span> <span class="s1">'-n'</span><span class="p">])</span>
<span class="bp">self</span><span class="o">.</span><span class="n">cooldown</span> <span class="o">=</span> <span class="mi">10</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="n">o</span> <span class="o">=</span> <span class="n">Orientation</span><span class="p">()</span>
<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
<span class="c1">#print o.x_rel, o.y_rel, o.cooldown</span>
<span class="n">o</span><span class="o">.</span><span class="n">tick</span><span class="p">()</span>
</pre></div>
</div>
<p>Все теперь можно запускать <code class="docutils literal"><span class="pre">cups</span></code> и баловаться.</p>
</div>
Как устроен дифференциал в автомобиле
http://uralbash.ru/articles/2013/car_differ/
2013-01-16T17:10:00Z
2013-01-16T17:10:00Z
Uralbash
<div class="section" id="id1">
<p>Отличное видео 1937г.</p>
<iframe width="420" height="315"
src="https://www.youtube.com/embed/yYAw79386WI" frameborder="0"
allowfullscreen></iframe><p>Источник: <a class="reference external" href="http://hackaday.com/2013/01/15/retrotechtacular-the-differential">hackaday</a></p>
</div>
Матрица в терминале на python
http://uralbash.ru/articles/2013/matrix/
2013-01-15T02:04:00Z
2013-01-15T02:04:00Z
Uralbash
<div class="section" id="python">
<p>Программа для консоли в <a class="reference external" href="https://www.kernel.org/">Linux</a>, которая имитирует поток бинарных цифр из
фильма матрица. Очень эффектно выглядит, рекомендую попробовать!</p>
<img alt="_static/2013/matrix_code.png" class="align-center" src="_static/2013/matrix_code.png" />
<p>Видео:</p>
<iframe width="560" height="315"
src="https://www.youtube.com/embed/96crI0NCbPg" frameborder="0"
allowfullscreen></iframe><p>Код:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="sd">""""Create "The Matrix" of binary numbers scrolling vertically in your terminal.</span>
<span class="sd">original code adapted from juancarlospaco:</span>
<span class="sd"> 1. http://ubuntuforums.org/showpost.php?p=10306676</span>
<span class="sd">Inspired by the movie: The Matrix</span>
<span class="sd"> 1. Corey Goldberg (2013)</span>
<span class="sd">Requires:</span>
<span class="sd"> 1. Linux</span>
<span class="sd"> 2. Python 2.7 or 3+</span>
<span class="sd">"""</span>
<span class="kn">import</span> <span class="nn">fcntl</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="kn">import</span> <span class="nn">random</span>
<span class="kn">import</span> <span class="nn">struct</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">termios</span>
<span class="k">class</span> <span class="nc">message</span><span class="p">(</span><span class="nb">str</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">text</span><span class="p">,</span> <span class="n">speed</span><span class="p">):</span>
<span class="bp">self</span> <span class="o">=</span> <span class="nb">super</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="bp">cls</span><span class="p">)</span><span class="o">.</span><span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">text</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">speed</span> <span class="o">=</span> <span class="n">speed</span>
<span class="bp">self</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span> <span class="o">*</span> <span class="nb">len</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">display</span><span class="p">()</span><span class="o">.</span><span class="n">width</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">skip</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">return</span> <span class="bp">self</span>
<span class="k">def</span> <span class="nf">move</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">speed</span> <span class="o">></span> <span class="bp">self</span><span class="o">.</span><span class="n">skip</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">skip</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">else</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">skip</span> <span class="o">=</span> <span class="mi">0</span>
<span class="bp">self</span><span class="o">.</span><span class="n">y</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">class</span> <span class="nc">display</span><span class="p">(</span><span class="nb">list</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">height</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">width</span> <span class="o">=</span> <span class="n">struct</span><span class="o">.</span><span class="n">unpack</span><span class="p">(</span><span class="s1">'hh'</span><span class="p">,</span> <span class="n">fcntl</span><span class="o">.</span><span class="n">ioctl</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">termios</span><span class="o">.</span><span class="n">TIOCGWINSZ</span><span class="p">,</span> <span class="s1">'1234'</span><span class="p">))</span>
<span class="bp">self</span><span class="p">[:]</span> <span class="o">=</span> <span class="p">[</span><span class="s1">' '</span> <span class="k">for</span> <span class="n">y</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">height</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">width</span><span class="p">)]</span>
<span class="k">def</span> <span class="nf">set_vertical</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">string</span><span class="p">):</span>
<span class="n">string</span> <span class="o">=</span> <span class="n">string</span><span class="p">[::</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="k">if</span> <span class="n">x</span> <span class="o"><</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">x</span> <span class="o">=</span> <span class="mi">80</span> <span class="o">+</span> <span class="n">x</span>
<span class="k">if</span> <span class="n">x</span> <span class="o">>=</span> <span class="bp">self</span><span class="o">.</span><span class="n">width</span><span class="p">:</span>
<span class="n">x</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">width</span> <span class="o">-</span> <span class="mi">1</span>
<span class="k">if</span> <span class="n">y</span> <span class="o"><</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">string</span> <span class="o">=</span> <span class="n">string</span><span class="p">[</span><span class="nb">abs</span><span class="p">(</span><span class="n">y</span><span class="p">):]</span>
<span class="n">y</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">if</span> <span class="n">y</span> <span class="o">+</span> <span class="nb">len</span><span class="p">(</span><span class="n">string</span><span class="p">)</span> <span class="o">></span> <span class="bp">self</span><span class="o">.</span><span class="n">height</span><span class="p">:</span>
<span class="n">string</span> <span class="o">=</span> <span class="n">string</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="bp">self</span><span class="o">.</span><span class="n">height</span> <span class="o">-</span> <span class="n">y</span><span class="p">]</span>
<span class="k">if</span> <span class="n">y</span> <span class="o">>=</span> <span class="bp">self</span><span class="o">.</span><span class="n">height</span><span class="p">:</span>
<span class="k">return</span>
<span class="n">start</span> <span class="o">=</span> <span class="n">y</span> <span class="o">*</span> <span class="bp">self</span><span class="o">.</span><span class="n">width</span> <span class="o">+</span> <span class="n">x</span>
<span class="n">length</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">width</span> <span class="o">*</span> <span class="p">(</span><span class="n">y</span> <span class="o">+</span> <span class="nb">len</span><span class="p">(</span><span class="n">string</span><span class="p">))</span>
<span class="n">step</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">width</span>
<span class="bp">self</span><span class="p">[</span><span class="n">start</span><span class="p">:</span><span class="n">length</span><span class="p">:</span><span class="n">step</span><span class="p">]</span> <span class="o">=</span> <span class="n">string</span>
<span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="s1">''</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">matrix</span><span class="p">(</span><span class="n">iterations</span><span class="p">,</span> <span class="n">sleep_time</span><span class="o">=.</span><span class="mi">08</span><span class="p">):</span>
<span class="n">messages</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">d</span> <span class="o">=</span> <span class="n">display</span><span class="p">()</span>
<span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">iterations</span><span class="p">):</span>
<span class="n">messages</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">message</span><span class="p">(</span><span class="s1">'10'</span> <span class="o">*</span> <span class="mi">16</span><span class="p">,</span> <span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">5</span><span class="p">)))</span>
<span class="k">for</span> <span class="n">text</span> <span class="ow">in</span> <span class="n">messages</span><span class="p">:</span>
<span class="n">d</span><span class="o">.</span><span class="n">set_vertical</span><span class="p">(</span><span class="n">text</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">text</span><span class="o">.</span><span class="n">y</span><span class="p">,</span> <span class="n">text</span><span class="p">)</span>
<span class="n">text</span><span class="o">.</span><span class="n">move</span><span class="p">()</span>
<span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s1">'</span><span class="se">\033</span><span class="s1">[1m</span><span class="se">\033</span><span class="s1">[32m</span><span class="si">%s</span><span class="se">\033</span><span class="s1">[0m</span><span class="se">\r</span><span class="s1">'</span> <span class="o">%</span> <span class="n">d</span><span class="p">)</span>
<span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">sleep_time</span><span class="p">)</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">matrix</span><span class="p">(</span><span class="mi">150</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span>
<span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s1">'</span><span class="se">\n\033</span><span class="s1">[1m</span><span class="se">\033</span><span class="s1">[32m=== Matrix Stopped ====</span><span class="se">\033</span><span class="s1">[0m</span><span class="se">\n</span><span class="s1">'</span><span class="p">)</span>
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">()</span>
</pre></div>
</div>
<p>Оригинал: <a class="reference external" href="http://coreygoldberg.blogspot.ru/2013/01/python-matrix-in-your-terminal.html">http://coreygoldberg.blogspot.ru/2013/01/python-matrix-in-your-terminal.html</a></p>
</div>
Пингвины императорские
http://uralbash.ru/articles/2013/penguin/
2013-01-07T19:36:00Z
2013-01-07T19:36:00Z
Uralbash
<div class="section" id="id1">
<p>Ускоряются за счет воздуха:</p>
<embed type="application/x-shockwave-flash"
src="http://s0.videopress.com/player.swf?v=1.04" width="400" height="224"
wmode="direct" seamlesstabbing="true" allowfullscreen="true"
allowscriptaccess="always" overstretch="true"
flashvars="guid=nH7YRgxB&isDynamicSeeking=true"></embed><img alt="_static/2013/pingviny-zhmut-na-gaz-big.jpg" class="align-center" src="_static/2013/pingviny-zhmut-na-gaz-big.jpg" />
<p>Подробнее <a class="reference external" href="http://juanvelascoblog.com/2012/11/29/emperor-penguins-hit-the-gas/">http://juanvelascoblog.com/2012/11/29/emperor-penguins-hit-the-gas/</a></p>
</div>
Wat
http://uralbash.ru/articles/2013/wat/
2013-01-01T19:36:00Z
2013-01-01T19:36:00Z
Uralbash
<div class="section" id="wat">
<iframe width="420" height="315"
src="https://www.youtube.com/embed/FqhZZNUyVFM" frameborder="0"
allowfullscreen></iframe></div>
Срань...
http://uralbash.ru/articles/2012/sran/
2012-12-19T15:27:00Z
2012-12-19T15:27:00Z
Uralbash
<div class="section" id="id1">
<p>В последнее время мне кажется что я пользователь <code class="docutils literal"><span class="pre">Интернета</span></code> в <code class="docutils literal"><span class="pre">Северной</span>
<span class="pre">Корее</span></code>.</p>
<img alt="_static/2012/sran1.png" class="align-center" src="_static/2012/sran1.png" />
<p>UPD:</p>
<img alt="_static/2012/sran2.png" class="align-center" src="_static/2012/sran2.png" />
</div>
Изучаем редакторы vi и Vim, книга на Русском
http://uralbash.ru/articles/2012/vi_book/
2012-12-07T16:56:00Z
2012-12-07T16:56:00Z
Uralbash
<div class="section" id="vi-vim">
<span id="vi-book"></span>
<p>Издательство “Символ” радует последнее время годной литературой. Для предзаказа
представлена ПЕРВАЯ книга на Русском языке по <code class="docutils literal"><span class="pre">vi</span></code> и <code class="docutils literal"><span class="pre">vim</span></code>. Я конечно
понимаю что можно прочитать <code class="docutils literal"><span class="pre">vimtutor</span></code>, но когда это все в картинках и со
стрелками то въезжаешь намного быстрее. В общем заказал, для меня очередной
хэндбук.</p>
<a class="reference external image-reference" href="http://www.books.ru/books/izuchaem-redaktory-vi-i-vim-7-e-izdanie-827256/?partner=490327"><img alt="_static/2012/vi_book.jpg" class="align-center" src="_static/2012/vi_book.jpg" style="width: 400px;" /></a>
</div>
Меняем заголовок ответа в Pyramid/Pylons
http://uralbash.ru/articles/2012/http_header_pyramid/
2012-12-04T15:27:00Z
2012-12-04T15:27:00Z
Uralbash
<div class="section" id="pyramid-pylons">
<p>Обычно в заголовке находится что то типа:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>Content-Length <span class="m">6657</span>
Content-Type text/html<span class="p">;</span> <span class="nv">charset</span><span class="o">=</span>UTF-8
итд
</pre></div>
</div>
<p>Изменить заголовок можно например в настройках <a class="reference external" href="http://www.apache.org">Apache</a> или <a class="reference external" href="http://nginx.org/">nginx</a> или в
самом приложении.</p>
<p>Для <a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">Pylons</a> пишем <code class="docutils literal"><span class="pre">WSGI</span> <span class="pre">middleware</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">HeaderMiddleware</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="sd">'''WSGI middleware'''</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">application</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">app</span> <span class="o">=</span> <span class="n">application</span>
<span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">environ</span><span class="p">,</span> <span class="n">start_response</span><span class="p">):</span>
<span class="n">request</span> <span class="o">=</span> <span class="n">Request</span><span class="p">(</span><span class="n">environ</span><span class="p">)</span>
<span class="n">resp</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">get_response</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">app</span><span class="p">)</span>
<span class="n">resp</span><span class="o">.</span><span class="n">headers</span><span class="p">[</span><span class="s1">'X-Frame-Options'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'DENY'</span>
<span class="k">return</span> <span class="n">resp</span><span class="p">(</span><span class="n">environ</span><span class="p">,</span> <span class="n">start_response</span><span class="p">)</span>
</pre></div>
</div>
<p>Для <a class="reference external" href="http://pylonsproject.org/">Pyramid</a> можно обойтись без <code class="docutils literal"><span class="pre">WSGI</span></code>:</p>
<div class="literal-block-wrapper docutils container" id="id1">
<div class="code-block-caption"><span class="caption-text">view.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pyramid.events</span> <span class="kn">import</span> <span class="n">subscriber</span>
<span class="kn">from</span> <span class="nn">pyramid.events</span> <span class="kn">import</span> <span class="n">NewRequest</span>
<span class="nd">@subscriber</span><span class="p">(</span><span class="n">NewRequest</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">add_header</span><span class="p">(</span><span class="n">event</span><span class="p">):</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">event</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">response</span>
<span class="n">response</span><span class="o">.</span><span class="n">headers</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s1">'X-Frame-Options'</span><span class="p">,</span> <span class="s1">'DENY'</span><span class="p">)</span>
</pre></div>
</div>
</div>
</div>
CMS на python-pyramid
http://uralbash.ru/articles/2012/cms_pyramid2/
2012-11-21T15:41:00Z
2012-11-21T15:41:00Z
Uralbash
<div class="section" id="cms-python-pyramid">
<p>Мне иногда приходится писать сайты знакомым, друзьям, знакомым друзей, знакомым знакомых друзей...
И почти всегда всем нужен простой сайт нахаляву визитка, но что бы можно было
вносить изменения периодически. Идеально для этого наверно подходит CMS, но CMS
слишком тяжелая и имеет зачастую слишком много ненужного. Поэтому я написал
движок сайта-визитки с выпиленным ненужным.</p>
<p><a class="reference external" href="https://pypi.python.org/pypi/pyramid_promosite">pyramid_promosite</a> - это не CMS это движок сайта написанный на Pyramid.
Этот движок дает вам из коробки редактор страниц как <a class="reference external" href="https://www.djangoproject.com/">django</a> <code class="docutils literal"><span class="pre">flatpages</span></code>,
простую админку, возможность переводить страницу на другие языки и ВАЙСВИГ
редактор с возможностью загружать изображения</p>
<p>Способ применения:</p>
<ul class="simple">
<li>устанавливаем <a class="reference external" href="https://pypi.python.org/pypi/pyramid_promosite">pyramid_promosite</a></li>
<li>создаем свой проект</li>
<li>включаем <a class="reference external" href="https://pypi.python.org/pypi/pyramid_promosite">pyramid_promosite</a> в свой проект через <code class="docutils literal"><span class="pre">include</span></code></li>
<li>делаем свои шаблоны</li>
<li>пишем свои страницы со вьюхами (если нужны)</li>
</ul>
<p>все...</p>
<p>Пример сайта <a class="reference external" href="https://github.com/uralbash/platonaps.ru">https://github.com/uralbash/platonaps.ru</a>:</p>
<img alt="_static/2012/platon.png" class="align-center" src="_static/2012/platon.png" />
<div class="line-block">
<div class="line">Подробнее на <a class="reference external" href="https://github.com/uralbash/pyramid_promosite">https://github.com/uralbash/pyramid_promosite</a></div>
<div class="line">Документация в планах, если что то непонятно то отвечу здесь либо в github’е</div>
</div>
</div>
Раздача Интернета с десктоп Linux машины
http://uralbash.ru/articles/2012/shared_net/
2012-11-16T14:08:00Z
2012-11-16T14:08:00Z
Uralbash
<div class="section" id="linux">
<div class="line-block">
<div class="line"><code class="docutils literal"><span class="pre">Дано</span></code>: ноутбук который смотрит в Интернет</div>
<div class="line"><code class="docutils literal"><span class="pre">Надо</span></code>: получить Интернет на другом компе (компах) через этот ноут</div>
</div>
<p>В ноутбук вставляем еще одну сетевую карту, например такую:</p>
<img alt="_static/2012/USB+RJ45.jpg" class="align-center" src="_static/2012/USB+RJ45.jpg" />
<p>В итоге у нас в ноуте <code class="docutils literal"><span class="pre">eth0</span></code> это Интернет, <code class="docutils literal"><span class="pre">eth1</span></code> это локалка. Для <code class="docutils literal"><span class="pre">eth1</span></code>
делаем например такие настройки ip <code class="docutils literal"><span class="pre">10.0.0.100</span></code> mask 24. Я делал через
<code class="docutils literal"><span class="pre">networkmanager</span></code>.</p>
<p>Дальше соединяем <code class="docutils literal"><span class="pre">eth1</span></code> ноута с компом из локалки или со свичом. На компе из
локалки делаем следующие настройки (для <a class="reference external" href="http://www.ubuntu.com/">Ubuntu</a> в
<code class="docutils literal"><span class="pre">/etc/network/interfaces</span></code>):</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>iface eth0 inet static
<span class="c1"># ip компа</span>
address <span class="m">10</span>.0.0.15
netmask <span class="m">255</span>.255.255.0
<span class="c1"># шлюз наш ноут</span>
gateway <span class="m">10</span>.0.0.100
<span class="c1"># днс'ы от гула фор фри, в версиях раньше 12.04 надо править /etc/resolv.conf</span>
dns-nameservers <span class="m">8</span>.8.8.8 <span class="m">8</span>.8.4.4
auto eth0
</pre></div>
</div>
<p>Я не сетевик и не админ и не фанатею за сети, поэтому здесь описывается самый
примитивный способ, как это заставить работать за 4мин18сек. В продакшине эту
схему конечно нельзя использовать (наверно), для этого нужно пользоваться
настройками фаервола и <code class="docutils literal"><span class="pre">NAT</span></code>.</p>
<p>Дальше устанавливаем на ноуте <code class="docutils literal"><span class="pre">firestarter</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ apt-get install firestarter
</pre></div>
</div>
<div class="line-block">
<div class="line">Запускаем и в ГУЕ указываем <code class="docutils literal"><span class="pre">eth0</span></code> как внешний интерфейс и <code class="docutils literal"><span class="pre">eth1</span></code> как</div>
<div class="line">внутренний.</div>
<div class="line">На локальной машине:</div>
</div>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ ping uralbash.ru
PING uralbash.ru <span class="o">(</span><span class="m">216</span>.239.36.21<span class="o">)</span> <span class="m">56</span><span class="o">(</span><span class="m">84</span><span class="o">)</span> bytes of data.
<span class="m">64</span> bytes from any-in-2415.1e100.net <span class="o">(</span><span class="m">216</span>.239.36.21<span class="o">)</span>: <span class="nv">icmp_req</span><span class="o">=</span><span class="m">1</span> <span class="nv">ttl</span><span class="o">=</span><span class="m">44</span> <span class="nv">time</span><span class="o">=</span><span class="m">59</span>.4 ms
<span class="m">64</span> bytes from any-in-2415.1e100.net <span class="o">(</span><span class="m">216</span>.239.36.21<span class="o">)</span>: <span class="nv">icmp_req</span><span class="o">=</span><span class="m">2</span> <span class="nv">ttl</span><span class="o">=</span><span class="m">44</span> <span class="nv">time</span><span class="o">=</span><span class="m">51</span>.6 ms
<span class="m">64</span> bytes from any-in-2415.1e100.net <span class="o">(</span><span class="m">216</span>.239.36.21<span class="o">)</span>: <span class="nv">icmp_req</span><span class="o">=</span><span class="m">3</span> <span class="nv">ttl</span><span class="o">=</span><span class="m">44</span> <span class="nv">time</span><span class="o">=</span><span class="m">50</span>.9 ms
<span class="m">64</span> bytes from any-in-2415.1e100.net <span class="o">(</span><span class="m">216</span>.239.36.21<span class="o">)</span>: <span class="nv">icmp_req</span><span class="o">=</span><span class="m">4</span> <span class="nv">ttl</span><span class="o">=</span><span class="m">44</span> <span class="nv">time</span><span class="o">=</span><span class="m">50</span>.0 ms
<span class="m">64</span> bytes from any-in-2415.1e100.net <span class="o">(</span><span class="m">216</span>.239.36.21<span class="o">)</span>: <span class="nv">icmp_req</span><span class="o">=</span><span class="m">5</span> <span class="nv">ttl</span><span class="o">=</span><span class="m">44</span> <span class="nv">time</span><span class="o">=</span><span class="m">51</span>.4 ms
<span class="m">64</span> bytes from any-in-2415.1e100.net <span class="o">(</span><span class="m">216</span>.239.36.21<span class="o">)</span>: <span class="nv">icmp_req</span><span class="o">=</span><span class="m">6</span> <span class="nv">ttl</span><span class="o">=</span><span class="m">44</span> <span class="nv">time</span><span class="o">=</span><span class="m">52</span>.5 ms
<span class="m">64</span> bytes from any-in-2415.1e100.net <span class="o">(</span><span class="m">216</span>.239.36.21<span class="o">)</span>: <span class="nv">icmp_req</span><span class="o">=</span><span class="m">7</span> <span class="nv">ttl</span><span class="o">=</span><span class="m">44</span> <span class="nv">time</span><span class="o">=</span><span class="m">52</span>.3 ms
<span class="m">64</span> bytes from any-in-2415.1e100.net <span class="o">(</span><span class="m">216</span>.239.36.21<span class="o">)</span>: <span class="nv">icmp_req</span><span class="o">=</span><span class="m">8</span> <span class="nv">ttl</span><span class="o">=</span><span class="m">44</span> <span class="nv">time</span><span class="o">=</span><span class="m">51</span>.1 ms
^C
--- uralbash.ru ping statistics ---
<span class="m">8</span> packets transmitted, <span class="m">8</span> received, <span class="m">0</span>% packet loss, <span class="nb">time</span> 7008ms
rtt min/avg/max/mdev <span class="o">=</span> <span class="m">50</span>.083/52.444/59.403/2.733 ms
</pre></div>
</div>
</div>
Работа с PostgreSQL настройка и масштабирование
http://uralbash.ru/articles/2012/pg_book/
2012-11-16T14:08:00Z
2012-11-16T14:08:00Z
Uralbash
<div class="section" id="postgresql">
<p>Шыкарная книга по <a class="reference external" href="http://postgresql.org">Postgres</a>. Много умных и полезных мыслей в одном месте.
Хорошо написано про репликацию и настройку производительности. Книга на
гитхабе в свободном доступе! Автору лучи добра и счастья, пиши исчо!</p>
<a class="reference external image-reference" href="http://postgresql.leopard.in.ua/"><img alt="_static/2012/pg_book.png" class="align-center" src="_static/2012/pg_book.png" style="width: 400px;" /></a>
</div>
Идеальная архитектура. Ведущие специалисты о красоте программных архитектур
http://uralbash.ru/articles/2012/arch_book/
2012-11-14T01:17:00Z
2012-11-14T01:17:00Z
Uralbash
<div class="section" id="id1">
<p>Т.к. я читаю много техлитературы, то периодически буду писать мысли о ней.</p>
<a class="reference external image-reference" href="http://www.books.ru/books/idealnaya-arkhitektura-vedushchie-spetsialisty-o-krasote-programmnykh-arkhitektur-761783/?partner=490327"><img alt="_static/2012/ideal_arch.jpg" class="align-center" src="_static/2012/ideal_arch.jpg" style="width: 400px;" /></a>
<p>Книга поделена на 5 больших частей: про Архитектуру в целом, архитектуру в
продакшине, на железе, приложений пользователя и ЯП. Сразу скажу что букв много
аж 500 в страницах, много воды и откровенно запихнутого текста для объема. А из
закона Архимеда мы знаем что больший объем вытесняет больше нашего бабла!
Перевод местами тоже весьма неайс например “уборщик мусора”. Если не обращать
на это внимание то есть главы которые доставляют и читаются на одном дыхании,
потому что часто описывается ситуация с которой ты сам сталкивался и толкуется
как нужно было поступить - это очень круто.</p>
<p>Советую прочитать главы “2 Повесть о двух системах”, 7 про виртуализацию, 3 про
гэймдев и особенно доставляет 11 про Emacs (про архитектуру Emacs). Остальное я
читал между строк и между абзацев, а иногда только номера страниц. Не советую
читать книгу если нет опыта. Именно опыта проектирования и внедрения, а не
рутины или написания сайтов визиток за две недели. Без опыта это будет не
интересно, нес чем будет сравнивать и чтение превратится в усыпляющий процесс.
Остальным один раз прочитать, вспомнить свои ошибки, прослезиться, усвоить и
положить на полку, поэтому лучше брать PDF он значительно дешевле и не собирает
пыль и еще бережет лес.</p>
</div>
Убираем свист коммутатора 3Com OfficeConnect Dual Speed Hub 8
http://uralbash.ru/articles/2012/3com/
2012-11-13T13:25:00Z
2012-11-13T13:25:00Z
Uralbash
<div class="section" id="com-officeconnect-dual-speed-hub-8">
<img alt="_static/2012/3com1.jpg" class="align-left" src="_static/2012/3com1.jpg" style="width: 400px;" />
<p>Если у вас засвистела электроника то 99% это схема питания, будь это нетбук
<code class="docutils literal"><span class="pre">x100e</span></code> или БП или коммутатор.</p>
<br clear="both"/><p>Для начала разберем:</p>
<img alt="_static/2012/3com2.png" class="align-center" src="_static/2012/3com2.png" style="width: 400px;" />
<p>Стрелками указанны цилиндры которые надо выпаять:</p>
<img alt="_static/2012/3com3.jpg" class="align-center" src="_static/2012/3com3.jpg" style="width: 400px;" />
<p>На фото видно что с ним стало, покупаем новые и впаеваем на место:</p>
<img alt="_static/2012/3com4.jpg" class="align-center" src="_static/2012/3com4.jpg" style="width: 400px;" />
<p>Все, собираем, подключаем и радуемся тишине. Я конечно не электронщик, но
объясните пожалуйста нахрена дросселя нужны в схеме которая питается от БП
DC12В ???</p>
<p>Вот полезная статья еще <a class="reference external" href="http://www.techmaniacs.ru/blog/repair/3.html">Избавляемся от писка дросселей питания</a>.</p>
</div>
x220 tablet и доп кнопки в Linux
http://uralbash.ru/articles/2012/x220t_buttons/
2012-11-12T00:23:00Z
2012-11-12T00:23:00Z
Uralbash
<div class="section" id="x220-tablet-linux">
<img alt="_static/2012/x220t.jpg" class="align-left" src="_static/2012/x220t.jpg" />
<p>В принципе мой <a class="reference external" href="https://www.debian.org/">Debian</a> Wheezy определил почти все системные клавиши кроме 2х
справа на картинке (<code class="docutils literal"><span class="pre">Ctr+Alt+Del</span></code> и <code class="docutils literal"><span class="pre">поворот</span> <span class="pre">экрана</span></code>), микрофон и zoom по
<code class="docutils literal"><span class="pre">Fn+пробел</span></code>. <code class="docutils literal"><span class="pre">Ctr+Alt+Del</span></code> не нужен, микрофон и зум это повод написать
отдельную тему, а про поворот экрана я напишу подробно.</p>
<br clear="both"/><p>Вначале определим код кнопки:</p>
<div class="line-block">
<div class="line">1 - запускаем команду <code class="docutils literal"><span class="pre">xev</span></code> и нажимаем кнопку если появляется код то гуд иначе <code class="docutils literal"><span class="pre">п.2</span></code></div>
<div class="line">2 - можно посмотреть код этой кнопки в файле <code class="docutils literal"><span class="pre">/lib/udev/keymaps/lenovo-thinkpad_x200_tablet</span></code> называется <code class="docutils literal"><span class="pre">"rotate</span> <span class="pre">screen"</span></code> код <code class="docutils literal"><span class="pre">0x6c</span></code>, или можно погуглить например <a class="reference external" href="http://www.thinkwiki.org/wiki/Tablet_Hardware_Buttons">http://www.thinkwiki.org/wiki/Tablet_Hardware_Buttons</a> или если не Ъ то запускаем <code class="docutils literal"><span class="pre">tail</span> <span class="pre">-f</span> <span class="pre">|</span> <span class="pre">dmesg</span></code> нажимаем кнопку и видим:</div>
</div>
<br/><div class="highlight-bash"><div class="highlight"><pre><span></span><span class="o">[</span> <span class="m">3650</span>.281439<span class="o">]</span> atkbd serio0: Unknown key released <span class="o">(</span>translated <span class="nb">set</span> <span class="m">2</span>, code 0x6c on isa0060/serio0<span class="o">)</span>.
<span class="o">[</span> <span class="m">3650</span>.281443<span class="o">]</span> atkbd serio0: Use <span class="s1">'setkeycodes 6c <keycode>'</span> to make it known.
</pre></div>
</div>
<p>Тут же нам подсказывают что надо задать <code class="docutils literal"><span class="pre">keycode</span></code> этой кнопке.</p>
<p>3 - ищем свободный код командой <code class="docutils literal"><span class="pre">getkeycodes|grep</span> <span class="pre"><код></span></code>, например: <code class="docutils literal"><span class="pre">getkeycodes|grep</span> <span class="pre">220</span></code></p>
<p>Если вывода не последовало то код свободен</p>
<div class="line-block">
<div class="line">4 - назначаем код кнопке, в файле <code class="docutils literal"><span class="pre">/etc/rc.local</span></code> пишем <code class="docutils literal"><span class="pre">exec</span> <span class="pre">sudo</span> <span class="pre">setkeycodes</span> <span class="pre">6c</span> <span class="pre">220</span> <span class="pre">&</span></code></div>
<div class="line">5 - рестартимся или выполняем <code class="docutils literal"><span class="pre">setkeycodes</span></code> вручную, запускаем <code class="docutils literal"><span class="pre">xev</span></code> и нажимаем кнопку поворота, должны появится надписи</div>
</div>
<p>Дальше я привязал кнопку к действию при помощи <code class="docutils literal"><span class="pre">xbindkeys</span></code> (<code class="docutils literal"><span class="pre">apt-get</span> <span class="pre">install</span>
<span class="pre">xbindkeys</span></code>):</p>
<div class="line-block">
<div class="line">1 - создаем <code class="docutils literal"><span class="pre">~/.xbindkeysrc</span></code></div>
<div class="line">2 - вызываем <code class="docutils literal"><span class="pre">xbindkeys</span> <span class="pre">-k</span></code></div>
<div class="line">3 - нажимаем кнопку и копируем вывод</div>
<div class="line">4 - записываем в <code class="docutils literal"><span class="pre">xbindkeysrc</span></code>:</div>
</div>
<br/><div class="highlight-bash"><div class="highlight"><pre><span></span><span class="s2">"think-rotate"</span>
m:0x10 + c:224
</pre></div>
</div>
<p>Выполняем <code class="docutils literal"><span class="pre">xbindkeys</span></code> и вуаля!</p>
<div class="line-block">
<div class="line"><code class="docutils literal"><span class="pre">think-rotate</span></code> это скрипт поворота экрана из директории <code class="docutils literal"><span class="pre">/usr/bin/</span></code>.</div>
<div class="line">Сам скрипт я скачал с github’a: <a class="reference external" href="https://github.com/martin-ueding/think-rotate">https://github.com/martin-ueding/think-rotate</a></div>
</div>
<br/><div class="line-block">
<div class="line">P.S.: Если вдруг у Вас не завелись другие кнопки то можно по аналогии привязать к ним скрипты от сюда:</div>
<div class="line">1 - <a class="reference external" href="http://www.debian-fr.org/x220-install-configuration-t36152.html#p364748">http://www.debian-fr.org/x220-install-configuration-t36152.html#p364748</a></div>
<div class="line">2 - <a class="reference external" href="https://github.com/aconbere/thinkpad-x201-acpi-scripts">https://github.com/aconbere/thinkpad-x201-acpi-scripts</a></div>
</div>
<br/><div class="line-block">
<div class="line">UPD: вот еще нашел хорошую инструкцию <a class="reference external" href="http://kubuntu.ru/book/export/html/3491">http://kubuntu.ru/book/export/html/3491</a></div>
<div class="line">UPDUPD: Если кому то нужна кнопка посередине на экране то код <code class="docutils literal"><span class="pre">0x67</span></code></div>
<div class="line">UPDUPDUPD: Кнопка может быть привязана через <code class="docutils literal"><span class="pre">acpi</span></code> поэтому неплохо бы еще вначале проверить <code class="docutils literal"><span class="pre">acpi_listen</span></code> и если гут, то все таки сделать через <code class="docutils literal"><span class="pre">acpi</span></code>.</div>
</div>
</div>
корова говорит fortune
http://uralbash.ru/articles/2012/fortune/
2012-11-11T16:46:00Z
2012-11-11T16:46:00Z
Uralbash
<div class="section" id="fortune">
<div class="highlight-bash"><div class="highlight"><pre><span></span>< ta-ta-taaa ta-ta tataaaa >
--------------------------
<span class="se">\ </span> __------~~-,
<span class="se">\ </span> ,<span class="s1">' ,</span>
<span class="s1"> / \</span>
<span class="s1"> / :</span>
<span class="s1"> | '</span>
<span class="p">|</span> <span class="p">|</span>
<span class="p">|</span> <span class="p">|</span>
<span class="p">|</span> _-- <span class="p">|</span>
_<span class="p">|</span> <span class="o">=</span>-. .-. <span class="o">||</span>
o<span class="p">|</span>/o/ _. <span class="p">|</span>
/ ~ <span class="se">\ </span><span class="p">|</span>
<span class="o">(</span>____@<span class="o">)</span> ___~ <span class="p">|</span>
<span class="p">|</span><span class="nv">_</span><span class="o">===</span>~~~.<span class="sb">`</span> <span class="p">|</span>
_______.--~ <span class="p">|</span>
<span class="se">\_</span>_______ <span class="p">|</span>
<span class="se">\ </span> <span class="p">|</span>
__/-___-- -__
/ _ <span class="se">\</span>
</pre></div>
</div>
<p>мой скрипт в <code class="docutils literal"><span class="pre">.bashrc</span></code> для животного говорящего цитаты при открытии
терминала.</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nv">cowperson</span><span class="o">=</span><span class="sb">`</span>cowsay -l <span class="p">|</span> sed <span class="s1">'1,1d'</span> <span class="p">|</span> sed <span class="s1">'s/ /\n/g'</span> <span class="p">|</span> shuf -n <span class="m">1</span><span class="sb">`</span>
fortune <span class="p">|</span> cowsay -f <span class="nv">$cowperson</span>
</pre></div>
</div>
<p>По порядку:</p>
<div class="line-block">
<div class="line"><code class="docutils literal"><span class="pre">cowperson</span></code> - это выбор персонажа по рэндому</div>
<div class="line"><code class="docutils literal"><span class="pre">cowsay</span> <span class="pre">-l</span></code> - список всех персонажей</div>
<div class="line"><code class="docutils literal"><span class="pre">sed</span> <span class="pre">'1,1d'</span></code> - удаление первой служебной строки с расположением папки с файлами <code class="docutils literal"><span class="pre">.cow</span></code></div>
<div class="line"><code class="docutils literal"><span class="pre">sed</span> <span class="pre">'s/</span> <span class="pre">/\n/g'</span></code> - преобразование слов разделенных пробелами в строки (принцип как и в <code class="docutils literal"><span class="pre">vim</span></code> команда замены <code class="docutils literal"><span class="pre">s/</span></code> далее чего “пробел” на <code class="docutils literal"><span class="pre">\n</span></code>)</div>
<div class="line"><code class="docutils literal"><span class="pre">shuf</span> <span class="pre">-n</span> <span class="pre">1</span></code> - случайный выбор строки</div>
</div>
<p><code class="docutils literal"><span class="pre">fortune</span> <span class="pre">|</span> <span class="pre">cowsay</span> <span class="pre">-f</span> <span class="pre">$cowperson</span></code> рисует случайного персонажа с цитатой переданной из фортуне</p>
<p>Иногда случаются довольно забавные сочетания :)</p>
<img alt="_static/2012/fortune1.png" class="align-center" src="_static/2012/fortune1.png" />
<img alt="_static/2012/fortune2.png" class="align-center" src="_static/2012/fortune2.png" />
</div>
Книга по Lisp на русском
http://uralbash.ru/articles/2012/lisp_book/
2012-11-10T21:26:00Z
2012-11-10T21:26:00Z
Uralbash
<div class="section" id="lisp">
<p>Внезапно, вышла книга НА РУССКОМ по кошерному, более чем, <code class="docutils literal"><span class="pre">Лиспу</span></code>.</p>
<a class="reference external image-reference" href="http://www.books.ru/books/ansi-common-lisp-827258/?partner=490327"><img alt="_static/2012/lisp_book.jpg" class="align-center" src="_static/2012/lisp_book.jpg" style="width: 400px;" /></a>
<p>Хорошая новость для любителей <code class="docutils literal"><span class="pre">шыфт90</span></code>.</p>
</div>
Redactor-js WYSIWYG редактор и python
http://uralbash.ru/articles/2012/redactor-js/
2012-11-02T16:11:00Z
2012-11-02T16:11:00Z
Uralbash
<div class="section" id="redactor-js-wysiwyg-python">
<p><a class="reference external" href="https://github.com/dybskiy/redactor-js">Redactor-js</a> - это простой вайсвиг с
возможностью загрузки изображений.</p>
<img alt="_static/2012/redactor-js.png" class="align-center" src="_static/2012/redactor-js.png" />
<div class="line-block">
<div class="line">demo: <a class="reference external" href="http://imperavi.com/redactor/">http://imperavi.com/redactor/</a></div>
<div class="line">github: <a class="reference external" href="https://github.com/dybskiy/redactor-js">https://github.com/dybskiy/redactor-js</a></div>
</div>
<p>Как сочленить это с <a class="reference external" href="http://php.net/">php</a> можно прочитать из документации
<a class="reference external" href="http://imperavi.com/redactor/docs/images/">http://imperavi.com/redactor/docs/images/</a>. Там же есть ссылка на <a class="reference external" href="http://paltman.com/2012/08/15/how-to-setup-upload-handler-for-redactor/">пример с
Django от Patrick Altman</a>. Я
же постараюсь описать как загружать картинки при помощи <a class="reference external" href="http://pylonsproject.org/">pyramid</a> фреймворка,
думаю переписать на что то другое не составит труда.</p>
<p>js функция redactor’а у меня выглядит вот так:</p>
<div class="highlight-html"><div class="highlight"><pre><span></span><span class="c"><!-- Redactor is here --></span>
<span class="p"><</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">"stylesheet"</span> <span class="na">href</span><span class="o">=</span><span class="s">"/static/redactor/redactor/redactor.css"</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">"/static/redactor/redactor/redactor.js"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/javascript"</span><span class="p">></span>
<span class="nx">$</span><span class="p">(</span><span class="nb">document</span><span class="p">).</span><span class="nx">ready</span><span class="p">(</span>
<span class="kd">function</span><span class="p">()</span>
<span class="p">{</span>
<span class="nx">$</span><span class="p">(</span><span class="s1">'#redactor_content'</span><span class="p">).</span><span class="nx">redactor</span><span class="p">({</span>
<span class="nx">imageUpload</span><span class="o">:</span> <span class="s1">'/image/upload'</span><span class="p">,</span>
<span class="nx">imageGetJson</span><span class="o">:</span> <span class="s1">'/image/GetJson'</span><span class="p">,</span>
<span class="nx">mobile</span><span class="o">:</span> <span class="kc">true</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="p">);</span>
<span class="p"></</span><span class="nt">script</span><span class="p">></span>
</pre></div>
</div>
<p>вьюха для загрузки изображений:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="nd">@view_config</span><span class="p">(</span><span class="n">route_name</span><span class="o">=</span><span class="s1">'upload_image'</span><span class="p">,</span> <span class="n">renderer</span><span class="o">=</span><span class="s1">'json'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">upload_image</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="c1"># путь к директории куда загружать картинку</span>
<span class="n">path</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">registry</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'redactor_images'</span><span class="p">)</span>
<span class="n">filename</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">())</span> <span class="o">+</span> <span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">[</span><span class="s1">'file'</span><span class="p">]</span><span class="o">.</span><span class="n">filename</span>
<span class="n">input_file</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">[</span><span class="s1">'file'</span><span class="p">]</span><span class="o">.</span><span class="n">file</span>
<span class="c1"># Using the filename like this without cleaning it is very</span>
<span class="c1"># insecure so please keep that in mind when writing your own</span>
<span class="c1"># file handling.</span>
<span class="n">file_path</span> <span class="o">=</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">path</span><span class="p">,</span> <span class="n">filename</span><span class="p">)</span>
<span class="n">output_file</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">file_path</span><span class="p">,</span> <span class="s1">'wb'</span><span class="p">)</span>
<span class="c1"># Finally write the data to the output file</span>
<span class="n">input_file</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="k">while</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">input_file</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">2</span> <span class="o"><<</span> <span class="mi">16</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">data</span><span class="p">:</span>
<span class="k">break</span>
<span class="n">output_file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="n">output_file</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">return</span> <span class="p">{</span><span class="s2">"filelink"</span><span class="p">:</span> <span class="s2">"/static/uploaded/images/"</span> <span class="o">+</span> <span class="n">filename</span><span class="p">}</span>
</pre></div>
</div>
<p>И вьюха для выбора изображений из уже загруженных:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="nd">@view_config</span><span class="p">(</span><span class="n">route_name</span><span class="o">=</span><span class="s1">'GetJson'</span><span class="p">),</span> <span class="n">renderer</span><span class="o">=</span><span class="s1">'json'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">imageGetJson</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="n">path</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">registry</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'redactor_images'</span><span class="p">)</span>
<span class="n">types</span> <span class="o">=</span> <span class="p">(</span><span class="s1">'*.jpg'</span><span class="p">,</span> <span class="s1">'*.jpeg'</span><span class="p">,</span> <span class="s1">'*.gif'</span><span class="p">)</span> <span class="c1"># the tuple of file types</span>
<span class="n">files_grabbed</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">files</span> <span class="ow">in</span> <span class="n">types</span><span class="p">:</span>
<span class="n">files_grabbed</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">glob</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="n">path</span> <span class="o">+</span> <span class="s2">"/"</span> <span class="o">+</span> <span class="n">files</span><span class="p">))</span>
<span class="n">images</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="nb">file</span> <span class="ow">in</span> <span class="n">files_grabbed</span><span class="p">:</span>
<span class="nb">file</span> <span class="o">=</span> <span class="nb">file</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span>
<span class="n">images</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s2">"thumb"</span><span class="p">:</span> <span class="s2">"/static/uploaded/images/"</span> <span class="o">+</span> <span class="nb">file</span><span class="p">,</span>
<span class="s2">"image"</span><span class="p">:</span> <span class="s2">"/static/uploaded/images/"</span> <span class="o">+</span> <span class="nb">file</span><span class="p">,</span>
<span class="s2">"title"</span><span class="p">:</span> <span class="nb">file</span><span class="p">,</span> <span class="s2">"folder"</span><span class="p">:</span> <span class="s2">"images"</span><span class="p">})</span>
<span class="k">return</span> <span class="n">images</span>
</pre></div>
</div>
<p>Пользуйтесь, хороший редактор.</p>
</div>
Генератор лабиринта на Питоне
http://uralbash.ru/articles/2012/python_labirint/
2012-10-18T18:31:00Z
2012-10-18T18:31:00Z
Uralbash
<div class="section" id="id1">
<p>Отличное приложение для создания лабиринтов. Написано на Python и доставляет
много фана.</p>
<img alt="_static/2012/maze.jpg" class="align-center" src="_static/2012/maze.jpg" />
<p>Вот ссылка на код <a class="reference external" href="https://github.com/daleobrien/maze">https://github.com/daleobrien/maze</a></p>
</div>
Еще пингвины...
http://uralbash.ru/articles/2012/penguin_vs_leo/
2012-10-14T15:50:00Z
2012-10-14T15:50:00Z
Uralbash
<div class="section" id="id1">
<iframe width="560" height="315"
src="https://www.youtube.com/embed/xzimPDxdZ8g" frameborder="0"
allowfullscreen></iframe></div>
Перевод шаблонов Jinja в Pyramid
http://uralbash.ru/articles/2012/jinja_pyramid_i18n/
2012-09-28T17:58:00Z
2012-09-28T17:58:00Z
Uralbash
<div class="section" id="jinja-pyramid">
<p>Основная документация как это делать <a class="reference external" href="http://pyramid.readthedocs.org/en/1.2-branch/narr/i18n.html">здесь</a>. Но как обычно
есть нюансы.</p>
<p>Рабочий пример можно посмотреть установив шаблон. Устанавливаем <a class="reference external" href="https://pypi.python.org/pypi/pyramid_jinja2">pyramid_jinja2</a>
и пишем:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ pcreate -t pyramid_jinja2_starter yoyoyoyo
</pre></div>
</div>
<div class="line-block">
<div class="line">Если лень устанавливать пример, то нужно сделать следующее:</div>
<div class="line">Добавить файл <code class="docutils literal"><span class="pre">message-extraction.ini</span></code></div>
</div>
<div class="highlight-ini"><div class="highlight"><pre><span></span><span class="k">[python: **.py]</span>
<span class="k">[jinja2: **.jinja2]</span>
<span class="na">encoding</span> <span class="o">=</span> <span class="s">utf-8</span>
</pre></div>
</div>
<p>Добавить в <code class="docutils literal"><span class="pre">setup.cfg</span></code>:</p>
<div class="highlight-ini"><div class="highlight"><pre><span></span><span class="k">[extract_messages]</span>
<span class="na">add_comments</span> <span class="o">=</span> <span class="s">TRANSLATORS:</span>
<span class="na">output_file</span> <span class="o">=</span> <span class="s">myprojectname/locale/myprojectname.pot</span>
<span class="na">width</span> <span class="o">=</span> <span class="s">80</span>
<span class="na">mapping_file</span> <span class="o">=</span> <span class="s">message-extraction.ini</span>
</pre></div>
</div>
<p>далее в <code class="docutils literal"><span class="pre">__init__.py</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">settings</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">settings</span><span class="p">)</span>
<span class="n">settings</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="s1">'jinja2.i18n.domain'</span><span class="p">,</span> <span class="s1">'myprojectname'</span><span class="p">)</span>
<span class="o">...</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_translation_dirs</span><span class="p">(</span><span class="s2">"myprojectname:locale/"</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">include</span><span class="p">(</span><span class="s1">'pyramid_jinja2'</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_jinja2_search_path</span><span class="p">(</span><span class="s2">"myprojectname:templates"</span><span class="p">)</span>
</pre></div>
</div>
<p>В шаблоне:</p>
<div class="highlight-jinja"><div class="highlight"><pre><span></span><span class="cp">{{</span> <span class="nv">gettext</span><span class="o">(</span><span class="s1">'Logo'</span><span class="o">)</span> <span class="cp">}}</span><span class="x"></span>
<span class="cp">{%</span> <span class="k">trans</span> <span class="cp">%}</span><span class="x">Home</span><span class="cp">{%</span> <span class="k">endtrans</span> <span class="cp">%}</span><span class="x"></span>
</pre></div>
</div>
<p>все остальное по документации... Я для упрощения использую скрипт <code class="docutils literal"><span class="pre">i18n.sh</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="ch">#!/usr/bin/env bash</span>
<span class="nv">py</span><span class="o">=</span>python
<span class="nv">$py</span> setup.py extract_messages
<span class="nv">$py</span> setup.py update_catalog
<span class="nv">$py</span> setup.py compile_catalog
<span class="c1"># vim:set et sts=4 ts=4 tw=80:</span>
</pre></div>
</div>
</div>
Перевод шаблонов Jinja в Pylons
http://uralbash.ru/articles/2012/jinja_pylons_i18n/
2012-09-27T20:07:00Z
2012-09-27T20:07:00Z
Uralbash
<div class="section" id="jinja-pylons">
<p>Все точно также как и с <a class="reference external" href="http://www.makotemplates.org/">mako</a>, “Но есть нюансы”©</p>
<p>Добавьте в <code class="docutils literal"><span class="pre">setup.py</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">package_data</span><span class="o">=</span><span class="p">{</span><span class="s1">'myproject'</span><span class="p">:</span> <span class="p">[</span><span class="s1">'i18n/*/LC_MESSAGES/*.mo'</span><span class="p">]},</span>
<span class="n">message_extractors</span><span class="o">=</span><span class="p">{</span><span class="s1">'myproject'</span><span class="p">:</span> <span class="p">[</span>
<span class="p">(</span><span class="s1">'**.py'</span><span class="p">,</span> <span class="s1">'python'</span><span class="p">,</span> <span class="bp">None</span><span class="p">),</span>
<span class="p">(</span><span class="s1">'templates/**.html'</span><span class="p">,</span> <span class="s1">'jinja2'</span><span class="p">,</span> <span class="bp">None</span><span class="p">),</span>
<span class="p">(</span><span class="s1">'public/**'</span><span class="p">,</span> <span class="s1">'ignore'</span><span class="p">,</span> <span class="bp">None</span><span class="p">)]},</span>
</pre></div>
</div>
<p>Добавьте в <code class="docutils literal"><span class="pre">lib/base.py</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pylons.i18n.translation</span> <span class="kn">import</span> <span class="n">_</span><span class="p">,</span> <span class="n">ungettext</span>
</pre></div>
</div>
<p>И что то типа того в <code class="docutils literal"><span class="pre">config/environment.py</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1"># Create the Jinja2 Environment</span>
<span class="n">config</span><span class="p">[</span><span class="s1">'pylons.app_globals'</span><span class="p">]</span><span class="o">.</span><span class="n">jinja2_env</span> <span class="o">=</span> <span class="n">Environment</span><span class="p">(</span><span class="n">loader</span><span class="o">=</span><span class="n">ChoiceLoader</span><span class="p">(</span>
<span class="p">[</span><span class="n">FileSystemLoader</span><span class="p">(</span><span class="n">path</span><span class="p">)</span> <span class="k">for</span> <span class="n">path</span> <span class="ow">in</span> <span class="n">paths</span><span class="p">[</span><span class="s1">'templates'</span><span class="p">]]),</span>
<span class="n">autoescape</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
<span class="n">extensions</span><span class="o">=</span><span class="p">[</span><span class="s1">'jinja2.ext.do'</span><span class="p">,</span> <span class="s1">'jinja2.ext.i18n'</span><span class="p">])</span>
<span class="n">config</span><span class="p">[</span><span class="s1">'pylons.app_globals'</span><span class="p">]</span><span class="o">.</span><span class="n">jinja2_env</span><span class="o">.</span><span class="n">install_gettext_translations</span><span class="p">(</span><span class="n">pylons</span><span class="o">.</span><span class="n">i18n</span><span class="p">)</span>
<span class="c1"># Jinja2's unable to request c's attributes without strict_c</span>
<span class="n">config</span><span class="p">[</span><span class="s1">'pylons.strict_c'</span><span class="p">]</span> <span class="o">=</span> <span class="bp">True</span>
</pre></div>
</div>
<p>Теперь можно переводить <code class="docutils literal"><span class="pre">{{</span> <span class="pre">_('Translate</span> <span class="pre">me!')</span> <span class="pre">}}</span></code>.</p>
</div>
CMS на Pyramid фреймворке
http://uralbash.ru/articles/2012/cms_pyramid/
2012-09-26T15:30:00Z
2012-09-26T15:30:00Z
Uralbash
<div class="section" id="cms-pyramid">
<p><a class="reference external" href="http://www.nive.co/cms/root.html">Poolyx CMS</a> - малоизвестная система
управления сайтом написанная на Python с применением <a class="reference external" href="http://pylonsproject.org/">Pyramid</a> немецкими
кодерами.</p>
<img alt="_static/2012/poolyx.jpeg" class="align-center" src="_static/2012/poolyx.jpeg" />
<p>В будущем будет называться <a class="reference external" href="https://pypi.python.org/pypi/nive">nive</a>. Советую попробовать, по крайне мере
мне показалась намного удобнее <a class="reference external" href="https://pypi.python.org/pypi/Kotti">Kotti</a>.</p>
</div>
Lisp...
http://uralbash.ru/articles/2012/lisp/
2012-09-24T16:48:00Z
2012-09-24T16:48:00Z
Uralbash
<div class="section" id="lisp">
<img alt="_static/2012/Sicp_cover.png" class="align-center" src="_static/2012/Sicp_cover.png" />
<div class="line-block">
<div class="line">На просторах рунета есть добрые люди уважающие <a class="reference external" href="http://lurkmore.to/SICP">SICP</a> и переводящие лекции.</div>
<div class="line">За что посылаю им лучи добра и благополучия.</div>
</div>
<p>Ссылка: <a class="reference external" href="http://video.yandex.ru/users/alexey-v-zubkov/collection/1/">лекции</a></p>
<p>Оставлю также это здесь:</p>
<p><a class="reference external" href="http://sicp.sergeykhenkin.com/">http://sicp.sergeykhenkin.com/</a>
<a class="reference external" href="http://rutracker.org/forum/viewtopic.php?p=37772721">http://rutracker.org/forum/viewtopic.php?p=37772721</a></p>
<p>Еще:</p>
<p><a class="reference external" href="http://newstar.rinet.ru/~goga/sicp/sicp.pdf">http://newstar.rinet.ru/~goga/sicp/sicp.pdf</a>
<a class="reference external" href="https://hexlet.org/course/sicp/">https://hexlet.org/course/sicp/</a></p>
</div>
debian business card зависает при установке
http://uralbash.ru/articles/2012/debian_bc/
2012-09-15T18:40:00Z
2012-09-15T18:40:00Z
Uralbash
<div class="section" id="debian-business-card">
<p>При установке дистрибутива <code class="docutils literal"><span class="pre">debian-6.0.5-amd64-businesscard.iso</span></code> было
замечено зависание на шаге <code class="docutils literal"><span class="pre">network</span> <span class="pre">detect</span></code>. Из-за чего это происходит я не
знаю, но лечится нажатием <code class="docutils literal"><span class="pre">Ctrl+C</span></code> один или два раза. После чего начинается
поиск настроек сети при помощи <code class="docutils literal"><span class="pre">DHCP</span></code>.</p>
</div>
Простой блог на фреймворке Pyramid
http://uralbash.ru/articles/2012/pyramid_blog/
2012-09-11T17:14:00Z
2012-09-11T17:14:00Z
Uralbash
<div class="section" id="pyramid">
<p>Пример простого блога на Pyramid <a class="reference external" href="https://github.com/uralbash/pyramid_easy_blog">https://github.com/uralbash/pyramid_easy_blog</a></p>
<p>Фьючерсы:</p>
<ul class="simple">
<li>wysiwyg редактор</li>
<li>загрузка изображений</li>
<li>мобайл фон реди</li>
</ul>
<img alt="_static/2012/blog1.png" class="align-center" src="_static/2012/blog1.png" style="width: 300px;" />
<p>Туду:</p>
<ul class="simple">
<li>коменты</li>
<li>теги</li>
<li>удаление изображений (файл менеджер)</li>
</ul>
<p>пул реквест реди</p>
<img alt="_static/2012/blog2.png" class="align-center" src="_static/2012/blog2.png" style="width: 600px;" />
</div>
Структура Pyramid приложений как в Django
http://uralbash.ru/articles/2012/pyramid_as_django/
2012-07-05T10:42:00Z
2012-07-05T10:42:00Z
Uralbash
<div class="section" id="pyramid-django">
<p>Одной из причин отказа развивать ветку <a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">Pylons</a> стала его архитектура
проекта. Все контроллеры хранятся в директории <code class="docutils literal"><span class="pre">controllers</span></code>, модели в
<code class="docutils literal"><span class="pre">models</span></code>, шаблоны в <code class="docutils literal"><span class="pre">templates</span></code>. Это очень удобно когда у вас маленький
проект, но если он разрастается до десятков и сотен сущностей, то становится
крайне сложно скакать по этим папкам выискивая нужный файл, относящийся именно
к этой сущности. В <a class="reference external" href="https://www.djangoproject.com/">Django</a> сделано по другому, в проекте хранятся
приложения (<code class="docutils literal"><span class="pre">application</span></code>) - это такие маленькие подпрограммы которые
отвечают за конкретный функционал проекта (например фотогалерея
<a class="reference external" href="https://pypi.python.org/pypi/django-photologue">django-photologue</a> или дерево сайта <a class="reference external" href="https://pypi.python.org/pypi/django-sitetree">django-sitetree</a> и прочее).
Каждое такое приложение имеет свою папку и уже в ней хранятся контроллеры
(<code class="docutils literal"><span class="pre">views</span></code> в данном случае) и модели (<code class="docutils literal"><span class="pre">models</span></code>). Т.е. вместо такой
архитектуры <a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">Pylons</a>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>Project/
controllers/
controllers1.py
controllers2.py
model/
models1.py
models2.py
templates/
templates1/
templates2/
routes.py
</pre></div>
</div>
<p>мы получаем:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>Project/
app1/
models.py
routes.py
views.py
app2/
models.py
routes.py
views.py
templates/
templates1/
templates2/
</pre></div>
</div>
<p>Разработчики не стали менять архитектуру <a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">Pylons</a> и создавать Pylons 2.0, а
начали развивать новый проект <a class="reference external" href="http://pylonsproject.org/">Pyramid</a> с похожей на <a class="reference external" href="https://www.djangoproject.com/">Django</a> структурой
проекта. При этом <a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">Pylons</a> не считается устаревшим, а просто имеет немного
другой подход к разработке.</p>
<p>Стоит ли сейчас выбирать <a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">Pylons</a>? Да, если вы его хорошо знаете и не
планируете создавать слишком масштабное приложение, иначе лучше все таки
выбрать <a class="reference external" href="http://pylonsproject.org/">Pyramid</a>.</p>
<p>Посмотрим как в нем организовать структуру проекта:</p>
<p>После создания проект выглядит так:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>MyProject/
├── CHANGES.txt
├── development.ini
├── MANIFEST.in
├── myproject
│ ├── __init__.py
│ ├── models.py
│ ├── scripts/
│ ├── static/
│ ├── templates/
│ ├── tests.py
│ └── views.py
├── production.ini
├── README.txt
├── setup.cfg
└── setup.py
</pre></div>
</div>
<p>Наша задача перенести <code class="docutils literal"><span class="pre">models.py</span></code>, <code class="docutils literal"><span class="pre">views.py</span></code>, <code class="docutils literal"><span class="pre">tests.py</span></code> в <code class="docutils literal"><span class="pre">app1</span></code>.
Создаем папку <code class="docutils literal"><span class="pre">app1</span></code> и переносим файлы.</p>
<p>Должно получится так:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>MyProject/
.
├── CHANGES.txt
├── development.ini
├── MANIFEST.in
├── myproject
│ ├── app1
│ │ ├── __init__.py
│ │ ├── models.py
│ │ ├── tests.py
│ │ └── views.py
│ ├── __init__.py
│ ├── scripts
│ │ ├── initializedb.py
│ │ └── __init__.py
│ ├── static
│ │ ├── favicon.ico
│ │ ├── footerbg.png
│ │ ├── headerbg.png
│ │ ├── ie6.css
│ │ ├── middlebg.png
│ │ ├── pylons.css
│ │ ├── pyramid.png
│ │ ├── pyramid-small.png
│ │ └── transparent.gif
│ └── templates
│ └── mytemplate.pt
├── production.ini
├── README.txt
├── setup.cfg
└── setup.py
</pre></div>
</div>
<p>Меняем <code class="docutils literal"><span class="pre">__init__.py</span></code> в проекте:</p>
<p>Вместо</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pyramid.config</span> <span class="kn">import</span> <span class="n">Configurator</span>
<span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">engine_from_config</span>
<span class="kn">from</span> <span class="nn">.models</span> <span class="kn">import</span> <span class="n">DBSession</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="n">global_config</span><span class="p">,</span> <span class="o">**</span><span class="n">settings</span><span class="p">):</span>
<span class="sd">""" This function returns a Pyramid WSGI application.</span>
<span class="sd"> """</span>
<span class="n">engine</span> <span class="o">=</span> <span class="n">engine_from_config</span><span class="p">(</span><span class="n">settings</span><span class="p">,</span> <span class="s1">'sqlalchemy.'</span><span class="p">)</span>
<span class="n">DBSession</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span><span class="n">bind</span><span class="o">=</span><span class="n">engine</span><span class="p">)</span>
<span class="n">config</span> <span class="o">=</span> <span class="n">Configurator</span><span class="p">(</span><span class="n">settings</span><span class="o">=</span><span class="n">settings</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_static_view</span><span class="p">(</span><span class="s1">'static'</span><span class="p">,</span> <span class="s1">'static'</span><span class="p">,</span> <span class="n">cache_max_age</span><span class="o">=</span><span class="mi">3600</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_route</span><span class="p">(</span><span class="s1">'home'</span><span class="p">,</span> <span class="s1">'/'</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">scan</span><span class="p">()</span>
<span class="k">return</span> <span class="n">config</span><span class="o">.</span><span class="n">make_wsgi_app</span><span class="p">()</span>
</pre></div>
</div>
<p>Делаем</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pyramid.config</span> <span class="kn">import</span> <span class="n">Configurator</span>
<span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">engine_from_config</span>
<span class="kn">from</span> <span class="nn">.models</span> <span class="kn">import</span> <span class="n">DBSession</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="n">global_config</span><span class="p">,</span> <span class="o">**</span><span class="n">settings</span><span class="p">):</span>
<span class="sd">""" This function returns a Pyramid WSGI application.</span>
<span class="sd"> """</span>
<span class="n">engine</span> <span class="o">=</span> <span class="n">engine_from_config</span><span class="p">(</span><span class="n">settings</span><span class="p">,</span> <span class="s1">'sqlalchemy.'</span><span class="p">)</span>
<span class="n">DBSession</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span><span class="n">bind</span><span class="o">=</span><span class="n">engine</span><span class="p">)</span>
<span class="n">config</span> <span class="o">=</span> <span class="n">Configurator</span><span class="p">(</span><span class="n">settings</span><span class="o">=</span><span class="n">settings</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_static_view</span><span class="p">(</span><span class="s1">'static'</span><span class="p">,</span> <span class="s1">'static'</span><span class="p">,</span> <span class="n">cache_max_age</span><span class="o">=</span><span class="mi">3600</span><span class="p">)</span>
<span class="c1"># add config for each of your subapps</span>
<span class="n">config</span><span class="o">.</span><span class="n">include</span><span class="p">(</span><span class="s1">'myproject.app1'</span><span class="p">)</span>
<span class="c1"># pyramid_jinja2 configuration</span>
<span class="n">config</span><span class="o">.</span><span class="n">include</span><span class="p">(</span><span class="s1">'pyramid_jinja2'</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_jinja2_search_path</span><span class="p">(</span><span class="s2">"myproject:templates"</span><span class="p">)</span>
<span class="k">return</span> <span class="n">config</span><span class="o">.</span><span class="n">make_wsgi_app</span><span class="p">()</span>
</pre></div>
</div>
<p>Теперь в этом <code class="docutils literal"><span class="pre">__init__.py</span></code> мы будем хранить глобальные настройки, а в инитах
апликайшинах настройки самих апликайшинов.</p>
<p>Добавляем <code class="docutils literal"><span class="pre">models.py</span></code> в основной проект:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>MyProject/
.
├── CHANGES.txt
├── development.ini
├── MANIFEST.in
├── myproject
│ ├── app1
│ │ ├── __init__.py
│ │ ├── models.py
│ │ ├── tests.py
│ │ └── views.py
│ ├── __init__.py
│ ├── scripts
│ │ ├── initializedb.py
│ │ └── __init__.py
│ ├── models.py
│ ├── static
│ │ ├── favicon.ico
│ │ ├── footerbg.png
│ │ ├── headerbg.png
│ │ ├── ie6.css
│ │ ├── middlebg.png
│ │ ├── pylons.css
│ │ ├── pyramid.png
│ │ ├── pyramid-small.png
│ │ └── transparent.gif
│ └── templates
│ └── mytemplate.pt
├── production.ini
├── README.txt
├── setup.cfg
└── setup.py
</pre></div>
</div>
<p>В нем будет хранится сессия <a class="reference external" href="http://sqlalchemy.org/">SQLAlchemy</a> общая для всех проектов:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">zope.sqlalchemy</span> <span class="kn">import</span> <span class="n">ZopeTransactionExtension</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.ext.declarative</span> <span class="kn">import</span> <span class="n">declarative_base</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.orm</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">scoped_session</span><span class="p">,</span>
<span class="n">sessionmaker</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">DBSession</span> <span class="o">=</span> <span class="n">scoped_session</span><span class="p">(</span><span class="n">sessionmaker</span><span class="p">(</span><span class="n">extension</span><span class="o">=</span><span class="n">ZopeTransactionExtension</span><span class="p">()))</span>
<span class="n">Base</span> <span class="o">=</span> <span class="n">declarative_base</span><span class="p">()</span>
</pre></div>
</div>
<p>Меняем <code class="docutils literal"><span class="pre">__init__.py</span></code> в <code class="docutils literal"><span class="pre">app1</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">includeme</span><span class="p">(</span><span class="n">config</span><span class="p">):</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_route</span><span class="p">(</span><span class="s1">'home'</span><span class="p">,</span> <span class="s1">'/'</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">scan</span><span class="p">()</span>
</pre></div>
</div>
<p>Меняем <code class="docutils literal"><span class="pre">models.py</span></code> в <code class="docutils literal"><span class="pre">app1</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">Column</span><span class="p">,</span>
<span class="n">Integer</span><span class="p">,</span>
<span class="n">Text</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.ext.declarative</span> <span class="kn">import</span> <span class="n">declarative_base</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.orm</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">scoped_session</span><span class="p">,</span>
<span class="n">sessionmaker</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span> <span class="nn">..models</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">DBSession</span><span class="p">,</span>
<span class="n">Base</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">class</span> <span class="nc">MyModel</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span>
<span class="n">__tablename__</span> <span class="o">=</span> <span class="s1">'models'</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">name</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Text</span><span class="p">,</span> <span class="n">unique</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">)</span>
<span class="k">def</span> <span class="fm">__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">value</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
<span class="bp">self</span><span class="o">.</span><span class="n">value</span> <span class="o">=</span> <span class="n">value</span>
</pre></div>
</div>
<p>Меняем <code class="docutils literal"><span class="pre">tests.py</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">unittest</span>
<span class="kn">import</span> <span class="nn">transaction</span>
<span class="kn">from</span> <span class="nn">pyramid</span> <span class="kn">import</span> <span class="n">testing</span>
<span class="kn">from</span> <span class="nn">..models</span> <span class="kn">import</span> <span class="n">DBSession</span>
<span class="k">class</span> <span class="nc">TestMyView</span><span class="p">(</span><span class="n">unittest</span><span class="o">.</span><span class="n">TestCase</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">setUp</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">config</span> <span class="o">=</span> <span class="n">testing</span><span class="o">.</span><span class="n">setUp</span><span class="p">()</span>
<span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">create_engine</span>
<span class="n">engine</span> <span class="o">=</span> <span class="n">create_engine</span><span class="p">(</span><span class="s1">'sqlite://'</span><span class="p">)</span>
<span class="kn">from</span> <span class="nn">.models</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">Base</span><span class="p">,</span>
<span class="n">MyModel</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">DBSession</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span><span class="n">bind</span><span class="o">=</span><span class="n">engine</span><span class="p">)</span>
<span class="n">Base</span><span class="o">.</span><span class="n">metadata</span><span class="o">.</span><span class="n">create_all</span><span class="p">(</span><span class="n">engine</span><span class="p">)</span>
<span class="k">with</span> <span class="n">transaction</span><span class="o">.</span><span class="n">manager</span><span class="p">:</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">MyModel</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">'one'</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="mi">55</span><span class="p">)</span>
<span class="n">DBSession</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">model</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">tearDown</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">DBSession</span><span class="o">.</span><span class="n">remove</span><span class="p">()</span>
<span class="n">testing</span><span class="o">.</span><span class="n">tearDown</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">test_it</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="kn">from</span> <span class="nn">.views</span> <span class="kn">import</span> <span class="n">my_view</span>
<span class="n">request</span> <span class="o">=</span> <span class="n">testing</span><span class="o">.</span><span class="n">DummyRequest</span><span class="p">()</span>
<span class="n">info</span> <span class="o">=</span> <span class="n">my_view</span><span class="p">(</span><span class="n">request</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">info</span><span class="p">[</span><span class="s1">'one'</span><span class="p">]</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="s1">'one'</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">info</span><span class="p">[</span><span class="s1">'project'</span><span class="p">],</span> <span class="s1">'MyProject'</span><span class="p">)</span>
</pre></div>
</div>
<p>Меняем <code class="docutils literal"><span class="pre">views.py</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">sqlalchemy.exc</span> <span class="kn">import</span> <span class="n">DBAPIError</span>
<span class="kn">from</span> <span class="nn">..models</span> <span class="kn">import</span> <span class="n">DBSession</span>
<span class="kn">from</span> <span class="nn">.models</span> <span class="kn">import</span> <span class="n">MyModel</span>
<span class="nd">@view_config</span><span class="p">(</span><span class="n">route_name</span><span class="o">=</span><span class="s1">'home'</span><span class="p">,</span> <span class="n">renderer</span><span class="o">=</span><span class="s1">'../templates/mytemplate.pt'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">my_view</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">one</span> <span class="o">=</span> <span class="n">DBSession</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">MyModel</span><span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">MyModel</span><span class="o">.</span><span class="n">name</span><span class="o">==</span><span class="s1">'one'</span><span class="p">)</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
<span class="k">except</span> <span class="n">DBAPIError</span><span class="p">:</span>
<span class="k">return</span> <span class="n">Response</span><span class="p">(</span><span class="n">conn_err_msg</span><span class="p">,</span> <span class="n">content_type</span><span class="o">=</span><span class="s1">'text/plain'</span><span class="p">,</span> <span class="n">status_int</span><span class="o">=</span><span class="mi">500</span><span class="p">)</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'one'</span><span class="p">:</span><span class="n">one</span><span class="p">,</span> <span class="s1">'project'</span><span class="p">:</span><span class="s1">'MyProject'</span><span class="p">}</span>
<span class="n">conn_err_msg</span> <span class="o">=</span> <span class="s2">"""</span><span class="se">\</span>
<span class="s2">Pyramid is having a problem using your SQL database. The problem</span>
<span class="s2">might be caused by one of the following things:</span>
<span class="s2">A. You may need to run the "initialize_MyProject_db" script</span>
<span class="s2"> to initialize your database tables. Check your virtual</span>
<span class="s2"> environment's "bin" directory for this script and try to run it.</span>
<span class="s2">B. Your database server may not be running. Check that the</span>
<span class="s2"> database server referred to by the "sqlalchemy.url" setting in</span>
<span class="s2"> your "development.ini" file is running.</span>
<span class="s2">After you fix the problem, please restart the Pyramid application to</span>
<span class="s2">try it again.</span>
<span class="s2">"""</span>
</pre></div>
</div>
<p>Меняем <code class="docutils literal"><span class="pre">initializedb.py</span></code> в <code class="docutils literal"><span class="pre">scripts</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">transaction</span>
<span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">engine_from_config</span>
<span class="kn">from</span> <span class="nn">pyramid.paster</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">get_appsettings</span><span class="p">,</span>
<span class="n">setup_logging</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span> <span class="nn">..models</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">DBSession</span><span class="p">,</span>
<span class="n">Base</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span> <span class="nn">..app1.models</span> <span class="kn">import</span> <span class="n">MyModel</span>
<span class="k">def</span> <span class="nf">usage</span><span class="p">(</span><span class="n">argv</span><span class="p">):</span>
<span class="n">cmd</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="k">print</span><span class="p">(</span><span class="s1">'usage: </span><span class="si">%s</span><span class="s1"> <config_uri></span><span class="se">\n</span><span class="s1">'</span>
<span class="s1">'(example: "</span><span class="si">%s</span><span class="s1"> development.ini")'</span> <span class="o">%</span> <span class="p">(</span><span class="n">cmd</span><span class="p">,</span> <span class="n">cmd</span><span class="p">))</span>
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="n">argv</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="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">argv</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">2</span><span class="p">:</span>
<span class="n">usage</span><span class="p">(</span><span class="n">argv</span><span class="p">)</span>
<span class="n">config_uri</span> <span class="o">=</span> <span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="n">setup_logging</span><span class="p">(</span><span class="n">config_uri</span><span class="p">)</span>
<span class="n">settings</span> <span class="o">=</span> <span class="n">get_appsettings</span><span class="p">(</span><span class="n">config_uri</span><span class="p">)</span>
<span class="n">engine</span> <span class="o">=</span> <span class="n">engine_from_config</span><span class="p">(</span><span class="n">settings</span><span class="p">,</span> <span class="s1">'sqlalchemy.'</span><span class="p">)</span>
<span class="n">DBSession</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span><span class="n">bind</span><span class="o">=</span><span class="n">engine</span><span class="p">)</span>
<span class="n">Base</span><span class="o">.</span><span class="n">metadata</span><span class="o">.</span><span class="n">create_all</span><span class="p">(</span><span class="n">engine</span><span class="p">)</span>
<span class="k">with</span> <span class="n">transaction</span><span class="o">.</span><span class="n">manager</span><span class="p">:</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">MyModel</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">'one'</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="n">DBSession</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">model</span><span class="p">)</span>
</pre></div>
</div>
<div class="line-block">
<div class="line">Выполняем <code class="docutils literal"><span class="pre">python</span> <span class="pre">setup.py</span> <span class="pre">install</span></code>, запускаем проект, профит!</div>
<div class="line">Остальные апликайшины добавляются по аналогии.</div>
<div class="line">Навеянно этим <a class="reference external" href="http://stackoverflow.com/questions/6012991/pyramid-project-structure">http://stackoverflow.com/questions/6012991/pyramid-project-structure</a></div>
</div>
</div>
pyramid_formalchemy
http://uralbash.ru/articles/2012/pyramid_formalchemy/
2012-07-04T11:51:00Z
2012-07-04T11:51:00Z
Uralbash
<div class="section" id="pyramid-formalchemy">
<p><a class="reference external" href="https://pypi.python.org/pypi/FormAlchemy">FormAlchemy</a> это <code class="docutils literal"><span class="pre">CRUD</span></code> для <a class="reference external" href="http://sqlalchemy.org/">SQLAlchemy</a>. Для <a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">Pylons</a>
существовало расширение прямо в самом модуле в разделе ext. Для Pyramid создали
отдельный пакет <a class="reference external" href="https://pypi.python.org/pypi/pyramid_formalchemy">pyramid_formalchemy</a>. Посмотрим как это работает:</p>
<p>Создаем проект:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ pcreate -s alchemy -s pyramid_fa myapp
</pre></div>
</div>
<p>добавляем в проект файл <code class="docutils literal"><span class="pre">forms.py</span></code>:</p>
<div class="literal-block-wrapper docutils container" id="id2">
<div class="code-block-caption"><span class="caption-text">forms.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">formalchemy</span> <span class="kn">import</span> <span class="n">FieldSet</span><span class="p">,</span> <span class="n">Grid</span>
</pre></div>
</div>
</div>
<p>структура файлов должна выглядеть так:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="p">|</span> <span class="p">|</span>+static/
<span class="p">|</span> <span class="p">|</span>+templates/
<span class="p">|</span> <span class="p">|</span>-__init__.py
<span class="p">|</span> <span class="p">|</span>-faforms.py
<span class="p">|</span> <span class="p">|</span>-fainit.py
<span class="p">|</span> <span class="p">|</span>-faroutes.py
<span class="p">|</span> <span class="p">|</span>-forms.py
<span class="p">|</span> <span class="p">|</span>-models.py
<span class="p">|</span> <span class="p">|</span>-tests.py
<span class="p">|</span> <span class="sb">`</span>-views.py
</pre></div>
</div>
<p>изменяем <code class="docutils literal"><span class="pre">__init__.py</span></code>:</p>
<div class="literal-block-wrapper docutils container" id="id3">
<div class="code-block-caption"><span class="caption-text">__init__.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pyramid.config</span> <span class="kn">import</span> <span class="n">Configurator</span>
<span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">engine_from_config</span>
<span class="kn">from</span> <span class="nn">.models</span> <span class="kn">import</span> <span class="n">DBSession</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="n">global_config</span><span class="p">,</span> <span class="o">**</span><span class="n">settings</span><span class="p">):</span>
<span class="sd">""" This function returns a Pyramid WSGI application.</span>
<span class="sd"> """</span>
<span class="n">engine</span> <span class="o">=</span> <span class="n">engine_from_config</span><span class="p">(</span><span class="n">settings</span><span class="p">,</span> <span class="s1">'sqlalchemy.'</span><span class="p">)</span>
<span class="n">DBSession</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span><span class="n">bind</span><span class="o">=</span><span class="n">engine</span><span class="p">)</span>
<span class="n">config</span> <span class="o">=</span> <span class="n">Configurator</span><span class="p">(</span><span class="n">settings</span><span class="o">=</span><span class="n">settings</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_static_view</span><span class="p">(</span><span class="s1">'static'</span><span class="p">,</span> <span class="s1">'static'</span><span class="p">,</span> <span class="n">cache_max_age</span><span class="o">=</span><span class="mi">3600</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">add_route</span><span class="p">(</span><span class="s1">'home'</span><span class="p">,</span> <span class="s1">'/'</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">scan</span><span class="p">()</span>
<span class="c1"># pyramid_formalchemy's configuration</span>
<span class="n">config</span><span class="o">.</span><span class="n">include</span><span class="p">(</span><span class="s1">'pyramid_fanstatic'</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">include</span><span class="p">(</span><span class="s1">'pyramid_formalchemy'</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">include</span><span class="p">(</span><span class="s1">'fa.jquery'</span><span class="p">)</span>
<span class="c1"># register an admin UI</span>
<span class="n">config</span><span class="o">.</span><span class="n">formalchemy_admin</span><span class="p">(</span><span class="s1">'/admin'</span><span class="p">,</span> <span class="n">package</span><span class="o">=</span><span class="s1">'youAppName'</span><span class="p">,</span>
<span class="n">view</span><span class="o">=</span><span class="s1">'fa.jquery.pyramid.ModelView'</span><span class="p">)</span>
<span class="k">return</span> <span class="n">config</span><span class="o">.</span><span class="n">make_wsgi_app</span><span class="p">()</span>
</pre></div>
</div>
</div>
<p>Заходим в <a class="reference external" href="http://0.0.0.0:6543/admin/">http://0.0.0.0:6543/admin/</a> и радуемся.</p>
<img alt="_static/2012/pyramid_formalchemy.png" class="align-center" src="_static/2012/pyramid_formalchemy.png" />
<p>Online демо находится <a class="reference external" href="http://docs.formalchemy.org/demo/admin/">здесь</a>.</p>
</div>
Установка ProxMox VE с USB флешки
http://uralbash.ru/articles/2012/proxmox/
2012-06-05T15:45:00Z
2012-06-05T15:45:00Z
Uralbash
<div class="section" id="proxmox-ve-usb">
<p>Взято от сюда <a class="reference external" href="http://c-nergy.be/blog/?p=897">http://c-nergy.be/blog/?p=897</a></p>
<div class="section" id="id1">
<h2>Шаг 1: создание загрузочной флешки</h2>
<p>Скачайте iso образ с сайта и установите его например при помощи <code class="docutils literal"><span class="pre">UNetbootin</span></code>.
У вас должно получиться что то типа того на флешке:</p>
<img alt="_static/2012/proxmox1.png" src="_static/2012/proxmox1.png" />
<p>Дальше удалите все катологи с флешки кроме boot и перенесите на нее iso образ
<code class="docutils literal"><span class="pre">proxmox</span></code> (в корень).</p>
<img alt="_static/2012/proxmox2.png" src="_static/2012/proxmox2.png" />
</div>
<div class="section" id="id2">
<h2>Шаг 2: загрузка в отладочном режиме</h2>
<p>Загрузитесь в <code class="docutils literal"><span class="pre">debug</span> <span class="pre">mode</span></code>:</p>
<img alt="_static/2012/proxmox3.png" src="_static/2012/proxmox3.png" />
<p>Вы должны увидеть что наша флешка обнаружена и увидеть следующую надпись:</p>
<p><code class="docutils literal"><span class="pre">no</span> <span class="pre">cdrom</span> <span class="pre">found</span> <span class="pre">–</span> <span class="pre">unable</span> <span class="pre">to</span> <span class="pre">continue</span> <span class="pre">(type</span> <span class="pre">exit</span> <span class="pre">or</span> <span class="pre">Ctrl-D</span> <span class="pre">to</span> <span class="pre">reboot)</span></code></p>
</div>
<div class="section" id="id3">
<h2>Шаг 3: монтирование флешки</h2>
<p>Смотрим как называется наша флешка <code class="docutils literal"><span class="pre">fdisk</span> <span class="pre">-l</span></code>.</p>
<img alt="_static/2012/proxmox4.png" src="_static/2012/proxmox4.png" />
<p>У меня она называется <code class="docutils literal"><span class="pre">/dev/sdb1</span></code>. Монтируем <code class="docutils literal"><span class="pre">mount</span> <span class="pre">/dev/sdb1</span> <span class="pre">/mnt</span></code>.</p>
<p>Пишем <code class="docutils literal"><span class="pre">mount</span></code>:</p>
<img alt="_static/2012/proxmox5.png" src="_static/2012/proxmox5.png" />
</div>
<div class="section" id="iso">
<h2>Шаг 4: монтируем ISO файл и запускаем установщик</h2>
<div class="line-block">
<div class="line">Вводим команду <code class="docutils literal"><span class="pre">mount</span> <span class="pre">-o</span> <span class="pre">loop</span> <span class="pre">-t</span> <span class="pre">iso9660</span> <span class="pre">/mnt/proxmox_1-7.iso</span> <span class="pre">/mnt</span></code>.</div>
<div class="line">Проверяем что все подмонтировалось <code class="docutils literal"><span class="pre">mount</span></code>.</div>
</div>
<p>Заходим в <code class="docutils literal"><span class="pre">mnt</span></code> <code class="docutils literal"><span class="pre">cd</span> <span class="pre">/mnt</span></code> и запускаем установщик <code class="docutils literal"><span class="pre">chroot</span> <span class="pre">/mnt</span> <span class="pre">sbin/unconfigured.sh</span></code>.</p>
<p>Появится окошко:</p>
<img alt="_static/2012/proxmox6.png" src="_static/2012/proxmox6.png" />
<p>Удачи!</p>
</div>
</div>
Настройка прокси для apt-get
http://uralbash.ru/articles/2012/proxy_apt/
2012-05-23T15:45:00Z
2012-05-23T15:45:00Z
Uralbash
<div class="section" id="apt-get">
<p>В файле <code class="docutils literal"><span class="pre">/etc/apt/apt.conf.d/proxy</span></code> (его небыло) добавить строки:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>Acquire::http::Proxy <span class="s2">"http://мой логин@ип моего прокси:порт"</span><span class="p">;</span>
Acquire::ftp::Proxy <span class="s2">"http://мой логин@ип моего прокси:порт"</span><span class="p">;</span>
Acquire::::Proxy <span class="s2">"true"</span><span class="p">;</span>
</pre></div>
</div>
</div>
Боян :)
http://uralbash.ru/articles/2012/boyan/
2012-05-22T01:40:00Z
2012-05-22T01:40:00Z
Uralbash
<div class="section" id="id1">
<iframe width="420" height="315"
src="https://www.youtube.com/embed/0TTXVMMWlbU" frameborder="0"
allowfullscreen></iframe><p>UPD: Создатель электромеханического бояна <code class="docutils literal"><span class="pre">Владимир</span> <span class="pre">Демин</span></code> - человек с
высоким ощущением прекрасного: <a class="reference external" href="http://hackaday.com/2012/05/25/interview-vladimir-denin-the-creator-of-the-player-guitar/?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+hackaday%2FLgoM+(Hack+a+Day)#">подробнее на Hack Day</a></p>
</div>
Обновление rrd задней датой при помощи faketime
http://uralbash.ru/articles/2012/rrd_faketime/
2012-05-10T11:40:00Z
2012-05-10T11:40:00Z
Uralbash
<div class="section" id="rrd-faketime">
<p>Иногда скрипты, выполнение которых зависит от времени, не срабатывают. Менять
время и запускать их повторно или менять код приложения неправильно. Что бы
выполнить их задним числом есть утилита <code class="docutils literal"><span class="pre">faketime</span></code>.</p>
<p>Установка:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo apt-get install faketime
</pre></div>
</div>
<p>Пример использования:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ faketime <span class="s1">'last Friday 5 pm'</span> /bin/date
$ faketime <span class="s1">'2008-12-24 08:15:42'</span> /bin/date
</pre></div>
</div>
<p>Также работает с <code class="docutils literal"><span class="pre">wine</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ faketime <span class="s1">'2006-09-20'</span> wine myprogramm.exe
</pre></div>
</div>
<p>У меня есть скрипт на питоне который добавляет записи в rrd каждый день.
Пересчитаем rrd за последние 3 дня.</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ faketime <span class="s1">'2012-05-05 5 am'</span> python updatemyrrd.py
$ faketime <span class="s1">'2012-05-04 5 am'</span> python updatemyrrd.py
$ faketime <span class="s1">'2012-05-03 5 am'</span> python updatemyrrd.py
</pre></div>
</div>
</div>
Установка pycrypto в virtualenv
http://uralbash.ru/articles/2012/pycrypto_virtualenv/
2012-04-26T00:24:00Z
2012-04-26T00:24:00Z
Uralbash
<div class="section" id="pycrypto-virtualenv">
<p>Если появляется ошибка типа <code class="docutils literal"><span class="pre">"RuntimeError:</span> <span class="pre">autoconf</span> <span class="pre">error"</span></code>, то необходимо
установить <code class="docutils literal"><span class="pre">C</span></code> компилятор:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ apt-get install gcc
</pre></div>
</div>
<p>или <code class="docutils literal"><span class="pre">"src/MD2.c:31:20:</span> <span class="pre">fatal</span> <span class="pre">error:</span> <span class="pre">Python.h:</span> <span class="pre">Нет</span> <span class="pre">такого</span> <span class="pre">файла</span> <span class="pre">или</span> <span class="pre">каталога"</span></code></p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ apt-get install python-dev
</pre></div>
</div>
<p>Далее стандартно:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ <span class="nb">source</span> mydevenv/bin/activate
$ pip install pycrypto
</pre></div>
</div>
</div>
Что юзать в Python'е для SNMP...
http://uralbash.ru/articles/2012/python_snmp/
2012-04-17T15:15:00Z
2012-04-17T15:15:00Z
Uralbash
<div class="section" id="python-snmp">
<p>Для <a class="reference external" href="https://en.wikipedia.org/wiki/Simple_Network_Management_Protocol">SNMP</a>
в питоне есть несколько библиотек но у всех свои недостатки.</p>
<p><a class="reference external" href="https://pypi.python.org/pypi/yapsnmp">yapsnmp</a> - быстрая, простая библиотека, но не обновлялась с 2004 года и
имеет некоторые глюки. Для установки во всякие там Линуксы требуется бубен. Не
работают многие флаги, например PRINT_NUMERIC_OIDS
(<a class="reference external" href="http://sourceforge.net/tracker/?func=detail&aid=1119247&group_id=21077&atid=121077">http://sourceforge.net/tracker/?func=detail&aid=1119247&group_id=21077&atid=121077</a>).</p>
<p><a class="reference external" href="https://pypi.python.org/pypi/PySNMP">PySNMP</a> - хорошая документация, но работает ОООооочень медленно, причем
даже в тредах. Для большого объема данных не подходит.</p>
<p><a class="reference external" href="http://net-snmp.sourceforge.net/wiki/index.php/Python_Bindings">Net-SNMP</a> -
обертка на питоне для netsnmp. Работает, синтаксис сложный.</p>
<p>Для просмотра таблицы коммутации используется команда типа:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>snmpwalk -v 2c -c mycomm <span class="m">192</span>.168.1.100 <span class="m">1</span>.3.6.1.2.1.17.7.1.2.2.1.2 -O n
</pre></div>
</div>
<p>Флаг <code class="docutils literal"><span class="pre">-0</span> <span class="pre">n</span></code> означает вывод в цифровом виде (вместо бинарного).</p>
<p>Если Вы хотите запрограммировать эту команду на питоне, то <code class="docutils literal"><span class="pre">yapsnmp</span></code> не
подходит из-за флагов, <code class="docutils literal"><span class="pre">pysnmp</span></code> неподойдет если вам нужно например пройти
пару сотен/тысяч свичей. <code class="docutils literal"><span class="pre">Net-SNMP</span></code> слишком много букв писать в коде для
такой простой команды.</p>
<p>Поэтому как решение можно делать так:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">ip</span> <span class="ow">in</span> <span class="n">hosts</span><span class="p">:</span>
<span class="n">fdb</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">popen</span><span class="p">(</span><span class="s2">"snmpwalk -v 2c -c mycomm </span><span class="si">%s</span><span class="s2"> 1.3.6.1.2.1.17.7.1.2.2.1.2 -O n"</span> <span class="o">%</span> <span class="n">ip</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">tmp</span> <span class="o">=</span> <span class="nb">map</span><span class="p">(</span><span class="nb">int</span><span class="p">,</span> <span class="n">e</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">"= INTEGER:"</span><span class="p">,</span> <span class="s2">"."</span><span class="p">)</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">"."</span><span class="p">)[</span><span class="mi">1</span><span class="p">:])</span>
<span class="k">except</span> <span class="ne">Exception</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span>
<span class="k">print</span> <span class="n">e</span>
<span class="k">continue</span>
<span class="n">mac</span> <span class="o">=</span> <span class="s2">"</span><span class="si">%02x</span><span class="s2">:</span><span class="si">%02x</span><span class="s2">:</span><span class="si">%02x</span><span class="s2">:</span><span class="si">%02x</span><span class="s2">:</span><span class="si">%02x</span><span class="s2">:</span><span class="si">%02x</span><span class="s2">"</span> <span class="o">%</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">tmp</span><span class="p">[</span><span class="o">-</span><span class="mi">7</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
<span class="n">port</span> <span class="o">=</span> <span class="n">tmp</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="n">vlan</span> <span class="o">=</span> <span class="n">tmp</span><span class="p">[</span><span class="o">-</span><span class="mi">8</span><span class="p">]</span>
</pre></div>
</div>
<p>Вообщем я негодуэ!</p>
</div>
Хостим документацию Sphinx на github
http://uralbash.ru/articles/2012/sphinx_github/
2012-04-12T18:55:00Z
2012-04-12T18:55:00Z
Uralbash
<div class="section" id="sphinx-github">
<p>Немного допиленная версия этого
<a class="reference external" href="http://djangonaut.blogspot.com/2009/05/sphinx-documentation-github-pages-3.html">http://djangonaut.blogspot.com/2009/05/sphinx-documentation-github-pages-3.html</a></p>
<p>По порядку:</p>
<ul class="simple">
<li>создать репозитарий на <a class="reference external" href="https://github.com/">github</a></li>
<li>добавить туда свой локальный репозитарий с проектом <code class="docutils literal"><span class="pre">Sphinx</span></code></li>
<li>захостить репозитарий через сервис <a class="reference external" href="https://pages.github.com/">Pages</a></li>
<li>поправить <code class="docutils literal"><span class="pre">Makefile</span></code> в <code class="docutils literal"><span class="pre">Sphinx</span></code> проекте</li>
</ul>
<div class="highlight-make"><div class="highlight"><pre><span></span><span class="nv">docs_dir</span> <span class="o">=</span> doc
<span class="nf">ghdocs</span><span class="o">:</span>
rm -rf <span class="k">$(</span>docs_dir<span class="k">)</span>
<span class="k">$(</span>MAKE<span class="k">)</span> clean
<span class="k">$(</span>MAKE<span class="k">)</span> html
cp -r build/html <span class="k">$(</span>docs_dir<span class="k">)</span>
mv <span class="k">$(</span>docs_dir<span class="k">)</span>/_static <span class="k">$(</span>docs_dir<span class="k">)</span>/static
mv <span class="k">$(</span>docs_dir<span class="k">)</span>/_sources <span class="k">$(</span>docs_dir<span class="k">)</span>/sources
perl -pi -e <span class="s2">"s/_sources/sources/g;"</span> <span class="k">$(</span>docs_dir<span class="k">)</span>/*.html
perl -pi -e <span class="s2">"s/_static/static/g;"</span> <span class="k">$(</span>docs_dir<span class="k">)</span>/*.html
git add .
git commit -a -m <span class="s2">"Updates </span><span class="k">$(</span>project<span class="k">)</span><span class="s2">."</span>
git checkout gh-pages
cp -rf <span class="k">$(</span>docs_dir<span class="k">)</span>/* .
git add .
git commit -a -m <span class="s1">'Updates $(project) documentation.'</span>
git checkout master
rm -rf <span class="k">$(</span>docs_dir<span class="k">)</span>
git push origin gh-pages
</pre></div>
</div>
<p>Теперь при запуске <code class="docutils literal"><span class="pre">make</span> <span class="pre">ghdocs</span></code> будет автоматом генерироваться новая
документация и пушаться на <a class="reference external" href="https://github.com/">github</a>.</p>
<p>Пример здесь <a class="reference external" href="http://uralbash.github.com/python-web-lectures/">http://uralbash.github.com/python-web-lectures/</a></p>
<p>Для автоматической замены директорий <code class="docutils literal"><span class="pre">_static</span></code> и <code class="docutils literal"><span class="pre">_sources</span></code>, можно
установить модуль <a class="reference external" href="https://pypi.python.org/pypi/sphinxtogithub">sphinxtogithub</a>.</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ pip install sphinxtogithub
</pre></div>
</div>
<p>И добавить в проекте в <code class="docutils literal"><span class="pre">config.py</span></code>:</p>
<div class="literal-block-wrapper docutils container" id="id1">
<div class="code-block-caption"><span class="caption-text">config.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">extensions</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"sphinxtogithub"</span><span class="p">,</span> <span class="p">]</span>
</pre></div>
</div>
</div>
<p>В этом случае нужно закомментировать в скрипте строчки:</p>
<p><code class="docutils literal"><span class="pre">mv</span> <span class="pre">$(docs_dir)/_static</span> <span class="pre">$(docs_dir)/static</span></code></p>
<p>и</p>
<p><code class="docutils literal"><span class="pre">mv</span> <span class="pre">$(docs_dir)/_sources</span> <span class="pre">$(docs_dir)/sources</span></code></p>
<p>Это необходимо делать потому-что <a class="reference external" href="https://github.com/">github</a> не понимает директории начинающиеся
с подчеркивания.</p>
</div>
RRDTool пример использования в python
http://uralbash.ru/articles/2012/rrdtool/
2012-04-11T12:42:00Z
2012-04-11T12:42:00Z
Uralbash
<div class="section" id="rrdtool-python">
<p><a class="reference external" href="http://oss.oetiker.ch/rrdtool/">RRDtool</a> (<cite>Round Robin Database</cite>). Обеспечивает хранение и отображение данных
мониторинга (загрузка каналов, температура и любая другая зависящая от времени
последовательность данных, которую можно получить некоторым способом).
Задумывалась как повторная, но более правильная реализация MRTG. Объём хранимых
данных не увеличивается со временем (ячейки хранения используются циклически).
Использование различных функций консолидации данных позволяет охватывать
большие интервалы времени без чрезмерного увеличения объема БД за счет снижения
разрешающей способности. В отличие от mrtg, программа не упаковывает старые
данные самостоятельно, это надо предусматривать при проектировании БД. Сбор
информации и генерация HTML-кода также производится с помощью внешних средств.
Более мощные средства генерации графиков. Все времена во внутреннем формате
Unix (число секунд с 1 января 1970 в UTC). Значения счетчиков могут быть целыми
или вещественными числами или специальным значением UNKNOWN. Лицензия - GPL (но
автор не будет против, если в благодарность послать ему CD/DVD из указанного им
списка; при установке rrdtool имитируется заказ CD на amazone.com ;-).
Необходимо иметь perl 5 (без perl rrdtool соберется, но не будет модулей
подержки perl) и обычный набор средств компиляции (make, gcc, autoconf,
automake, libtool). Имеется также поддержка tcl и python. Нельзя использовать
для учета и биллинга - слишком много он усредняет и сглаживает, используя
достаточно сложные алгоритмы.</p>
<p>Очень хорошее описание <a class="reference external" href="http://www.bog.pp.ru/work/rrdtool.html#at">http://www.bog.pp.ru/work/rrdtool.html#at</a></p>
<div class="section" id="id1">
<h2>Создаем файл</h2>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">rrd_file</span> <span class="o">=</span> <span class="s2">"/usr/local/www/nagios/2week.rrd"</span>
<span class="k">def</span> <span class="nf">rrd_create</span><span class="p">(</span><span class="n">rrd_file</span><span class="p">):</span>
<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">rrd_file</span><span class="p">):</span>
<span class="n">rrdtool</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">rrd_file</span><span class="p">,</span>
<span class="s2">"--step"</span><span class="p">,</span> <span class="s2">"86400"</span><span class="p">,</span>
<span class="s2">"DS:available:GAUGE:172800:0.0:100.0"</span><span class="p">,</span>
<span class="s2">"RRA:AVERAGE:0.5:1:366"</span><span class="p">,</span>
<span class="p">)</span>
</pre></div>
</div>
<div class="line-block">
<div class="line"><code class="docutils literal"><span class="pre">step</span></code> - интервал через который будут обновляться значения. У нас 86400 сек - это 1 день т.е. ежедневно.</div>
<div class="line"><code class="docutils literal"><span class="pre">DS:available:GAUGE:172800:0:100</span></code> - источник данных</div>
<div class="line"><code class="docutils literal"><span class="pre">available</span></code> - название источника</div>
<div class="line"><code class="docutils literal"><span class="pre">GAUGE</span></code> - тип (в данном случае поддерживает числа с плавающей точкой)</div>
<div class="line"><code class="docutils literal"><span class="pre">172800</span></code> - значение которое должно быть 2*step :)</div>
<div class="line"><code class="docutils literal"><span class="pre">0:100</span></code> - интервал допустимых значений</div>
<div class="line"><br /></div>
<div class="line"><code class="docutils literal"><span class="pre">RRA:AVERAGE:0.5:1:366</span></code> - архив значений</div>
<div class="line"><code class="docutils literal"><span class="pre">AVERAGE</span></code> - тип (в данном случае среднее значение)</div>
<div class="line"><code class="docutils literal"><span class="pre">1:366</span></code> - означает что в архиве 366 записей с интервалом 1*step</div>
</div>
</div>
<div class="section" id="id2">
<h2>Вносим данные</h2>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">rrd_update</span><span class="p">(</span><span class="n">rrd_file</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
<span class="n">rrdtool</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">rrd_file</span><span class="p">,</span> <span class="s2">"N:</span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="nb">str</span><span class="p">(</span><span class="n">value</span><span class="p">))</span>
</pre></div>
</div>
<div class="line-block">
<div class="line"><code class="docutils literal"><span class="pre">N</span></code> - означает на текущее время (<code class="docutils literal"><span class="pre">Now</span></code>)</div>
<div class="line">через двоеточие указываются значения <code class="docutils literal"><span class="pre">DS</span></code> (В случае нескольких <code class="docutils literal"><span class="pre">DS</span></code> могло быть так <code class="docutils literal"><span class="pre">N:%s:%s:%s</span></code>)</div>
</div>
</div>
<div class="section" id="png">
<h2>Создаем график в png</h2>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">tempfile</span>
<span class="n">fd</span><span class="p">,</span><span class="n">path</span> <span class="o">=</span> <span class="n">tempfile</span><span class="o">.</span><span class="n">mkstemp</span><span class="p">(</span><span class="s1">'.png'</span><span class="p">)</span>
<span class="n">rrdtool</span><span class="o">.</span><span class="n">graph</span><span class="p">(</span><span class="s2">"/tmp/net.png"</span><span class="p">,</span>
<span class="s2">"--imgformat"</span><span class="p">,</span> <span class="s2">"PNG"</span><span class="p">,</span>
<span class="s2">"--height"</span><span class="p">,</span> <span class="s2">"250"</span><span class="p">,</span>
<span class="s2">"--width"</span><span class="p">,</span> <span class="s2">"550"</span><span class="p">,</span>
<span class="s2">"--end"</span><span class="p">,</span> <span class="s2">"now"</span><span class="p">,</span>
<span class="s2">"--start"</span><span class="p">,</span> <span class="s2">"end-2w-1h"</span><span class="p">,</span>
<span class="s2">"--lower-limit"</span><span class="p">,</span> <span class="s2">"99.3"</span><span class="p">,</span>
<span class="s2">"--upper-limit"</span><span class="p">,</span> <span class="s2">"100.0"</span><span class="p">,</span>
<span class="s2">"--zoom"</span><span class="p">,</span> <span class="s2">"1.5"</span><span class="p">,</span>
<span class="s2">"--y-grid"</span><span class="p">,</span> <span class="s2">"0.05:1"</span><span class="p">,</span>
<span class="s2">"--x-grid=DAY:1:DAY:1:DAY:2:0:%a"</span><span class="p">,</span>
<span class="s2">"--right-axis"</span><span class="p">,</span> <span class="s2">"1:0"</span><span class="p">,</span>
<span class="s2">"--right-axis-format"</span><span class="p">,</span> <span class="s2">"</span><span class="si">%0.2lf%%</span><span class="s2">"</span><span class="p">,</span>
<span class="s2">"--slope-mode"</span><span class="p">,</span>
<span class="s2">"--vertical-label=Up times/day"</span><span class="p">,</span>
<span class="s2">"DEF:avl=</span><span class="si">%s</span><span class="s2">:available:AVERAGE"</span> <span class="o">%</span> <span class="n">rrd_file</span><span class="p">,</span>
<span class="s2">"AREA:avl#00FF00:Up times(%)"</span><span class="p">,</span>
<span class="s1">'GPRINT:avl:AVERAGE:avg\: </span><span class="si">%2.2lf%%</span><span class="s1">'</span><span class="p">)</span>
</pre></div>
</div>
<p>Описание всех параметров есть в ссылке приведенной выше.</p>
</div>
<div class="section" id="backup-restore">
<h2>Backup и Restore</h2>
<p>Фаил <a class="reference external" href="http://oss.oetiker.ch/rrdtool/">rrd</a> платформо зависим и может не заработать на другом железе или
ОС (например из 32бит в 64бит), поэтому принято хранить бэкапы в xml.</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ rrdtool dump файл.rrd > бэкап.xml
</pre></div>
</div>
<p>XML можно править вручную и залить обратно в <a class="reference external" href="http://oss.oetiker.ch/rrdtool/">rrd</a>.</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ rrdtool restore бэкап.xml > файл.rrd
</pre></div>
</div>
<p>Результат:</p>
<div class="figure align-center" id="id3">
<img alt="_static/2012/rrdtool.png" src="_static/2012/rrdtool.png" />
<p class="caption"><span class="caption-text">rrdtool пример графика</span></p>
</div>
<p>Для обучения лучше выбрать меньший интервал чем 1 день, например 2 мин (step = 120).</p>
</div>
</div>
SQLAlchemy и большие таблицы (Memory error)
http://uralbash.ru/articles/2012/sa_big_table/
2012-04-11T11:56:00Z
2012-04-11T11:56:00Z
Uralbash
<div class="section" id="sqlalchemy-memory-error">
<p><a class="reference external" href="http://sqlalchemy.org/">SQLAlchemy</a> в больших таблицах при таком запросе <code class="docutils literal"><span class="pre">s.query(TableName).all()</span></code>
зависает и выдает ошибку <code class="docutils literal"><span class="pre">Memory</span> <span class="pre">error</span></code>. Для решения проблемы нужно
использовать метод <code class="xref py py-meth docutils literal"><span class="pre">yield_per()</span></code>. Если
необходимо еще изменять данные, то нужно делать коммиты каждые N записей.</p>
<p>Пример:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">fdbarp</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">''' Функция переноса арпов из одной таблицы в другую.</span>
<span class="sd"> Около 3млн записей.</span>
<span class="sd"> '''</span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">arp</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">s</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">Arp</span><span class="p">)</span><span class="o">.</span><span class="n">yield_per</span><span class="p">(</span><span class="mi">100</span><span class="p">)):</span>
<span class="n">new_arp</span> <span class="o">=</span> <span class="n">newArp</span><span class="p">()</span>
<span class="n">new_arp</span><span class="o">.</span><span class="n">equipment_id</span> <span class="o">=</span> <span class="n">arp</span><span class="o">.</span><span class="n">equipment</span>
<span class="n">new_arp</span><span class="o">.</span><span class="n">mac</span> <span class="o">=</span> <span class="n">arp</span><span class="o">.</span><span class="n">mac</span>
<span class="n">new_arp</span><span class="o">.</span><span class="n">ip</span> <span class="o">=</span> <span class="n">arp</span><span class="o">.</span><span class="n">ip</span>
<span class="n">new_arp</span><span class="o">.</span><span class="n">first_seen</span> <span class="o">=</span> <span class="n">arp</span><span class="o">.</span><span class="n">first_seen</span>
<span class="n">new_arp</span><span class="o">.</span><span class="n">last_seen</span> <span class="o">=</span> <span class="n">arp</span><span class="o">.</span><span class="n">last_seen</span>
<span class="n">new_arp</span><span class="o">.</span><span class="n">times</span> <span class="o">=</span> <span class="n">arp</span><span class="o">.</span><span class="n">times</span>
<span class="n">s</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">new_arp</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">i</span><span class="o">%</span><span class="mi">10000</span><span class="p">:</span>
<span class="n">s</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
<span class="n">s</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">print</span> <span class="s2">"arp "</span><span class="p">,</span> <span class="n">i</span>
<span class="n">s</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
</pre></div>
</div>
</div>
Qtile жив
http://uralbash.ru/articles/2012/qtile/
2012-04-02T13:39:00Z
2012-04-02T13:39:00Z
Uralbash
<div class="section" id="qtile">
<p><a class="reference external" href="http://qtile.org">Qtile</a> - это тайловый оконный менеджер написанный на <a class="reference external" href="http://www.python.org/">Python</a>. Последний
месяц активно коммитится на github’е. Свежая инфа здесь
<a class="reference external" href="http://qtile.readthedocs.org/en/latest/">http://qtile.readthedocs.org/en/latest/</a> (<a class="reference external" href="http://Qtile.org">http://Qtile.org</a> обновляется редко.)</p>
</div>
Троллинг от Пингвинов :)))
http://uralbash.ru/articles/2012/penguin_troll/
2012-03-28T13:30:00Z
2012-03-28T13:30:00Z
Uralbash
<div class="section" id="id1">
<iframe width="560" height="315"
src="https://www.youtube.com/embed/pYP-VZ6JSRU" frameborder="0"
allowfullscreen></iframe></div>
Pylons обработка csv с веб формы (метод POST)
http://uralbash.ru/articles/2012/pylons_csv/
2012-03-27T23:38:00Z
2012-03-27T23:38:00Z
Uralbash
<div class="section" id="pylons-csv-post">
<p>Небольшой “хинт” как при помощи <a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">Pylons</a> обрабатывать CSV файлы,
отправленные из формы.</p>
<p>Создаем шаблон:</p>
<div class="highlight-html+jinja"><div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">form</span> <span class="na">action</span><span class="o">=</span><span class="s">""</span> <span class="na">method</span><span class="o">=</span><span class="s">"POST"</span> <span class="na">enctype</span><span class="o">=</span><span class="s">"multipart/form-data"</span><span class="p">></span>
CSV file: <span class="p"><</span><span class="nt">input</span> <span class="na">name</span><span class="o">=</span><span class="s">"csvfile"</span> <span class="na">type</span><span class="o">=</span><span class="s">"file"</span><span class="p">></span>
<span class="p"><</span><span class="nt">button</span><span class="p">></span>OK<span class="p"></</span><span class="nt">button</span><span class="p">></span>
<span class="p"></</span><span class="nt">form</span><span class="p">></span>
<span class="p"><</span><span class="nt">table</span> <span class="na">class</span><span class="o">=</span><span class="s">"simpletable"</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">data</span> <span class="k">in</span> <span class="nv">c.data</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">tr</span><span class="p">></span>
<span class="p"><</span><span class="nt">td</span><span class="p">></span><span class="cp">{{</span> <span class="nv">data</span><span class="o">[</span><span class="m">0</span><span class="o">]</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">td</span><span class="p">></span>
<span class="p"><</span><span class="nt">td</span><span class="p">></span><span class="cp">{{</span> <span class="nv">data</span><span class="o">[</span><span class="m">1</span><span class="o">]</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">td</span><span class="p">></span>
<span class="p"></</span><span class="nt">tr</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
<span class="p"></</span><span class="nt">table</span><span class="p">></span>
</pre></div>
</div>
<p>Метод контроллера выглядит как то так:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1"># coding=utf8</span>
<span class="kn">import</span> <span class="nn">pylons</span>
<span class="kn">import</span> <span class="nn">csv</span>
<span class="kn">from</span> <span class="nn">cStringIO</span> <span class="kn">import</span> <span class="n">StringIO</span>
<span class="kn">from</span> <span class="nn">pylons</span> <span class="kn">import</span> <span class="n">request</span><span class="p">,</span> <span class="n">response</span><span class="p">,</span> <span class="n">session</span><span class="p">,</span> <span class="n">tmpl_context</span> <span class="k">as</span> <span class="n">c</span><span class="p">,</span> <span class="n">url</span>
<span class="kn">from</span> <span class="nn">myproject.lib.base</span> <span class="kn">import</span> <span class="n">BaseController</span><span class="p">,</span> <span class="n">render</span>
<span class="k">class</span> <span class="nc">CsvController</span><span class="p">(</span><span class="n">BaseController</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">index</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'csvfile'</span><span class="p">,</span> <span class="s1">''</span><span class="p">)</span>
<span class="k">if</span> <span class="n">data</span><span class="p">:</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">value</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="s2">"/example/csv/index.html"</span><span class="p">)</span>
<span class="n">f</span> <span class="o">=</span> <span class="n">StringIO</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="n">c</span><span class="o">.</span><span class="n">data</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">csv</span><span class="o">.</span><span class="n">reader</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
<span class="n">c</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">row</span><span class="p">[</span><span class="mi">5</span><span class="p">]))</span>
<span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="s2">"/example/csv/index.html"</span><span class="p">)</span>
</pre></div>
</div>
</div>
Установка Matplotlib и Numpy в virtualenv на Debian
http://uralbash.ru/articles/2012/matplotlib_numpy_and_virtualenv/
2012-03-12T16:59:00Z
2012-03-12T16:59:00Z
Uralbash
<div class="section" id="matplotlib-numpy-virtualenv-debian">
<p>Взято от <a class="reference external" href="http://coreygoldberg.blogspot.com/2012/01/python-matplotlib-and-numpy-on.html">сюда</a>.
Если вы хотите в <a class="reference external" href="https://pypi.python.org/pypi/virtualenv">virtualenv</a>, через <code class="docutils literal"><span class="pre">pip</span> <span class="pre">install</span></code> установить
<a class="reference external" href="https://pypi.python.org/pypi/Numpy">Numpy</a> и <a class="reference external" href="https://pypi.python.org/pypi/Matplotlib">Matplotlib</a>, то необходимо вначале поставить в систему:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo apt-get install build-essential python-dev libfreetype6-dev libpng-dev python-virtualenv
</pre></div>
</div>
<p>Дальше устанавливаем пакеты в окружении:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ virtualenv env
$ <span class="nb">cd</span> env
$ <span class="nb">source</span> bin/activate
<span class="o">(</span>env<span class="o">)</span>$ pip install numpy matplotlib
...
...
Successfully installed numpy matplotlib
Cleaning up...
</pre></div>
</div>
</div>
Pylons система плагинов для своего проекта (yapsy)
http://uralbash.ru/articles/2012/pylons_yapsy/
2012-02-27T14:30:00Z
2012-02-27T14:30:00Z
Uralbash
<div class="section" id="pylons-yapsy">
<p>При проектировании любого проекта, через определенное время, встает проблема
маштабируемости, конечно если вы не пишите сайт-визитку или что то подобное.
Проект может состоять из одного большого монолитного ядра с множеством
контроллеров, сотнями или даже тысячами таблиц и бессчетным количеством разных
шаблонов, библиотек итд итп. Под ядром подразумевается та часть проекта
(<a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">pylons</a>), которую либо нельзя изменить совсем, либо это потребует очень
больших усилий. Для того что бы создать гибкий и легко масштабируемый веб (и не
только) проект, необходимо иметь небольшое ядро, которое будет выполнять
минимальный функционал соответствующий логически завершенной программе.
Остальные функции, пусть даже улучшающие программу, нужно выносить за пределы
ядра. Вообще я знаю только два способа решения этой проблемы:</p>
<ul class="simple">
<li>это создание API;</li>
<li>создание подключаемых модулей(плагинов).</li>
</ul>
<p>В этой статье рассмотрим систему плагинов. Для работы понадобится очень
неплохая библиотека <a class="reference external" href="https://pypi.python.org/pypi/yapsy">yapsy</a> и любой проект на <a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">pylons</a> (по аналогии
можно реализовать это например в <a class="reference external" href="https://www.djangoproject.com/">Django</a> или <a class="reference external" href="https://pypi.python.org/pypi/web.py">web.py</a> или ... bla bla bla).</p>
<p>Добавим в проект папку откуда будут браться плагины:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>.
├── config
├── controllers
├── forms
├── lib
├── model
├── plugins
├── public
├── tasks
├── templates
└── tests
</pre></div>
</div>
<p>Добавим пару плагинов в папку <code class="docutils literal"><span class="pre">plugins</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>.
├── autoloads
│ ├── inline
│ │ └── osmMap
│ │ ├── osm_map.py
│ │ └── osm_map.yapsy-plugin
│ └── menu
│ └── about
│ ├── about.py
│ └── about.yapsy-plugin
├── categories
│ ├── __init__.py
│ ├── inline.py
│ └── menu.py
└── __init__.py
</pre></div>
</div>
<p>Из директорий видно что мы создали два типа плагинов <code class="docutils literal"><span class="pre">inline</span></code> и <code class="docutils literal"><span class="pre">menu</span></code>.
<code class="docutils literal"><span class="pre">Inline</span></code> это плагины встраиваемые на страницу, <code class="docutils literal"><span class="pre">menu</span></code> это дополнительные
пункты в меню. Папки и категории можно формировать как угодно и в любой
вложенности. Сами плагины должны иметь ОБЯЗАТЕЛЬНО файл с таким же именем и
расширением <code class="docutils literal"><span class="pre">yapsy-plugin</span></code>. В нашем случае <code class="docutils literal"><span class="pre">osm-map</span></code> выводит
<a class="reference external" href="http://www.openstreetmap.org">OpenStreetMap</a> карту, а <code class="docutils literal"><span class="pre">about</span></code> добавляет в меню новый пункт. Дальше я
бегло опишу то что у меня получилось, а посмотреть код можно здесь
<a class="reference external" href="https://github.com/uralbash/pylons_yapsy_plugin">https://github.com/uralbash/pylons_yapsy_plugin</a>. Думаю не имеет смысла
описывать все подробно, т.к. в коде много комментариев.</p>
<p>После старта проекта Вы увидите окно с картой и меню <code class="docutils literal"><span class="pre">"about"</span></code>. Наши плагины
автоматически подгрузились.</p>
<div class="figure align-center" id="id1">
<img alt="_static/2012/osm_yapsy.png" src="_static/2012/osm_yapsy.png" />
<p class="caption"><span class="caption-text">yapsy plugin example</span></p>
</div>
<p>Теперь перейдем на вкладку <code class="docutils literal"><span class="pre">"plugin"</span></code> и отключим <a class="reference external" href="http://www.openstreetmap.org">OpenStreetMap</a>:</p>
<div class="figure align-center" id="id2">
<img alt="_static/2012/osm_yapsy2.png" src="_static/2012/osm_yapsy2.png" />
<p class="caption"><span class="caption-text">yapsy plugin deactivate</span></p>
</div>
<p>Заходим во вкладку <code class="docutils literal"><span class="pre">"home"</span></code>:</p>
<div class="figure align-center" id="id3">
<img alt="_static/2012/osm_yapsy3.png" src="_static/2012/osm_yapsy3.png" />
<p class="caption"><span class="caption-text">yapsy plugin deactivated</span></p>
</div>
<p>И “О черт Дэвид Блэйн! Верни ее на место!!!”.</p>
<p>То же самое с меню при отключении оно пропадет. Отключенные плагины хранятся в
БД в таблице <code class="docutils literal"><span class="pre">DeactivatedPlugins</span></code>.</p>
<p>P.S.: Для чего это нужно еще раз? Для того например если руководство решило
убрать из программы карту <a class="reference external" href="http://www.openstreetmap.org">OpenStreetMap</a> немедленно. Вы тут же бросились
это все выпиливать... да? А через неделю руководство вдруг решило что нужна
карта! Вы начинаете ее запиливать обратно итд итп. Мне например проще нажать
одну кнопку, чем переписывать MVC. В этом и есть гибкость. Пользуйтесь.</p>
</div>
AJAX тройной выпадающий список (triple select)
http://uralbash.ru/articles/2012/ajax_triple_select/
2012-02-22T13:58:00Z
2012-02-22T13:58:00Z
Uralbash
<div class="section" id="ajax-triple-select">
<p>Опишу очень простую реализацию трех выпадающих списков, данные которых связанны
последовательно. Выглядит это примерно так <code class="docutils literal"><span class="pre">"Город"</span> <span class="pre">-></span> <span class="pre">"Улица"</span> <span class="pre">-></span> <span class="pre">"Дом"</span></code>.
После выбора дома, на основе <code class="docutils literal"><span class="pre">AJAX</span></code> запроса, генерируется список улиц этого
города, а после выбора улицы генерируется список домов на этой улице. Создадим
html файл:</p>
<div class="literal-block-wrapper docutils container" id="id1">
<div class="code-block-caption"><span class="caption-text">index.html</span></div>
<div class="highlight-html"><div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">table</span><span class="p">></span>
<span class="p"><</span><span class="nt">tbody</span><span class="p">></span>
<span class="p"><</span><span class="nt">tr</span><span class="p">></span>
<span class="p"><</span><span class="nt">td</span><span class="p">></span>City:<span class="p"></</span><span class="nt">td</span><span class="p">></span>
<span class="p"><</span><span class="nt">td</span><span class="p">></span>
<span class="p"><</span><span class="nt">select</span> <span class="na">id</span><span class="o">=</span><span class="s">"city"</span> <span class="na">name</span><span class="o">=</span><span class="s">"city"</span> <span class="na">onchange</span><span class="o">=</span><span class="s">"getStreet(this);"</span><span class="p">></span>
<span class="p"><</span><span class="nt">option</span> <span class="na">selected</span><span class="o">=</span><span class="s">"selected"</span> <span class="na">value</span><span class="o">=</span><span class="s">"None"</span><span class="p">></span>-----------<span class="p"></</span><span class="nt">option</span><span class="p">></span>
<span class="p"><</span><span class="nt">option</span> <span class="na">value</span><span class="o">=</span><span class="s">"Екатеринбург"</span><span class="p">></span>Екатеринбург<span class="p"></</span><span class="nt">option</span><span class="p">></span>
<span class="p"><</span><span class="nt">option</span> <span class="na">value</span><span class="o">=</span><span class="s">"Березовский"</span><span class="p">></span>Березовскийг<span class="p"></</span><span class="nt">option</span><span class="p">></span>
<span class="p"><</span><span class="nt">option</span> <span class="na">value</span><span class="o">=</span><span class="s">"Артемоский"</span><span class="p">></span>Артемовский<span class="p"></</span><span class="nt">option</span><span class="p">></span>
<span class="p"></</span><span class="nt">select</span><span class="p">></span>
<span class="p"></</span><span class="nt">td</span><span class="p">></span>
<span class="p"></</span><span class="nt">tr</span><span class="p">></span>
<span class="p"><</span><span class="nt">tr</span><span class="p">><</span><span class="nt">td</span><span class="p">></span>Street:<span class="p"></</span><span class="nt">td</span><span class="p">><</span><span class="nt">td</span><span class="p">><</span><span class="nt">span</span> <span class="na">id</span><span class="o">=</span><span class="s">"streetAJAX"</span><span class="p">></</span><span class="nt">span</span><span class="p">></</span><span class="nt">td</span><span class="p">></</span><span class="nt">tr</span><span class="p">></span>
<span class="p"><</span><span class="nt">tr</span><span class="p">><</span><span class="nt">td</span><span class="p">></span>Build:<span class="p"></</span><span class="nt">td</span><span class="p">><</span><span class="nt">td</span><span class="p">><</span><span class="nt">span</span> <span class="na">id</span><span class="o">=</span><span class="s">"buildAJAX"</span><span class="p">></</span><span class="nt">span</span><span class="p">></</span><span class="nt">td</span><span class="p">></</span><span class="nt">tr</span><span class="p">></span>
<span class="p"></</span><span class="nt">tbody</span><span class="p">></span>
<span class="p"></</span><span class="nt">table</span><span class="p">></span>
</pre></div>
</div>
</div>
<p>При выборе города срабатывает функция <code class="docutils literal"><span class="pre">getStreet</span></code>, которая генерирует код
списка улиц. Добавим ниже javascript:</p>
<div class="highlight-html"><div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">script</span> <span class="na">language</span><span class="o">=</span><span class="s">"JavaScript"</span><span class="p">></span>
<span class="c1">//Gets the browser specific XmlHttpRequest Object</span>
<span class="kd">function</span> <span class="nx">getXmlHttpRequestObject</span><span class="p">()</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nb">window</span><span class="p">.</span><span class="nx">XMLHttpRequest</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nx">XMLHttpRequest</span><span class="p">();</span> <span class="c1">//Not IE</span>
<span class="p">}</span> <span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="nb">window</span><span class="p">.</span><span class="nx">ActiveXObject</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nx">ActiveXObject</span><span class="p">(</span><span class="s2">"Microsoft.XMLHTTP"</span><span class="p">);</span> <span class="c1">//IE</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="c1">//Display your error message here.</span>
<span class="c1">//and inform the user they might want to upgrade</span>
<span class="c1">//their browser.</span>
<span class="nx">alert</span><span class="p">(</span><span class="s2">"Your browser doesn't support the XmlHttpRequest object. Better upgrade to Firefox."</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">//Get our browser specific XmlHttpRequest object.</span>
<span class="kd">var</span> <span class="nx">receiveReq</span> <span class="o">=</span> <span class="nx">getXmlHttpRequestObject</span><span class="p">();</span>
<span class="c1">//Initiate the asyncronous request.</span>
<span class="kd">function</span> <span class="nx">getStreet</span><span class="p">(</span><span class="nx">sel</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">//If our XmlHttpRequest object is not in the middle of a request, start the new asyncronous call.</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s1">'buildAJAX'</span><span class="p">).</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="s1">''</span>
<span class="kd">var</span> <span class="nx">value</span> <span class="o">=</span> <span class="nx">sel</span><span class="p">.</span><span class="nx">options</span><span class="p">[</span><span class="nx">sel</span><span class="p">.</span><span class="nx">selectedIndex</span><span class="p">].</span><span class="nx">value</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">receiveReq</span><span class="p">.</span><span class="nx">readyState</span> <span class="o">==</span> <span class="mi">4</span> <span class="o">||</span> <span class="nx">receiveReq</span><span class="p">.</span><span class="nx">readyState</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">//Setup the connection as a GET call to SayHello.html.</span>
<span class="c1">//True explicity sets the request to asyncronous (default).</span>
<span class="nx">receiveReq</span><span class="p">.</span><span class="nx">open</span><span class="p">(</span><span class="s2">"GET"</span><span class="p">,</span> <span class="s2">"/ajax/get_ajax_street?city="</span><span class="o">+</span><span class="nx">value</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
<span class="c1">//Set the function that will be called when the XmlHttpRequest objects state changes.</span>
<span class="nx">receiveReq</span><span class="p">.</span><span class="nx">onreadystatechange</span> <span class="o">=</span> <span class="nx">handleStreet</span><span class="p">;</span>
<span class="c1">//Make the actual request.</span>
<span class="nx">receiveReq</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="kc">null</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">//Called every time our XmlHttpRequest objects state changes.</span>
<span class="kd">function</span> <span class="nx">handleStreet</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">//Check to see if the XmlHttpRequests state is finished.</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">receiveReq</span><span class="p">.</span><span class="nx">readyState</span> <span class="o">==</span> <span class="mi">4</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">//Set the contents of our span element to the result of the asyncronous call.</span>
<span class="c1">//document.getElementById('span_result').innerHTML = receiveReq.responseText;</span>
<span class="c1">//alert(receiveReq.responseText);</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s1">'streetAJAX'</span><span class="p">).</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="nx">receiveReq</span><span class="p">.</span><span class="nx">responseText</span><span class="p">;</span>
<span class="nx">getBuild</span><span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s1">'street'</span><span class="p">));</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p"></</span><span class="nt">script</span><span class="p">></span>
</pre></div>
</div>
<p>Теперь проделаем то же само для выбора улицы, добавим функции:</p>
<div class="highlight-javascript"><div class="highlight"><pre><span></span><span class="kd">function</span> <span class="nx">getBuild</span><span class="p">(</span><span class="nx">sel</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">//If our XmlHttpRequest object is not in the middle of a request, start the new asyncronous call.</span>
<span class="kd">var</span> <span class="nx">value</span> <span class="o">=</span> <span class="nx">sel</span><span class="p">.</span><span class="nx">options</span><span class="p">[</span><span class="nx">sel</span><span class="p">.</span><span class="nx">selectedIndex</span><span class="p">].</span><span class="nx">value</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">receiveReq</span><span class="p">.</span><span class="nx">readyState</span> <span class="o">==</span> <span class="mi">4</span> <span class="o">||</span> <span class="nx">receiveReq</span><span class="p">.</span><span class="nx">readyState</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">//Setup the connection as a GET call to SayHello.html.</span>
<span class="c1">//True explicity sets the request to asyncronous (default).</span>
<span class="nx">receiveReq</span><span class="p">.</span><span class="nx">open</span><span class="p">(</span><span class="s2">"GET"</span><span class="p">,</span> <span class="s2">"/ajax/get_ajax_build?street="</span><span class="o">+</span><span class="nx">value</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
<span class="c1">//Set the function that will be called when the XmlHttpRequest objects state changes.</span>
<span class="nx">receiveReq</span><span class="p">.</span><span class="nx">onreadystatechange</span> <span class="o">=</span> <span class="nx">handleBuild</span><span class="p">;</span>
<span class="c1">//Make the actual request.</span>
<span class="nx">receiveReq</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="kc">null</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">//Called every time our XmlHttpRequest objects state changes.</span>
<span class="kd">function</span> <span class="nx">handleBuild</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">//Check to see if the XmlHttpRequests state is finished.</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">receiveReq</span><span class="p">.</span><span class="nx">readyState</span> <span class="o">==</span> <span class="mi">4</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">//Set the contents of our span element to the result of the asyncronous call.</span>
<span class="c1">//document.getElementById('span_result').innerHTML = receiveReq.responseText;</span>
<span class="c1">//alert(receiveReq.responseText);</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s1">'buildAJAX'</span><span class="p">).</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="nx">receiveReq</span><span class="p">.</span><span class="nx">responseText</span><span class="p">;</span>
<span class="nx">summAddress</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Все должно работать :) Осталось написать функции на стороне сервера, для AJAX
запросов. Тут их две <code class="docutils literal"><span class="pre">get_ajax_build</span></code> и <code class="docutils literal"><span class="pre">get_ajax_street</span></code>. Обе возвращают
обычный HTML список формата:</p>
<div class="highlight-xml"><div class="highlight"><pre><span></span><span class="nt"><select</span> <span class="na">id=</span><span class="s">"street"</span> <span class="na">name=</span><span class="s">"street"</span> <span class="na">onchange=</span><span class="s">"getBuild(this);"</span><span class="nt">></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1750"</span><span class="nt">></span>8 Марта<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1718"</span><span class="nt">></span>Академика Королева<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1734"</span><span class="nt">></span>Анучина<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1733"</span><span class="nt">></span>БЗСК пос<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1715"</span><span class="nt">></span>Больничный городок<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1744"</span><span class="nt">></span>Брусницына<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1704"</span><span class="nt">></span>Воротникова<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1747"</span><span class="nt">></span>Восточная<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1709"</span><span class="nt">></span>Гагарина<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1701"</span><span class="nt">></span>Героев труда<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1714"</span><span class="nt">></span>Горького<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1721"</span><span class="nt">></span>Декабристов<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1735"</span><span class="nt">></span>Загвозкина<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1746"</span><span class="nt">></span>Заречная (Шиловка)<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1738"</span><span class="nt">></span>Исакова<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1731"</span><span class="nt">></span>Кирова<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1707"</span><span class="nt">></span>Коммуны<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1708"</span><span class="nt">></span>Комсомольская<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1706"</span><span class="nt">></span>Косых<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1737"</span><span class="nt">></span>Красноармейская<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1702"</span><span class="nt">></span>Красных героев<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1745"</span><span class="nt">></span>Ленина<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1742"</span><span class="nt">></span>ЛЕНИНСКИИ (ШИЛОВКА)<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1705"</span><span class="nt">></span>Ленинский (Шиловка)<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1736"</span><span class="nt">></span>Мамина-Сибиряка<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1740"</span><span class="nt">></span>Машинистов<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1732"</span><span class="nt">></span>Маяковского<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1741"</span><span class="nt">></span>Мебельщиков<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1717"</span><span class="nt">></span>Мира<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1725"</span><span class="nt">></span>Мичурина<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1722"</span><span class="nt">></span>Новая (Шиловка)<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1723"</span><span class="nt">></span>Овощное отделение<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1728"</span><span class="nt">></span>Парковая (Шиловка)<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1720"</span><span class="nt">></span>Первомайская<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1739"</span><span class="nt">></span>Первомайский пос<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1703"</span><span class="nt">></span>Пролетарская<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1743"</span><span class="nt">></span>Смирнова<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1710"</span><span class="nt">></span>Совхозная (Шиловка)<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1713"</span><span class="nt">></span>Спортивная<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1727"</span><span class="nt">></span>Старых Большевиков<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1729"</span><span class="nt">></span>Строителей<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1716"</span><span class="nt">></span>Театральная<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1748"</span><span class="nt">></span>Толбухина<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1730"</span><span class="nt">></span>Февральская<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1749"</span><span class="nt">></span>Фурманова<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1724"</span><span class="nt">></span>Циолковского<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1711"</span><span class="nt">></span>Чапаева<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1712"</span><span class="nt">></span>Чкалова<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1726"</span><span class="nt">></span>Шиловская<span class="nt"></option></span>
<span class="nt"><option</span> <span class="na">value=</span><span class="s">"1755"</span><span class="nt">></span>Энергостроителей<span class="nt"></option></span>
<span class="nt"></select></span>
</pre></div>
</div>
<p>У меня на питоне они выглядят так:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">get_ajax_street</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">city</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">GET</span><span class="p">[</span><span class="s1">'city'</span><span class="p">]</span>
<span class="n">streets</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">Streets</span><span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">Streets</span><span class="o">.</span><span class="n">city</span><span class="o">==</span><span class="n">city</span><span class="p">)</span><span class="o">.</span>\
<span class="n">order_by</span><span class="p">(</span><span class="n">Streets</span><span class="o">.</span><span class="n">name</span><span class="p">)</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
<span class="n">html</span> <span class="o">=</span> <span class="s1">''</span>
<span class="k">for</span> <span class="n">street</span> <span class="ow">in</span> <span class="n">streets</span><span class="p">:</span>
<span class="n">html</span> <span class="o">+=</span> <span class="s2">"<option value="</span><span class="o">%</span><span class="n">s</span><span class="s2">">"</span> <span class="o">%</span> <span class="nb">str</span><span class="p">(</span><span class="n">street</span><span class="o">.</span><span class="n">id</span><span class="p">)</span> <span class="o">+</span>\
<span class="s2">"</span><span class="si">%s</span><span class="s2"></option></span><span class="se">\n</span><span class="s2">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">street</span><span class="o">.</span><span class="n">name</span> <span class="ow">or</span> <span class="s1">'No name'</span><span class="p">)</span>
<span class="k">if</span> <span class="n">html</span><span class="p">:</span>
<span class="n">html</span> <span class="o">=</span> <span class="s2">"<select "</span><span class="o">=</span><span class="s2">""</span> <span class="s2">"onchange="</span><span class="n">getBuild</span><span class="p">(</span><span class="n">this</span><span class="p">);</span><span class="s2">" +\="" id="</span><span class="n">street</span><span class="s2">" name="</span><span class="n">street</span><span class="s2">"></span><span class="se">\n</span><span class="s2">"</span> <span class="o">+</span> <span class="n">html</span> <span class="o">+</span> <span class="s2">"</select>"</span>
<span class="k">return</span> <span class="n">html</span>
<span class="k">def</span> <span class="nf">get_ajax_build</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">street</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">GET</span><span class="p">[</span><span class="s1">'street'</span><span class="p">]</span>
<span class="n">builds</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">Builds</span><span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">Builds</span><span class="o">.</span><span class="n">streetid</span><span class="o">==</span><span class="n">street</span><span class="p">)</span><span class="o">.</span>\
<span class="n">order_by</span><span class="p">(</span><span class="n">Builds</span><span class="o">.</span><span class="n">building</span><span class="p">)</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
<span class="n">html</span> <span class="o">=</span> <span class="s1">''</span>
<span class="k">for</span> <span class="n">build</span> <span class="ow">in</span> <span class="n">builds</span><span class="p">:</span>
<span class="n">html</span> <span class="o">+=</span> <span class="s2">"<option value="</span><span class="o">%</span><span class="n">s</span><span class="s2">">"</span> <span class="o">%</span> <span class="nb">str</span><span class="p">(</span><span class="n">build</span><span class="o">.</span><span class="n">id</span><span class="p">)</span> <span class="o">+</span>\
<span class="s2">"</span><span class="si">%s</span><span class="s2"></option></span><span class="se">\n</span><span class="s2">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">build</span><span class="o">.</span><span class="n">building</span> <span class="ow">or</span> <span class="s1">'No name'</span><span class="p">)</span>
<span class="k">if</span> <span class="n">html</span><span class="p">:</span>
<span class="n">html</span> <span class="o">=</span> <span class="s2">"<select "</span><span class="o">=</span><span class="s2">""</span> <span class="s2">"onchange="</span><span class="n">summAddress</span><span class="p">();</span><span class="s2">" +\="" id="</span><span class="n">build</span><span class="s2">" name="</span><span class="n">build</span><span class="s2">"></span><span class="se">\n</span><span class="s2">"</span> <span class="o">+</span> <span class="n">html</span> <span class="o">+</span> <span class="s2">"</select>"</span>
<span class="k">return</span> <span class="n">html</span>
</pre></div>
</div>
<p>Выглядит это как-то так:</p>
<img alt="_static/2012/triple_select.png" class="align-center" src="_static/2012/triple_select.png" />
<p>Думаю понятно, что функции должны быть доступны по адресам
<code class="docutils literal"><span class="pre">/ajax/get_ajax_street</span></code> и <code class="docutils literal"><span class="pre">/ajax/get_ajax_build</span></code> соответственно.</p>
<p>Пользуйтесь )</p>
</div>
pyandexmap работа с Яндекс Карты API используя Python
http://uralbash.ru/articles/2012/pyyandexmap/
2012-02-10T15:14:00Z
2012-02-10T15:14:00Z
Uralbash
<div class="section" id="pyandexmap-api-python">
<p>У Яндекс Карт хороший геокодинг и есть API, но нет автодополнение поисковой
строки (как в гугле). У гугла плохой геокодинг (для России) но есть
автодополнение. Более подробно можно прочитать например <a class="reference external" href="http://clubs.ya.ru/mapsapi/replies.xml?item_no=17733">здесь</a>. Парадокс какой-то. Я
написал простой модуль для вычленения данных через API при помощи
питона. Это очень удобно использовать в AJAX запросах. Пример использования
здесь (<a class="reference internal" href="../articles/2012/osm_geotagging/#osm_geotagging"><span class="std std-ref">OpenStreetMap, Геокодирование и автодополнение адреса в строке поиска (как у гугла) с помощью Яндекс API :)</span></a>). Код для изучения/исправления здесь
<a class="reference external" href="https://github.com/uralbash/pyandexmap">https://github.com/uralbash/pyandexmap</a>.</p>
</div>
Размещаем свои python проекты на https://pypi.python.org
http://uralbash.ru/articles/2012/pypi/
2012-02-10T13:17:00Z
2012-02-10T13:17:00Z
Uralbash
<div class="section" id="python-https-pypi-python-org">
<p>Я периодически использую свои скрипты в разных местах, для того что бы не
копипастить их постоянно и следить за обновлением удобно добавить их в
<a class="reference external" href="https://pypi.python.org">https://pypi.python.org</a> и устанавливать/обновлять через <code class="docutils literal"><span class="pre">pip</span> <span class="pre">install</span></code>. Для
этого необходимо подготовить наш модуль.</p>
<div class="admonition seealso">
<p class="first admonition-title">См.также</p>
<ul class="last simple">
<li><a class="reference external" href="https://packaging.python.org/en/latest/distributing.html">https://packaging.python.org/en/latest/distributing.html</a></li>
<li><a class="reference external" href="http://pythonhosted.org/setuptools/">http://pythonhosted.org/setuptools/</a></li>
</ul>
</div>
<p>Структура файлов:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>.
├── myproject
│ ├── mymodel.py
│ └── __init__.py
├── README.rst
└── setup.py
</pre></div>
</div>
<div class="literal-block-wrapper docutils container" id="id2">
<div class="code-block-caption"><span class="caption-text">setup.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">setuptools</span> <span class="kn">import</span> <span class="n">setup</span>
<span class="k">def</span> <span class="nf">read</span><span class="p">(</span><span class="n">fname</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">open</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">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="vm">__file__</span><span class="p">),</span> <span class="n">fname</span><span class="p">))</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="n">setup</span><span class="p">(</span>
<span class="n">name</span><span class="o">=</span><span class="s1">'pyandexmap'</span><span class="p">,</span>
<span class="n">version</span><span class="o">=</span><span class="s1">'0.0.2'</span><span class="p">,</span>
<span class="n">description</span><span class="o">=</span><span class="s1">'Scripts for get data from yandex map API'</span><span class="p">,</span>
<span class="n">author</span><span class="o">=</span><span class="s1">''</span><span class="p">,</span>
<span class="n">author_email</span><span class="o">=</span><span class="s1">''</span><span class="p">,</span>
<span class="n">url</span><span class="o">=</span><span class="s1">'http://github.com/uralbash/pyandexmap/'</span><span class="p">,</span>
<span class="n">keywords</span> <span class="o">=</span> <span class="s2">"yandex map api search ajax geocode geocodding directions</span><span class="se">\</span>
<span class="s2"> navigation json"</span><span class="p">,</span>
<span class="n">install_requires</span><span class="o">=</span><span class="p">[</span><span class="s1">''</span><span class="p">],</span>
<span class="n">license</span><span class="o">=</span><span class="s1">'GPL'</span><span class="p">,</span>
<span class="n">packages</span><span class="o">=</span><span class="p">[</span><span class="s1">'pyandexmap'</span><span class="p">],</span>
<span class="n">long_description</span><span class="o">=</span><span class="n">read</span><span class="p">(</span><span class="s1">'README.rst'</span><span class="p">),</span>
<span class="n">classifiers</span><span class="o">=</span><span class="p">[</span>
<span class="s1">'Development Status :: 3 - Alpha'</span><span class="p">,</span>
<span class="s1">'Environment :: Console'</span><span class="p">,</span>
<span class="s1">'Intended Audience :: Developers'</span><span class="p">,</span>
<span class="s1">'License :: OSI Approved :: GNU General Public License (GPL)'</span><span class="p">,</span>
<span class="s1">'Natural Language :: English'</span><span class="p">,</span>
<span class="s1">'Natural Language :: Russian'</span><span class="p">,</span>
<span class="s1">'Operating System :: OS Independent'</span><span class="p">,</span>
<span class="s1">'Programming Language :: Python'</span><span class="p">,</span>
<span class="s1">'Topic :: Scientific/Engineering :: GIS'</span><span class="p">,</span>
<span class="p">],</span>
<span class="p">)</span>
</pre></div>
</div>
</div>
<p><a class="reference external" href="https://pypi.python.org/pypi?:action=list_classifiers">classifiers</a> - это
список разделов куда попадет ваш пакет, взять существующие можно <a class="reference external" href="https://pypi.python.org/pypi?:action=browse">здесь</a></p>
<p>Затем регаем свой модуль так:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ python setup.py register
$ python setup.py sdist upload
</pre></div>
</div>
<p>Отвечаем на вопросы если вы еще не зарегистрированы и все :)</p>
</div>
Jinja замена None, Null, итд на пустую строку
http://uralbash.ru/articles/2012/jinja_silent_none/
2012-02-10T13:17:00Z
2012-02-10T13:17:00Z
Uralbash
<div class="section" id="jinja-none-null">
<p>В питоне пустые значения возвращаются как <code class="docutils literal"><span class="pre">None</span></code>. Поэтому в шаблонах
<a class="reference external" href="http://jinja.pocoo.org/">Jinja</a> вместо пустых значений отображаются <code class="docutils literal"><span class="pre">None</span></code>. Что бы поправить это
нужно изменить метод <code class="docutils literal"><span class="pre">finalize</span></code>. Пример из google groups:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">silent_none</span><span class="p">(</span><span class="n">value</span><span class="p">):</span>
<span class="k">if</span> <span class="n">value</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
<span class="k">return</span> <span class="s1">''</span>
<span class="k">return</span> <span class="n">value</span>
<span class="kn">from</span> <span class="nn">jinja2</span> <span class="kn">import</span> <span class="n">Environment</span>
<span class="n">env</span> <span class="o">=</span> <span class="n">Environment</span><span class="p">()</span>
<span class="n">env</span><span class="o">.</span><span class="n">finalize</span> <span class="o">=</span> <span class="n">silent_none</span>
</pre></div>
</div>
<p>Теперь вместо None будет писаться пустая строка ‘’. В pylons нужно править файл
environment.py:</p>
<div class="literal-block-wrapper docutils container" id="id1">
<div class="code-block-caption"><span class="caption-text">environment.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">silent_none</span><span class="p">(</span><span class="n">value</span><span class="p">):</span>
<span class="sd">""" Jinja fix output None</span>
<span class="sd"> For more details:</span>
<span class="sd"> http://groups.google.com/group/pocoo-libs/browse_thread/thread/490f6e6e8fca6a6c</span>
<span class="sd"> """</span>
<span class="k">if</span> <span class="n">value</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
<span class="k">return</span> <span class="s1">''</span>
<span class="k">return</span> <span class="n">value</span>
<span class="k">def</span> <span class="nf">load_environment</span><span class="p">(</span><span class="n">global_conf</span><span class="p">,</span> <span class="n">app_conf</span><span class="p">):</span>
<span class="sd">"""Configure the Pylons environment via the ``pylons.config``</span>
<span class="sd"> object</span>
<span class="sd"> """</span>
<span class="n">bla</span> <span class="n">bla</span> <span class="n">bla</span><span class="o">...</span>
<span class="c1"># Create the Jinja2 Environment</span>
<span class="n">config</span><span class="p">[</span><span class="s1">'pylons.app_globals'</span><span class="p">]</span><span class="o">.</span><span class="n">jinja2_env</span> <span class="o">=</span> <span class="n">Environment</span><span class="p">(</span><span class="n">loader</span><span class="o">=</span><span class="n">ChoiceLoader</span><span class="p">(</span>
<span class="p">[</span><span class="n">FileSystemLoader</span><span class="p">(</span><span class="n">path</span><span class="p">)</span> <span class="k">for</span> <span class="n">path</span> <span class="ow">in</span> <span class="n">paths</span><span class="p">[</span><span class="s1">'templates'</span><span class="p">]]))</span>
<span class="c1"># replace None output to ''</span>
<span class="n">config</span><span class="p">[</span><span class="s1">'pylons.app_globals'</span><span class="p">]</span><span class="o">.</span><span class="n">jinja2_env</span><span class="o">.</span><span class="n">finalize</span> <span class="o">=</span> <span class="n">silent_none</span>
<span class="c1"># Jinja2's unable to request c's attributes without strict_c</span>
<span class="n">config</span><span class="p">[</span><span class="s1">'pylons.strict_c'</span><span class="p">]</span> <span class="o">=</span> <span class="bp">True</span>
<span class="n">bla</span> <span class="n">bla</span> <span class="n">bla</span><span class="o">...</span>
</pre></div>
</div>
</div>
</div>
Скрипты работающие в окружении проекта на Pylons
http://uralbash.ru/articles/2012/pylons_console/
2012-02-10T12:32:00Z
2012-02-10T12:32:00Z
Uralbash
<div class="section" id="pylons">
<p>Иногда необходимо написать скрипт который выполняется из консоли и использует
окружение проекта на Pylons. Копипастю простой пример с <a class="reference external" href="http://pylonshq.com/snippets/running_commands_with_the_app_environment">pylonshq</a>.
Так-как там есть привычка периодически удалять информацию.</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">optparse</span>
<span class="kn">import</span> <span class="nn">pylons</span>
<span class="kn">from</span> <span class="nn">paste.deploy</span> <span class="kn">import</span> <span class="n">appconfig</span>
<span class="kn">from</span> <span class="nn">YOURAPP.config.environment</span> <span class="kn">import</span> <span class="n">load_environment</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="n">option_parser</span> <span class="o">=</span> <span class="n">optparse</span><span class="o">.</span><span class="n">OptionParser</span><span class="p">()</span>
<span class="n">option_parser</span><span class="o">.</span><span class="n">add_option</span><span class="p">(</span><span class="s1">'--ini'</span><span class="p">,</span>
<span class="n">help</span><span class="o">=</span><span class="s1">'INI file to use for pylons settings'</span><span class="p">,</span>
<span class="nb">type</span><span class="o">=</span><span class="s1">'str'</span><span class="p">,</span>
<span class="n">default</span><span class="o">=</span><span class="s1">'development.ini'</span><span class="p">)</span>
<span class="n">options</span><span class="p">,</span> <span class="n">args</span> <span class="o">=</span> <span class="n">option_parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
<span class="c1"># Initialize the Pylons app</span>
<span class="n">conf</span> <span class="o">=</span> <span class="n">appconfig</span><span class="p">(</span><span class="s1">'config:'</span> <span class="o">+</span> <span class="n">options</span><span class="o">.</span><span class="n">ini</span><span class="p">,</span> <span class="n">relative_to</span><span class="o">=</span><span class="s1">'.'</span><span class="p">)</span>
<span class="n">load_environment</span><span class="p">(</span><span class="n">conf</span><span class="o">.</span><span class="n">global_conf</span><span class="p">,</span> <span class="n">conf</span><span class="o">.</span><span class="n">local_conf</span><span class="p">)</span>
<span class="c1"># Now code can be run, the SQLalchemy Session can be used, etc.</span>
<span class="o">....</span>
</pre></div>
</div>
</div>
Python + ssh или основы paramiko
http://uralbash.ru/articles/2012/paramiko/
2012-02-10T12:32:00Z
2012-02-10T12:32:00Z
Uralbash
<div class="section" id="python-ssh-paramiko">
<p>Для работы с ssh в питоновских скриптах идеально подходит модуль
<a class="reference external" href="https://pypi.python.org/pypi/paramiko">paramiko</a>.</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ pip install paramiko
</pre></div>
</div>
<p>В сети много примеров как подключиться при помощи пароля, я приведу пример как
подключаться при помощи ключа.</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">paramiko</span>
<span class="kn">from</span> <span class="nn">cStringIO</span> <span class="kn">import</span> <span class="n">StringIO</span>
<span class="n">ssh</span> <span class="o">=</span> <span class="n">paramiko</span><span class="o">.</span><span class="n">SSHClient</span><span class="p">()</span>
<span class="c1"># Убираем логи</span>
<span class="c1"># в случае если вы используете их, например в Pylons окружении</span>
<span class="n">paramiko</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="n">logging</span><span class="o">.</span><span class="n">disable</span><span class="p">(</span><span class="n">ssh</span><span class="p">)</span>
<span class="c1"># Подтверждаем ключи от хостов автоматически</span>
<span class="n">ssh</span><span class="o">.</span><span class="n">set_missing_host_key_policy</span><span class="p">(</span><span class="n">paramiko</span><span class="o">.</span><span class="n">AutoAddPolicy</span><span class="p">())</span>
<span class="c1"># Наш ключ для доступа без пароля</span>
<span class="n">key</span> <span class="o">=</span> <span class="n">StringIO</span><span class="p">(</span><span class="s1">'''-----BEGIN RSA PRIVATE KEY-----</span><span class="se">\n</span><span class="s1"></span>
<span class="s1">DIxdStYlzBCzySh60ewXurqUnv7KdPLzxXBeBN8LEpbekMkdXdhNBskT4JtDV3N8</span>
<span class="s1">/43yEoNtjAN6iCXhcsCJNNkNHqMvI5jeiv64oZA/LgG3JLjiQNvG5IujxY1B8fNI</span>
<span class="s1">bla bla bla...</span>
<span class="s1">DIxdStYlzBCzySh60ewXurqUnv7KdPLzxXBeBN8LEpbekMkdXdhNBskT4JtDV3N8</span>
<span class="s1">8GqlxiXnUhwQBk12G3QbyN6sxqKlH4wVpyN3lbV4LWFD9rj7Xr6avrAPxsIO1LF4</span>
<span class="s1">W4IpuJT9+ABPCmxqWvVzj/YTTluHsvgGaDc+VhHSYmT1ti8plA==</span><span class="se">\n</span><span class="s1"></span>
<span class="s1">-----END RSA PRIVATE KEY-----</span><span class="se">\n</span><span class="s1">'''</span><span class="p">)</span>
<span class="c1"># если нужно читать ключ из файла (например из ~/.ssh/mykey)</span>
<span class="c1"># используйте функцию "from_private_key_file"</span>
<span class="n">privkey</span> <span class="o">=</span> <span class="n">paramiko</span><span class="o">.</span><span class="n">RSAKey</span><span class="o">.</span><span class="n">from_private_key</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
<span class="c1"># Соединяемся</span>
<span class="c1"># SSH connect cli like:</span>
<span class="c1"># ssh -o StrictHostKeyChecking=no -i /xxx/.ssh/mykey <user>@<ip></span>
<span class="n">ssh</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s1">'192.168.0.113'</span><span class="p">,</span> <span class="n">username</span><span class="o">=</span><span class="s1">'admin'</span><span class="p">,</span> <span class="n">pkey</span><span class="o">=</span><span class="n">privkey</span><span class="p">)</span>
<span class="c1"># Выполняем команду</span>
<span class="n">stdin</span><span class="p">,</span> <span class="n">stdout</span><span class="p">,</span> <span class="n">stderr</span> <span class="o">=</span> <span class="n">ssh</span><span class="o">.</span><span class="n">exec_command</span><span class="p">(</span><span class="s1">'ls -la'</span><span class="p">)</span>
<span class="c1"># проверяем на ошибки</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">stderr</span><span class="o">.</span><span class="n">readlines</span><span class="p">():</span>
<span class="c1"># считываем вывод</span>
<span class="n">res</span> <span class="o">=</span> <span class="n">stdout</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span>
</pre></div>
</div>
</div>
OpenStreetMap, Геокодирование и автодополнение адреса в строке поиска (как у гугла) с помощью Яндекс API :)
http://uralbash.ru/articles/2012/osm_geotagging/
2012-02-10T11:47:00Z
2012-02-10T11:47:00Z
Uralbash
<div class="section" id="openstreetmap-api">
<span id="osm-geotagging"></span>
<p><cite>Геокоди́рование</cite> — процесс назначения географических идентификаторов (таких как
<a class="reference external" href="http://ru.wikipedia.org/wiki/%D0%93%D0%B5%D0%BE%D0%B3%D1%80%D0%B0%D1%84%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B5_%D0%BA%D0%BE%D0%BE%D1%80%D0%B4%D0%B8%D0%BD%D0%B0%D1%82%D1%8B">географические координаты</a>,
выраженные в виде <a class="reference external" href="http://ru.wikipedia.org/wiki/%D0%A8%D0%B8%D1%80%D0%BE%D1%82%D0%B0">широты</a> и
<a class="reference external" href="http://ru.wikipedia.org/wiki/%D0%94%D0%BE%D0%BB%D0%B3%D0%BE%D1%82%D0%B0">долготы</a>)
объектам карты и записям данных.</p>
<p>Например, геокодированием является назначение координат записям, описывающим
адрес (улица/дом) или фотографиям (где было сделано фото) или IP-адресам, или
любой другой информации, имеющей географический компонент. Геокодированные
объекты могут быть использованы в <a class="reference external" href="http://ru.wikipedia.org/wiki/%D0%93%D0%B5%D0%BE%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D0%B0%D1%8F_%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0">геоинформационных системах</a>.</p>
<p>Создадим карту и строку поиска объекта по адресу, через API Яндекс Карты.
Служба Яндекс.Карт предлагает своим пользователям сервис геокодирования. Он
позволяет определять координаты и получать сведения о географическом объекте
по его названию или адресу и наоборот, определять адрес объекта на карте по
его координатам (обратное геокодирование).</p>
<p>Например, по запросу «Москва, ул. Малая Грузинская, д. 27/13» геокодер
возвратит географические координаты этого дома: “37.571309, 55.767190”
(долгота, широта). И, наоборот, если в запросе указать географические
коордианты дома “37.571309, 55.767190”, то геокодер вернет его адрес.
К геокодеру можно обращаться как по HTTP-протоколу, так и с помощью <a class="reference external" href="http://api.yandex.ru/maps/jsapi">JavaScript
API</a>. При обращении к геокодеру по
HTTP-протоколу ответ может быть сформирован либо в виде XML-документа формата
<a class="reference external" href="http://api.yandex.ru/maps/ymapsml">YMapsML</a>, либо в формате <a class="reference external" href="http://ru.wikipedia.org/wiki/JSON">JSON</a>.</p>
<p>При обращении к геокодеру по HTTP-протоколу в параметрах запроса требуется
указывать API-ключ. Ключ можно получить, заполнив соответствующую <a class="reference external" href="http://api.yandex.ru/maps/form.xml">форму</a>.
В данном документе описаны <a class="reference external" href="http://api.yandex.ru/maps/geocoder/doc/desc/concepts/input_params.xml">параметры HTTP-запроса</a> к
геокодеру, его <a class="reference external" href="http://api.yandex.ru/maps/geocoder/doc/desc/concepts/response_structure.xml">ответ</a>,
а также приведены примеры использования.</p>
<p>Как добавить карту на сайт можно посмотреть здесь <a class="reference internal" href="../articles/2012/osm_example/#osm_example"><span class="std std-ref">Пример карты OpenStreetMap на своем сайте</span></a>.</p>
<p>Я приведу пример использования в окружении <a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">Pylons</a> и шаблонизатора
<a class="reference external" href="http://jinja.pocoo.org/">Jinja</a>. При желании переделать скрипты под другие фреймворки не составит
труда. Главное понять принципы.</p>
<p>Добавим поле для поиска</p>
<div class="highlight-html"><div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">input</span> <span class="na">id</span><span class="o">=</span><span class="s">"searchAddress"</span> <span class="na">name</span><span class="o">=</span><span class="s">"address"</span> <span class="na">size</span><span class="o">=</span><span class="s">"73"</span> <span class="na">type</span><span class="o">=</span><span class="s">"text"</span> <span class="p">/></span>
</pre></div>
</div>
<p>Напишем AJAX функцию для выпадающего списка при автодополнении
(<a class="reference external" href="http://www.devbridge.com/projects/autocomplete/jquery/">http://www.devbridge.com/projects/autocomplete/jquery/</a>):</p>
<div class="highlight-html+jinja"><div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">"/jquery/jquery.min.js"</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/javascript"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">"/jquery/jquery.autocomplete.js"</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/javascript"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span><span class="p">></span>
<span class="c1">// Автокомплит для адреса</span>
<span class="c1">//var options, a;</span>
<span class="nx">jQuery</span><span class="p">(</span><span class="kd">function</span><span class="p">(){</span>
<span class="nx">options</span> <span class="o">=</span> <span class="p">{</span>
<span class="nx">serviceUrl</span><span class="o">:</span><span class="s2">"</span><span class="cp">{{</span> <span class="nv">url</span><span class="o">(</span><span class="nv">controller</span><span class="o">=</span><span class="s1">'common'</span><span class="o">,</span> <span class="nv">action</span><span class="o">=</span><span class="s1">'geocodding_ajax'</span><span class="o">)</span> <span class="cp">}}</span><span class="s2">"</span><span class="p">,</span>
<span class="nx">width</span><span class="o">:</span><span class="mi">900</span><span class="p">,</span>
<span class="nx">deferRequestBy</span><span class="o">:</span> <span class="mi">100</span><span class="p">,</span> <span class="c1">//miliseconds</span>
<span class="p">};</span>
<span class="nx">a</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="s1">'#searchAddress'</span><span class="p">).</span><span class="nx">autocomplete</span><span class="p">(</span><span class="nx">options</span><span class="p">);</span>
<span class="p">});</span>
<span class="p"></</span><span class="nt">script</span><span class="p">></span>
</pre></div>
</div>
<p>Создадим контроллер который будет отдавать данные по AJAX запросу:</p>
<div class="literal-block-wrapper docutils container" id="id7">
<div class="code-block-caption"><span class="caption-text">common.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1"># coding=utf8</span>
<span class="kn">import</span> <span class="nn">logging</span>
<span class="kn">import</span> <span class="nn">pylons</span>
<span class="kn">from</span> <span class="nn">pyandexmap</span> <span class="kn">import</span> <span class="n">geotagging</span>
<span class="kn">from</span> <span class="nn">pylons</span> <span class="kn">import</span> <span class="n">request</span><span class="p">,</span> <span class="n">response</span><span class="p">,</span> <span class="n">session</span><span class="p">,</span> <span class="n">tmpl_context</span> <span class="k">as</span> <span class="n">c</span><span class="p">,</span> <span class="n">url</span>
<span class="kn">from</span> <span class="nn">pylons.controllers.util</span> <span class="kn">import</span> <span class="n">abort</span><span class="p">,</span> <span class="n">redirect</span>
<span class="kn">from</span> <span class="nn">myapp.lib.base</span> <span class="kn">import</span> <span class="n">BaseController</span><span class="p">,</span> <span class="n">render</span>
<span class="n">log</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">CommonController</span><span class="p">(</span><span class="n">BaseController</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">geocodding_ajax</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">""" for autocomplete search in Yandex API</span>
<span class="sd"> """</span>
<span class="c1"># Ключ для Яндекс карт из development.ini</span>
<span class="n">key</span> <span class="o">=</span> <span class="n">pylons</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">'yandexKey'</span><span class="p">]</span>
<span class="n">address</span> <span class="o">=</span> <span class="s1">''</span>
<span class="k">for</span> <span class="n">addr</span> <span class="ow">in</span> <span class="n">geotagging</span><span class="o">.</span><span class="n">listGeoObject</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">GET</span><span class="p">[</span><span class="s1">'query'</span><span class="p">],</span> <span class="n">key</span><span class="p">):</span>
<span class="k">if</span> <span class="n">address</span><span class="p">:</span>
<span class="n">address</span> <span class="o">=</span> <span class="n">address</span> <span class="o">+</span><span class="s2">", '"</span><span class="o">+</span><span class="n">addr</span><span class="o">+</span><span class="s2">"'"</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">address</span> <span class="o">=</span> <span class="s2">"['"</span><span class="o">+</span><span class="n">addr</span><span class="o">+</span><span class="s2">"'"</span>
<span class="n">resp</span> <span class="o">=</span> <span class="s1">'''{</span>
<span class="s1"> query:'</span><span class="si">%s</span><span class="s1">',</span>
<span class="s1"> suggestions: </span><span class="si">%s</span><span class="s1">,</span>
<span class="s1"> data:[]</span>
<span class="s1"> }'''</span> <span class="o">%</span> <span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">GET</span><span class="p">[</span><span class="s1">'query'</span><span class="p">],</span> <span class="n">address</span><span class="o">+</span><span class="s1">']'</span><span class="p">)</span>
<span class="k">return</span> <span class="n">resp</span>
</pre></div>
</div>
</div>
<p>Формат ответа выглядит так:</p>
<div class="highlight-javascript"><div class="highlight"><pre><span></span><span class="p">{</span>
<span class="nx">query</span><span class="o">:</span><span class="s1">'Li'</span><span class="p">,</span>
<span class="nx">suggestions</span><span class="o">:</span><span class="p">[</span><span class="s1">'Liberia'</span><span class="p">,</span><span class="s1">'Libyan Arab Jamahiriya'</span><span class="p">,</span><span class="s1">'Liechtenstein'</span><span class="p">,</span><span class="s1">'Lithuania'</span><span class="p">],</span>
<span class="nx">data</span><span class="o">:</span><span class="p">[</span><span class="s1">'LR'</span><span class="p">,</span><span class="s1">'LY'</span><span class="p">,</span><span class="s1">'LI'</span><span class="p">,</span><span class="s1">'LT'</span><span class="p">]</span>
<span class="p">}</span>
</pre></div>
</div>
<p><a class="reference external" href="https://pypi.python.org/pypi/pyandexmap">pyandexmap</a> устанавливаем из <a class="reference external" href="https://pypi.python.org/">pypi</a> (про этот модуль я напишу позже).</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ pip install pyandexmap
</pre></div>
</div>
<p>Все должно заработать, остались только стили;</p>
<div class="highlight-html"><div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">style</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/css"</span><span class="p">></span>
<span class="p">.</span><span class="nc">autocomplete-w1</span> <span class="p">{</span> <span class="k">background</span><span class="p">:</span><span class="nb">url</span><span class="p">(</span><span class="sx">img/shadow.png</span><span class="p">)</span> <span class="kc">no-repeat</span> <span class="kc">bottom</span> <span class="kc">right</span><span class="p">;</span> <span class="k">position</span><span class="p">:</span><span class="kc">absolute</span><span class="p">;</span> <span class="k">top</span><span class="p">:</span><span class="mi">0</span><span class="kt">px</span><span class="p">;</span> <span class="k">left</span><span class="p">:</span><span class="mi">0</span><span class="kt">px</span><span class="p">;</span> <span class="k">margin</span><span class="p">:</span><span class="mi">6</span><span class="kt">px</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">6</span><span class="kt">px</span><span class="p">;</span> <span class="c">/* IE6 fix: */</span> <span class="n">_background</span><span class="p">:</span><span class="kc">none</span><span class="p">;</span> <span class="n">_margin</span><span class="p">:</span><span class="mi">1</span><span class="kt">px</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span>
<span class="p">.</span><span class="nc">autocomplete</span> <span class="p">{</span> <span class="k">border</span><span class="p">:</span><span class="mi">1</span><span class="kt">px</span> <span class="kc">solid</span> <span class="mh">#999</span><span class="p">;</span> <span class="k">background</span><span class="p">:</span><span class="mh">#FFF</span><span class="p">;</span> <span class="k">cursor</span><span class="p">:</span><span class="kc">default</span><span class="p">;</span> <span class="k">text-align</span><span class="p">:</span><span class="kc">left</span><span class="p">;</span> <span class="k">max-height</span><span class="p">:</span><span class="mi">350</span><span class="kt">px</span><span class="p">;</span> <span class="k">overflow</span><span class="p">:</span><span class="kc">auto</span><span class="p">;</span> <span class="k">margin</span><span class="p">:</span><span class="mi">-6</span><span class="kt">px</span> <span class="mi">6</span><span class="kt">px</span> <span class="mi">6</span><span class="kt">px</span> <span class="mi">-6</span><span class="kt">px</span><span class="p">;</span> <span class="c">/* IE6 specific: */</span> <span class="n">_height</span><span class="p">:</span><span class="mi">350</span><span class="kt">px</span><span class="p">;</span> <span class="n">_margin</span><span class="p">:</span><span class="mi">0</span><span class="p">;</span> <span class="n">_overflow-x</span><span class="p">:</span><span class="kc">hidden</span><span class="p">;</span> <span class="p">}</span>
<span class="p">.</span><span class="nc">autocomplete</span> <span class="p">.</span><span class="nc">selected</span> <span class="p">{</span> <span class="k">background</span><span class="p">:</span><span class="mh">#F0F0F0</span><span class="p">;</span> <span class="p">}</span>
<span class="p">.</span><span class="nc">autocomplete</span> <span class="nt">div</span> <span class="p">{</span> <span class="k">padding</span><span class="p">:</span><span class="mi">2</span><span class="kt">px</span> <span class="mi">5</span><span class="kt">px</span><span class="p">;</span> <span class="k">white-space</span><span class="p">:</span><span class="kc">nowrap</span><span class="p">;</span> <span class="k">overflow</span><span class="p">:</span><span class="kc">hidden</span><span class="p">;</span> <span class="p">}</span>
<span class="p">.</span><span class="nc">autocomplete</span> <span class="nt">strong</span> <span class="p">{</span> <span class="k">font-weight</span><span class="p">:</span><span class="kc">normal</span><span class="p">;</span> <span class="k">color</span><span class="p">:</span><span class="mh">#3399FF</span><span class="p">;</span> <span class="p">}</span>
<span class="p"></</span><span class="nt">style</span><span class="p">></span>
</pre></div>
</div>
<p>Результат:</p>
<div class="figure align-center" id="id8">
<img alt="_static/2012/osm_geotagging.png" src="_static/2012/osm_geotagging.png" />
<p class="caption"><span class="caption-text">Яндекс Карты автодополнение через геокодинг</span></p>
</div>
</div>
Пример карты OpenStreetMap на своем сайте
http://uralbash.ru/articles/2012/osm_example/
2012-02-10T10:33:00Z
2012-02-10T10:33:00Z
Uralbash
<div class="section" id="openstreetmap">
<span id="osm-example"></span>
<p><a class="reference external" href="http://www.openstreetmap.org">OpenStreetMap</a> — это свободно редактируемая карта всего мира. Она сделана
такими же людьми, как и вы. <a class="reference external" href="http://www.openstreetmap.org">OpenStreetMap</a> позволяет совместно
просматривать, изменять и использовать географические данные в любой точке
Земли. Также позволяет накладывать разные слои в том числе и карты Яндекса с
Гуглом. У гугла проблема с детализацией карт в России у Яндекса с API поэтому
<a class="reference external" href="http://www.openstreetmap.org">OpenStreetMap</a> смотрится наиболее красивым решением, при том что софт и
сами карты распространяются по свободным лицензиям.</p>
<p>Добавим js:</p>
<div class="highlight-html"><div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">"http://www.openlayers.org/api/OpenLayers.js"</span><span class="p">></span>
<span class="p"></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">"http://www.openlayers.org/api/OpenLayers.js"</span><span class="p">></span>
<span class="p"></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/javascript"</span><span class="p">></span>
<span class="kd">function</span> <span class="nx">GetMap</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">map</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">OpenLayers</span><span class="p">.</span><span class="nx">Map</span><span class="p">(</span><span class="s2">"OSMap"</span><span class="p">);</span><span class="c1">//инициализация карты</span>
<span class="kd">var</span> <span class="nx">mapnik</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">OpenLayers</span><span class="p">.</span><span class="nx">Layer</span><span class="p">.</span><span class="nx">OSM</span><span class="p">();</span><span class="c1">//создание слоя карты</span>
<span class="nx">map</span><span class="p">.</span><span class="nx">addLayer</span><span class="p">(</span><span class="nx">mapnik</span><span class="p">);</span><span class="c1">//добавление слоя</span>
<span class="nx">map</span><span class="p">.</span><span class="nx">zoomToMaxExtent</span><span class="p">();</span>
<span class="c1">// Широта/долгота</span>
<span class="kd">var</span> <span class="nx">lonlat</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">OpenLayers</span><span class="p">.</span><span class="nx">LonLat</span><span class="p">(</span><span class="mf">66.666</span><span class="p">,</span> <span class="mf">77.777</span><span class="p">);</span>
<span class="nx">map</span><span class="p">.</span><span class="nx">setCenter</span><span class="p">(</span><span class="nx">lonlat</span><span class="p">.</span><span class="nx">transform</span><span class="p">(</span>
<span class="k">new</span> <span class="nx">OpenLayers</span><span class="p">.</span><span class="nx">Projection</span><span class="p">(</span><span class="s2">"EPSG:4326"</span><span class="p">),</span> <span class="c1">// переобразование в WGS 1984</span>
<span class="k">new</span> <span class="nx">OpenLayers</span><span class="p">.</span><span class="nx">Projection</span><span class="p">(</span><span class="s2">"EPSG:900913"</span><span class="p">)</span> <span class="c1">// переобразование проекции</span>
<span class="p">),</span> <span class="mi">17</span> <span class="c1">// масштаб 17 крут</span>
<span class="p">);</span>
<span class="c1">//создаем новый слой оборудования</span>
<span class="kd">var</span> <span class="nx">layerMarkers</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">OpenLayers</span><span class="p">.</span><span class="nx">Layer</span><span class="p">.</span><span class="nx">Markers</span><span class="p">(</span><span class="s2">"Equipments"</span><span class="p">);</span>
<span class="nx">map</span><span class="p">.</span><span class="nx">addLayer</span><span class="p">(</span><span class="nx">layerMarkers</span><span class="p">);</span><span class="c1">//добавляем этот слой к карте</span>
<span class="c1">// Маркер текущего еквипмента</span>
<span class="kd">var</span> <span class="nx">size</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">OpenLayers</span><span class="p">.</span><span class="nx">Size</span><span class="p">(</span><span class="mi">21</span><span class="p">,</span> <span class="mi">25</span><span class="p">);</span><span class="c1">//размер картинки для маркера</span>
<span class="c1">//смещение картинки для маркера</span>
<span class="kd">var</span> <span class="nx">offset</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">OpenLayers</span><span class="p">.</span><span class="nx">Pixel</span><span class="p">(</span><span class="o">-</span><span class="p">(</span><span class="nx">size</span><span class="p">.</span><span class="nx">w</span> <span class="o">/</span> <span class="mi">2</span><span class="p">),</span> <span class="o">-</span><span class="nx">size</span><span class="p">.</span><span class="nx">h</span><span class="p">);</span>
<span class="c1">//картинка для маркера</span>
<span class="kd">var</span> <span class="nx">icon</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">OpenLayers</span><span class="p">.</span><span class="nx">Icon</span><span class="p">(</span><span class="s1">'/img/common/switch_svg.gif'</span><span class="p">,</span> <span class="nx">size</span><span class="p">,</span> <span class="nx">offset</span><span class="p">);</span>
<span class="nx">layerMarkers</span><span class="p">.</span><span class="nx">addMarker</span><span class="p">(</span><span class="c1">//добавляем маркер к слою маркеров</span>
<span class="k">new</span> <span class="nx">OpenLayers</span><span class="p">.</span><span class="nx">Marker</span><span class="p">(</span><span class="nx">lonlat</span><span class="p">,</span> <span class="c1">//координаты вставки маркера</span>
<span class="nx">icon</span><span class="p">));</span><span class="c1">//иконка маркера</span>
<span class="c1">// шкала для выбора заранее настроенного масштаба</span>
<span class="c1">//map.addControl(new OpenLayers.Control.PanZoomBar());</span>
<span class="c1">// панель инструментов (сдвиг и масштабирование)</span>
<span class="c1">//map.addControl(new OpenLayers.Control.MouseToolbar());</span>
<span class="c1">// переключатель видимости слоев</span>
<span class="nx">map</span><span class="p">.</span><span class="nx">addControl</span><span class="p">(</span><span class="k">new</span> <span class="nx">OpenLayers</span><span class="p">.</span><span class="nx">Control</span><span class="p">.</span><span class="nx">LayerSwitcher</span><span class="p">({</span><span class="s1">'ascending'</span><span class="o">:</span><span class="kc">false</span><span class="p">}));</span>
<span class="c1">// ссылка внизу карты на текущее положение/масштаб</span>
<span class="c1">//map.addControl(new OpenLayers.Control.Permalink());</span>
<span class="c1">//map.addControl(new OpenLayers.Control.Permalink('permalink'));</span>
<span class="c1">// координаты текущего положения мыши</span>
<span class="c1">// преобразование из метров в градусы с помощью proj4js</span>
<span class="nx">map</span><span class="p">.</span><span class="nx">addControl</span><span class="p">(</span>
<span class="k">new</span> <span class="nx">OpenLayers</span><span class="p">.</span><span class="nx">Control</span><span class="p">.</span><span class="nx">MousePosition</span><span class="p">({</span>
<span class="nx">displayProjection</span><span class="o">:</span> <span class="k">new</span> <span class="nx">OpenLayers</span><span class="p">.</span><span class="nx">Projection</span><span class="p">(</span><span class="s1">'EPSG:4326'</span><span class="p">)</span>
<span class="p">})</span>
<span class="p">);</span>
<span class="c1">// обзорная карта</span>
<span class="c1">//map.addControl(new OpenLayers.Control.OverviewMap());</span>
<span class="c1">// горячие клавиши</span>
<span class="c1">//map.addControl(new OpenLayers.Control.KeyboardDefaults());</span>
<span class="p">}</span>
<span class="p"></</span><span class="nt">script</span><span class="p">></span>
</pre></div>
</div>
<p>На карте добавлен слой <code class="docutils literal"><span class="pre">"Equipments"</span></code> и маркер с картинкой <code class="docutils literal"><span class="pre">switch_svg.gif</span></code>.</p>
<p>На странице вставляем тег карты:</p>
<div class="highlight-html"><div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">"OSMap"</span><span class="p">></</span><span class="nt">div</span><span class="p">></span>
</pre></div>
</div>
<p>И в тег <code class="docutils literal"><span class="pre"><body></span></code> добавляем <code class="docutils literal"><span class="pre">onload="GetMap();"</span></code>.</p>
<p>Результат:</p>
<div class="figure align-center" id="id2">
<img alt="_static/2012/osm.png" src="_static/2012/osm.png" />
<p class="caption"><span class="caption-text">OpenStreeMap пример</span></p>
</div>
<p><a class="reference external" href="http://habrahabr.ru/post/145117/">Хорошая статья на Хабре</a></p>
</div>
Набор snmp скриптов облегчающие жизнь
http://uralbash.ru/articles/2011/snmp/
2011-12-26T11:16:00Z
2011-12-26T11:16:00Z
Uralbash
<div class="section" id="snmp">
<p>Скрипты написаны на питоне, для установки достаточно форкнуть <code class="docutils literal"><span class="pre">git</span></code> репозитарий
<a class="reference external" href="https://github.com/uralbash/snmpdesk">https://github.com/uralbash/snmpdesk</a>. Документация как работать со скриптами
будет выкладываться на <code class="docutils literal"><span class="pre">github</span></code>. Сейчас пока только 1 для извлечения таблицы
коммутации (<code class="docutils literal"><span class="pre">fdb</span></code>), со временем будут появляться остальные.</p>
<p>Pull Request’ы приветствуются :)</p>
</div>
upd: Режем пики в rrd
http://uralbash.ru/articles/2011/rrd_cut2/
2011-12-21T23:02:00Z
2011-12-21T23:02:00Z
Uralbash
<div class="section" id="upd-rrd">
<p>Обновления в скрипте <a class="reference internal" href="../articles/2011/rrd_cut/#rrd_cut"><span class="std std-ref">Срезаем пики в RRD при помощи python</span></a>. В предыдущем варианте скрипт получал
предельное значение и если любое значение в <a class="reference external" href="http://oss.oetiker.ch/rrdtool/">rrd</a> файле его превышало, то
оно обнулялось. Это неудобно когда для каждого <code class="docutils literal"><span class="pre">datasource</span></code> нужно задавать
свой предел. Ниже пример где несколько строк, в каждой строке 6 значений.</p>
<div class="highlight-xml"><div class="highlight"><pre><span></span><span class="nt"><database></span>
<span class="nt"><row><v></span>1.2531404050e+04<span class="nt"></v><v></span>1.1760614140e+03<span class="nt"></v><v></span>1.0547667362e+01<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v></row></span>
<span class="nt"><row><v></span>6.2535788107e+03<span class="nt"></v><v></span>6.5077305135e+02<span class="nt"></v><v></span>5.9844172295e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v></row></span>
<span class="nt"><row><v></span>7.4349123852e+03<span class="nt"></v><v></span>7.2086196285e+02<span class="nt"></v><v></span>6.7862914917e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v></row></span>
<span class="nt"><row><v></span>6.6044470194e+03<span class="nt"></v><v></span>6.1316221529e+02<span class="nt"></v><v></span>6.2081965076e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v></row></span>
<span class="nt"><row><v></span>1.6377377735e+04<span class="nt"></v><v></span>2.8213539887e+03<span class="nt"></v><v></span>1.4662221016e+01<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v></row></span>
<span class="nt"><row><v></span>1.4991881969e+04<span class="nt"></v><v></span>1.9741971231e+03<span class="nt"></v><v></span>1.3208469357e+01<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v></row></span>
...
<span class="nt"></database></span>
</pre></div>
</div>
<p>Намного юзабильней когда можно задать для каждого из этих 6 значений своё
ограничение. Код и примеры брать здесь
<a class="reference external" href="https://github.com/uralbash/rrd_killerpeak">https://github.com/uralbash/rrd_killerpeak</a></p>
</div>
Как поднять demo версию проекта на paster + virtualenv в Debian
http://uralbash.ru/articles/2011/demo/
2011-12-19T11:48:00Z
2011-12-19T11:48:00Z
Uralbash
<div class="section" id="demo-paster-virtualenv-debian">
<p>Иногда необходимо поднять демо версию своего проекта для тестов. Склонируем
наш <code class="docutils literal"><span class="pre">git</span></code> проект на сервер где будет демо:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ git clone --bare ~/myproject ssh://uralbash@myserver/~/my_project.git
</pre></div>
</div>
<p>Проект склонируется в домашнюю директорию сервера <code class="docutils literal"><span class="pre">myserver</span></code>. Ключ <code class="docutils literal"><span class="pre">--bare</span></code>
означает что клон предназначен только для <code class="docutils literal"><span class="pre">push</span></code> или <code class="docutils literal"><span class="pre">pull</span></code> т.е. все
коммиты мы будем делать у себя локально а потом пушить на сервак. Далее напишем
скрипт который будет из нашего bare репозитария создавать проект для запуска демки:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ rm -r /home/uralbash/my_project
$ git clone /home/uralbash/my_project.git /home/uralbash/my_project
</pre></div>
</div>
<p>После этого создаем <a class="reference external" href="https://virtualenv.pypa.io/en/latest">virtualenv</a> окружение (<code class="docutils literal"><span class="pre">/home/uralbash/mypythonenv/</span></code>)
и добавляем скрипт запуска в <code class="docutils literal"><span class="pre">/etc/init.d/my_project.sh</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="ch">#! /bin/sh</span>
<span class="c1">### BEGIN INIT INFO</span>
<span class="c1"># Required-Start: $all</span>
<span class="c1"># Default-Start: 2 3 4 5</span>
<span class="c1"># Default-Stop: 0 1 6</span>
<span class="c1"># Short-Description: starts the paster server</span>
<span class="c1"># Description: starts paster</span>
<span class="c1">### END INIT INFO</span>
<span class="nv">PROJECT</span><span class="o">=</span>/home/uralbash/my_project
<span class="nv">PID_DIR</span><span class="o">=</span>/var/run/my_project/
<span class="nv">PID_FILE</span><span class="o">=</span>/var/run/my_project/paster.pid
<span class="nv">LOG_FILE</span><span class="o">=</span>/home/uralbash/logs/my_project/paster.log
<span class="nv">USER</span><span class="o">=</span>root
<span class="nv">GROUP</span><span class="o">=</span>root
<span class="nv">PROD_FILE</span><span class="o">=</span>/home/uralbash/demo.ini
<span class="nv">RET_VAL</span><span class="o">=</span><span class="m">0</span>
<span class="nb">cd</span> <span class="nv">$PROJECT</span>
<span class="k">case</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span> in
start<span class="o">)</span>
../mypythonenv/bin/paster serve <span class="se">\</span>
--daemon <span class="se">\</span>
--pid-file<span class="o">=</span><span class="nv">$PID_FILE</span> <span class="se">\</span>
--log-file<span class="o">=</span><span class="nv">$LOG_FILE</span> <span class="se">\</span>
--user<span class="o">=</span><span class="nv">$USER</span> <span class="se">\</span>
--group<span class="o">=</span><span class="nv">$GROUP</span> <span class="se">\</span>
<span class="nv">$PROD_FILE</span> <span class="se">\</span>
start
<span class="p">;;</span>
stop<span class="o">)</span>
../mypythonenv/bin/paster serve <span class="se">\</span>
--daemon <span class="se">\</span>
--pid-file<span class="o">=</span><span class="nv">$PID_FILE</span> <span class="se">\</span>
--log-file<span class="o">=</span><span class="nv">$LOG_FILE</span> <span class="se">\</span>
--user<span class="o">=</span><span class="nv">$USER</span> <span class="se">\</span>
--group<span class="o">=</span><span class="nv">$GROUP</span> <span class="se">\</span>
<span class="nv">$PROD_FILE</span> <span class="se">\</span>
stop
<span class="p">;;</span>
restart<span class="o">)</span>
../mypythonenv/bin/paster serve <span class="se">\</span>
--daemon <span class="se">\</span>
--pid-file<span class="o">=</span><span class="nv">$PID_FILE</span> <span class="se">\</span>
--log-file<span class="o">=</span><span class="nv">$LOG_FILE</span> <span class="se">\</span>
--user<span class="o">=</span><span class="nv">$USER</span> <span class="se">\</span>
--group<span class="o">=</span><span class="nv">$GROUP</span> <span class="se">\</span>
<span class="nv">$PROD_FILE</span> <span class="se">\</span>
restart
<span class="p">;;</span>
*<span class="o">)</span>
<span class="nb">echo</span> $<span class="s2">"Usage: </span><span class="nv">$0</span><span class="s2"> {start|stop|restart}"</span>
<span class="nb">exit</span> <span class="m">1</span>
<span class="k">esac</span>
</pre></div>
</div>
<p>Для того что бы не хранить пароли в репозитарии файл с настройками вынесен
отдельно <code class="docutils literal"><span class="pre">/home/uralbash/demo.ini</span></code>:</p>
<p>И добавляем в крон перезапуск:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># выполнять каждый четный час в 00 мин</span>
<span class="m">0</span> */2 * * * /etc/init.d/my_project.sh stop > /dev/null
<span class="c1"># выполнять каждый четный час в 01 мин</span>
<span class="m">1</span> */2 * * * /etc/init.d/my_project.sh start > /dev/null
<span class="c1"># выполнять в 9:00</span>
<span class="m">0</span> <span class="m">9</span> * * * /home/uralbash/demo_update.sh > /dev/null
</pre></div>
</div>
<p>После этого каждый день в 9:00 будет обновляться код и каждые 2 часа
перезапускаться сервер (на случай если он полег по какойто причине). Останется
только периодически отправлять коммиты.</p>
</div>
FormAlchemy KeyError: "Key not found: "
http://uralbash.ru/articles/2011/fa_keyerror/
2011-12-18T22:51:00Z
2011-12-18T22:51:00Z
Uralbash
<div class="section" id="formalchemy-keyerror-key-not-found">
<p>Ошибка в <a class="reference external" href="http://docs.formalchemy.org/">FormAlchemy</a> типа <code class="docutils literal"><span class="pre">KeyError:</span> <span class="pre">"Key</span> <span class="pre">not</span> <span class="pre">found:</span>
<span class="pre">u'Task--super_task_id'"</span></code> лечится обновлением:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ pip install formalchemy --upgrade
</pre></div>
</div>
<p>При этом новая версия подтянет бетта версию <a class="reference external" href="http://docs.webob.org/en/latest/">webob</a> 1.2 с которым
<a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">pylons</a> 1 еще не работает из-за:</p>
<p><code class="docutils literal"><span class="pre">DeprecationWarning:</span> <span class="pre">decode_param_names</span> <span class="pre">is</span> <span class="pre">deprecated</span> <span class="pre">and</span> <span class="pre">will</span> <span class="pre">not</span> <span class="pre">be</span> <span class="pre">supported</span> <span class="pre">starting</span> <span class="pre">with</span> <span class="pre">WebOb</span> <span class="pre">1.2</span></code></p>
<p>Откатимся:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ pip install <span class="nv">webob</span><span class="o">==</span><span class="m">1</span>.1.1
</pre></div>
</div>
<p>Ошибка должна исчезнуть, вот обсуждение <a class="reference external" href="http://groups.google.com/group/formalchemy/browse_thread/thread/19348cc5faae8711/3aaf49efffd9f160?lnk=gst&q=key+not+found#3aaf49efffd9f160">google groups</a></p>
</div>
Установка psycopg2 в virtualenv для Postgres 9.1
http://uralbash.ru/articles/2011/psycopg2/
2011-12-16T18:45:00Z
2011-12-16T18:45:00Z
Uralbash
<div class="section" id="psycopg2-virtualenv-postgres-9-1">
<p>При установке <a class="reference external" href="http://initd.org/psycopg/">psycopg</a> в <a class="reference external" href="https://virtualenv.pypa.io/en/latest">virtualenv</a> может возникнуть ошибка:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="o">(</span>mypythonenv<span class="o">)</span>uralbash@server:~$ pip install psycopg
Downloading/unpacking psycopg
Downloading psycopg2-2.4.3.tar.gz <span class="o">(</span>687Kb<span class="o">)</span>: 687Kb downloaded
Running setup.py egg_info <span class="k">for</span> package psycopg
Error: You need to install postgresql-server-dev-X.Y <span class="k">for</span> building a server-side extension or libpq-dev <span class="k">for</span> building a client-side application.
Complete output from <span class="nb">command</span> python setup.py egg_info:
running egg_info
creating pip-egg-info/psycopg2.egg-info
writing pip-egg-info/psycopg2.egg-info/PKG-INFO
writing top-level names to pip-egg-info/psycopg2.egg-info/top_level.txt
writing dependency_links to pip-egg-info/psycopg2.egg-info/dependency_links.txt
writing manifest file <span class="s1">'pip-egg-info/psycopg2.egg-info/SOURCES.txt'</span>
warning: manifest_maker: standard file <span class="s1">'-c'</span> not found
Error: You need to install postgresql-server-dev-X.Y <span class="k">for</span> building a server-side extension or libpq-dev <span class="k">for</span> building a client-side application.
----------------------------------------
Command python setup.py egg_info failed with error code <span class="m">1</span>
Storing <span class="nb">complete</span> log in /home/uralbash/.pip/pip.log
</pre></div>
</div>
<p>Это возникает из-за утилиты <code class="docutils literal"><span class="pre">pg_config</span></code> которая требуется для установки <a class="reference external" href="http://initd.org/psycopg/">psycopg</a>.
В случае если у Вас <a class="reference external" href="http://postgresql.org">Postgres</a> 8.4 нужно добавить <code class="docutils literal"><span class="pre">pg_config</span></code> в <code class="docutils literal"><span class="pre">PATH</span></code> (как то
так <code class="docutils literal"><span class="pre">PATH=$PATH:/usr/bin/</span></code>). Путь до <code class="docutils literal"><span class="pre">pg_config</span></code> можно узнать:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ whereis pg_config
pg_config: /usr/bin/pg_config
</pre></div>
</div>
<p>И установить пакеты:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo apt-get install libpq-dev python-dev
</pre></div>
</div>
<p>Но если стоит 9.1 версия то может возникнуть ошибка:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>Reading package lists... Done
Building dependency tree
Reading state information... Done
Some packages could not be installed. This may mean that you have
requested an impossible situation or <span class="k">if</span> you are using the unstable
distribution that some required packages have not yet been created
or been moved out of Incoming.
The following information may <span class="nb">help</span> to resolve the situation:
The following packages have unmet dependencies:
libpq-dev : Depends: libpq5 <span class="o">(=</span> <span class="m">8</span>.4.9-0squeeze1<span class="o">)</span> but <span class="m">9</span>.1.1-1~bpo60+1 is to be installed
E: Broken packages
</pre></div>
</div>
<p>В этом случае устанавливаем <a class="reference external" href="http://initd.org/psycopg/">psycopg</a> не в окружении через:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo pip install psycopg2
</pre></div>
</div>
<p>Смотрим куда это встало:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo python -c <span class="s2">"import psycopg2;print psycopg2.__file__"</span>
/usr/lib/python2.6/dist-packages/psycopg2/__init__.pyc
</pre></div>
</div>
<p>И копируем к себе в lib’ы в <a class="reference external" href="https://virtualenv.pypa.io/en/latest">virtualenv</a>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo cp -r /usr/lib/python2.6/dist-packages/psycopg2 mypythonenv/lib/python2.6/site-packages/
</pre></div>
</div>
<p>Копипастим яйцо:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo cp /usr/lib/python2.6/dist-packages/psycopg2-2.4.4.egg-info mypythonenv/lib/python2.6/site-packages/
</pre></div>
</div>
<p>Еще надо будет скопировать <code class="docutils literal"><span class="pre">mx</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo cp -r /usr/lib/python2.6/dist-packages/mx mypythonenv/lib/python2.6/site-packages/
</pre></div>
</div>
<p>Жеский дьютихак но главное что работает малой кровью.</p>
</div>
Срезаем пики в RRD при помощи python
http://uralbash.ru/articles/2011/rrd_cut/
2011-12-09T10:47:00Z
2011-12-09T10:47:00Z
Uralbash
<div class="section" id="rrd-python">
<span id="rrd-cut"></span>
<p>В некоторых случаях на <a class="reference external" href="http://oss.oetiker.ch/rrdtool/">rrd</a> графиках появляются пики, как например после
перезагрузки сетевой карты:</p>
<div class="figure align-center" id="id1">
<img alt="_static/2011/rrd_pick.png" src="_static/2011/rrd_pick.png" />
<p class="caption"><span class="caption-text">пики в rrd</span></p>
</div>
<p>Для их удаления нам нужно воспользоваться утилитой <code class="docutils literal"><span class="pre">dump</span></code> из <a class="reference external" href="http://oss.oetiker.ch/rrdtool/">rrdtool</a>,
которая переводит файл <a class="reference external" href="http://oss.oetiker.ch/rrdtool/">rrd</a> в формат xml. Затем обнулить значение пиков и
записать изменения обратно в <a class="reference external" href="http://oss.oetiker.ch/rrdtool/">rrd</a> файл при помощи утилиты restore. На оф.
сайте <a class="reference external" href="http://oss.oetiker.ch/rrdtool/">rrdtool</a> можно найти скрипт на <a class="reference external" href="http://perl.org/">perl</a> <code class="docutils literal"><span class="pre">removespikes</span></code> и на
<a class="reference external" href="http://php.net/">php</a> для <code class="docutils literal"><span class="pre">cacti</span></code> <code class="docutils literal"><span class="pre">spikekill</span></code>. <code class="docutils literal"><span class="pre">removespike</span></code> работает не всегда
корректно, поэтому рассмотрим как можно обрезать графики при помощи скрипта на
<a class="reference external" href="http://www.python.org/">python</a>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="ch">#!/usr/bin/env python</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">shutil</span>
<span class="kn">from</span> <span class="nn">xml.etree</span> <span class="kn">import</span> <span class="n">ElementTree</span> <span class="k">as</span> <span class="n">ET</span>
<span class="kn">from</span> <span class="nn">optparse</span> <span class="kn">import</span> <span class="n">OptionParser</span>
<span class="n">__version__</span> <span class="o">=</span> <span class="s1">'0.1'</span>
<span class="k">def</span> <span class="nf">get_configuration</span><span class="p">():</span>
<span class="n">parser</span> <span class="o">=</span> <span class="n">OptionParser</span><span class="p">(</span><span class="n">version</span><span class="o">=</span><span class="s2">"%prog v"</span> <span class="o">+</span> <span class="n">__version__</span><span class="p">,</span>
<span class="n">usage</span><span class="o">=</span><span class="s2">"%prog <filename>"</span><span class="p">)</span>
<span class="n">parser</span><span class="o">.</span><span class="n">add_option</span><span class="p">(</span><span class="s2">"-v"</span><span class="p">,</span> <span class="s2">"--verbose"</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s2">"count"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span>
<span class="n">help</span><span class="o">=</span><span class="s2">"produce more output"</span><span class="p">)</span>
<span class="n">parser</span><span class="o">.</span><span class="n">add_option</span><span class="p">(</span><span class="s1">'-b'</span><span class="p">,</span> <span class="s1">'--border'</span><span class="p">,</span> <span class="n">action</span> <span class="o">=</span><span class="s1">'store'</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="mi">10</span><span class="o">**</span><span class="mi">10</span><span class="p">,</span>
<span class="n">help</span><span class="o">=</span><span class="s1">'Min value of peak. Default 100000'</span><span class="p">)</span>
<span class="n">options</span><span class="p">,</span> <span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
<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">args</span><span class="p">[</span><span class="mi">0</span><span class="p">]):</span>
<span class="n">parser</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">"Not found file"</span><span class="p">)</span>
<span class="k">return</span> <span class="p">[</span> <span class="n">options</span> <span class="p">]</span> <span class="o">+</span> <span class="n">args</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="n">options</span><span class="p">,</span> <span class="n">filename</span> <span class="o">=</span> <span class="n">get_configuration</span><span class="p">()</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">rrd_dump</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">system</span><span class="p">(</span><span class="s2">"rrdtool dump '</span><span class="si">%s</span><span class="s2">' > 'old.xml'"</span> <span class="o">%</span> <span class="p">(</span><span class="n">filename</span><span class="p">))</span>
<span class="k">except</span><span class="p">:</span>
<span class="k">print</span> <span class="s2">"Error RRD file type"</span>
<span class="k">raise</span>
<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">exists</span><span class="p">(</span><span class="s1">'rrd_bak'</span><span class="p">):</span>
<span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="s1">'rrd_bak'</span><span class="p">)</span>
<span class="n">shutil</span><span class="o">.</span><span class="n">copy2</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s1">'rrd_bak'</span><span class="p">)</span>
<span class="n">tree</span> <span class="o">=</span> <span class="n">ET</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="s1">'old.xml'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">iterparent</span><span class="p">(</span><span class="n">tree</span><span class="p">):</span>
<span class="k">for</span> <span class="n">parent</span> <span class="ow">in</span> <span class="n">tree</span><span class="o">.</span><span class="n">getiterator</span><span class="p">():</span>
<span class="k">for</span> <span class="n">child</span> <span class="ow">in</span> <span class="n">parent</span><span class="p">:</span>
<span class="k">yield</span> <span class="n">parent</span><span class="p">,</span> <span class="n">child</span>
<span class="k">for</span> <span class="n">parent</span><span class="p">,</span> <span class="n">child</span> <span class="ow">in</span> <span class="n">iterparent</span><span class="p">(</span><span class="n">tree</span><span class="p">):</span>
<span class="k">if</span> <span class="n">child</span><span class="o">.</span><span class="n">tag</span> <span class="o">==</span> <span class="s1">'v'</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">float</span><span class="p">(</span><span class="n">child</span><span class="o">.</span><span class="n">text</span><span class="p">)</span> <span class="o">></span> <span class="n">options</span><span class="o">.</span><span class="n">border</span><span class="p">:</span>
<span class="k">print</span> <span class="s1">'peak detect in </span><span class="si">%s</span><span class="s1">'</span> <span class="o">%</span> <span class="n">filename</span>
<span class="n">child</span><span class="o">.</span><span class="n">text</span> <span class="o">=</span> <span class="s1">'NaN'</span>
<span class="n">tree</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s1">'new.xml'</span><span class="p">)</span>
<span class="n">os</span><span class="o">.</span><span class="n">unlink</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
<span class="n">os</span><span class="o">.</span><span class="n">system</span><span class="p">(</span><span class="s2">"rrdtool restore 'new.xml' '</span><span class="si">%s</span><span class="s2">'"</span> <span class="o">%</span> <span class="n">filename</span><span class="p">)</span>
<span class="n">os</span><span class="o">.</span><span class="n">unlink</span><span class="p">(</span><span class="s1">'new.xml'</span><span class="p">)</span>
<span class="n">os</span><span class="o">.</span><span class="n">unlink</span><span class="p">(</span><span class="s1">'old.xml'</span><span class="p">)</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>
</pre></div>
</div>
<p>Для того что бы парсить параметры командной строки воспользуемся модулем
<a class="reference external" href="https://docs.python.org/3/library/optparse.html#module-optparse" title="(в Python v3.10)"><code class="xref py py-mod docutils literal"><span class="pre">optparse</span></code></a>.</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">get_configuration</span><span class="p">():</span>
<span class="n">parser</span> <span class="o">=</span> <span class="n">OptionParser</span><span class="p">(</span><span class="n">version</span><span class="o">=</span><span class="s2">"%prog v"</span> <span class="o">+</span> <span class="n">__version__</span><span class="p">,</span>
<span class="n">usage</span><span class="o">=</span><span class="s2">"%prog <filename>"</span><span class="p">)</span>
<span class="n">parser</span><span class="o">.</span><span class="n">add_option</span><span class="p">(</span><span class="s2">"-v"</span><span class="p">,</span> <span class="s2">"--verbose"</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s2">"count"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span>
<span class="n">help</span><span class="o">=</span><span class="s2">"produce more output"</span><span class="p">)</span>
<span class="n">parser</span><span class="o">.</span><span class="n">add_option</span><span class="p">(</span><span class="s1">'-b'</span><span class="p">,</span> <span class="s1">'--border'</span><span class="p">,</span> <span class="n">action</span> <span class="o">=</span><span class="s1">'store'</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="mi">10</span><span class="o">**</span><span class="mi">10</span><span class="p">,</span>
<span class="n">help</span><span class="o">=</span><span class="s1">'Min value of peak. Default 100000'</span><span class="p">)</span>
<span class="n">options</span><span class="p">,</span> <span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
<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">args</span><span class="p">[</span><span class="mi">0</span><span class="p">]):</span>
<span class="n">parser</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">"Not found file"</span><span class="p">)</span>
<span class="k">return</span> <span class="p">[</span> <span class="n">options</span> <span class="p">]</span> <span class="o">+</span> <span class="n">args</span>
</pre></div>
</div>
<p>Дампим <a class="reference external" href="http://oss.oetiker.ch/rrdtool/">rrd</a> файл в xml:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">try</span><span class="p">:</span>
<span class="n">rrd_dump</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">system</span><span class="p">(</span><span class="s2">"rrdtool dump '</span><span class="si">%s</span><span class="s2">' > 'old.xml'"</span> <span class="o">%</span> <span class="p">(</span><span class="n">filename</span><span class="p">))</span>
<span class="k">except</span><span class="p">:</span>
<span class="k">print</span> <span class="s2">"Error RRD file type"</span>
<span class="k">raise</span>
</pre></div>
</div>
<p>На всякий случай копируем старый <a class="reference external" href="http://oss.oetiker.ch/rrdtool/">rrd</a> в папку <code class="docutils literal"><span class="pre">rrd_bak</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><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">exists</span><span class="p">(</span><span class="s1">'rrd_bak'</span><span class="p">):</span>
<span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="s1">'rrd_bak'</span><span class="p">)</span>
<span class="n">shutil</span><span class="o">.</span><span class="n">copy2</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s1">'rrd_bak'</span><span class="p">)</span>
</pre></div>
</div>
<p>Функция для получения списка всех элементов из xml:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">iterparent</span><span class="p">(</span><span class="n">tree</span><span class="p">):</span>
<span class="k">for</span> <span class="n">parent</span> <span class="ow">in</span> <span class="n">tree</span><span class="o">.</span><span class="n">getiterator</span><span class="p">():</span>
<span class="k">for</span> <span class="n">child</span> <span class="ow">in</span> <span class="n">parent</span><span class="p">:</span>
<span class="k">yield</span> <span class="n">parent</span><span class="p">,</span> <span class="n">child</span>
</pre></div>
</div>
<p>Записи в xml выглядят так:</p>
<div class="highlight-xml"><div class="highlight"><pre><span></span><span class="nt"><database></span>
<span class="nt"><row><v></span>1.2531404050e+04<span class="nt"></v><v></span>1.1760614140e+03<span class="nt"></v><v></span>1.0547667362e+01<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v></row></span>
<span class="nt"><row><v></span>6.2535788107e+03<span class="nt"></v><v></span>6.5077305135e+02<span class="nt"></v><v></span>5.9844172295e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v></row></span>
<span class="nt"><row><v></span>7.4349123852e+03<span class="nt"></v><v></span>7.2086196285e+02<span class="nt"></v><v></span>6.7862914917e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v></row></span>
<span class="nt"><row><v></span>6.6044470194e+03<span class="nt"></v><v></span>6.1316221529e+02<span class="nt"></v><v></span>6.2081965076e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v></row></span>
<span class="nt"><row><v></span>1.6377377735e+04<span class="nt"></v><v></span>2.8213539887e+03<span class="nt"></v><v></span>1.4662221016e+01<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v></row></span>
<span class="nt"><row><v></span>1.4991881969e+04<span class="nt"></v><v></span>1.9741971231e+03<span class="nt"></v><v></span>1.3208469357e+01<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v><v></span>0.0000000000e+00<span class="nt"></v></row></span>
...
<span class="nt"></database></span>
</pre></div>
</div>
<p>Пробегаем по всем тегам и ищем значения которые больше порогового 10 в степени
10 и записываем нулевое значение (<code class="docutils literal"><span class="pre">NaN</span></code>):</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">parent</span><span class="p">,</span> <span class="n">child</span> <span class="ow">in</span> <span class="n">iterparent</span><span class="p">(</span><span class="n">tree</span><span class="p">):</span>
<span class="k">if</span> <span class="n">child</span><span class="o">.</span><span class="n">tag</span> <span class="o">==</span> <span class="s1">'v'</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">float</span><span class="p">(</span><span class="n">child</span><span class="o">.</span><span class="n">text</span><span class="p">)</span> <span class="o">></span> <span class="n">options</span><span class="o">.</span><span class="n">border</span><span class="p">:</span>
<span class="k">print</span> <span class="s1">'peak detect in </span><span class="si">%s</span><span class="s1">'</span> <span class="o">%</span> <span class="n">filename</span>
<span class="n">child</span><span class="o">.</span><span class="n">text</span> <span class="o">=</span> <span class="s1">'NaN'</span>
</pre></div>
</div>
<p>Сохраняем xml и импортируем изменения в <a class="reference external" href="http://oss.oetiker.ch/rrdtool/">rrd</a>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">tree</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s1">'new.xml'</span><span class="p">)</span>
<span class="n">os</span><span class="o">.</span><span class="n">system</span><span class="p">(</span><span class="s2">"rrdtool restore 'new.xml' '</span><span class="si">%s</span><span class="s2">'"</span> <span class="o">%</span> <span class="n">filename</span><span class="p">)</span>
</pre></div>
</div>
<p>Полученный результат:</p>
<div class="figure align-center" id="id2">
<img alt="_static/2011/rrd_cut_pick.png" src="_static/2011/rrd_cut_pick.png" />
<p class="caption"><span class="caption-text">rrd график без пиков</span></p>
</div>
<p>Скрипт на <code class="docutils literal"><span class="pre">bash</span></code> для удаления пиков во всей директории:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="ch">#!/bin/bash</span>
<span class="k">if</span> <span class="o">[</span> -a <span class="nv">$1</span> <span class="o">]</span>
<span class="k">then</span>
<span class="k">for</span> file in <span class="nv">$1</span>*
<span class="k">do</span>
<span class="nb">echo</span> <span class="nv">$file</span>
python killerpeak.py <span class="nv">$file</span>
<span class="k">done</span>
<span class="k">fi</span>
<span class="nb">echo</span> <span class="s2">"Don't forget delete directory rrd_bak if all is ok"</span>
<span class="nb">exit</span> <span class="m">0</span>
</pre></div>
</div>
<p>Запуск скрипта <code class="docutils literal"><span class="pre">killerpeak.py</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo ./killerpeak.py data/rrdfile/7890.rrd
peak detect in data/rrdfile/7890.rrd
peak detect in data/rrdfile/7890.rrd
peak detect in data/rrdfile/7890.rrd
peak detect in data/rrdfile/7890.rrd
</pre></div>
</div>
<p>Запуск скрипта на <code class="docutils literal"><span class="pre">bash</span></code> <code class="docutils literal"><span class="pre">killpeak.sh</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ ./killpeak.sh data/rrdfile
</pre></div>
</div>
<p>Взять код или поправить можно на <a class="reference external" href="https://github.com/">github</a> <a class="reference external" href="https://github.com/uralbash/rrd_killerpeak">https://github.com/uralbash/rrd_killerpeak</a></p>
</div>
Основы CouchDB
http://uralbash.ru/articles/2011/couchdb/
2011-11-28T10:53:00Z
2011-11-28T10:53:00Z
Uralbash
<div class="section" id="couchdb">
<span id="wtforms"></span>
<img alt="_static/2011/couchdb.jpg" class="align-left" src="_static/2011/couchdb.jpg" />
<p><a class="reference external" href="http://couchdb.apache.org/">CouchDB</a> - документо-ориентированная СУБД, в которой удобно хранить разную
информацию с изменяющимся количеством параметров. Например сущность товары
могут иметь бесконечное количество параметров. Создавать в РСУБД миллионы
таблиц или одну огромную не вариант. В <a class="reference external" href="http://couchdb.apache.org/">couchdb</a> хранятся документы, т.е.
простые записи. В записи может быть сколько угодно разных параметров. А для
унификации записей обычно создают параметр type который заменяет имя таблицы в
РСУБД.</p>
<br clear="both"/><div class="section" id="id1">
<h2>Установка</h2>
<div class="section" id="debian">
<h3>Debian</h3>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo apt-get install couchdb
</pre></div>
</div>
</div>
<div class="section" id="from-source">
<h3>From source</h3>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ wget http://erlang.org/download/otp_src_R12B-5.tar.gz
$ tar -xvzf otp_src_R12B-5.tar.gz
$ <span class="nb">cd</span> otp_src_R12B-5
$ ./configure
$ sudo make <span class="o">&&</span> make install
$ wget http://download.filehat.com/apache/incubator/couchdb/0.8.1-incubating/apache-couchdb-0.8.1-incubating.tar.gz
$ tar -xvzf apache-couchdb-0.8.1-incubating.tar.gz
$ <span class="nb">cd</span> apache-couchdb-0.8.1-incubating
$ ./configure
$ sudo make <span class="o">&&</span> make install
</pre></div>
</div>
</div>
<div class="section" id="macos-android-ios">
<h3>MacOS, Android, iOS</h3>
<p><a class="reference external" href="http://www.couchbase.com/downloads">http://www.couchbase.com/downloads</a></p>
<p><a class="reference external" href="http://couchdb.apache.org/">CouchDB</a> можно установить на смартфон, причем он может работать как
автономно, так и в режиме репликации когда появляется связь с основной базой.</p>
</div>
</div>
<div class="section" id="futon">
<h2>Futon</h2>
<p><a class="reference external" href="https://couchdb.readthedocs.org/en/1.4.x/intro.html">Futon</a> это веб интерфейс для управления <a class="reference external" href="http://couchdb.apache.org/">CouchDB</a>, что то типа <a class="reference external" href="http://phpmyadmin.net/">phpmyadmin</a>. После
запуска <a class="reference external" href="http://couchdb.apache.org/">CouchDB</a> появится доступ к <a class="reference external" href="https://couchdb.readthedocs.org/en/1.4.x/intro.html">Futon</a> по <a class="reference external" href="http://127.0.0.1:5984/">http://127.0.0.1:5984/</a>. Для того что
бы увидеть инструменты Futon нужно перейти на <a class="reference external" href="http://127.0.0.1:5984/_utils/">http://127.0.0.1:5984/_utils/</a></p>
<div class="figure align-center" id="id7">
<img alt="_static/2011/couchdb1.png" src="_static/2011/couchdb1.png" />
<p class="caption"><span class="caption-text">Couchdb Futon</span></p>
</div>
<p>Все манипуляции с базой происходят через http при помощи <a class="reference external" href="https://ru.wikipedia.org/wiki/REST">REST</a> интерфейса.
Поэтому можно пользоваться как браузером, так и curl или например модулем urllib в
python. <a class="reference external" href="https://couchdb.readthedocs.org/en/1.4.x/intro.html">Futon</a> использует для запросов плагин на <a class="reference external" href="https://jquery.org/">jQuery</a>. Посмотреть его можно
здесь: <a class="reference external" href="http://127.0.0.1:5984/_utils/script/jquery.couch.js">http://127.0.0.1:5984/_utils/script/jquery.couch.js</a></p>
</div>
<div class="section" id="id2">
<h2>Пользователи</h2>
<p>По умолчанию к <a class="reference external" href="http://couchdb.apache.org/">CouchDB</a> открыт доступ всем, но его можно ограничить нажав
на “Welcome to Admin Party! Everyone is admin. Fix this” в нижнем правом углу.</p>
</div>
<div class="section" id="id3">
<h2>Создание документа</h2>
<p>Вначале создадим базу (тоже кстати документ), нажимаем “Create Database...” и
вводим название, дальше нажимаем “New document” и заводим значения:</p>
<div class="figure align-center" id="id8">
<img alt="_static/2011/couchdb2.png" src="_static/2011/couchdb2.png" />
<p class="caption"><span class="caption-text">CouchDB создание документа</span></p>
</div>
<p>Для сохранения нажимаем “Save document”. Как видно можно вводить русские
названия параметров. Поле _id формируется автоматически при создании. Поле _rev
формируется автоматически при каждом изменении, первая цифра означает
количество изменений. _rev используется для внутренних служб системы при
репликации.</p>
</div>
<div class="section" id="curl">
<h2>Создание документа с помощью cURL</h2>
<p>Данные в <a class="reference external" href="http://couchdb.apache.org/">CouchDB</a> обрабатываются в формате JSON. Создадим документ <code class="docutils literal"><span class="pre">giant.json</span></code>:</p>
<div class="literal-block-wrapper docutils container" id="id9">
<div class="code-block-caption"><span class="caption-text">giant.json</span></div>
<div class="highlight-json"><div class="highlight"><pre><span></span><span class="p">{</span>
<span class="nt">"manufacture"</span><span class="p">:</span> <span class="s2">"Giant"</span><span class="p">,</span>
<span class="nt">"model"</span><span class="p">:</span> <span class="s2">"REVEL 2"</span><span class="p">,</span>
<span class="nt">"цвет"</span><span class="p">:</span> <span class="s2">"синий"</span><span class="p">,</span>
<span class="nt">"цена"</span><span class="p">:</span> <span class="mi">16000</span><span class="p">,</span>
<span class="nt">"type"</span><span class="p">:</span> <span class="s2">"bike"</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
<p>Для вставки этого документа введем в консоле:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ curl -X POST http://127.0.0.1:5984/test/ -d @giant.json -H <span class="s2">"Content-Type: application/json"</span>
</pre></div>
</div>
<p>В базе появится документ типа:</p>
<div class="highlight-json"><div class="highlight"><pre><span></span><span class="p">{</span><span class="nt">"ok"</span><span class="p">:</span><span class="kc">true</span><span class="p">,</span><span class="nt">"id"</span><span class="p">:</span><span class="s2">"08601f0b9d3574a116ee390bf0000f44"</span><span class="p">,</span><span class="nt">"rev"</span><span class="p">:</span><span class="s2">"1-67d8f0ad3100d85952dbb17ba68b08eb"</span><span class="p">}</span>
</pre></div>
</div>
<p>Принятые правила в <a class="reference external" href="https://ru.wikipedia.org/wiki/REST">REST</a>:</p>
<div class="line-block">
<div class="line"><code class="docutils literal"><span class="pre">POST</span></code> – создать новую запись</div>
<div class="line"><code class="docutils literal"><span class="pre">GET</span></code> – получить значения</div>
<div class="line"><code class="docutils literal"><span class="pre">PUT</span></code> – обновить записи</div>
<div class="line"><code class="docutils literal"><span class="pre">DELETE</span></code> – удалить</div>
</div>
</div>
<div class="section" id="id4">
<h2>Выбрать все записи</h2>
<p>В <a class="reference external" href="http://couchdb.apache.org/">CouchDB</a> есть view которые по определенным условиям фильтруют данные.
Выбор всех данных это стандартная <code class="docutils literal"><span class="pre">view</span> <span class="pre">_all_docs</span></code>.</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ curl -X GET http://127.0.0.1:5984/mycouchshop/_all_docs
</pre></div>
</div>
<p>Получим:</p>
<div class="highlight-json"><div class="highlight"><pre><span></span><span class="p">{</span><span class="nt">"total_rows"</span><span class="p">:</span><span class="mi">2</span><span class="p">,</span><span class="nt">"offset"</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span class="nt">"rows"</span><span class="p">:[</span>
<span class="p">{</span><span class="nt">"id"</span><span class="p">:</span><span class="s2">"08601f0b9d3574a116ee390bf0000f44"</span><span class="p">,</span><span class="nt">"key"</span><span class="p">:</span><span class="s2">"08601f0b9d3574a116ee390bf0000f44"</span><span class="p">,</span><span class="nt">"value"</span><span class="p">:{</span><span class="nt">"rev"</span><span class="p">:</span><span class="s2">"1-67d8f0ad3100d85952dbb17ba68b08eb"</span><span class="p">}},</span>
<span class="p">{</span><span class="nt">"id"</span><span class="p">:</span><span class="s2">"2f6904cbb5d279fbdbb9e9eef40015ec"</span><span class="p">,</span><span class="nt">"key"</span><span class="p">:</span><span class="s2">"2f6904cbb5d279fbdbb9e9eef40015ec"</span><span class="p">,</span><span class="nt">"value"</span><span class="p">:{</span><span class="nt">"rev"</span><span class="p">:</span><span class="s2">"3-6d0577a0a515178f0cd939b5caa19572"</span><span class="p">}}</span>
<span class="p">]}</span>
</pre></div>
</div>
</div>
<div class="section" id="id5">
<h2>Создание представлений</h2>
<p>Представления работают по принципу <code class="docutils literal"><span class="pre">map/reduce</span></code>:</p>
<div class="line-block">
<div class="line"><code class="docutils literal"><span class="pre">map</span></code> - это выбор и фильтрация документов</div>
<div class="line"><code class="docutils literal"><span class="pre">reduce</span></code> - это последующая обработка данных</div>
</div>
<p>Простая <code class="docutils literal"><span class="pre">map</span></code> функция:</p>
<div class="highlight-javascript"><div class="highlight"><pre><span></span><span class="kd">function</span> <span class="p">(</span><span class="nx">doc</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">doc</span><span class="p">.</span><span class="nx">type</span> <span class="o">===</span> <span class="s2">"bike"</span> <span class="o">&&</span> <span class="nx">doc</span><span class="p">.</span><span class="nx">manufacture</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">emit</span><span class="p">(</span><span class="nx">doc</span><span class="p">.</span><span class="nx">manufacture</span><span class="p">,</span> <span class="nx">doc</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Функции создаются в правом верхнем углу в <code class="docutils literal"><span class="pre">Temporary</span> <span class="pre">View</span></code>:</p>
<div class="figure align-center">
<img alt="_static/2011/couchdb3.png" src="_static/2011/couchdb3.png" />
</div>
<p>Сохраним view по нажатию “Save As...”</p>
<div class="figure align-center">
<img alt="_static/2011/couchdb4.png" src="_static/2011/couchdb4.png" />
</div>
<p>Вызовем из консоли:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ curl -X GET http://127.0.0.1:5984/test/_design/product/_view/bike
</pre></div>
</div>
<p>Результат:</p>
<div class="highlight-json"><div class="highlight"><pre><span></span><span class="p">{</span><span class="nt">"total_rows"</span><span class="p">:</span><span class="mi">1</span><span class="p">,</span><span class="nt">"offset"</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span class="nt">"rows"</span><span class="p">:[</span>
<span class="p">{</span><span class="nt">"id"</span><span class="p">:</span><span class="s2">"08601f0b9d3574a116ee390bf0000f44"</span><span class="p">,</span><span class="nt">"key"</span><span class="p">:</span><span class="s2">"Giant"</span><span class="p">,</span><span class="nt">"value"</span><span class="p">:{</span><span class="nt">"_id"</span><span class="p">:</span><span class="s2">"08601f0b9d3574a116ee390bf0000f44"</span><span class="p">,</span><span class="nt">"_rev"</span><span class="p">:</span><span class="s2">"1-67d8f0ad3100d85952dbb17ba68b08eb"</span><span class="p">,</span><span class="nt">"manufacture"</span><span class="p">:</span><span class="s2">"Giant"</span><span class="p">,</span><span class="nt">"model"</span><span class="p">:</span><span class="s2">"REVEL 2"</span><span class="p">,</span><span class="nt">"\u0446\u0432\u0435\u0442"</span><span class="p">:</span><span class="s2">"\u0441\u0438\u043d\u0438\u0439"</span><span class="p">,</span><span class="nt">"\u0446\u0435\u043d\u0430"</span><span class="p">:</span><span class="s2">"16000"</span><span class="p">,</span><span class="nt">"type"</span><span class="p">:</span><span class="s2">"bike"</span><span class="p">}}</span>
<span class="p">]}</span>
</pre></div>
</div>
</div>
<div class="section" id="reduce">
<h2>Reduce функции</h2>
<p>Map функция:</p>
<div class="highlight-javascript"><div class="highlight"><pre><span></span><span class="kd">function</span> <span class="p">(</span><span class="nx">doc</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">doc</span><span class="p">.</span><span class="nx">type</span> <span class="o">===</span> <span class="s2">"bike"</span> <span class="o">&&</span> <span class="nx">doc</span><span class="p">.</span><span class="nx">цена</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">emit</span><span class="p">(</span><span class="nx">doc</span><span class="p">.</span><span class="nx">_id</span><span class="p">,</span> <span class="nx">doc</span><span class="p">.</span><span class="nx">цена</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Получим:</p>
<div class="highlight-json"><div class="highlight"><pre><span></span><span class="p">{</span><span class="nt">"total_rows"</span><span class="p">:</span><span class="mi">2</span><span class="p">,</span><span class="nt">"offset"</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span class="nt">"rows"</span><span class="p">:[</span>
<span class="p">{</span><span class="nt">"id"</span><span class="p">:</span><span class="s2">"08601f0b9d3574a116ee390bf0000f44"</span><span class="p">,</span><span class="nt">"key"</span><span class="p">:</span><span class="s2">"08601f0b9d3574a116ee390bf0000f44"</span><span class="p">,</span><span class="nt">"value"</span><span class="p">:</span><span class="mi">12000</span><span class="p">},</span>
<span class="p">{</span><span class="nt">"id"</span><span class="p">:</span><span class="s2">"08601f0b9d3574a116ee390bf0001130"</span><span class="p">,</span><span class="nt">"key"</span><span class="p">:</span><span class="s2">"08601f0b9d3574a116ee390bf0001130"</span><span class="p">,</span><span class="nt">"value"</span><span class="p">:</span><span class="mi">16000</span><span class="p">}</span>
<span class="p">]}</span>
</pre></div>
</div>
<p>Reduce функция:</p>
<div class="highlight-javascript"><div class="highlight"><pre><span></span><span class="kd">function</span><span class="p">(</span><span class="nx">keys</span><span class="p">,</span> <span class="nx">prices</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">sum</span><span class="p">(</span><span class="nx">prices</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Получаем сумму:</p>
<div class="highlight-json"><div class="highlight"><pre><span></span><span class="p">{</span><span class="nt">"rows"</span><span class="p">:[</span>
<span class="p">{</span><span class="nt">"key"</span><span class="p">:</span><span class="kc">null</span><span class="p">,</span><span class="nt">"value"</span><span class="p">:</span><span class="mi">28000</span><span class="p">}</span>
<span class="p">]}</span>
</pre></div>
</div>
<p>В заключение можно сказать что NoSQL в виде <a class="reference external" href="http://couchdb.apache.org/">CouchDB</a> мне показался
очень простым и удобным механизмом.</p>
<p>Для дополнительного чтения:
<a class="reference external" href="http://net.tutsplus.com/tutorials/getting-started-with-couchdb/">http://net.tutsplus.com/tutorials/getting-started-with-couchdb/</a></p>
</div>
</div>
WTForm валидация
http://uralbash.ru/articles/2011/wtform_validation/
2011-11-27T22:37:00Z
2011-11-27T22:37:00Z
Uralbash
<div class="section" id="wtform">
<p>Продолжение статьи <a class="reference internal" href="../articles/2011/wtforms/#wtforms"><span class="std std-ref">готовим Pylons + WTForms</span></a>. Рассмотрим как создать свой
класс для валидации. Здесь можно найти стандартные валидаторы
<a class="reference external" href="http://wtforms.simplecodes.com/docs/0.6/validators.html">http://wtforms.simplecodes.com/docs/0.6/validators.html</a></p>
<p>Добавим файл <code class="docutils literal"><span class="pre">equipments.py</span></code> в папку <code class="docutils literal"><span class="pre">validators</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="p">|</span>~forms/
<span class="p">|</span> <span class="p">|</span>~mycontrollers/
<span class="p">|</span> <span class="p">|</span> <span class="p">|</span>-__init__.py
<span class="p">|</span> <span class="p">|</span> <span class="sb">`</span>-equipments.py
<span class="p">|</span> <span class="p">|</span>~validators/
<span class="p">|</span> <span class="p">|</span> <span class="p">|</span>-__init__.py
<span class="p">|</span> <span class="p">|</span> <span class="sb">`</span>-equipments.py
<span class="p">|</span> <span class="sb">`</span>-__init__.py
</pre></div>
</div>
<p>Напишем валидатор IP адресов, вообще в <a class="reference external" href="http://wtforms.simplecodes.com/">WTForm</a> есть класс
<a class="reference external" href="https://wtforms.readthedocs.io/en/latest/validators.html#wtforms.validators.IPAddress" title="(в WTForms v3.0)"><code class="xref py py-class docutils literal"><span class="pre">wtforms.validators.IPAddress</span></code></a>, но он работает только с IPv4 адресами
(на момент написания статьи).</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">ipaddr</span>
<span class="kn">from</span> <span class="nn">wtforms.validators</span> <span class="kn">import</span> <span class="n">ValidationError</span>
<span class="k">class</span> <span class="nc">IPNetwork</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="sd">"""</span>
<span class="sd"> Validates an IP(v4 and v6) address.</span>
<span class="sd"> :param message:</span>
<span class="sd"> Error message to raise in case of a validation error.</span>
<span class="sd"> """</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">message</span>
<span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">form</span><span class="p">,</span> <span class="n">field</span><span class="p">):</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">field</span><span class="o">.</span><span class="n">data</span>
<span class="c1"># Use PEP3144 for validation</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">ipaddr</span><span class="o">.</span><span class="n">IPNetwork</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="ow">and</span> <span class="n">data</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">field</span><span class="o">.</span><span class="n">gettext</span><span class="p">(</span><span class="sa">u</span><span class="s1">'Invalid IP address.'</span><span class="p">)</span>
<span class="k">raise</span> <span class="n">ValidationError</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">message</span><span class="p">)</span>
</pre></div>
</div>
<p>Сначала получаем значение поля, а потом при помощи модуля <a class="reference external" href="https://pypi.python.org/pypi/ipaddr">ipaddr</a> проверяем. Если проверка не проходит то
генерируем исключение <code class="docutils literal"><span class="pre">ValidationError</span></code>. Теперь напишем похожий валидатор для
MAC адреса.</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="o">...</span>
<span class="kn">from</span> <span class="nn">wtforms.validators</span> <span class="kn">import</span> <span class="n">Regexp</span>
<span class="o">...</span>
<span class="k">class</span> <span class="nc">MACAddress</span><span class="p">(</span><span class="n">Regexp</span><span class="p">):</span>
<span class="sd">"""</span>
<span class="sd"> Validates an MAC address.</span>
<span class="sd"> :param message:</span>
<span class="sd"> Error message to raise in case of a validation error.</span>
<span class="sd"> """</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
<span class="nb">super</span><span class="p">(</span><span class="n">MACAddress</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="sa">r</span><span class="s1">'^([a-f\d]{1,2}\:){5}[a-f\d]{1,2}$'</span><span class="p">,</span>\
<span class="n">message</span><span class="o">=</span><span class="n">message</span><span class="p">)</span>
<span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">form</span><span class="p">,</span> <span class="n">field</span><span class="p">):</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">field</span><span class="o">.</span><span class="n">gettext</span><span class="p">(</span><span class="sa">u</span><span class="s1">'Invalid MAC address.'</span><span class="p">)</span>
<span class="k">if</span> <span class="n">field</span><span class="o">.</span><span class="n">data</span><span class="p">:</span>
<span class="nb">super</span><span class="p">(</span><span class="n">MACAddress</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__call__</span><span class="p">(</span><span class="n">form</span><span class="p">,</span> <span class="n">field</span><span class="p">)</span>
</pre></div>
</div>
<p>Здесь мы использовали встроенный класс <a class="reference external" href="https://wtforms.readthedocs.io/en/latest/validators.html#wtforms.validators.Regexp" title="(в WTForms v3.0)"><code class="xref py py-class docutils literal"><span class="pre">Regexp</span></code></a>. В
файле формы это используется так:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="o">...</span>
<span class="kn">from</span> <span class="nn">myapp.forms.validators.mycontroller</span> <span class="kn">import</span> <span class="n">IPNetwork</span><span class="p">,</span> <span class="n">MACAddress</span>
<span class="o">...</span>
<span class="k">class</span> <span class="nc">EditForm</span><span class="p">(</span><span class="n">Form</span><span class="p">):</span>
<span class="n">ip</span> <span class="o">=</span> <span class="n">TextField</span><span class="p">(</span><span class="s1">'IP address'</span><span class="p">,</span> <span class="p">[</span><span class="n">IPNetwork</span><span class="p">()])</span>
<span class="n">mac</span> <span class="o">=</span> <span class="n">TextField</span><span class="p">(</span><span class="s1">'MAC address'</span><span class="p">,</span> <span class="p">[</span><span class="n">MACAddress</span><span class="p">()])</span>
</pre></div>
</div>
<div class="figure align-center" id="id1">
<img alt="_static/2011/wtforms_validation.png" src="_static/2011/wtforms_validation.png" />
<p class="caption"><span class="caption-text">WTForm валидация</span></p>
</div>
</div>
Вот он плеер моей мечты - Peyote
http://uralbash.ru/articles/2011/peyote/
2011-11-27T16:17:00Z
2011-11-27T16:17:00Z
Uralbash
<div class="section" id="peyote">
<p>Плеер который в Линуксе нормально отображает кодировки и читает на ура
<code class="docutils literal"><span class="pre">lossless</span></code>, написан на <a class="reference external" href="http://www.python.org/">python</a>, работает в консоле. Интерфейс как в
<a class="reference external" href="http://www.midnight-commander.org/">mc</a> - очень удобно музыку перемещать + поддержка мышки.
<a class="reference external" href="http://peyote.sourceforge.net/about.rus.html">http://peyote.sourceforge.net/about.rus.html</a></p>
<div class="figure align-center" id="id1">
<img alt="_static/2011/peyote.png" src="_static/2011/peyote.png" />
<p class="caption"><span class="caption-text">Peyote плеер для Linux</span></p>
</div>
<p>Плюшки:</p>
<ul class="simple">
<li>wv, wav, flac, ape, ogg, mp3, m4a аудио форматы</li>
<li>ID3v2, APEv2, FLAC, Vorbis тэги</li>
<li>несколько плейлистов</li>
<li>табы</li>
<li>cue жрутся, даже если в них указанны файлы с ошибками(.wav вместо .flac)</li>
<li>Автоопределение кодировки (utf8/cp1251[or other]) для тэгов, .m3u(плейлистов), .cue</li>
<li>возможность прослушивания http(чз плейлист)</li>
<li>HTTP-fs</li>
<li>встроеный mp3 энкодер</li>
<li>Работа с файловой системой: копирование, удаление, перемещение, переименование</li>
<li>10-полосный эквалайзер</li>
<li>Плавный переход ( crossfade )</li>
</ul>
</div>
готовим Pylons + WTForms
http://uralbash.ru/articles/2011/wtforms/
2011-11-22T02:51:00Z
2011-11-22T02:51:00Z
Uralbash
<div class="section" id="pylons-wtforms">
<span id="wtforms"></span>
<p><a class="reference external" href="http://wtforms.simplecodes.com/">WTForm</a> простая, но довольно удобная библиотека для создания форм. И еще
<a class="reference external" href="http://wtforms.simplecodes.com/">WTForm</a> очень похожа на формы в <a class="reference external" href="https://www.djangoproject.com/">Django</a> - одно из немногого что в
джанге сделано хорошо. Посмотрим как это работает с <a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">Pylons</a>. Для удобства
будем хранить формы отдельно:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span>|+config/
|+controllers/
|~forms/
| |~mycontroller/
| | |-__init__.py
| | `-equipments.py
| |+validators/
| `-__init__.py
</pre></div>
</div>
<p>Создаем форму для редактирования оборудования <code class="docutils literal"><span class="pre">equipments.py</span></code>:</p>
<div class="literal-block-wrapper docutils container" id="id1">
<div class="code-block-caption"><span class="caption-text">equipments.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">myapp.model.meta</span> <span class="kn">import</span> <span class="n">Session</span> <span class="k">as</span> <span class="n">s</span>
<span class="kn">from</span> <span class="nn">myapp.model.mymodel</span> <span class="kn">import</span> <span class="n">EquipmentType</span>
<span class="kn">from</span> <span class="nn">wtforms</span> <span class="kn">import</span> <span class="n">Form</span><span class="p">,</span> <span class="n">TextField</span><span class="p">,</span> <span class="n">validators</span>
<span class="kn">from</span> <span class="nn">wtforms.ext.sqlalchemy.fields</span> <span class="kn">import</span> <span class="n">QuerySelectField</span>
<span class="c1"># Выбор всех разновидностей оборудования для списка type в форме</span>
<span class="k">def</span> <span class="nf">all_equipment_types</span><span class="p">():</span>
<span class="k">return</span> <span class="n">s</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">EquipmentType</span><span class="p">)</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
<span class="k">class</span> <span class="nc">EditForm</span><span class="p">(</span><span class="n">Form</span><span class="p">):</span>
<span class="n">ip</span> <span class="o">=</span> <span class="n">TextField</span><span class="p">(</span><span class="s1">'ip address'</span><span class="p">)</span>
<span class="n">netmask</span> <span class="o">=</span> <span class="n">TextField</span><span class="p">(</span><span class="s1">'network mask'</span><span class="p">)</span>
<span class="n">mac</span> <span class="o">=</span> <span class="n">TextField</span><span class="p">(</span><span class="s1">'mac address'</span><span class="p">)</span>
<span class="nb">type</span> <span class="o">=</span> <span class="n">QuerySelectField</span><span class="p">(</span><span class="s1">'type of equipment'</span><span class="p">,</span>
<span class="n">query_factory</span><span class="o">=</span><span class="n">all_equipment_types</span><span class="p">)</span>
</pre></div>
</div>
</div>
<p><code class="docutils literal"><span class="pre">QuerySelectField</span></code> это поле из расширения <a class="reference external" href="http://wtforms.simplecodes.com/">WTForm</a> для <a class="reference external" href="http://sqlalchemy.org/">SQLAlchemy</a>,
которое позволяет создавать списки на основе выборок. Также есть расширения для
<a class="reference external" href="https://www.djangoproject.com/">Django</a> и GAE. Инициализируем нашу форму в контроллере и передадим шаблону:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">myapp.forms.mycontroller.equipments</span> <span class="kn">import</span> <span class="n">EditForm</span>
<span class="k">class</span> <span class="nc">EquipmentsController</span><span class="p">(</span><span class="n">BaseController</span><span class="p">):</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">edit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="nb">id</span><span class="p">,</span> <span class="n">format</span><span class="o">=</span><span class="s1">'html'</span><span class="p">):</span>
<span class="sd">"""GET /myapp/equipments/id/edit: Form to edit an existing item"""</span>
<span class="c1"># url('myapp_edit_equipment', id=ID)</span>
<span class="n">c</span><span class="o">.</span><span class="n">equipment</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">Equipment</span><span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="nb">id</span><span class="o">==</span><span class="nb">id</span><span class="p">)</span>
<span class="n">c</span><span class="o">.</span><span class="n">form</span> <span class="o">=</span> <span class="n">EditForm</span><span class="p">(</span><span class="n">ip</span><span class="o">=</span><span class="n">c</span><span class="o">.</span><span class="n">equipment</span><span class="o">.</span><span class="n">ip</span><span class="p">,</span> <span class="n">mac</span><span class="o">=</span><span class="n">c</span><span class="o">.</span><span class="n">equipment</span><span class="o">.</span><span class="n">mac</span><span class="p">,</span>
<span class="nb">type</span><span class="o">=</span><span class="n">c</span><span class="o">.</span><span class="n">equipment</span><span class="o">.</span><span class="n">equipmenttype</span><span class="p">,</span>
<span class="n">netmask</span><span class="o">=</span><span class="n">c</span><span class="o">.</span><span class="n">equipment</span><span class="o">.</span><span class="n">netmask</span><span class="p">)</span>
<span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="s1">'/myapp/equipments/edit.html'</span><span class="p">)</span>
</pre></div>
</div>
<p>После передачи одноименных полям параметров в форму, значения этих параметров
будут по умолчанию выведены в форме. Напишем шаблон на <a class="reference external" href="http://jinja.pocoo.org/">Jinja</a>:</p>
<div class="highlight-html+jinja"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">"base.html"</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">content</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">form</span> <span class="na">action</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">url</span><span class="o">(</span><span class="nv">controller</span><span class="o">=</span><span class="s1">'myapp/equipments'</span><span class="o">,</span> <span class="nv">action</span><span class="o">=</span><span class="s1">'update'</span><span class="o">,</span> <span class="nv">id</span><span class="o">=</span><span class="nv">c.equipment.id</span><span class="o">)</span> <span class="cp">}}</span><span class="s">"</span> <span class="na">method</span><span class="o">=</span><span class="s">"POST"</span><span class="p">></span>
<span class="p"><</span><span class="nt">table</span> <span class="na">class</span><span class="o">=</span><span class="s">"simpletable"</span><span class="p">></span>
<span class="p"><</span><span class="nt">caption</span><span class="p">></span>
Edit equipment of <span class="cp">{{</span> <span class="nv">c.equipment.equipmenttype</span> <span class="cp">}}</span>
(<span class="cp">{{</span> <span class="nv">c.equipment.ip</span> <span class="cp">}}</span>)
<span class="p"></</span><span class="nt">caption</span><span class="p">></span>
<span class="p"><</span><span class="nt">tbody</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">field</span> <span class="k">in</span> <span class="nv">c.form.data</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">tr</span><span class="p">><</span><span class="nt">td</span><span class="p">></span><span class="cp">{{</span> <span class="nv">c.form</span><span class="o">[</span><span class="nv">field</span><span class="o">]</span><span class="nv">.label</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">td</span><span class="p">></span>
<span class="p"><</span><span class="nt">td</span><span class="p">></span><span class="cp">{{</span> <span class="nv">c.form</span><span class="o">[</span><span class="nv">field</span><span class="o">]</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">td</span><span class="p">></span>
<span class="p"></</span><span class="nt">tr</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">tr</span><span class="p">><</span><span class="nt">td</span> <span class="na">colspan</span><span class="o">=</span><span class="s">"5"</span><span class="p">></span>
<span class="p"><</span><span class="nt">button</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"/img/common/save.png"</span> <span class="p">/></span>Save<span class="p"></</span><span class="nt">button</span><span class="p">></span>
<span class="p"><</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">"hidden"</span> <span class="na">name</span><span class="o">=</span><span class="s">"_method"</span> <span class="na">value</span><span class="o">=</span><span class="s">"PUT"</span> <span class="p">/></span>
<span class="p"></</span><span class="nt">td</span><span class="p">></</span><span class="nt">tr</span><span class="p">></span>
<span class="p"></</span><span class="nt">tbody</span><span class="p">></span>
<span class="p"></</span><span class="nt">table</span><span class="p">></span>
<span class="p"></</span><span class="nt">form</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
</pre></div>
</div>
<p>В примере поля выводятся в цикле из списка <code class="docutils literal"><span class="pre">form.data</span></code>. Я использую <a class="reference external" href="https://ru.wikipedia.org/wiki/REST">REST</a>
контроллеры поэтому обновление происходит в методе <code class="docutils literal"><span class="pre">update</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">myapp.forms.mycontroller.equipments</span> <span class="kn">import</span> <span class="n">EditForm</span>
<span class="k">class</span> <span class="nc">EquipmentsController</span><span class="p">(</span><span class="n">BaseController</span><span class="p">):</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="nb">id</span><span class="p">):</span>
<span class="sd">"""PUT /myapp/equipments/id: Update an existing item"""</span>
<span class="c1"># Forms posted to this method should contain a hidden field:</span>
<span class="c1"># <input name="_method" value="PUT" type="hidden"></span>
<span class="c1"># Or using helpers:</span>
<span class="c1"># h.form(url('myapp_equipment', id=ID),</span>
<span class="c1"># method='put')</span>
<span class="c1"># url('myapp_equipment', id=ID)</span>
<span class="n">equipment</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">Equipment</span><span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="nb">id</span><span class="p">)</span>
<span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">[</span><span class="s1">'ip'</span><span class="p">]:</span>
<span class="n">equipment</span><span class="o">.</span><span class="n">ip</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">[</span><span class="s1">'ip'</span><span class="p">]</span>
<span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">[</span><span class="s1">'netmask'</span><span class="p">]:</span>
<span class="n">equipment</span><span class="o">.</span><span class="n">netmask</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">[</span><span class="s1">'netmask'</span><span class="p">]</span>
<span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">[</span><span class="s1">'mac'</span><span class="p">]:</span>
<span class="n">equipment</span><span class="o">.</span><span class="n">mac</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">[</span><span class="s1">'mac'</span><span class="p">]</span>
<span class="nb">type</span> <span class="o">=</span> <span class="n">EquipmentType</span><span class="o">.</span><span class="n">by_id</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">[</span><span class="s1">'type'</span><span class="p">])</span>
<span class="n">equipment</span><span class="o">.</span><span class="n">equipmenttype</span> <span class="o">=</span> <span class="nb">type</span>
<span class="n">s</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
<span class="n">came_from</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'HTTP_REFERER'</span><span class="p">,</span> <span class="s1">''</span><span class="p">))</span> <span class="ow">or</span> <span class="n">url</span><span class="p">(</span><span class="s1">'/'</span><span class="p">)</span>
<span class="n">redirect</span><span class="p">(</span><span class="n">came_from</span><span class="p">)</span>
</pre></div>
</div>
<p>Последние две строки возвращают пользователя обратно на страницу
редактирования. Выглядит это как-то так:</p>
<div class="figure align-center" id="id2">
<img alt="_static/2011/wtform_eq.png" src="_static/2011/wtform_eq.png" />
<p class="caption"><span class="caption-text">Пример <a class="reference external" href="http://wtforms.simplecodes.com/">WTForm</a> и <a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">Pylons</a></span></p>
</div>
</div>
Альтернатива SQL триггерам в SQLAlchemy
http://uralbash.ru/articles/2011/sqlalchemy_trigger/
2011-11-19T20:47:00Z
2011-11-19T20:47:00Z
Uralbash
<div class="section" id="sql-sqlalchemy">
<p>Когда необходимо выполнять какие-то действия при записи в базу, обычно создают
триггеры <code class="docutils literal"><span class="pre">before</span></code>, <code class="docutils literal"><span class="pre">after</span> <span class="pre">INSERT</span> <span class="pre">UPDATE</span></code>. В <a class="reference external" href="http://sqlalchemy.org/">SQLAlchemy</a> можно
реализовать аналогичный механизм но работающий на стороне питона а не БД. В
версии 0.6 это делается при помощи
<code class="xref py py-class docutils literal"><span class="pre">MapperExtension</span></code>, в 0.7
<code class="xref py py-class docutils literal"><span class="pre">MapperExtension</span></code> заменили на <code class="xref py py-func docutils literal"><span class="pre">sqlalchemy.event.listen()</span></code>.</p>
<div class="section" id="mapperextension">
<h2>MapperExtension</h2>
<p>Пример <code class="xref py py-class docutils literal"><span class="pre">MapperExtension</span></code> с <a class="reference external" href="http://www.nagare.org/trac/blog/SQLAlchemyMapperExtension">сайта nagare.org</a>.</p>
<blockquote>
<div>Создадим таблицу пользователи:</div></blockquote>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">User</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__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="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
<span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">Table</span><span class="p">,</span> <span class="n">Column</span><span class="p">,</span> <span class="n">Integer</span><span class="p">,</span> <span class="n">Text</span>
<span class="n">users_table</span> <span class="o">=</span> <span class="n">Table</span><span class="p">(</span><span class="s1">'users'</span><span class="p">,</span>
<span class="n">Column</span><span class="p">(</span><span class="s1">'id'</span><span class="p">,</span> <span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="bp">True</span><span class="p">),</span>
<span class="n">Column</span><span class="p">(</span><span class="s1">'name'</span><span class="p">,</span> <span class="n">Text</span><span class="p">))</span>
</pre></div>
</div>
<p>Допустим мы хотим переводить первую букву имени пользователя в верхний регистр
при каждом SQL запросе <code class="docutils literal"><span class="pre">UPDATE</span></code> или <code class="docutils literal"><span class="pre">INSERT</span></code>. Для этого в
<code class="xref py py-class docutils literal"><span class="pre">MapperExtension</span></code> есть методы аналогичные
триггерам SQL: <code class="docutils literal"><span class="pre">before_insert</span></code>, <code class="docutils literal"><span class="pre">before_update</span></code>, <code class="docutils literal"><span class="pre">after_insert</span></code>,
<code class="docutils literal"><span class="pre">after_update</span></code> и другие:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">sqlalchemy.orm</span> <span class="kn">import</span> <span class="n">MapperExtension</span>
<span class="k">class</span> <span class="nc">CapitalizeNameMapperExtension</span><span class="p">(</span><span class="n">MapperExtension</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">_capitalize_name</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">instance</span><span class="p">):</span>
<span class="k">if</span> <span class="n">instance</span><span class="o">.</span><span class="n">name</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
<span class="n">instance</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">instance</span><span class="o">.</span><span class="n">name</span><span class="o">.</span><span class="n">capitalize</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">before_insert</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">mapper</span><span class="p">,</span> <span class="n">connection</span><span class="p">,</span> <span class="n">instance</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_capitalize_name</span><span class="p">(</span><span class="n">instance</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">before_update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">mapper</span><span class="p">,</span> <span class="n">connection</span><span class="p">,</span> <span class="n">instance</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_capitalize_name</span><span class="p">(</span><span class="n">instance</span><span class="p">)</span>
</pre></div>
</div>
<p>Теперь надо привязать наше расширение к модели:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">sqlalchemy.orm</span> <span class="kn">import</span> <span class="n">mapper</span>
<span class="n">user_mapper</span> <span class="o">=</span> <span class="n">mapper</span><span class="p">(</span><span class="n">User</span><span class="p">,</span> <span class="n">users_table</span><span class="p">,</span>
<span class="n">extension</span><span class="o">=</span><span class="n">CapitalizeNameMapperExtension</span><span class="p">())</span>
</pre></div>
</div>
<p>Капитализация в действии:</p>
<div class="highlight-ipython"><div class="highlight"><pre><span></span>>>> user1 = User("mynameis")
>>> print user1.name
mynameis
>>> from nagare import database
>>> database.session.add(user1)
>>> print user1.name
mynameis
>>> database.session.flush()
>>> print user1.name
Mynameis
</pre></div>
</div>
<p>Вначале было введено имя в нижнем регистре, а после записи автоматом сработала
наша функция и перевела первую букву имени в верхний регистр.</p>
</div>
<div class="section" id="event">
<h2>Event</h2>
<p>Теперь рассмотрим пример с event для <a class="reference external" href="http://sqlalchemy.org/">SQLAlchemy</a> 0.7 (текущей версией на данный момент)</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Host</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span>
<span class="sd">"""Hosts of net."""</span>
<span class="n">__tablename__</span><span class="o">=</span><span class="s2">"host"</span>
<span class="n">ip</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">postgresql</span><span class="o">.</span><span class="n">INET</span><span class="p">,</span> <span class="n">unique</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">mac</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">postgresql</span><span class="o">.</span><span class="n">MACADDR</span><span class="p">)</span>
<span class="n">description</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">UnicodeText</span><span class="p">())</span>
<span class="n">created_by</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'user.user_id'</span><span class="p">,</span> <span class="n">onupdate</span><span class="o">=</span><span class="s2">"cascade"</span><span class="p">,</span> <span class="n">ondelete</span><span class="o">=</span><span class="s2">"restrict"</span><span class="p">))</span>
<span class="n">updated_by</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'user.user_id'</span><span class="p">,</span> <span class="n">onupdate</span><span class="o">=</span><span class="s2">"cascade"</span><span class="p">,</span> <span class="n">ondelete</span><span class="o">=</span><span class="s2">"restrict"</span><span class="p">))</span>
<span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="s2">"</span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">cidr</span>
</pre></div>
</div>
<p>Создадим функции-триггеры:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">host_before_insert_listener</span><span class="p">(</span><span class="n">mapper</span><span class="p">,</span> <span class="n">connection</span><span class="p">,</span> <span class="n">target</span><span class="p">):</span>
<span class="c1"># execute a stored procedure upon INSERT,</span>
<span class="c1"># apply the value to the row to be inserted</span>
<span class="c1">#target.calculated_value = connection.scalar(</span>
<span class="c1"># "select my_special_function(%d)"</span>
<span class="c1"># % target.special_number)</span>
<span class="n">identity</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'repoze.who.identity'</span><span class="p">)</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">identity</span><span class="p">[</span><span class="s1">'user'</span><span class="p">]</span><span class="o">.</span><span class="n">user_id</span>
<span class="n">target</span><span class="o">.</span><span class="n">created_by</span> <span class="o">=</span> <span class="nb">id</span>
<span class="k">def</span> <span class="nf">host_before_update_listener</span><span class="p">(</span><span class="n">mapper</span><span class="p">,</span> <span class="n">connection</span><span class="p">,</span> <span class="n">target</span><span class="p">):</span>
<span class="c1"># execute a stored procedure upon INSERT,</span>
<span class="c1"># apply the value to the row to be inserted</span>
<span class="c1">#target.calculated_value = connection.scalar(</span>
<span class="c1"># "select my_special_function(%d)"</span>
<span class="c1"># % target.special_number)</span>
<span class="n">identity</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'repoze.who.identity'</span><span class="p">)</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">identity</span><span class="p">[</span><span class="s1">'user'</span><span class="p">]</span><span class="o">.</span><span class="n">user_id</span>
<span class="n">target</span><span class="o">.</span><span class="n">updated_by</span> <span class="o">=</span> <span class="nb">id</span>
</pre></div>
</div>
<p>Здесь мы получаем из переменных окружения <code class="docutils literal"><span class="pre">id</span></code> текущего пользователя и
присваиваем его полю <code class="docutils literal"><span class="pre">updated_by</span></code> или <code class="docutils literal"><span class="pre">created_by</span></code>. Привяжем наши функции к
модели.</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1"># associate the listener function with CreatedMixin,</span>
<span class="c1"># to execute during the "before_insert" hook</span>
<span class="n">event</span><span class="o">.</span><span class="n">listen</span><span class="p">(</span><span class="n">Host</span><span class="p">,</span> <span class="s1">'before_insert'</span><span class="p">,</span> <span class="n">host_before_insert_listener</span><span class="p">)</span>
<span class="n">event</span><span class="o">.</span><span class="n">listen</span><span class="p">(</span><span class="n">Host</span><span class="p">,</span> <span class="s1">'before_update'</span><span class="p">,</span> <span class="n">host_before_update_listener</span><span class="p">)</span>
</pre></div>
</div>
<p>Всё, теперь при добавлении или обновлении Host будут автоматически заполняться
поля <code class="docutils literal"><span class="pre">created_by</span></code> или <code class="docutils literal"><span class="pre">updated_by</span></code> соответственно. На мой взгляд намного удобней
держать логику в одном месте, так как в будущем ее будет проще поддерживать и
проводить тестирование.</p>
</div>
</div>
Установка Java Environment на Debian для Iceweasel (FireFox)
http://uralbash.ru/articles/2011/java_iceweasel/
2011-11-19T19:01:00Z
2011-11-19T19:01:00Z
Uralbash
<div class="section" id="java-environment-debian-iceweasel-firefox">
<p>Часто веб интерфейс какого-нибудь устройства требует <a class="reference external" href="http://www.java.com">Java</a>. Что бы ее
поставить на <a class="reference external" href="https://www.debian.org/">Debian</a> необходимо выполнить команды:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo apt-get install sun-java6-jre sun-java6-plugin
$ update-alternatives --config java
</pre></div>
</div>
<p>После перезагрузки браузера настройки применяться.</p>
</div>
SQLAlchemy почему PostgreSQL?
http://uralbash.ru/articles/2011/sqlalchemy_why_postgres/
2011-11-16T00:42:00Z
2011-11-16T00:42:00Z
Uralbash
<div class="section" id="sqlalchemy-postgresql">
<p>Потому что я могу делать так:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">c</span><span class="o">.</span><span class="n">nets</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">Net</span><span class="p">)</span>
<span class="n">ip_type</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">GET</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'ip_type'</span><span class="p">,</span> <span class="s1">''</span><span class="p">)</span>
<span class="k">if</span> <span class="n">ip_type</span><span class="o">==</span><span class="s1">'4'</span><span class="p">:</span>
<span class="n">c</span><span class="o">.</span><span class="n">nets</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">Net</span><span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="s2">"family(cidr)=4"</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">ip_type</span><span class="o">==</span><span class="s1">'6'</span><span class="p">:</span>
<span class="n">c</span><span class="o">.</span><span class="n">nets</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">Net</span><span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="s2">"family(cidr)=6"</span><span class="p">)</span>
<span class="n">c</span><span class="o">.</span><span class="n">nets</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">nets</span><span class="o">.</span><span class="n">order_by</span><span class="p">(</span><span class="n">Net</span><span class="o">.</span><span class="n">cidr</span><span class="p">)</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
</pre></div>
</div>
<p>Здесь если GET переменная <code class="docutils literal"><span class="pre">ip_type=4</span></code> то выбираются все строки где <code class="docutils literal"><span class="pre">cidr</span></code>
IPv4, если 6 то все стоки где <code class="docutils literal"><span class="pre">cidr</span></code> IPv6, иначе просто отдается все. Для
фильтрации используется стандартная функция <a class="reference external" href="http://postgresql.org">Postgres</a> <code class="docutils literal"><span class="pre">family</span></code>. Пример
был так расписан для наглядности, теперь сократим:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">c</span><span class="o">.</span><span class="n">nets</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">Net</span><span class="p">)</span>
<span class="n">ip_type</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">GET</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'ip_type'</span><span class="p">,</span> <span class="s1">''</span><span class="p">)</span>
<span class="k">if</span> <span class="n">ip_type</span><span class="p">:</span>
<span class="n">c</span><span class="o">.</span><span class="n">nets</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">Net</span><span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="s2">"family(cidr)=</span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="n">ip_type</span><span class="p">)</span>
<span class="n">c</span><span class="o">.</span><span class="n">nets</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">nets</span><span class="o">.</span><span class="n">order_by</span><span class="p">(</span><span class="n">Net</span><span class="o">.</span><span class="n">cidr</span><span class="p">)</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
</pre></div>
</div>
<p>По моему это просто шЫкарно.</p>
<img alt="_static/2011/awesome.jpeg" src="_static/2011/awesome.jpeg" />
</div>
Красивые графики javascriptRRD + Float
http://uralbash.ru/articles/2011/js_rrd/
2011-11-13T22:02:00Z
2011-11-13T22:02:00Z
Uralbash
<div class="section" id="javascriptrrd-float">
<p>В продолжение статьи <a class="reference internal" href="../articles/2011/rrdtool_ds18b20/#py-rrdtool-temp"><span class="std std-ref">Python + Tornado + RRDTool: температура на улице и в серверной</span></a>: температура на улице и в
серверной рассмотрим как можно рисовать <a class="reference external" href="http://oss.oetiker.ch/rrdtool/">RRD</a> используя только
javascript на стороне клиента. Результат будет такой:</p>
<img alt="_static/2011/js_rrd.png" class="align-center" src="_static/2011/js_rrd.png" />
<p>Используем библиотеку <a class="reference external" href="http://sourceforge.net/projects/javascriptrrd/">javascriptrrd</a>. Качаем и добавляем
следующие файлы из нее в наш шаблон в <code class="docutils literal"><span class="pre"><head></span></code>:</p>
<div class="highlight-html"><div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/javascript"</span> <span class="na">src</span><span class="o">=</span><span class="s">"media/js/lib/binaryXHR.js"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/javascript"</span> <span class="na">src</span><span class="o">=</span><span class="s">"media/js/lib/rrdFile.js"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="c"><!-- rrdFlot class needs the following four include files !--></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/javascript"</span> <span class="na">src</span><span class="o">=</span><span class="s">"media/js/lib/rrdFlotSupport.js"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/javascript"</span> <span class="na">src</span><span class="o">=</span><span class="s">"media/js/lib/rrdFlot.js"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/javascript"</span> <span class="na">src</span><span class="o">=</span><span class="s">"media/flot/jquery.js"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/javascript"</span> <span class="na">src</span><span class="o">=</span><span class="s">"media/flot/jquery.flot.js"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/javascript"</span> <span class="na">src</span><span class="o">=</span><span class="s">"media/flot/jquery.flot.selection.js"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/javascript"</span> <span class="na">src</span><span class="o">=</span><span class="s">"media/flot/jquery.flot.tooltip.js"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
</pre></div>
</div>
<p>И саму js функцию для отрисовки:</p>
<div class="highlight-html"><div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">h2</span><span class="p">></span>javascriptRRD пример<span class="p"></</span><span class="nt">h2</span><span class="p">></span>
<span class="p"><</span><span class="nt">table</span> <span class="na">id</span><span class="o">=</span><span class="s">"infotable"</span> <span class="na">border</span><span class="o">=</span><span class="s">1</span><span class="p">></span>
<span class="p"><</span><span class="nt">tr</span><span class="p">><</span><span class="nt">td</span> <span class="na">colspan</span><span class="o">=</span><span class="s">"21"</span><span class="p">><</span><span class="nt">b</span><span class="p">></span>Javascript needed for this page to work<span class="p"></</span><span class="nt">b</span><span class="p">></</span><span class="nt">td</span><span class="p">></</span><span class="nt">tr</span><span class="p">></span>
<span class="p"><</span><span class="nt">tr</span><span class="p">><</span><span class="nt">td</span><span class="p">><</span><span class="nt">b</span><span class="p">></span>RRD file<span class="p"></</span><span class="nt">b</span><span class="p">></</span><span class="nt">td</span><span class="p">><</span><span class="nt">td</span> <span class="na">id</span><span class="o">=</span><span class="s">"fname"</span> <span class="na">colspan</span><span class="o">=</span><span class="s">"5"</span><span class="p">></span>None<span class="p"></</span><span class="nt">td</span><span class="p">></</span><span class="nt">tr</span><span class="p">></span>
<span class="p"></</span><span class="nt">table</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">"mygraph"</span><span class="p">></</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/javascript"</span><span class="p">></span>
<span class="c1">// Remove the Javascript warning</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">"infotable"</span><span class="p">).</span><span class="nx">deleteRow</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="c1">// fname and rrd_data are the global variable used by all the functions below</span>
<span class="nx">fname</span><span class="o">=</span><span class="s2">"media/temperature.rrd"</span><span class="p">;</span>
<span class="nx">rrd_data</span><span class="o">=</span><span class="kc">undefined</span><span class="p">;</span>
<span class="c1">// This function updates the Web Page with the data from the RRD archive header</span>
<span class="c1">// when a new file is selected</span>
<span class="kd">function</span> <span class="nx">update_fname</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">// Finally, update the file name and enable the update button</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">"fname"</span><span class="p">).</span><span class="nx">firstChild</span><span class="p">.</span><span class="nx">data</span><span class="o">=</span><span class="nx">fname</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">graph_opts</span><span class="o">=</span><span class="p">{</span><span class="nx">legend</span><span class="o">:</span> <span class="p">{</span> <span class="nx">noColumns</span><span class="o">:</span><span class="mi">4</span><span class="p">}};</span>
<span class="kd">var</span> <span class="nx">ds_graph_opts</span><span class="o">=</span><span class="p">{</span><span class="s1">'Oscilator'</span><span class="o">:</span><span class="p">{</span> <span class="nx">color</span><span class="o">:</span> <span class="s2">"#ff8000"</span><span class="p">,</span>
<span class="nx">lines</span><span class="o">:</span> <span class="p">{</span> <span class="nx">show</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">fill</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">fillColor</span><span class="o">:</span><span class="s2">"#ffff80"</span><span class="p">}</span> <span class="p">},</span>
<span class="s1">'Idle'</span><span class="o">:</span><span class="p">{</span> <span class="nx">label</span><span class="o">:</span> <span class="s1">'IdleJobs'</span><span class="p">,</span> <span class="nx">color</span><span class="o">:</span> <span class="s2">"#00c0c0"</span><span class="p">,</span>
<span class="nx">lines</span><span class="o">:</span> <span class="p">{</span> <span class="nx">show</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">fill</span><span class="o">:</span> <span class="kc">true</span><span class="p">}</span> <span class="p">},</span>
<span class="s1">'Running'</span><span class="o">:</span><span class="p">{</span><span class="nx">color</span><span class="o">:</span> <span class="s2">"#000000"</span><span class="p">,</span><span class="nx">yaxis</span><span class="o">:</span><span class="mi">2</span><span class="p">}};</span>
<span class="c1">// the rrdFlot object creates and handles the graph</span>
<span class="kd">var</span> <span class="nx">f</span><span class="o">=</span><span class="k">new</span> <span class="nx">rrdFlot</span><span class="p">(</span><span class="s2">"mygraph"</span><span class="p">,</span><span class="nx">rrd_data</span><span class="p">,</span><span class="nx">graph_opts</span><span class="p">,</span><span class="nx">ds_graph_opts</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// This is the callback function that,</span>
<span class="c1">// given a binary file object,</span>
<span class="c1">// verifies that it is a valid RRD archive</span>
<span class="c1">// and performs the update of the Web page</span>
<span class="kd">function</span> <span class="nx">update_fname_handler</span><span class="p">(</span><span class="nx">bf</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">i_rrd_data</span><span class="o">=</span><span class="kc">undefined</span><span class="p">;</span>
<span class="k">try</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">i_rrd_data</span><span class="o">=</span><span class="k">new</span> <span class="nx">RRDFile</span><span class="p">(</span><span class="nx">bf</span><span class="p">);</span>
<span class="p">}</span> <span class="k">catch</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">alert</span><span class="p">(</span><span class="s2">"File "</span><span class="o">+</span><span class="nx">fname</span><span class="o">+</span><span class="s2">" is not a valid RRD archive!"</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">i_rrd_data</span><span class="o">!=</span><span class="kc">undefined</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">rrd_data</span><span class="o">=</span><span class="nx">i_rrd_data</span><span class="p">;</span>
<span class="nx">update_fname</span><span class="p">()</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">// this function is invoked when the RRD file name changes</span>
<span class="kd">function</span> <span class="nx">fname_update</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">fname</span><span class="o">=</span><span class="s2">"media/temperature.rrd"</span><span class="p">;</span>
<span class="k">try</span> <span class="p">{</span>
<span class="nx">FetchBinaryURLAsync</span><span class="p">(</span><span class="nx">fname</span><span class="p">,</span><span class="nx">update_fname_handler</span><span class="p">);</span>
<span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">alert</span><span class="p">(</span><span class="s2">"Failed loading "</span><span class="o">+</span><span class="nx">fname</span><span class="o">+</span><span class="s2">"\n"</span><span class="o">+</span><span class="nx">err</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p"></</span><span class="nt">script</span><span class="p">></span>
</pre></div>
</div>
<p>Для автоматического запуска функции при загрузки страницы добавим событие
<code class="docutils literal"><span class="pre">onLoad</span></code> в <code class="docutils literal"><span class="pre">body</span></code>:</p>
<div class="highlight-html"><div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">body</span> <span class="na">bgcolor</span><span class="o">=</span><span class="s">"white"</span> <span class="na">text</span><span class="o">=</span><span class="s">"black"</span> <span class="na">onLoad</span><span class="o">=</span><span class="s">"fname_update()"</span><span class="p">></span>
</pre></div>
</div>
<p>Всё, радуемся результату.</p>
</div>
Pylons + FormAlchemy REST Controller
http://uralbash.ru/articles/2011/fa_rest_controller/
2011-11-13T21:10:00Z
2011-11-13T21:10:00Z
Uralbash
<div class="section" id="pylons-formalchemy-rest-controller">
<p>Для своих <a class="reference external" href="https://ru.wikipedia.org/wiki/REST">REST</a> контроллеров можно использовать, формы <a class="reference external" href="http://docs.formalchemy.org/">FormAlchemy</a>.</p>
<p>Создаем контроллер:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>/path/to/youproj$ paster restcontroller comment comments
Creating yourproj/yourproj/controllers/comments.py
Creating yourproj/yourproj/tests/functional/test_comments.py
</pre></div>
</div>
<p>Или если нужно в отдельной директории:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>/path/to/yourproj$ paster restcontroller admin/tracback admin/trackbacks
Creating yourproj/controllers/admin
Creating yourproj/yourproj/controllers/admin/trackbacks.py
Creating yourproj/yourproj/tests/functional/test_admin_trackbacks.py
</pre></div>
</div>
<p>В файле нашего <a class="reference external" href="https://ru.wikipedia.org/wiki/REST">REST</a> контроллера добавим:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">formalchemy.ext.pylons.controller</span> <span class="kn">import</span> <span class="n">RESTController</span>
</pre></div>
</div>
<p>И в конце файла обернем его так:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1"># wrap with formalchemy RESTController</span>
<span class="n">CommentsController</span> <span class="o">=</span> <span class="n">RESTController</span><span class="p">(</span><span class="n">CommentsController</span><span class="p">,</span> <span class="s1">'comment'</span><span class="p">,</span> <span class="s1">'comments'</span><span class="p">)</span>
</pre></div>
</div>
<p>Теперь если закомментировать какой-нибудь из стандартных методов в
контроллере (<code class="docutils literal"><span class="pre">index</span></code>, <code class="docutils literal"><span class="pre">new</span></code>, <code class="docutils literal"><span class="pre">update</span></code>, <code class="docutils literal"><span class="pre">delete</span></code>, <code class="docutils literal"><span class="pre">show</span></code>, <code class="docutils literal"><span class="pre">edit</span></code>) он
будет браться из контроллера <a class="reference external" href="http://docs.formalchemy.org/">FormAlchemy</a> со стандартными формами. Довольно
удобно в разработке.</p>
</div>
Python + Tornado + RRDTool: температура на улице и в серверной
http://uralbash.ru/articles/2011/rrdtool_ds18b20/
2011-11-13T00:42:00Z
2011-11-13T00:42:00Z
Uralbash
<div class="section" id="python-tornado-rrdtool">
<span id="py-rrdtool-temp"></span>
<p>Рассмотрим как можно мониторить температуру при помощи сервера. Алгоритм
довольно простой: подключаем датчик температуры к компу, пишем скрипт который
снимает данные с датчика, записываем данные и отдаем по запросу пользователю.
Результат будет выглядеть так:</p>
<img alt="_static/2011/rrdtool_example.png" class="align-center" src="_static/2011/rrdtool_example.png" />
<p>Датчик температуры можно выбрать любой. Я сделал для COM порта по схеме
<a class="reference external" href="http://msevm.com/main/therm/ds18b20t.htm">“Электронный термометр на DS-18B20”</a>. Стоимось вышла около 450р., без
кожуха и разъемов раза в 2 дешевле.</p>
<img alt="_static/2011/rs232.png" class="align-center" src="_static/2011/rs232.png" />
<p>Сам датчик температуры (<a class="reference external" href="http://www.maximintegrated.com/en/products/analog/sensors-and-sensor-interface/DS18B20.html">DS-18B20</a>) можно соединять параллельно с другими (до
100шт.) и он будет нормально работать на одной шине длиной до 300м. После
подключения скорей всего он определится на последовательном порту <code class="docutils literal"><span class="pre">/dev/ttyS0</span></code>.
Для снятия показателей нужна программа <a class="reference external" href="https://www.digitemp.com/">digitemp</a>.</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ sudo apt-get install digitemp
</pre></div>
</div>
<p>Чтобы получить данные введем:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ /usr/bin/digitemp_DS9097 -t <span class="m">0</span> -s /dev/ttyS0 -q -o <span class="s2">"%.2C"</span>
-7.62
</pre></div>
</div>
<p>При обращении к датчику он блокируется и если в этот момент запустить еще раз
команду <a class="reference external" href="https://www.digitemp.com/">digitemp</a> то она вернет пустое значение. Для избежания этой ситуации
напишем скрипт который по крону каждую минуту будет снимать данные и записывать
в файл:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="ch">#!/bin/bash</span>
<span class="nb">echo</span> <span class="sb">`</span>/usr/bin/digitemp_DS9097 -t <span class="m">0</span> -s /dev/ttyS0 -q -o <span class="s2">"%.2C"</span><span class="sb">`</span> > /projects/scripts/temp.cashe
</pre></div>
</div>
<p>Сейчас напишем скрипт который будет формировать rrd базу и добавлять в нее
данные из temp.cashe каждую минуту.</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">rrdcontroller</span> <span class="kn">import</span> <span class="n">RRDController</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="k">def</span> <span class="nf">update_rrd</span><span class="p">(</span><span class="n">rrd</span><span class="p">):</span>
<span class="n">f</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s1">'temp.cashe'</span><span class="p">)</span>
<span class="n">temp</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="n">rrd</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">temperature</span><span class="o">=</span><span class="n">temp</span><span class="p">)</span>
<span class="n">rrd</span><span class="o">.</span><span class="n">graph</span><span class="p">(</span><span class="n">period</span><span class="o">=</span><span class="s1">'day'</span><span class="p">)</span>
<span class="n">rrd</span><span class="o">.</span><span class="n">graph</span><span class="p">(</span><span class="n">period</span><span class="o">=</span><span class="s1">'week'</span><span class="p">)</span>
<span class="n">rrd</span><span class="o">.</span><span class="n">graph</span><span class="p">(</span><span class="n">period</span><span class="o">=</span><span class="s1">'month'</span><span class="p">)</span>
<span class="n">rrd</span><span class="o">.</span><span class="n">graph</span><span class="p">(</span><span class="n">period</span><span class="o">=</span><span class="s1">'year'</span><span class="p">)</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="n">rrdfile</span> <span class="o">=</span> <span class="s1">'media/temperature.rrd'</span>
<span class="n">imgdir</span> <span class="o">=</span> <span class="s1">'media'</span>
<span class="n">rrd</span> <span class="o">=</span> <span class="n">RRDController</span><span class="p">(</span><span class="n">rrdfile</span><span class="o">=</span><span class="n">rrdfile</span><span class="p">,</span> <span class="n">static_path</span> <span class="o">=</span> <span class="n">imgdir</span><span class="p">)</span>
<span class="n">rrd</span><span class="o">.</span><span class="n">create</span><span class="p">()</span>
<span class="k">while</span><span class="p">(</span><span class="mi">1</span><span class="p">):</span>
<span class="n">update_rrd</span><span class="p">(</span><span class="n">rrd</span><span class="p">)</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">60</span><span class="p">)</span>
</pre></div>
</div>
<p>И файл rrdcontroller.py</p>
<div class="literal-block-wrapper docutils container" id="id3">
<div class="code-block-caption"><span class="caption-text">rrdcontroller.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pyrrd.rrd</span> <span class="kn">import</span> <span class="n">RRD</span><span class="p">,</span> <span class="n">RRA</span><span class="p">,</span> <span class="n">DS</span>
<span class="kn">from</span> <span class="nn">pyrrd.graph</span> <span class="kn">import</span> <span class="n">DEF</span><span class="p">,</span> <span class="n">CDEF</span><span class="p">,</span> <span class="n">VDEF</span>
<span class="kn">from</span> <span class="nn">pyrrd.graph</span> <span class="kn">import</span> <span class="n">LINE</span><span class="p">,</span> <span class="n">AREA</span><span class="p">,</span> <span class="n">GPRINT</span>
<span class="kn">from</span> <span class="nn">pyrrd.graph</span> <span class="kn">import</span> <span class="n">ColorAttributes</span><span class="p">,</span> <span class="n">Graph</span>
<span class="kn">import</span> <span class="nn">os</span><span class="o">,</span> <span class="nn">logging</span><span class="o">,</span> <span class="nn">time</span>
<span class="k">class</span> <span class="nc">RRDController</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">rrdfile</span><span class="p">,</span> <span class="n">static_path</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">rrdfile</span> <span class="o">=</span> <span class="n">rrdfile</span>
<span class="bp">self</span><span class="o">.</span><span class="n">static_path</span> <span class="o">=</span> <span class="n">static_path</span>
<span class="k">def</span> <span class="nf">delete</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">os</span><span class="o">.</span><span class="n">unlink</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">rrdfile</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">create</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">rrdfile</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">rrd</span> <span class="o">=</span> <span class="n">RRD</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">rrdfile</span><span class="p">)</span>
<span class="k">return</span>
<span class="n">dss</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">ds1</span> <span class="o">=</span> <span class="n">DS</span><span class="p">(</span><span class="n">dsName</span><span class="o">=</span><span class="s2">"temperature"</span><span class="p">,</span> <span class="n">dsType</span><span class="o">=</span><span class="s2">"GAUGE"</span><span class="p">,</span> <span class="n">heartbeat</span><span class="o">=</span><span class="mi">120</span><span class="p">,</span>
<span class="n">minval</span><span class="o">=-</span><span class="mf">10000000.0</span><span class="p">,</span> <span class="n">maxval</span><span class="o">=</span><span class="mf">100000000.0</span><span class="p">)</span>
<span class="n">dss</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ds1</span><span class="p">)</span>
<span class="n">day</span> <span class="o">=</span> <span class="mi">24</span> <span class="o">*</span> <span class="mi">60</span> <span class="o">*</span> <span class="mi">60</span>
<span class="n">week</span> <span class="o">=</span> <span class="mi">7</span> <span class="o">*</span> <span class="n">day</span>
<span class="n">month</span> <span class="o">=</span> <span class="n">day</span> <span class="o">*</span> <span class="mi">30</span>
<span class="n">quarter</span> <span class="o">=</span> <span class="n">month</span> <span class="o">*</span> <span class="mi">3</span>
<span class="n">half</span> <span class="o">=</span> <span class="mi">365</span> <span class="o">*</span> <span class="n">day</span> <span class="o">/</span> <span class="mi">2</span>
<span class="n">year</span> <span class="o">=</span> <span class="mi">365</span> <span class="o">*</span> <span class="n">day</span>
<span class="n">step</span> <span class="o">=</span> <span class="mi">60</span>
<span class="n">rras</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">rra1</span> <span class="o">=</span> <span class="n">RRA</span><span class="p">(</span><span class="n">cf</span><span class="o">=</span><span class="s2">"AVERAGE"</span><span class="p">,</span> <span class="n">xff</span><span class="o">=</span><span class="mf">0.5</span><span class="p">,</span> <span class="n">steps</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">rows</span><span class="o">=</span><span class="n">day</span><span class="o">/</span><span class="n">step</span><span class="p">)</span>
<span class="n">rra2</span> <span class="o">=</span> <span class="n">RRA</span><span class="p">(</span><span class="n">cf</span><span class="o">=</span><span class="s2">"AVERAGE"</span><span class="p">,</span> <span class="n">xff</span><span class="o">=</span><span class="mf">0.5</span><span class="p">,</span> <span class="n">steps</span><span class="o">=</span><span class="mi">30</span><span class="p">,</span> <span class="n">rows</span><span class="o">=</span><span class="n">week</span><span class="o">/</span><span class="p">(</span><span class="mi">30</span><span class="o">*</span><span class="n">step</span><span class="p">))</span>
<span class="n">rra3</span> <span class="o">=</span> <span class="n">RRA</span><span class="p">(</span><span class="n">cf</span><span class="o">=</span><span class="s2">"AVERAGE"</span><span class="p">,</span> <span class="n">xff</span><span class="o">=</span><span class="mf">0.5</span><span class="p">,</span> <span class="n">steps</span><span class="o">=</span><span class="mi">120</span><span class="p">,</span> <span class="n">rows</span><span class="o">=</span><span class="n">month</span><span class="o">/</span><span class="p">(</span><span class="mi">120</span><span class="o">*</span><span class="n">step</span><span class="p">))</span>
<span class="n">rra4</span> <span class="o">=</span> <span class="n">RRA</span><span class="p">(</span><span class="n">cf</span><span class="o">=</span><span class="s2">"AVERAGE"</span><span class="p">,</span> <span class="n">xff</span><span class="o">=</span><span class="mf">0.5</span><span class="p">,</span> <span class="n">steps</span><span class="o">=</span><span class="mi">720</span><span class="p">,</span> <span class="n">rows</span><span class="o">=</span><span class="n">year</span><span class="o">/</span><span class="p">(</span><span class="mi">720</span><span class="o">*</span><span class="n">step</span><span class="p">))</span>
<span class="n">rras</span><span class="o">.</span><span class="n">extend</span><span class="p">([</span><span class="n">rra1</span><span class="p">,</span> <span class="n">rra2</span><span class="p">,</span> <span class="n">rra3</span><span class="p">,</span> <span class="n">rra4</span><span class="p">])</span>
<span class="n">rras</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">rra1</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">rrd</span> <span class="o">=</span> <span class="n">RRD</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">rrdfile</span><span class="p">,</span> <span class="n">step</span><span class="o">=</span><span class="n">step</span><span class="p">,</span> <span class="n">ds</span><span class="o">=</span><span class="n">dss</span><span class="p">,</span> <span class="n">rra</span><span class="o">=</span><span class="n">rras</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">rrd</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">debug</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">temperature</span><span class="p">):</span>
<span class="k">print</span> <span class="n">temperature</span>
<span class="bp">self</span><span class="o">.</span><span class="n">rrd</span><span class="o">.</span><span class="n">bufferValue</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">(),</span> <span class="n">temperature</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">rrd</span><span class="o">.</span><span class="n">update</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">graph_temperature</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">period</span><span class="o">=</span><span class="s1">'day'</span><span class="p">):</span>
<span class="n">def1</span> <span class="o">=</span> <span class="n">DEF</span><span class="p">(</span><span class="n">rrdfile</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">rrdfile</span><span class="p">,</span> <span class="n">vname</span><span class="o">=</span><span class="s1">'temp'</span><span class="p">,</span> <span class="n">dsName</span><span class="o">=</span><span class="s2">"temperature"</span><span class="p">,</span>
<span class="n">cdef</span><span class="o">=</span><span class="s2">"AVERAGE"</span><span class="p">)</span>
<span class="c1"># TOTAL</span>
<span class="n">vdef1</span> <span class="o">=</span> <span class="n">VDEF</span><span class="p">(</span><span class="n">vname</span><span class="o">=</span><span class="s1">'max'</span><span class="p">,</span> <span class="n">rpn</span><span class="o">=</span><span class="s1">'temp,MAXIMUM'</span><span class="p">)</span>
<span class="n">vdef2</span> <span class="o">=</span> <span class="n">VDEF</span><span class="p">(</span><span class="n">vname</span><span class="o">=</span><span class="s1">'avg'</span><span class="p">,</span> <span class="n">rpn</span><span class="o">=</span><span class="s1">'temp,AVERAGE'</span><span class="p">)</span>
<span class="n">vdef3</span> <span class="o">=</span> <span class="n">VDEF</span><span class="p">(</span><span class="n">vname</span><span class="o">=</span><span class="s1">'last'</span><span class="p">,</span> <span class="n">rpn</span><span class="o">=</span><span class="s1">'temp,LAST'</span><span class="p">)</span>
<span class="n">vdef4</span> <span class="o">=</span> <span class="n">VDEF</span><span class="p">(</span><span class="n">vname</span><span class="o">=</span><span class="s1">'min'</span><span class="p">,</span> <span class="n">rpn</span><span class="o">=</span><span class="s1">'temp,MINIMUM'</span><span class="p">)</span>
<span class="n">line1</span> <span class="o">=</span> <span class="n">LINE</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">defObj</span><span class="o">=</span><span class="n">def1</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s1">'#FF2222'</span><span class="p">,</span> <span class="n">legend</span><span class="o">=</span><span class="s1">'Total'</span><span class="p">)</span>
<span class="n">gprint1</span> <span class="o">=</span> <span class="n">GPRINT</span><span class="p">(</span><span class="n">vdef1</span><span class="p">,</span> <span class="s2">"Max</span><span class="se">\\</span><span class="s2">: </span><span class="si">%5.1lf</span><span class="s2"> %S"</span><span class="p">)</span>
<span class="n">gprint2</span> <span class="o">=</span> <span class="n">GPRINT</span><span class="p">(</span><span class="n">vdef2</span><span class="p">,</span> <span class="s2">"Avg</span><span class="se">\\</span><span class="s2">: </span><span class="si">%5.1lf</span><span class="s2"> %S"</span><span class="p">)</span>
<span class="n">gprint3</span> <span class="o">=</span> <span class="n">GPRINT</span><span class="p">(</span><span class="n">vdef3</span><span class="p">,</span> <span class="s2">"Current</span><span class="se">\\</span><span class="s2">: </span><span class="si">%5.1lf</span><span class="s2"> %S"</span><span class="p">)</span>
<span class="n">gprint4</span> <span class="o">=</span> <span class="n">GPRINT</span><span class="p">(</span><span class="n">vdef4</span><span class="p">,</span> <span class="s2">"Min</span><span class="se">\\</span><span class="s2">: </span><span class="si">%5.1lf</span><span class="s2"> %S</span><span class="se">\\</span><span class="s2">n"</span><span class="p">)</span>
<span class="n">ca</span> <span class="o">=</span> <span class="n">ColorAttributes</span><span class="p">()</span>
<span class="n">ca</span><span class="o">.</span><span class="n">back</span> <span class="o">=</span> <span class="s1">'#FFFFFF'</span>
<span class="n">ca</span><span class="o">.</span><span class="n">canvas</span> <span class="o">=</span> <span class="s1">'#FFFFFF'</span>
<span class="n">ca</span><span class="o">.</span><span class="n">shadea</span> <span class="o">=</span> <span class="s1">'#000000'</span>
<span class="n">ca</span><span class="o">.</span><span class="n">shadeb</span> <span class="o">=</span> <span class="s1">'#111111'</span>
<span class="n">ca</span><span class="o">.</span><span class="n">mgrid</span> <span class="o">=</span> <span class="s1">'#CCCCCC'</span>
<span class="n">ca</span><span class="o">.</span><span class="n">axis</span> <span class="o">=</span> <span class="s1">'#333333'</span>
<span class="n">ca</span><span class="o">.</span><span class="n">frame</span> <span class="o">=</span> <span class="s1">'#AAAAAA'</span>
<span class="n">ca</span><span class="o">.</span><span class="n">font</span> <span class="o">=</span> <span class="s1">'#333333'</span>
<span class="n">ca</span><span class="o">.</span><span class="n">arrow</span> <span class="o">=</span> <span class="s1">'#333333'</span>
<span class="n">img</span> <span class="o">=</span> <span class="s2">"temperature-</span><span class="si">%s</span><span class="s2">.png"</span> <span class="o">%</span> <span class="n">period</span>
<span class="n">imgname</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">static_path</span> <span class="o">+</span><span class="s2">"/"</span><span class="o">+</span> <span class="n">img</span>
<span class="n">start</span> <span class="o">=</span> <span class="s1">'-1'</span><span class="o">+</span><span class="n">period</span>
<span class="n">g</span> <span class="o">=</span> <span class="n">Graph</span><span class="p">(</span><span class="n">imgname</span><span class="p">,</span> <span class="n">imgformat</span><span class="o">=</span><span class="s1">'PNG'</span><span class="p">,</span> <span class="n">step</span><span class="o">=</span><span class="n">start</span><span class="p">,</span>
<span class="n">vertical_label</span><span class="o">=</span><span class="s1">'temperature'</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="n">ca</span><span class="p">,</span>
<span class="n">width</span><span class="o">=</span><span class="mi">700</span><span class="p">,</span> <span class="n">height</span><span class="o">=</span><span class="mi">150</span>
<span class="p">)</span>
<span class="n">g</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">extend</span><span class="p">([</span><span class="n">def1</span><span class="p">,</span> <span class="n">vdef1</span><span class="p">,</span> <span class="n">vdef2</span><span class="p">,</span> <span class="n">vdef3</span><span class="p">,</span> <span class="n">vdef4</span><span class="p">,</span> <span class="n">line1</span><span class="p">,</span> <span class="n">gprint1</span><span class="p">,</span>
<span class="n">gprint2</span><span class="p">,</span> <span class="n">gprint3</span><span class="p">,</span> <span class="n">gprint4</span><span class="p">])</span>
<span class="n">g</span><span class="o">.</span><span class="n">write</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">graph</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">period</span><span class="o">=</span><span class="s1">'day'</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">graph_temperature</span><span class="p">(</span><span class="n">period</span><span class="p">)</span>
</pre></div>
</div>
</div>
<p>После запуска скрипта он создаст <a class="reference external" href="http://oss.oetiker.ch/rrdtool/">RRD</a> базу если ее еще нет, начнет каждые 60 сек
добавлять значения и отрисовывать графики. Осталось только отдать эти графики
по запросу. Для этого используем фреймворк <a class="reference external" href="www.tornadoweb.org/">Tornado</a>.</p>
<p>Создадим файл <code class="docutils literal"><span class="pre">weather_srv.py</span></code> в той же директории где папка <code class="docutils literal"><span class="pre">media</span></code> с нашими графиками:</p>
<div class="literal-block-wrapper docutils container" id="id4">
<div class="code-block-caption"><span class="caption-text">weather_srv.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="ch">#!/usr/bin/python</span>
<span class="c1">#coding: utf-8</span>
<span class="kn">import</span> <span class="nn">tornado.ioloop</span>
<span class="kn">import</span> <span class="nn">tornado.web</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="k">class</span> <span class="nc">MainHandler</span><span class="p">(</span><span class="n">tornado</span><span class="o">.</span><span class="n">web</span><span class="o">.</span><span class="n">RequestHandler</span><span class="p">):</span>
<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">f</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s1">'temp.cashe'</span><span class="p">)</span>
<span class="n">temp</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">render</span><span class="p">(</span><span class="s2">"index.html"</span><span class="p">,</span> <span class="n">temp</span><span class="o">=</span><span class="n">temp</span><span class="p">)</span>
<span class="n">application</span> <span class="o">=</span> <span class="n">tornado</span><span class="o">.</span><span class="n">web</span><span class="o">.</span><span class="n">Application</span><span class="p">([</span>
<span class="p">(</span><span class="sa">r</span><span class="s2">"/"</span><span class="p">,</span> <span class="n">MainHandler</span><span class="p">),</span>
<span class="p">(</span><span class="sa">r</span><span class="s2">"/media/(.*)"</span><span class="p">,</span> <span class="n">tornado</span><span class="o">.</span><span class="n">web</span><span class="o">.</span><span class="n">StaticFileHandler</span><span class="p">,</span> <span class="p">{</span><span class="s2">"path"</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">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="vm">__file__</span><span class="p">),</span> <span class="s2">"media"</span><span class="p">)}),</span>
<span class="p">])</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span>
<span class="n">application</span><span class="o">.</span><span class="n">listen</span><span class="p">(</span><span class="mi">8009</span><span class="p">)</span>
<span class="n">tornado</span><span class="o">.</span><span class="n">ioloop</span><span class="o">.</span><span class="n">IOLoop</span><span class="o">.</span><span class="n">instance</span><span class="p">()</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
</pre></div>
</div>
</div>
<p>Шаблон index.html</p>
<div class="literal-block-wrapper docutils container" id="id5">
<div class="code-block-caption"><span class="caption-text">index.html</span></div>
<div class="highlight-html+jinja"><div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">html</span><span class="p">></span>
<span class="p"><</span><span class="nt">head</span><span class="p">></span>
<span class="p"><</span><span class="nt">title</span><span class="p">></span>Температура на улице<span class="p"></</span><span class="nt">title</span><span class="p">></span>
<span class="p"></</span><span class="nt">head</span><span class="p">></span>
<span class="p"><</span><span class="nt">body</span> <span class="na">bgcolor</span><span class="o">=</span><span class="s">"white"</span> <span class="na">text</span><span class="o">=</span><span class="s">"black"</span><span class="p">></span>
<span class="p"><</span><span class="nt">center</span><span class="p">><</span><span class="nt">font</span> <span class="na">size</span><span class="o">=</span><span class="s">"5"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">escape</span><span class="o">(</span><span class="nv">temp</span><span class="o">)</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">b</span><span class="p">></span>C°<span class="p"></</span><span class="nt">font</span><span class="p">></span>
<span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"media/temperature-day.png"</span> <span class="na">title</span><span class="o">=</span><span class="s">"температура за день"</span><span class="p">></span>
<span class="p"></</span><span class="nt">center</span><span class="p">></span>
<span class="p"></</span><span class="nt">body</span><span class="p">></span>
<span class="p"></</span><span class="nt">html</span><span class="p">></span>
</pre></div>
</div>
</div>
<div class="line-block">
<div class="line">Запускаем <code class="docutils literal"><span class="pre">weather_srv.py</span></code> и радуемся графикам.</div>
<div class="line">Описание по измерению температуры <a class="reference external" href="http://termal.me">http://termal.me</a></div>
</div>
<p>Дополнительно для прочтения:</p>
<ul class="simple">
<li><a class="reference external" href="http://bozza.ru/art-105.html">Перевод документации RRDTool</a></li>
<li><a class="reference external" href="http://habrahabr.ru/blogs/python/30655/">Пример с хабра</a></li>
<li><a class="reference external" href="https://github.com/marcelnicolay/nginx-monitor/blob/master/nmonitor/util/rrdcontroller.py">nginx-monitor похожий пример для nginx</a></li>
</ul>
</div>
The Content Assignment
http://uralbash.ru/articles/2011/content_assigment/
2011-11-06T01:49:00Z
2011-11-06T01:49:00Z
Uralbash
<div class="section" id="the-content-assignment">
<p>В этом топике вольный перевод довольно интересной статьи <a class="reference external" href="http://knolleary.net">http://knolleary.net</a>
об одной книге издательства <a class="reference external" href="http://www.penguin.co.uk/">penguin books</a>.</p>
<p>Хотел бы я знать полную историю этой книги, не самого содержания, а того кто
сделал эти замечательные записи. Рассказ в книге о шпионе “триллер” (я использую
эти слова с осторожностью), действующий в годы холодной войны. Написанная от
первого лица, британским репортером John Terrant, который пытается выследит
таинственного Ellen Content с которой он имел контакт в Берлине. Опубликованная
в 1954 году, книга, безусловно, продукт своей эпохи - но об этом позже.</p>
<p>Я думаю в этом месте нужно добавить предупреждение. Что после прочтения этой
статьи будут раскрыты многие аспекты книги (автор имеет ввиду что после
прочтения раскроются многие факты из книги и в последующем интерес к прочтению
может пропасть).</p>
<img alt="_static/2011/ca1.jpg" class="align-center" src="_static/2011/ca1.jpg" />
<p>Мы еще вернемся к этой книге которую я сейчас держу в руках, но прежде я должен
кое что рассказать. Насколько мне известно она когда-то принадлежала моим
старикам и потом досталась мне уже от родителей. А до них книга принадлежала
некой “Gioladys O Williams”. Откуда я это знаю? Она просто написала свое имя
здесь. Вообще я отлично знаю Английский имея 28 лет практики, но ее имя
несомненно меня озадачило - может быть “Gladys” а не “Gioladys”?</p>
<p>Обновление: <a class="reference external" href="http://knolleary.net/2009/11/12/the-content-assignment/#comment-12451">Adrian</a>
любезно пояснил ниже(имеется ввиду в комментах), что это “Gwladys”. Учитывая
тот факт что “Gwladys” побеждает “Gioladys” в сервисе <a class="reference external" href="http://www.googlefight.com/index.php?lang=en_GB&word1=gioladys&word2=gwladys">google fight</a>,
я подозреваю, что так оно и есть. На самом деле, теперь я не могу читать ее как
что-нибудь кроме “Gwladys”.</p>
<img alt="_static/2011/ca2.jpg" class="align-center" src="_static/2011/ca2.jpg" style="width: 500px;" />
<p>Книга рассказывает как John, наш главный герой, обнаруживает объявление в
газете, что мис Ellen Content вернулась в Нью-Йорк через океан. По причинам до
сих пор необъяснимым, не теряет решимости добраться до Нью-Йорка за ней. Он
утверждает своего редактора профинансировать это как письменное задание - the
Content Assignment.</p>
<p>Перейдем ко второй главе, где начинается самое интересное. Весь полет, John
вспоминает как он впервые встретился с Ellen Content. Перенося нас в Берлин
1948 года, сцена происходит в городе. “денацификации была почти завершена в
британской и американской зоне, идет медленно во французской, и почти совсем
нет в русской”. Это первый признак того когда была написанна книга; понятно что
Россия представляется не в лучшем свете. То что удосужило написать меня о, в
противном случае забытой книге, это то что мисс Williams не остановилась на
простом написании своего имени на обложке. Она сделала гораздо больше.</p>
<img alt="_static/2011/ca3.jpg" class="align-center" src="_static/2011/ca3.jpg" style="width: 500px;" />
<p>Очевидно что она не согласна с написанным, но восхищает что она продолжила читать...</p>
<p>Вначале я подумал это отрицательный образ Русских расстраивает ее, но дальше
она показывает что не ограничивается только этим.</p>
<img alt="_static/2011/ca4.jpg" class="align-center" src="_static/2011/ca4.jpg" style="width: 500px;" />
<br/><img alt="_static/2011/ca5.jpg" class="align-center" src="_static/2011/ca5.jpg" style="width: 500px;" />
<p>Имея ввиду что книга была написана от первого лица, трудно сказать кому
адресуются комментарии автору или John главному герою.</p>
<p>До этого момента, все комментарии касались отдельных кусочков текста. Это
продолжалось до стр. 38, мисс Williams невыдержала и начала писать то, что она
действительно думает.</p>
<img alt="_static/2011/ca6.jpg" class="align-center" src="_static/2011/ca6.jpg" style="width: 500px;" />
<p>Бьюсь об заклад, после этого ей стало легче хотя это спорно судя по следующим
комментариям. Замечу что ни кто не застрахован от ее записей. В первую очередь
Британские спецслужбы и полиция.</p>
<img alt="_static/2011/ca7.jpg" class="align-center" src="_static/2011/ca7.jpg" style="width: 500px;" />
<br/><img alt="_static/2011/ca8.jpg" class="align-center" src="_static/2011/ca8.jpg" style="width: 500px;" />
<p>Она имеет ввиду бизнес (я так понял продажные спецслужбы) и потом подписывается
своим именем.</p>
<p>Шокирующий поворот событий, когда она согласится с чем то в книге.</p>
<img alt="_static/2011/ca9.jpg" class="align-center" src="_static/2011/ca9.jpg" style="width: 500px;" />
<p>Но она не может сдерживать себя. Здания Нью-Йорка преподносят сюрпризы в ее
карательный список.</p>
<img alt="_static/2011/ca10.jpg" class="align-center" src="_static/2011/ca10.jpg" style="width: 500px;" />
<p>Должно быть, она устала в этот момент, так как ее следующий комментарий всего
одно слово, которое не вполне очевидно объясняет ее точку зрения. Возможно
ирония John как часть чего то странного в этой книге.</p>
<img alt="_static/2011/ca11.jpg" class="align-center" src="_static/2011/ca11.jpg" style="width: 500px;" />
<p>Снова мисс Williams не может до конца определиться в высказывании - характер
оскорбительно плохово написания или плохово стиля написания.</p>
<img alt="_static/2011/ca12.jpg" class="align-center" src="_static/2011/ca12.jpg" style="width: 500px;" />
<p>Ближе к концу книги, она возвращается к своей любимой теме.</p>
<img alt="_static/2011/ca13.jpg" class="align-center" src="_static/2011/ca13.jpg" style="width: 500px;" />
<p>и опять же плохой почерк. (здесь написано “not all Russians”)</p>
<img alt="_static/2011/ca14.jpg" class="align-center" src="_static/2011/ca14.jpg" style="width: 500px;" />
<p>В заключительных страницах, она решает сказать то, что действительно думает.</p>
<img alt="_static/2011/ca15.jpg" class="align-center" src="_static/2011/ca15.jpg" style="width: 500px;" />
<p>Я надеюсь они получат сообщение - мисс Williams это не нравится. Я почти жалею
что это посление сообщение. Но на этом все.</p>
<img alt="_static/2011/ca16.jpg" class="align-center" src="_static/2011/ca16.jpg" style="width: 500px;" />
<p>Я слышу ее маниакально смеясь, она положила перо, закрыв книгу и почувствовала
невероятное удовлетворение, направив мир в нужное русло.</p>
<p>Это то что люди делают пока имеют свое мнение.</p>
<p>Ничего себе. Просто ничего себе.</p>
<p>P.S.: Меня восхитило не то что здесь восхваляют Русских, хотя это однозначно
приятно, а то что во время информационной войны есть люди которые сохраняют
свой разум, вместо того что бы пастись под всей этой политической бестией.
Причем это касается многих стран к сожалению и Россию.</p>
<p>P.P.S.: Возможно в переводе есть ошибки прошу поправить меня..</p>
</div>
Linux xfce настройка двух мониторов
http://uralbash.ru/articles/2011/xfce_display/
2011-11-05T19:24:00Z
2011-11-05T19:24:00Z
Uralbash
<div class="section" id="linux-xfce">
<p>В <a class="reference external" href="http://www.xfce.org/">Xfce</a> по умолчанию второй монитор работает в режиме зеркало. Что бы
настроить его под себя придется лезть в консоль, т.к. более менее нормальных
desktop приложений я не обнаружил. Нам понадобится команда <a class="reference external" href="http://www.x.org/wiki/Projects/XRandR/">xrandr</a>. Если ее запустить без параметров то
она покажет параметры мониторов:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ xrandr
Screen <span class="m">0</span>: minimum <span class="m">320</span> x <span class="m">200</span>, current <span class="m">3200</span> x <span class="m">1080</span>, maximum <span class="m">3200</span> x <span class="m">2646</span>
LVDS connected 1280x768+0+0 <span class="o">(</span>normal left inverted right x axis y axis<span class="o">)</span> 256mm x 144mm
1366x768 <span class="m">60</span>.0 +
1280x768 <span class="m">60</span>.0*+
1280x720 <span class="m">60</span>.0 +
1024x768 <span class="m">60</span>.0 +
1280x600 <span class="m">60</span>.0 +
1024x600 <span class="m">60</span>.0 +
800x600 <span class="m">60</span>.0 +
800x480 <span class="m">60</span>.0 +
640x480 <span class="m">60</span>.0 +
CRT1 connected 1920x1080+1280+0 <span class="o">(</span>normal left inverted right x axis y axis<span class="o">)</span> 510mm x 287mm
1280x1024 <span class="m">60</span>.0 +
1920x1080 <span class="m">60</span>.0*+
1680x1050 <span class="m">60</span>.0
1400x1050 <span class="m">60</span>.0
1440x900 <span class="m">59</span>.9
1280x960 <span class="m">60</span>.0
1366x768 <span class="m">59</span>.9
1280x800 <span class="m">60</span>.0
1152x864 <span class="m">75</span>.0 <span class="m">60</span>.0
1280x768 <span class="m">59</span>.9
1280x720 <span class="m">60</span>.0
1024x768 <span class="m">75</span>.0 <span class="m">70</span>.1 <span class="m">60</span>.0
1280x600 <span class="m">60</span>.0
1024x600 <span class="m">60</span>.0
800x600 <span class="m">75</span>.0 <span class="m">70</span>.0 <span class="m">60</span>.3 <span class="m">56</span>.2
800x480 <span class="m">60</span>.0
640x480 <span class="m">75</span>.0 <span class="m">60</span>.0
</pre></div>
</div>
<p><code class="docutils literal"><span class="pre">CRT1</span></code> у меня это дополнительный (второй) монитор. <code class="docutils literal"><span class="pre">LVDS</span></code> - монитор
ноутбука. Для того что было так:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span> <span class="o">++++++++++++++++++++++++</span>
<span class="o">+</span> <span class="o">+</span>
<span class="o">+++++++++++++++</span> <span class="o">+</span>
<span class="o">+</span> <span class="o">+</span> <span class="n">CRT1</span> <span class="o">+</span>
<span class="o">+</span> <span class="n">LVDS</span> <span class="o">+</span> <span class="o">+</span>
<span class="o">+</span> <span class="o">+</span> <span class="o">+</span>
<span class="o">++++++++++++++++++++++++++++++++++++++</span>
</pre></div>
</div>
<p>Выполним команду:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ xrandr --output LVDS --mode 1280x768 --output CRT1 --mode 1920x1080 --right-of LVDS
</pre></div>
</div>
<div class="line-block">
<div class="line"><code class="docutils literal"><span class="pre">--output</span> <span class="pre">LVDS</span> <span class="pre">--mode</span> <span class="pre">1280x768</span></code> это разрешение первого экрана</div>
<div class="line"><code class="docutils literal"><span class="pre">--output</span> <span class="pre">CRT1</span> <span class="pre">--mode</span> <span class="pre">1920x1080</span></code> разрешение второго экрана</div>
<div class="line"><code class="docutils literal"><span class="pre">--right-of</span> <span class="pre">LVDS</span></code> расположение экрана (также может быть <code class="docutils literal"><span class="pre">left-of</span></code>, <code class="docutils literal"><span class="pre">before</span></code>, <code class="docutils literal"><span class="pre">after</span></code>)</div>
</div>
<p>Это расширенный режим и если в нем возникнет ошибка связанная с разрешением то
либо вы указали разрешение которое не поддерживает монитор, либо ширина данного
режима больше чем указанно в настройках <a class="reference external" href="http://www.x.org/">X.org</a> (<code class="docutils literal"><span class="pre">/etx/X11/xorg.conf</span></code>).</p>
<p>Для сдвига панели нужно пользоваться ключом <code class="docutils literal"><span class="pre">--pos</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ xrandr --output LVDS --mode 1280x768 --pos 320x156 --output CRT1 --mode 1920x1080 --right-of LVDS --pos 0x0
</pre></div>
</div>
<p>Я вычислял <code class="docutils literal"><span class="pre">pos</span></code> так <code class="docutils literal"><span class="pre">([1280x768]-[1920x1080])/2=320x156</span></code></p>
<p>Для сброса настроек монитора есть ключ <code class="docutils literal"><span class="pre">--off</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ xrandr --off CRT1
</pre></div>
</div>
</div>
Админка FormAlchemy для Pylons и Jinja
http://uralbash.ru/articles/2011/formalchemy/
2011-10-27T03:31:00Z
2011-10-27T03:31:00Z
Uralbash
<div class="section" id="formalchemy-pylons-jinja">
<p>Для <a class="reference external" href="http://sqlalchemy.org/">SQLAlchemy</a> существуют интерфейсы управления моделями(что-то типа админки).
Как минимум их 2, это <a class="reference external" href="http://brickenstein.bitbucket.org/rum-docs/user/tutorial.html">Rum</a> и
<a class="reference external" href="http://docs.formalchemy.org/formalchemy/ext/pylons.html">formalchemy.ext.pylons</a>.</p>
<p>Рассмотрим <a class="reference external" href="http://docs.formalchemy.org/">FormAlchemy</a>. Вообще как обычно можно прочитать документацию, но я
опишу еще как это все состыковать с шаблонами на <a class="reference external" href="http://jinja.pocoo.org/">Jinja</a> и поддержкой полей
<a class="reference external" href="http://postgresql.org">Postgres</a> таких как <code class="docutils literal"><span class="pre">MAC</span></code>, <code class="docutils literal"><span class="pre">CIDR</span></code>, <code class="docutils literal"><span class="pre">NET</span></code> и т.д..</p>
<p>Создаем контроллер <code class="docutils literal"><span class="pre">admin</span></code>:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ paster controller admin
</pre></div>
</div>
<p>Далее редактируем его:</p>
<div class="literal-block-wrapper docutils container" id="id1">
<div class="code-block-caption"><span class="caption-text">controllers/admin.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1"># coding=utf-8</span>
<span class="kn">import</span> <span class="nn">logging</span>
<span class="kn">from</span> <span class="nn">pylons</span> <span class="kn">import</span> <span class="n">request</span><span class="p">,</span> <span class="n">response</span><span class="p">,</span> <span class="n">session</span><span class="p">,</span> <span class="n">tmpl_context</span> <span class="k">as</span> <span class="n">c</span><span class="p">,</span> <span class="n">url</span>
<span class="kn">from</span> <span class="nn">formalchemy.ext.pylons.controller</span> <span class="kn">import</span> <span class="n">ModelsController</span>
<span class="kn">from</span> <span class="nn">webhelpers.paginate</span> <span class="kn">import</span> <span class="n">Page</span>
<span class="kn">from</span> <span class="nn">repoze.what.predicates</span> <span class="kn">import</span> <span class="n">has_permission</span>
<span class="kn">from</span> <span class="nn">repoze.what.plugins.pylonshq</span> <span class="kn">import</span> <span class="n">ControllerProtector</span>
<span class="kn">from</span> <span class="nn">myapp.lib.base</span> <span class="kn">import</span> <span class="n">BaseController</span>
<span class="kn">from</span> <span class="nn">myapp</span> <span class="kn">import</span> <span class="n">model</span>
<span class="kn">from</span> <span class="nn">myapp</span> <span class="kn">import</span> <span class="n">forms</span>
<span class="kn">from</span> <span class="nn">myapp.model</span> <span class="kn">import</span> <span class="n">meta</span>
<span class="n">log</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">AdminControllerBase</span><span class="p">(</span><span class="n">BaseController</span><span class="p">):</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">model</span> <span class="c1"># where your SQLAlchemy mappers are</span>
<span class="n">forms</span> <span class="o">=</span> <span class="n">forms</span> <span class="c1"># module containing FormAlchemy fieldsets definitions</span>
<span class="k">def</span> <span class="nf">Session</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="c1"># Session factory</span>
<span class="k">return</span> <span class="n">meta</span><span class="o">.</span><span class="n">Session</span>
<span class="c1">## customize the query for a model listing</span>
<span class="c1"># def get_page(self):</span>
<span class="c1"># if self.model_name == 'Foo':</span>
<span class="c1"># return Page(meta.Session.query(model.Foo).order_by(model.Foo.bar)</span>
<span class="c1"># return super(AdminControllerBase, self).get_page()</span>
<span class="n">AdminController</span> <span class="o">=</span> <span class="n">ModelsController</span><span class="p">(</span><span class="n">AdminControllerBase</span><span class="p">,</span>
<span class="n">prefix_name</span><span class="o">=</span><span class="s1">'admin'</span><span class="p">,</span>
<span class="n">member_name</span><span class="o">=</span><span class="s1">'model'</span><span class="p">,</span>
<span class="n">collection_name</span><span class="o">=</span><span class="s1">'models'</span><span class="p">,)</span>
</pre></div>
</div>
</div>
<p>Дальше добавляем пути:</p>
<div class="literal-block-wrapper docutils container" id="id2">
<div class="code-block-caption"><span class="caption-text">config/routing.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1"># ADMIN</span>
<span class="c1"># Map the /admin url to FA's AdminController</span>
<span class="c1"># Map static files</span>
<span class="nb">map</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s1">'fa_static'</span><span class="p">,</span> <span class="s1">'/admin/_static/{path_info:.*}'</span><span class="p">,</span>
<span class="n">controller</span><span class="o">=</span><span class="s1">'admin'</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s1">'static'</span><span class="p">)</span>
<span class="c1"># Index page</span>
<span class="nb">map</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s1">'admin'</span><span class="p">,</span> <span class="s1">'/admin'</span><span class="p">,</span> <span class="n">controller</span><span class="o">=</span><span class="s1">'admin'</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s1">'models'</span><span class="p">)</span>
<span class="nb">map</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s1">'formatted_admin'</span><span class="p">,</span> <span class="s1">'/admin.json'</span><span class="p">,</span> <span class="n">controller</span><span class="o">=</span><span class="s1">'admin'</span><span class="p">,</span>
<span class="n">action</span><span class="o">=</span><span class="s1">'models'</span><span class="p">,</span> <span class="n">format</span><span class="o">=</span><span class="s1">'json'</span><span class="p">)</span>
<span class="c1"># Models</span>
<span class="nb">map</span><span class="o">.</span><span class="n">resource</span><span class="p">(</span><span class="s1">'model'</span><span class="p">,</span> <span class="s1">'models'</span><span class="p">,</span> <span class="n">path_prefix</span><span class="o">=</span><span class="s1">'/admin/{model_name}'</span><span class="p">,</span>
<span class="n">controller</span><span class="o">=</span><span class="s1">'admin'</span><span class="p">)</span>
</pre></div>
</div>
</div>
<p>И добавим в шаблоны папку <code class="docutils literal"><span class="pre">myapp/templates/forms</span></code> можно взять с <a class="reference external" href="https://github.com/FormAlchemy/formalchemy/tree/master/pylonsapp/pylonsapp/templates">github</a>.</p>
<p>Правим следующим образом:</p>
<div class="literal-block-wrapper docutils container" id="id3">
<div class="code-block-caption"><span class="caption-text">myapp/forms/__init__.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pylons.templating</span> <span class="kn">import</span> <span class="n">render_mako</span>
<span class="kn">from</span> <span class="nn">pylons</span> <span class="kn">import</span> <span class="n">config</span>
<span class="kn">from</span> <span class="nn">myapp</span> <span class="kn">import</span> <span class="n">model</span>
<span class="kn">from</span> <span class="nn">myapp.lib.base</span> <span class="kn">import</span> <span class="n">render</span>
<span class="kn">from</span> <span class="nn">formalchemy</span> <span class="kn">import</span> <span class="n">config</span> <span class="k">as</span> <span class="n">fa_config</span>
<span class="kn">from</span> <span class="nn">formalchemy</span> <span class="kn">import</span> <span class="n">templates</span>
<span class="kn">from</span> <span class="nn">formalchemy</span> <span class="kn">import</span> <span class="n">validators</span>
<span class="kn">from</span> <span class="nn">formalchemy</span> <span class="kn">import</span> <span class="n">fields</span>
<span class="kn">from</span> <span class="nn">formalchemy</span> <span class="kn">import</span> <span class="n">forms</span>
<span class="kn">from</span> <span class="nn">formalchemy</span> <span class="kn">import</span> <span class="n">tables</span>
<span class="kn">from</span> <span class="nn">formalchemy.ext.fsblob</span> <span class="kn">import</span> <span class="n">FileFieldRenderer</span>
<span class="kn">from</span> <span class="nn">formalchemy.ext.fsblob</span> <span class="kn">import</span> <span class="n">ImageFieldRenderer</span>
<span class="n">fa_config</span><span class="o">.</span><span class="n">encoding</span> <span class="o">=</span> <span class="s1">'utf-8'</span>
<span class="k">class</span> <span class="nc">TemplateEngine</span><span class="p">(</span><span class="n">templates</span><span class="o">.</span><span class="n">TemplateEngine</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">render</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="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">return</span> <span class="n">render_mako</span><span class="p">(</span><span class="s1">'/forms/</span><span class="si">%s</span><span class="s1">.mako'</span> <span class="o">%</span> <span class="n">name</span><span class="p">,</span> <span class="n">extra_vars</span><span class="o">=</span><span class="n">kwargs</span><span class="p">)</span>
<span class="n">fa_config</span><span class="o">.</span><span class="n">engine</span> <span class="o">=</span> <span class="n">TemplateEngine</span><span class="p">()</span>
<span class="k">class</span> <span class="nc">FieldSet</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">FieldSet</span><span class="p">):</span>
<span class="k">pass</span>
<span class="k">class</span> <span class="nc">Grid</span><span class="p">(</span><span class="n">tables</span><span class="o">.</span><span class="n">Grid</span><span class="p">):</span>
<span class="k">pass</span>
<span class="c1">## Initialize fieldsets</span>
<span class="c1">#Foo = FieldSet(model.Foo)</span>
<span class="c1">#Reflected = FieldSet(Reflected)</span>
<span class="c1">## Initialize grids</span>
<span class="c1">#FooGrid = Grid(model.Foo)</span>
<span class="c1">#ReflectedGrid = Grid(Reflected)</span>
</pre></div>
</div>
</div>
<p>Сейчас, как и пишут в документации, вы действительно по адресу
<code class="docutils literal"><span class="pre">http://localhost:5000/admin</span></code> попадете в админку! Но только если вы не
используете особенностей БД, например <code class="xref py py-mod docutils literal"><span class="pre">sqlalchemy.databases.postgresql</span></code>.
Вторая проблема в том что шаблоны админки не встроены в ваши шаблоны.</p>
<p>Для поддержки <a class="reference external" href="http://postgresql.org">Postgres</a> полей в <a class="reference external" href="http://docs.formalchemy.org/">FormAlchemy</a> необходимо добавить:</p>
<div class="literal-block-wrapper docutils container" id="id4">
<div class="code-block-caption"><span class="caption-text">lib/base.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">formalchemy.fields</span> <span class="kn">import</span> <span class="n">FieldRenderer</span>
<span class="kn">from</span> <span class="nn">formalchemy.tests</span> <span class="kn">import</span> <span class="n">FieldSet</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.databases</span> <span class="kn">import</span> <span class="n">postgresql</span>
<span class="k">class</span> <span class="nc">PostgresFieldRenderer</span><span class="p">(</span><span class="n">FieldRenderer</span><span class="p">):</span>
<span class="sd">"""render a field as a postgres field"""</span>
<span class="k">def</span> <span class="nf">render</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">return</span> <span class="n">h</span><span class="o">.</span><span class="n">text_field</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="n">value</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">value</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="c1"># fix postgres field in FormAlchemy</span>
<span class="c1"># tnx for http://code.google.com/p/formalchemy/issues/detail?id=167</span>
<span class="n">FieldSet</span><span class="o">.</span><span class="n">default_renderers</span><span class="p">[</span><span class="n">postgresql</span><span class="o">.</span><span class="n">CIDR</span><span class="p">]</span> <span class="o">=</span> <span class="n">PostgresFieldRenderer</span>
<span class="n">FieldSet</span><span class="o">.</span><span class="n">default_renderers</span><span class="p">[</span><span class="n">postgresql</span><span class="o">.</span><span class="n">MACADDR</span><span class="p">]</span> <span class="o">=</span> <span class="n">PostgresFieldRenderer</span>
<span class="n">FieldSet</span><span class="o">.</span><span class="n">default_renderers</span><span class="p">[</span><span class="n">postgresql</span><span class="o">.</span><span class="n">INET</span><span class="p">]</span> <span class="o">=</span> <span class="n">PostgresFieldRenderer</span>
</pre></div>
</div>
</div>
<p>Здесь мы создали 3 правила для <a class="reference external" href="http://docs.formalchemy.org/">FormAlchemy</a> как рендерить поля
<code class="docutils literal"><span class="pre">postgresql.CIDR</span></code>, <code class="docutils literal"><span class="pre">postgresql.MACADDR</span></code> и <code class="docutils literal"><span class="pre">INET</span></code>. Этот трюк можно
проделать со всем чем угодно :) Более подробно здесь
<a class="reference external" href="http://code.google.com/p/formalchemy/issues/detail?id=167">http://code.google.com/p/formalchemy/issues/detail?id=167</a></p>
<p>И наконец встраиваем админку в ваш шаблон.</p>
<p>Для того что бы это сделать придется переписать все шаблоны на <a class="reference external" href="http://jinja.pocoo.org/">jinja</a> и
возможно поменять некоторые файлы (как минимум <code class="docutils literal"><span class="pre">forms/__init__.py</span></code>). Я
приведу более ленивый и простой метод. У меня в шаблонах есть <code class="docutils literal"><span class="pre">header.html</span></code>
который я инклудом добавляю в <code class="docutils literal"><span class="pre">base.html</span></code> в самом начале. Так же и здесь
добавим его в начало админки <a class="reference external" href="http://docs.formalchemy.org/">FormAlchemy</a>.</p>
<div class="literal-block-wrapper docutils container" id="id5">
<div class="code-block-caption"><span class="caption-text">lib/base.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">BaseController</span><span class="p">(</span><span class="n">WSGIController</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">environ</span><span class="p">,</span> <span class="n">start_response</span><span class="p">):</span>
<span class="sd">"""Invoke the Controller"""</span>
<span class="c1"># WSGIController.__call__ dispatches to the Controller method</span>
<span class="c1"># the request is routed to. This routing information is</span>
<span class="c1"># available in environ['pylons.routes_dict']</span>
<span class="c1"># Костыль с mako шаблонами в админке FormAlchemy</span>
<span class="c1"># FIXME: для чистоты кода, переписать шаблоны с mako на jinja в папке forms</span>
<span class="n">c</span><span class="o">.</span><span class="n">jinja_menu</span> <span class="o">=</span> <span class="n">render</span><span class="p">(</span><span class="s1">'/common/header.html'</span><span class="p">)</span>
</pre></div>
</div>
</div>
<p>И в шаблоне <code class="docutils literal"><span class="pre">templates/form/restfieldset.mako</span></code></p>
<div class="literal-block-wrapper docutils container" id="id6">
<div class="code-block-caption"><span class="caption-text">templates/form/restfieldset.mako</span></div>
<div class="highlight-html+mako"><div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">body</span><span class="p">></span>
<span class="cp">${</span><span class="n">c</span><span class="o">.</span><span class="n">jinja_menu</span><span class="cp">}</span>
<span class="p"><</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">"content"</span> <span class="na">class</span><span class="o">=</span><span class="s">"ui-admin ui-widget"</span><span class="p">></span>
...
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
...
<span class="p"></</span><span class="nt">body</span><span class="p">></span>
</pre></div>
</div>
</div>
<p>Сразу после <code class="docutils literal"><span class="pre"><body></span></code> добавляем <code class="docutils literal"><span class="pre">${c.jinja_menu}</span></code>. Тем самым в админку уже
отдается отрендеренное меню.</p>
<p>В документации показан интерфейс <code class="docutils literal"><span class="pre">fa.jquery</span></code> на самом деле будет обычный. Для
<a class="reference external" href="https://jquery.org/">jquery</a> его еще надо дополнительно пилить, добавлять в <code class="docutils literal"><span class="pre">controller/admin</span></code>
<code class="docutils literal"><span class="pre">from</span> <span class="pre">fa.jquery.pylons</span> <span class="pre">import</span> <span class="pre">ModelsController</span> <span class="pre">as</span> <span class="pre">ModelsControllerJQ</span></code> и
дальше как сказано в исходниках
<a class="reference external" href="https://github.com/FormAlchemy/fa.jquery/blob/master/fa/jquery/pylons.py">https://github.com/FormAlchemy/fa.jquery/blob/master/fa/jquery/pylons.py</a>
обернуть наш контроллер. Что то вроде этого:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">AdminController</span> <span class="o">=</span> <span class="n">ModelsController</span><span class="p">(</span><span class="n">AdminControllerBase</span><span class="p">,</span>
<span class="n">prefix_name</span><span class="o">=</span><span class="s1">'admin'</span><span class="p">,</span>
<span class="n">member_name</span><span class="o">=</span><span class="s1">'model'</span><span class="p">,</span>
<span class="n">collection_name</span><span class="o">=</span><span class="s1">'models'</span><span class="p">,)</span>
<span class="n">AdminController</span> <span class="o">=</span> <span class="n">ModelsControllerJQ</span><span class="p">(</span><span class="n">AdminController</span><span class="p">,</span>
<span class="n">prefix_name</span><span class="o">=</span><span class="s1">'admin'</span><span class="p">,</span>
<span class="n">member_name</span><span class="o">=</span><span class="s1">'model'</span><span class="p">,</span>
<span class="n">collection_name</span><span class="o">=</span><span class="s1">'models'</span><span class="p">,)</span>
</pre></div>
</div>
<p>В целом <a class="reference external" href="http://docs.formalchemy.org/">FormAlchemy</a> довольно мощная штука, но очень сильно привязана к
<a class="reference external" href="http://www.makotemplates.org/">mako</a>, поэтому пользоваться ей не удобно и к сожалению придется искать что
то другое.</p>
</div>
Pylons + Routes фикс слэша в конце URL
http://uralbash.ru/articles/2011/pylons_backslash/
2011-10-27T02:07:00Z
2011-10-27T02:07:00Z
Uralbash
<div class="section" id="pylons-routes-url">
<p>Если мапить URL’ы вот так:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="nb">map</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s1">'/logs'</span><span class="p">,</span> <span class="n">controller</span><span class="o">=</span><span class="s1">'logs'</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s1">'logs'</span><span class="p">)</span>
</pre></div>
</div>
<p>То при попытке открыть URL <code class="docutils literal"><span class="pre">/logs/</span></code> вместо <code class="docutils literal"><span class="pre">/logs</span></code> появится страница 404.</p>
<p>Можно конечно делать так:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="nb">map</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s1">'/logs/'</span><span class="p">,</span> <span class="n">controller</span><span class="o">=</span><span class="s1">'logs'</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s1">'logs'</span><span class="p">)</span>
<span class="nb">map</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s1">'/logs'</span><span class="p">,</span> <span class="n">controller</span><span class="o">=</span><span class="s1">'logs'</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s1">'logs'</span><span class="p">)</span>
</pre></div>
</div>
<p>Но это жутко неудобно.</p>
<p>По совету <a class="reference external" href="http://stackoverflow.com/questions/235191/trailing-slashes-in-pylons-routes">stackoverflow</a>
можно обойти эту проблему простым редиректом:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="nb">map</span><span class="o">.</span><span class="n">redirect</span><span class="p">(</span><span class="s1">'/*(url)/'</span><span class="p">,</span> <span class="s1">'/{url}'</span><span class="p">,</span>
<span class="n">_redirect_code</span><span class="o">=</span><span class="s1">'301 Moved Permanently'</span><span class="p">)</span>
</pre></div>
</div>
<p>Теперь все запросы оканчивающиеся на слэш будут перенаправляться на адрес без слэша.</p>
</div>
Pylons + SQLalchemy расширенная модель (Mixin)
http://uralbash.ru/articles/2011/sqlalchemy_mixin/
2011-10-27T00:07:00Z
2011-10-27T00:07:00Z
Uralbash
<div class="section" id="pylons-sqlalchemy-mixin">
<p>Часто при проектировании структуры БД появляется необходимость повторять одни
и те же действия с таблицами. Добавлять одинаковые поля, ссылки, счетчики и
т.д. Модели в <a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">Pylons</a> (<a class="reference external" href="http://sqlalchemy.org/">SQLAlchemy</a>), как и в большинстве других фреймворках
использующих паттерн MVC, являются классом и соответственно могут быть
унаследованы от других классов. Это позволяет нам избежать рутинной работы с
повторяющимися действиями.</p>
<p>Все расширения для наших моделей будем добавлять в <code class="docutils literal"><span class="pre">models/common.py</span></code>.
Создадим базовую модель в которой будет поле <code class="docutils literal"><span class="pre">id</span></code>, автоматическая генерация
названия таблицы (<code class="docutils literal"><span class="pre">__tablename__</span></code>) и метод выбора элемента по <code class="docutils literal"><span class="pre">id</span></code> (<code class="docutils literal"><span class="pre">SELECT</span> <span class="pre">*</span> <span class="pre">FROM</span>
<span class="pre">table</span> <span class="pre">WHERE</span> <span class="pre">id=integer</span></code>):</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Base</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="sd">"""Базовая модель. Добавляет во всех наследников поле id и атрибут</span>
<span class="sd"> __tablename__ который заполняется автоматически. Имя таблицы берется из</span>
<span class="sd"> названия класса и переводится в нижний регистр. Таблица наследник имеет по</span>
<span class="sd"> умолчанию название и поле id, сильно облегчая жизнь.</span>
<span class="sd"> """</span>
<span class="nd">@declared_attr</span>
<span class="k">def</span> <span class="nf">__tablename__</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
<span class="k">if</span> <span class="p">(</span><span class="n">has_inherited_table</span><span class="p">(</span><span class="bp">cls</span><span class="p">)</span> <span class="ow">and</span>
<span class="n">Tablename</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__bases__</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">None</span>
<span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
<span class="c1"># Method "byId" for use in code like this:</span>
<span class="c1"># session.query(Table).byId(5)</span>
<span class="c1">#</span>
<span class="c1"># SQL statement like:</span>
<span class="c1"># SELECT * FROM Table WHERE id = 5;</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">byId</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="nb">id</span><span class="p">)</span> <span class="p">:</span>
<span class="k">return</span> <span class="n">Session</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="bp">cls</span><span class="p">)</span><span class="o">.</span><span class="n">filter_by</span><span class="p">(</span><span class="nb">id</span> <span class="o">=</span> <span class="nb">id</span><span class="p">)</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">autoincrement</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
</pre></div>
</div>
<p>Метод <code class="docutils literal"><span class="pre">byId</span></code> сильно сокращает запись в коде например:</p>
<div class="line-block">
<div class="line">before: <code class="docutils literal"><span class="pre">Session.query(net).filter_by(id</span> <span class="pre">=</span> <span class="pre">id).first()</span></code></div>
<div class="line">after: <code class="docutils literal"><span class="pre">net.byId(id)</span></code></div>
</div>
<p>Теперь создадим нашу модель унаследовав все плюшки с базовой модели:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Net</span><span class="p">(</span><span class="n">Base</span><span class="p">,</span> <span class="n">DeclarativeBase</span><span class="p">):</span>
<span class="sd">"""Net or subnet."""</span>
<span class="n">cidr</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">postgresql</span><span class="o">.</span><span class="n">CIDR</span><span class="p">,</span> <span class="n">index</span> <span class="o">=</span> <span class="bp">True</span><span class="p">)</span>
<span class="n">description</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">UnicodeText</span><span class="p">())</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">cidr</span><span class="o">=</span><span class="s1">''</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">cidr</span> <span class="o">=</span> <span class="n">cidr</span>
<span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="s2">"</span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">cidr</span>
</pre></div>
</div>
<p>Наша модель связанна с БД при помощи наследования от <code class="docutils literal"><span class="pre">DeclarativeBase</span></code>, имеет
название, поле <code class="docutils literal"><span class="pre">id</span></code> и метод <code class="docutils literal"><span class="pre">byId</span></code> благодаря наследованию от базовой модели
<code class="docutils literal"><span class="pre">Base</span></code> из файла <code class="docutils literal"><span class="pre">common.py</span></code>.</p>
<p>Для более наглядного примера создадим типовую модель для таблиц которые должны
содержать служебную информацию. Модель будет добавлять в другие модели поля:</p>
<div class="line-block">
<div class="line"><code class="docutils literal"><span class="pre">created_by</span></code> - кто создал</div>
<div class="line"><code class="docutils literal"><span class="pre">updated_by</span></code> - последний кто обновил</div>
<div class="line"><code class="docutils literal"><span class="pre">created_at</span></code> - дата создания</div>
<div class="line"><code class="docutils literal"><span class="pre">updated_at</span></code> - дата последнего обновления</div>
</div>
<p>Поля заполняются автоматически. Кто создал и обновил ссылаются на модель
<code class="docutils literal"><span class="pre">auth.User</span></code>. Пользователь берется из текущей сессии, при помощи библиотеки
<code class="docutils literal"><span class="pre">lib.auth</span></code> и метода <code class="docutils literal"><span class="pre">get_user</span></code>. Откуда взялась модель <code class="docutils literal"><span class="pre">User</span></code> можно узнать из этой
статьи <a class="reference internal" href="../articles/2011/repoze.what/#repoze-what"><span class="std std-ref">Авторизация в Pylons за 5 мин при помощи repoze.what</span></a>.</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">CreatedMixin</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="sd">"""Абстрактная примесь которая добавляет в другие модели поля:</span>
<span class="sd"> created_by - кто создал</span>
<span class="sd"> updated_by - последний кто обновил</span>
<span class="sd"> created_at - дата создания</span>
<span class="sd"> updated_at - дата последнего обновления</span>
<span class="sd"> Поля заполняются автоматически. Кто создал и обновил ссылаются на модель</span>
<span class="sd"> auth.User. Пользователь берется из текущей сессии, при помощи библиотеки</span>
<span class="sd"> lib.auth и метода get_user</span>
<span class="sd"> """</span>
<span class="nd">@declared_attr</span>
<span class="k">def</span> <span class="nf">created_by</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
<span class="k">return</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'user.user_id'</span><span class="p">,</span>
<span class="n">onupdate</span><span class="o">=</span><span class="s2">"cascade"</span><span class="p">,</span> <span class="n">ondelete</span><span class="o">=</span><span class="s2">"restrict"</span><span class="p">))</span>
<span class="nd">@declared_attr</span>
<span class="k">def</span> <span class="nf">updated_by</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
<span class="k">return</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'user.user_id'</span><span class="p">,</span>
<span class="n">onupdate</span><span class="o">=</span><span class="s2">"cascade"</span><span class="p">,</span> <span class="n">ondelete</span><span class="o">=</span><span class="s2">"restrict"</span><span class="p">))</span>
<span class="n">created_at</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">DateTime</span><span class="p">,</span> <span class="n">nullable</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">dt</span><span class="o">.</span><span class="n">now</span><span class="p">())</span>
<span class="n">updated_at</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">DateTime</span><span class="p">,</span> <span class="n">nullable</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">dt</span><span class="o">.</span><span class="n">now</span><span class="p">(),</span>
<span class="n">onupdate</span><span class="o">=</span><span class="n">dt</span><span class="o">.</span><span class="n">now</span><span class="p">())</span>
</pre></div>
</div>
<p>Внешние ссылки и другие атрибуты отличающиеся от обычных полей нужно добавлять
при помощи декоратора <code class="docutils literal"><span class="pre">declare_attr</span></code>. Теперь меняем нашу модель <code class="docutils literal"><span class="pre">Net</span></code> просто
добавив <code class="docutils literal"><span class="pre">CreateMixin</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Net</span><span class="p">(</span><span class="n">Base</span><span class="p">,</span> <span class="n">DeclarativeBase</span><span class="p">,</span> <span class="n">CreatedMixin</span><span class="p">):</span>
</pre></div>
</div>
<p>Вот полный листинг <code class="docutils literal"><span class="pre">common.py</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1"># coding=utf-8</span>
<span class="sd">"""Модуль с типовыми моделями</span>
<span class="sd">"""</span>
<span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">Column</span><span class="p">,</span> <span class="n">ForeignKey</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.orm</span> <span class="kn">import</span> <span class="n">relation</span><span class="p">,</span> <span class="n">relationship</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.types</span> <span class="kn">import</span> <span class="n">Integer</span><span class="p">,</span> <span class="n">String</span><span class="p">,</span> <span class="n">DateTime</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.ext.declarative</span> <span class="kn">import</span> <span class="n">declared_attr</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.ext.declarative</span> <span class="kn">import</span> <span class="n">has_inherited_table</span>
<span class="kn">from</span> <span class="nn">gottlieb.model.auth</span> <span class="kn">import</span> <span class="n">User</span>
<span class="kn">from</span> <span class="nn">gottlieb.lib</span> <span class="kn">import</span> <span class="n">auth</span>
<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span> <span class="k">as</span> <span class="n">dt</span>
<span class="k">class</span> <span class="nc">Base</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="sd">"""Базовая модель. Добавляет во всех наследников поле id и атрибут</span>
<span class="sd"> __tablename__ который заполняется автоматически. Имя таблицы берется из</span>
<span class="sd"> названия класса и переводится в нижний регистр. Таблица наследник имеет по</span>
<span class="sd"> умолчанию название и поле id, сильно облегчая жизнь.</span>
<span class="sd"> """</span>
<span class="nd">@declared_attr</span>
<span class="k">def</span> <span class="nf">__tablename__</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
<span class="k">if</span> <span class="p">(</span><span class="n">has_inherited_table</span><span class="p">(</span><span class="bp">cls</span><span class="p">)</span> <span class="ow">and</span>
<span class="n">Tablename</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__bases__</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">None</span>
<span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
<span class="c1"># Method "byId" for use in code like this:</span>
<span class="c1"># session.query(Table).byId(5)</span>
<span class="c1">#</span>
<span class="c1"># SQL statement like:</span>
<span class="c1"># SELECT * FROM Table WHERE id = 5;</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">byId</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="nb">id</span><span class="p">)</span> <span class="p">:</span>
<span class="k">return</span> <span class="n">Session</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="bp">cls</span><span class="p">)</span><span class="o">.</span><span class="n">filter_by</span><span class="p">(</span><span class="nb">id</span> <span class="o">=</span> <span class="nb">id</span><span class="p">)</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">autoincrement</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">CreatedMixin</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="sd">"""Абстрактная примесь которая добавляет в другие модели поля:</span>
<span class="sd"> created_by - кто создал</span>
<span class="sd"> updated_by - последний кто обновил</span>
<span class="sd"> created_at - дата создания</span>
<span class="sd"> updated_at - дата последнего обновления</span>
<span class="sd"> Поля заполняются автоматически. Кто создал и обновил ссылаются на модель</span>
<span class="sd"> auth.User. Пользователь берется из текущей сессии, при помощи библиотеки</span>
<span class="sd"> lib.auth и метода get_user</span>
<span class="sd"> """</span>
<span class="nd">@declared_attr</span>
<span class="k">def</span> <span class="nf">created_by</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
<span class="k">return</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'user.user_id'</span><span class="p">,</span>
<span class="n">onupdate</span><span class="o">=</span><span class="s2">"cascade"</span><span class="p">,</span> <span class="n">ondelete</span><span class="o">=</span><span class="s2">"restrict"</span><span class="p">))</span>
<span class="nd">@declared_attr</span>
<span class="k">def</span> <span class="nf">updated_by</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
<span class="k">return</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">ForeignKey</span><span class="p">(</span><span class="s1">'user.user_id'</span><span class="p">,</span>
<span class="n">onupdate</span><span class="o">=</span><span class="s2">"cascade"</span><span class="p">,</span> <span class="n">ondelete</span><span class="o">=</span><span class="s2">"restrict"</span><span class="p">))</span>
<span class="n">created_at</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">DateTime</span><span class="p">,</span> <span class="n">nullable</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">dt</span><span class="o">.</span><span class="n">now</span><span class="p">())</span>
<span class="n">updated_at</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">DateTime</span><span class="p">,</span> <span class="n">nullable</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">dt</span><span class="o">.</span><span class="n">now</span><span class="p">(),</span>
<span class="n">onupdate</span><span class="o">=</span><span class="n">dt</span><span class="o">.</span><span class="n">now</span><span class="p">())</span>
</pre></div>
</div>
<p>Для полной картины приведу аналогичный пример на <a class="reference external" href="https://www.djangoproject.com/">Django</a> + DjangoORM.</p>
<div class="literal-block-wrapper docutils container" id="id1">
<div class="code-block-caption"><span class="caption-text">myapp/accompaniment/models.py</span></div>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>
<span class="kn">from</span> <span class="nn">django.contrib.auth.models</span> <span class="kn">import</span> <span class="n">User</span>
<span class="c1"># Create your models here.</span>
<span class="k">class</span> <span class="nc">ExtendedModel</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
<span class="n">created_by</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span><span class="n">User</span><span class="p">,</span> <span class="n">null</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">blank</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
<span class="n">editable</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">related_name</span><span class="o">=</span><span class="s1">'</span><span class="si">%(class)s</span><span class="s1">_creator'</span><span class="p">)</span>
<span class="n">created_time</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">DateTimeField</span><span class="p">(</span><span class="n">auto_now_add</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">editable</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="n">modified_by</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span><span class="n">User</span><span class="p">,</span> <span class="n">null</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">blank</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
<span class="n">editable</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">related_name</span><span class="o">=</span><span class="s1">'</span><span class="si">%(class)s</span><span class="s1">_modifier'</span><span class="p">)</span>
<span class="n">modified_time</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">DateTimeField</span><span class="p">(</span><span class="n">auto_now</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">editable</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
<span class="n">abstract</span> <span class="o">=</span> <span class="bp">True</span>
</pre></div>
</div>
</div>
<p>В папке accompaniment я привык держать всякие такие хелперы для проекта. Теперь
используем эту модель в нашем проекте <code class="docutils literal"><span class="pre">myapp/projectname/models.py</span></code>:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>
<span class="kn">from</span> <span class="nn">accompaniment.models</span> <span class="kn">import</span> <span class="n">ExtendedModel</span>
<span class="k">class</span> <span class="nc">Ticket</span><span class="p">(</span><span class="n">ExtendedModel</span><span class="p">):</span>
<span class="n">OPEN_STATUS</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">REOPENED_STATUS</span> <span class="o">=</span> <span class="mi">2</span>
<span class="n">RESOLVED_STATUS</span> <span class="o">=</span> <span class="mi">3</span>
<span class="n">CLOSED_STATUS</span> <span class="o">=</span> <span class="mi">4</span>
<span class="n">DUPLICATE_STATUS</span> <span class="o">=</span> <span class="mi">5</span>
<span class="n">STATUS_CHOICES</span> <span class="o">=</span> <span class="p">(</span>
<span class="p">(</span><span class="n">OPEN_STATUS</span><span class="p">,</span> <span class="n">_</span><span class="p">(</span><span class="s1">'Open'</span><span class="p">)),</span>
<span class="p">(</span><span class="n">REOPENED_STATUS</span><span class="p">,</span> <span class="n">_</span><span class="p">(</span><span class="s1">'Reopened'</span><span class="p">)),</span>
<span class="p">(</span><span class="n">RESOLVED_STATUS</span><span class="p">,</span> <span class="n">_</span><span class="p">(</span><span class="s1">'Resolved'</span><span class="p">)),</span>
<span class="p">(</span><span class="n">CLOSED_STATUS</span><span class="p">,</span> <span class="n">_</span><span class="p">(</span><span class="s1">'Closed'</span><span class="p">)),</span>
<span class="p">(</span><span class="n">DUPLICATE_STATUS</span><span class="p">,</span> <span class="n">_</span><span class="p">(</span><span class="s1">'Duplicate'</span><span class="p">)),</span>
<span class="p">)</span>
<span class="n">PRIORITY_CHOICES</span> <span class="o">=</span> <span class="p">(</span>
<span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">_</span><span class="p">(</span><span class="s1">'1. Critical'</span><span class="p">)),</span>
<span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="n">_</span><span class="p">(</span><span class="s1">'2. High'</span><span class="p">)),</span>
<span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">_</span><span class="p">(</span><span class="s1">'3. Normal'</span><span class="p">)),</span>
<span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="n">_</span><span class="p">(</span><span class="s1">'4. Low'</span><span class="p">)),</span>
<span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="n">_</span><span class="p">(</span><span class="s1">'5. Very Low'</span><span class="p">)),</span>
<span class="p">)</span>
<span class="n">title</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span>
<span class="n">_</span><span class="p">(</span><span class="s1">'Title'</span><span class="p">),</span>
<span class="n">max_length</span><span class="o">=</span><span class="mi">200</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">queue</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span>
<span class="n">Queue</span><span class="p">,</span>
<span class="n">verbose_name</span><span class="o">=</span><span class="n">_</span><span class="p">(</span><span class="s1">'Queue'</span><span class="p">),</span>
<span class="p">)</span>
<span class="n">assigned_to</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span>
<span class="n">User</span><span class="p">,</span>
<span class="n">related_name</span><span class="o">=</span><span class="s1">'assigned_to'</span><span class="p">,</span>
<span class="n">blank</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
<span class="n">null</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
<span class="n">verbose_name</span><span class="o">=</span><span class="n">_</span><span class="p">(</span><span class="s1">'Assigned to'</span><span class="p">),</span>
<span class="p">)</span>
<span class="n">status</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">IntegerField</span><span class="p">(</span>
<span class="n">_</span><span class="p">(</span><span class="s1">'Status'</span><span class="p">),</span>
<span class="n">choices</span><span class="o">=</span><span class="n">STATUS_CHOICES</span><span class="p">,</span>
<span class="n">default</span><span class="o">=</span><span class="n">OPEN_STATUS</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">description</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">TextField</span><span class="p">(</span>
<span class="n">_</span><span class="p">(</span><span class="s1">'Description'</span><span class="p">),</span>
<span class="n">blank</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
<span class="n">null</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
<span class="n">help_text</span><span class="o">=</span><span class="n">_</span><span class="p">(</span><span class="s1">'The content of the customers query.'</span><span class="p">),</span>
<span class="p">)</span>
<span class="n">priority</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">IntegerField</span><span class="p">(</span>
<span class="n">_</span><span class="p">(</span><span class="s1">'Priority'</span><span class="p">),</span>
<span class="n">choices</span><span class="o">=</span><span class="n">PRIORITY_CHOICES</span><span class="p">,</span>
<span class="n">default</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span>
<span class="n">blank</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
<span class="n">get_latest_by</span> <span class="o">=</span> <span class="s2">"created"</span>
<span class="n">verbose_name</span> <span class="o">=</span> <span class="sa">u</span><span class="s1">'Заявки'</span>
<span class="n">verbose_name_plural</span> <span class="o">=</span> <span class="sa">u</span><span class="s1">'Заявки'</span>
<span class="k">def</span> <span class="fm">__unicode__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="sa">u</span><span class="s1">'</span><span class="si">%s</span><span class="s1">'</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">title</span>
<span class="k">def</span> <span class="nf">save</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">force_insert</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">force_update</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">priority</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">priority</span> <span class="o">=</span> <span class="mi">3</span>
<span class="nb">super</span><span class="p">(</span><span class="n">Ticket</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">force_insert</span><span class="p">,</span> <span class="n">force_update</span><span class="p">)</span>
</pre></div>
</div>
<p>Такой несложный метод освобождает нас от размножения кучи одинаковых полей в
моделях.</p>
<p>Update: в моделях Mixin был атрибут <code class="docutils literal"><span class="pre">__abstract__</span> <span class="pre">=</span> <span class="pre">True</span></code> это неправильно,
так-как все таблицы стают абстрактными. НО! Это вполне прокатит на версиях
меньше 0.7, там этот атрибут почему-то не учитывается. На 0.7 версии работает
как надо. Вот описание проблемы: <a class="reference external" href="http://stackoverflow.com/questions/7990790/sqlalchemy-0-7-mapperevent-error">stackoverflow</a></p>
</div>
Авторизация в Pylons за 5 мин при помощи repoze.what
http://uralbash.ru/articles/2011/repoze.what/
2011-10-26T23:35:00Z
2011-10-26T23:35:00Z
Uralbash
<div class="section" id="pylons-5-repoze-what">
<span id="repoze-what"></span>
<p>Статья по сути вольный перевод <a class="reference external" href="http://countergram.com/open-source/PylonsTemplates">PylonsTemplates: extra Paster templates for
Pylons apps</a> с моими
дополнениями.</p>
<p><a class="reference external" href="https://github.com/countergram/PylonsTemplates/">PylonsTemplates</a> дает вам дополнительные шаблоны в paster для приложений на
<a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">Pylons</a>. После установки <a class="reference external" href="https://github.com/countergram/PylonsTemplates/">PylonsTemplates</a> можно создать новый проект на
<a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">Pylons</a> примерно так:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ paster create -t <span class="o">[</span>templatename<span class="o">]</span> <span class="o">[</span>projectname<span class="o">]</span>
</pre></div>
</div>
<div class="section" id="pylons-repoze-what">
<h2>pylons_repoze_what</h2>
<p>Шаблон <code class="docutils literal"><span class="pre">pylons_repoze_what</span></code> добавляет систему авторизации основанную на
<a class="reference external" href="http://what.repoze.org/docs/1.0/index.html#module-repoze.what" title="(в repoze.what v1.0)"><code class="xref py py-mod docutils literal"><span class="pre">repoze.what</span></code></a> и <code class="xref py py-mod docutils literal"><span class="pre">repoze.what.plugins.quickstart</span></code>. (При этом аутентификация на
<a class="reference external" href="https://repoze.readthedocs.io/projects/repozewho/en/latest/index.html#module-repoze.who" title="(в repoze.who v2.2)"><code class="xref py py-mod docutils literal"><span class="pre">repoze.who</span></code></a> устанавливается автоматически.)</p>
<p>Шаблон включает в себя:</p>
<ul class="simple">
<li>Модели <code class="docutils literal"><span class="pre">User</span></code>, <code class="docutils literal"><span class="pre">Group</span></code> и <code class="docutils literal"><span class="pre">Permission</span></code> для <a class="reference external" href="http://sqlalchemy.org/">SQLALchemy</a></li>
<li>Контроллер login (& logout)</li>
<li>Простой шаблон для входа</li>
<li>Зависимость от <code class="xref py py-mod docutils literal"><span class="pre">repoze.what.plugins.pylonshq</span></code>, включающая декораторы которые можно
использовать в контроллерах и действиях (action).</li>
<li>Закоментированный код в websetup.py который создает user, group и permission.</li>
</ul>
<p>Список всех шаблонов:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>paster create --list-templates
</pre></div>
</div>
<p>Создание проекта:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>paster create -t pylons_repoze_what myapp
</pre></div>
</div>
</div>
<div class="section" id="repoze-what-pylons">
<h2>Пример с repoze.what-pylons</h2>
<p>После создания проекта используя <code class="docutils literal"><span class="pre">paster</span> <span class="pre">create</span> <span class="pre">-t</span> <span class="pre">pylons_repoze_what</span></code>, вам нужно
защитить контроллеры и их действия от несанкционированного доступа. Ниже
простой пример:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">repoze.what.predicates</span> <span class="kn">import</span> <span class="n">has_permission</span>
<span class="kn">from</span> <span class="nn">repoze.what.plugins.pylonshq</span> <span class="kn">import</span> <span class="n">ActionProtector</span>
<span class="k">class</span> <span class="nc">HelloWorldController</span><span class="p">(</span><span class="n">BaseController</span><span class="p">):</span>
<span class="nd">@ActionProtector</span><span class="p">(</span><span class="n">has_permission</span><span class="p">(</span><span class="s1">'be_cool'</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">index</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="s1">'Hello World'</span>
</pre></div>
</div>
<p>Здесь запрещен доступ к действию <code class="docutils literal"><span class="pre">index</span></code> всем у кого нет прав <code class="docutils literal"><span class="pre">be_cool</span></code>. Что бы
запретить весь контроллер есть декоратор
<code class="xref py py-class docutils literal"><span class="pre">repoze.what.plugins.pylonshq.protectors.ControllerProtector</span></code>. Более
подробно об этом можно почитать в документации на <code class="xref py py-mod docutils literal"><span class="pre">repoze.what.plugins.pylonshq</span></code>.</p>
<p>У меня в шаблонах отображается постоянно кто сейчас залогирован.
Что бы это сделать, создадим <code class="docutils literal"><span class="pre">lib/auth.py</span></code></p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pylons</span> <span class="kn">import</span> <span class="n">request</span>
<span class="k">def</span> <span class="nf">get_user</span><span class="p">(</span><span class="n">default</span><span class="p">):</span>
<span class="sd">"""Return the user object from the `repoze.who` Metadata Plugin</span>
<span class="sd"> :param default: default item to send back if user not logged in</span>
<span class="sd"> Since we might not be logged in and template choke on trying to output</span>
<span class="sd"> None/empty data we can pass in a blank User object to get back as a default</span>
<span class="sd"> and the templates should work ok with default empty values on that</span>
<span class="sd"> """</span>
<span class="k">if</span> <span class="s1">'repoze.who.identity'</span> <span class="ow">in</span> <span class="n">request</span><span class="o">.</span><span class="n">environ</span><span class="p">:</span>
<span class="k">return</span> <span class="n">request</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s1">'repoze.who.identity'</span><span class="p">][</span><span class="s1">'user'</span><span class="p">]</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="n">default</span>
</pre></div>
</div>
<p>И добавим контекстную переменную во все контроллеры при помощи <code class="docutils literal"><span class="pre">lib/base.py</span></code></p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">gottlieb.model.auth</span> <span class="kn">import</span> <span class="n">User</span>
<span class="kn">from</span> <span class="nn">gottlieb.lib</span> <span class="kn">import</span> <span class="n">auth</span>
<span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">environ</span><span class="p">,</span> <span class="n">start_response</span><span class="p">):</span>
<span class="sd">"""Invoke the Controller"""</span>
<span class="c1"># WSGIController.__call__ dispatches to the Controller method</span>
<span class="c1"># the request is routed to. This routing information is</span>
<span class="c1"># available in environ['pylons.routes_dict']</span>
<span class="c1"># if there's no user set, just setup a blank instance</span>
<span class="n">c</span><span class="o">.</span><span class="n">current_user</span> <span class="o">=</span> <span class="n">auth</span><span class="o">.</span><span class="n">get_user</span><span class="p">(</span><span class="n">User</span><span class="p">())</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="n">WSGIController</span><span class="o">.</span><span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">environ</span><span class="p">,</span> <span class="n">start_response</span><span class="p">)</span>
<span class="k">finally</span><span class="p">:</span>
<span class="n">meta</span><span class="o">.</span><span class="n">Session</span><span class="o">.</span><span class="n">remove</span><span class="p">()</span>
</pre></div>
</div>
<p>Теперь можно в шаблоны вставлять что то вроде того (примеры на <a class="reference external" href="http://jinja.pocoo.org/">Jinja</a>):</p>
<div class="highlight-html+jinja"><div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"userBox"</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">c.current_user.user_name</span> <span class="cp">%}</span>
<span class="cp">{{</span> <span class="nv">c.current_user.user_name</span> <span class="cp">}}</span> <span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"/logout"</span><span class="p">></span>(logout)<span class="p"></</span><span class="nt">a</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">else</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"/login"</span><span class="p">></span>login<span class="p"></</span><span class="nt">a</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
</pre></div>
</div>
<p>или</p>
<div class="highlight-html+jinja"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">for</span> <span class="nv">group</span> <span class="k">in</span> <span class="nv">c.current_user.groups</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">group.group_name</span> <span class="o">==</span> <span class="s1">'admin'</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">li</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"/admin"</span> <span class="na">target</span><span class="o">=</span><span class="s">"_self"</span><span class="p">></span>Admin<span class="p"></</span><span class="nt">a</span><span class="p">></span>
<span class="p"></</span><span class="nt">li</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
</pre></div>
</div>
<div class="figure align-center" id="id1">
<img alt="_static/2011/header_login_logout.png" src="_static/2011/header_login_logout.png" />
<p class="caption"><span class="caption-text">отображение залогированного пользователя</span></p>
</div>
<div class="figure align-center" id="id2">
<img alt="_static/2011/login_form.png" src="_static/2011/login_form.png" />
<p class="caption"><span class="caption-text">форма авторизации</span></p>
</div>
</div>
</div>
Простые хлебные крошки для Pylons и не только...
http://uralbash.ru/articles/2011/breadcrumbs/
2011-10-26T13:59:00Z
2011-10-26T13:59:00Z
Uralbash
<div class="section" id="pylons">
<p>В Интернете множество советов как делать хлебные крошки. Для <a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">Pylons</a> эти советы
довольно запутанные, сложные в реализации и рутины в поддержке на мой взгляд.
Поэтому я рассмотрю простой способ парсить URI. Нас будет интересовать только
URN (та часть которая идет после названия сайта).</p>
<p>Пример:</p>
<p>URI: <code class="docutils literal"><span class="pre">http://example.ru/js/scripts/test</span></code>
URN: <code class="docutils literal"><span class="pre">js/scripts/test</span></code>
breadcrumbs: <code class="docutils literal"><span class="pre">js</span> <span class="pre">>></span> <span class="pre">scripts</span> <span class="pre">>></span> <span class="pre">test</span></code></p>
<p>Есть хороший пример <a class="reference external" href="http://www.webreference.com/js/scripts/breadcrumbs/">http://www.webreference.com/js/scripts/breadcrumbs/</a>, но он
отображает в последней крошке(текущей) не распарсенный URN, а название сайта
document.title. Это не очень удобно в некоторых случаях.</p>
<p>Вот мой вариант этого решения:</p>
<div class="literal-block-wrapper docutils container" id="id1">
<div class="code-block-caption"><span class="caption-text">добавляем public/js/breadcrumbs.js</span></div>
<div class="highlight-javascript"><div class="highlight"><pre><span></span><span class="kd">function</span> <span class="nx">breadcrumbs</span><span class="p">(){</span>
<span class="nx">sURL</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">String</span><span class="p">;</span>
<span class="nx">bits</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Object</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">stop</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">output</span> <span class="o">=</span> <span class="s2">"<a href=\"/\">Home</a> &nbsp;&#187;&nbsp; "</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">end</span> <span class="o">=</span> <span class="s2">""</span><span class="p">;</span>
<span class="nx">sURL</span> <span class="o">=</span> <span class="nx">location</span><span class="p">.</span><span class="nx">href</span><span class="p">;</span>
<span class="nx">sURL</span> <span class="o">=</span> <span class="nx">sURL</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span><span class="nx">sURL</span><span class="p">.</span><span class="nx">length</span><span class="p">);</span>
<span class="nx">chunkStart</span> <span class="o">=</span> <span class="nx">sURL</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s2">"/"</span><span class="p">);</span>
<span class="nx">sURL</span> <span class="o">=</span> <span class="nx">sURL</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="nx">chunkStart</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span><span class="nx">sURL</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span>
<span class="k">while</span><span class="p">(</span><span class="o">!</span><span class="nx">stop</span><span class="p">){</span>
<span class="nx">chunkStart</span> <span class="o">=</span> <span class="nx">sURL</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s2">"/"</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">chunkStart</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">){</span>
<span class="nx">bits</span><span class="p">[</span><span class="nx">x</span><span class="p">]</span> <span class="o">=</span> <span class="nx">sURL</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="nx">chunkStart</span><span class="p">)</span>
<span class="nx">sURL</span> <span class="o">=</span> <span class="nx">sURL</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="nx">chunkStart</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span><span class="nx">sURL</span><span class="p">.</span><span class="nx">length</span><span class="p">);</span>
<span class="p">}</span><span class="k">else</span><span class="p">{</span>
<span class="nx">chunkStart</span> <span class="o">=</span> <span class="nx">sURL</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span>
<span class="nx">end</span> <span class="o">=</span> <span class="nx">sURL</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="nx">chunkStart</span><span class="p">)</span>
<span class="nx">stop</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
<span class="nx">x</span><span class="o">++</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">for</span><span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="k">in</span> <span class="nx">bits</span><span class="p">){</span>
<span class="nx">output</span> <span class="o">+=</span> <span class="s2">"<a href=\""</span><span class="p">;</span>
<span class="k">for</span><span class="p">(</span><span class="nx">y</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span><span class="nx">y</span><span class="o"><</span><span class="nx">x</span><span class="o">-</span><span class="nx">i</span><span class="p">;</span><span class="nx">y</span><span class="o">++</span><span class="p">){</span>
<span class="nx">output</span> <span class="o">+=</span> <span class="s2">"../"</span><span class="p">;</span>
<span class="p">}</span>
<span class="nx">output</span> <span class="o">+=</span> <span class="nx">bits</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">+</span> <span class="s2">"/\">"</span> <span class="o">+</span> <span class="nx">bits</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">+</span> <span class="s2">"</a> &nbsp;&#187;&nbsp;"</span><span class="p">;</span>
<span class="p">}</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="nx">output</span> <span class="o">+</span> <span class="nx">end</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
<p>В шаблон вставляем следующий код:</p>
<div class="highlight-html"><div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">script</span> <span class="na">language</span><span class="o">=</span><span class="s">"JavaScript"</span><span class="p">></span>
<span class="nx">breadcrumbs</span><span class="p">();</span>
<span class="p"></</span><span class="nt">script</span><span class="p">></span>
</pre></div>
</div>
<div class="figure align-center" id="id2">
<img alt="_static/2011/breadcrumbs.png" src="_static/2011/breadcrumbs.png" />
<p class="caption"><span class="caption-text">breadcrumbs + javascript</span></p>
</div>
</div>
Pylons javascript и css link
http://uralbash.ru/articles/2011/pylons_jscss_minificator/
2011-10-25T00:36:00Z
2011-10-25T00:36:00Z
Uralbash
<div class="section" id="pylons-javascript-css-link">
<p>В <a class="reference external" href="http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/">Pylons</a>, в шаблоны есть возможность вставить <a class="reference external" href="http://www.w3.org/Style/CSS/">CSS</a> или JS при помощи
<a class="reference external" href="https://docs.pylonsproject.org/projects/webhelpers/en/latest/modules/pylonslib/minify.html#webhelpers.pylonslib.minify.stylesheet_link" title="(в WebHelpers v1.3)"><code class="xref py py-func docutils literal"><span class="pre">stylesheet_link()</span></code></a> и
<a class="reference external" href="https://docs.pylonsproject.org/projects/webhelpers/en/latest/modules/pylonslib/minify.html#webhelpers.pylonslib.minify.javascript_link" title="(в WebHelpers v1.3)"><code class="xref py py-func docutils literal"><span class="pre">javascript_link()</span></code></a>. Но существует расширение
<a class="reference external" href="http://minification-webhelpers.readthedocs.org/en/latest/">MinificationWebHelpers</a> которое позволяет также удобно добавлять javascript
файлы.</p>
<p>Установка:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ pip install MinificationWebHelpers
</pre></div>
</div>
<p>Пример использования:</p>
<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">${h.javascript_link('/js/file1.js',</span>
<span class="x"> '/js/file2.js',</span>
<span class="x"> minified=True,</span>
<span class="x"> combined=True,</span>
<span class="x"> combined_filename='all_javascript_files')}</span>
<span class="x">${h.stylesheet_link('/css/style1.css',</span>
<span class="x"> '/css/style2.css',</span>
<span class="x"> minified=True,</span>
<span class="x"> combined=True,</span>
<span class="x"> beaker_kwargs=dict(invalidate_on_startup=False))}</span>
</pre></div>
</div>
<p>Очень удобная штука, особенно когда нужно добавить много файлов.</p>
</div>
SQLalchemy UML диаграмма
http://uralbash.ru/articles/2011/sqlalchemy_uml/
2011-10-24T19:27:00Z
2011-10-24T19:27:00Z
Uralbash
<div class="section" id="sqlalchemy-uml">
<div class="admonition note">
<p class="first admonition-title">Примечание</p>
<p class="last">UPD: <a class="reference external" href="https://pypi.python.org/pypi/sadisplay">sadisplay</a> - замечательная штука!</p>
</div>
<p>Для визуализации своей базы в <a class="reference external" href="http://sqlalchemy.org/">SQLAlchemy</a> удобно использовать <a class="reference external" href="http://www.graphviz.org/">graphviz</a>
и библиотеку <a class="reference external" href="https://github.com/fschulze/sqlalchemy_schemadisplay">sqlalchemy_schemadisplay</a>.</p>
<p>Установка:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ apt-get install graphviz
$ pip install sqlalchemy_schemadisplay
</pre></div>
</div>
<p>Далее читаем доки <a class="reference external" href="http://www.sqlalchemy.org/trac/wiki/UsageRecipes/SchemaDisplay">SQLAlchemy Schema Display</a></p>
<p>Для Ъ:</p>
<p>Схема БД строится на основании данных базы.</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">MetaData</span>
<span class="kn">from</span> <span class="nn">sqlalchemy_schemadisplay</span> <span class="kn">import</span> <span class="n">create_schema_graph</span>
<span class="c1"># create the pydot graph object by autoloading all tables via a bound metadata object</span>
<span class="n">graph</span> <span class="o">=</span> <span class="n">create_schema_graph</span><span class="p">(</span>
<span class="n">metadata</span><span class="o">=</span><span class="n">MetaData</span><span class="p">(</span><span class="s1">'postgres://user:pwd@host/database'</span><span class="p">),</span>
<span class="n">show_datatypes</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="c1"># The image would get nasty big if we'd show the datatypes</span>
<span class="n">show_indexes</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="c1"># ditto for indexes</span>
<span class="n">rankdir</span><span class="o">=</span><span class="s1">'LR'</span><span class="p">,</span> <span class="c1"># From left to right (instead of top to bottom)</span>
<span class="n">concentrate</span><span class="o">=</span><span class="bp">False</span> <span class="c1"># Don't try to join the relation lines together</span>
<span class="p">)</span>
<span class="n">graph</span><span class="o">.</span><span class="n">write_png</span><span class="p">(</span><span class="s1">'dbschema.png'</span><span class="p">)</span> <span class="c1"># write out the file</span>
</pre></div>
</div>
<div class="figure align-center" id="id1">
<img alt="_static/2011/dbschema.png" src="_static/2011/dbschema.png" />
<p class="caption"><span class="caption-text">Схема БД Postgres</span></p>
</div>
<p>Схема UML строится по моделям проекта.</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">myapp</span> <span class="kn">import</span> <span class="n">model</span>
<span class="kn">from</span> <span class="nn">sqlalchemy_schemadisplay</span> <span class="kn">import</span> <span class="n">create_uml_graph</span>
<span class="kn">from</span> <span class="nn">sqlalchemy.orm</span> <span class="kn">import</span> <span class="n">class_mapper</span>
<span class="c1"># lets find all the mappers in our model</span>
<span class="n">mappers</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">attr</span> <span class="ow">in</span> <span class="nb">dir</span><span class="p">(</span><span class="n">model</span><span class="p">):</span>
<span class="k">if</span> <span class="n">attr</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s1">'_'</span><span class="p">:</span> <span class="k">continue</span>
<span class="k">try</span><span class="p">:</span>
<span class="bp">cls</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">model</span><span class="p">,</span> <span class="n">attr</span><span class="p">)</span>
<span class="n">mappers</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">class_mapper</span><span class="p">(</span><span class="bp">cls</span><span class="p">))</span>
<span class="k">except</span><span class="p">:</span>
<span class="k">pass</span>
<span class="c1"># pass them to the function and set some formatting options</span>
<span class="n">graph</span> <span class="o">=</span> <span class="n">create_uml_graph</span><span class="p">(</span><span class="n">mappers</span><span class="p">,</span>
<span class="n">show_operations</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="c1"># not necessary in this case</span>
<span class="n">show_multiplicity_one</span><span class="o">=</span><span class="bp">False</span> <span class="c1"># some people like to see the ones, some don't</span>
<span class="p">)</span>
<span class="n">graph</span><span class="o">.</span><span class="n">write_png</span><span class="p">(</span><span class="s1">'schema.png'</span><span class="p">)</span> <span class="c1"># write out the file</span>
</pre></div>
</div>
<div class="figure align-center" id="id2">
<img alt="_static/2011/schema.png" src="_static/2011/schema.png" />
<p class="caption"><span class="caption-text">Схема моделей в Pylons</span></p>
</div>
<p>Для <a class="reference external" href="https://www.djangoproject.com/">Django</a> кодеров есть модуль <a class="reference external" href="https://github.com/django-extensions/django-extensions">django-extension</a> который добавляет
много полезных команд для <code class="docutils literal"><span class="pre">manage.py</span></code>. Вот мой вариант скрипта для <a class="reference external" href="https://www.djangoproject.com/">Django</a>:</p>
<div class="literal-block-wrapper docutils container" id="id3">
<div class="code-block-caption"><span class="caption-text">project_dir/_visualozation/visualized.sh</span></div>
<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nv">curent_d</span><span class="o">=</span><span class="s2">"`date +%H%M_%d%m%y`"</span>
<span class="nb">exec</span> python ../manage.py graph_models -a -g -o scheme_of_<span class="nv">$curent_d</span>.png
</pre></div>
</div>
</div>
<div class="figure align-center" id="id4">
<img alt="_static/2011/django_uml.png" src="_static/2011/django_uml.png" />
<p class="caption"><span class="caption-text">пример django-extension + graphviz</span></p>
</div>
</div>
ThinkPad TrackPoint настройка в Linux
http://uralbash.ru/articles/2011/thinkpad_trackpoint/
2011-10-17T23:22:00Z
2011-10-17T23:22:00Z
Uralbash
<div class="section" id="thinkpad-trackpoint-linux">
<p>Вообще всю информацию по настройке <a class="reference external" href="https://ru.wikipedia.org/wiki/Тензометрический_джойстик">trackpoint</a> можно взять здесь: <a class="reference external" href="http://www.thinkwiki.org/wiki/How_to_configure_the_TrackPoint">How to
configure the TrackPoint</a></p>
<p>Но для ленивых ниже скрипт для автозагрузки:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span><span class="ch">#!/bin/sh</span>
xinput list <span class="p">|</span> sed -ne <span class="s1">'s/^[^ ][^V].*id=\([0-9]*\).*/\1/p'</span> <span class="p">|</span> <span class="k">while</span> <span class="nb">read</span> id
<span class="k">do</span>
<span class="k">case</span> <span class="sb">`</span>xinput list-props <span class="nv">$id</span><span class="sb">`</span> in
*<span class="s2">"Middle Button Emulation"</span>*<span class="o">)</span>
xinput set-int-prop <span class="nv">$id</span> <span class="s2">"Evdev Wheel Emulation"</span> <span class="m">8</span> <span class="m">1</span>
xinput set-int-prop <span class="nv">$id</span> <span class="s2">"Evdev Wheel Emulation Button"</span> <span class="m">8</span> <span class="m">2</span>
xinput set-int-prop <span class="nv">$id</span> <span class="s2">"Evdev Wheel Emulation Timeout"</span> <span class="m">8</span> <span class="m">200</span>
xinput set-int-prop <span class="nv">$id</span> <span class="s2">"Evdev Wheel Emulation Axes"</span> <span class="m">8</span> <span class="m">6</span> <span class="m">7</span> <span class="m">4</span> <span class="m">5</span>
xinput set-int-prop <span class="nv">$id</span> <span class="s2">"Evdev Middle Button Emulation"</span> <span class="m">8</span> <span class="m">1</span>
xinput set-int-prop <span class="nv">$id</span> <span class="s2">"Evdev Middle Button Timeout"</span> <span class="m">8</span> <span class="m">50</span>
<span class="p">;;</span>
<span class="k">esac</span>
<span class="k">done</span>
<span class="c1"># disable middle button</span>
<span class="c1">#xmodmap -e "pointer = 1 9 3 4 5 6 7 8 2"</span>
</pre></div>
</div>
</div>
Отключить CapsLock
http://uralbash.ru/articles/2011/capslock/
2011-10-17T23:13:00Z
2011-10-17T23:13:00Z
Uralbash
<div class="section" id="capslock">
<p>Отключение:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>xmodmap -e <span class="s2">"clear Lock"</span>
</pre></div>
</div>
<p>Включение:</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>xmodmap -e <span class="s2">"add Lock = Caps_Lock"</span>
</pre></div>
</div>
<p>или в <code class="docutils literal"><span class="pre">/usr/share/X11/xkb/keycodes/xfree86</span></code> заменить <code class="docutils literal"><span class="pre">CAPS</span></code> код 66 на 100500</p>
</div>
Xfce перенос кнопок окна влево
http://uralbash.ru/articles/2011/xfce_button/
2011-10-17T00:08:00Z
2011-10-17T00:08:00Z
Uralbash
<div class="section" id="xfce">
<p>Для того что бы кнопки закрыть-развернуть-свернуть оказались слева, например
как в <a class="reference external" href="http://www.ubuntu.com/">Ubuntu</a> или <a class="reference external" href="http://www.apple.com/osx/">MacOS</a>, необходимо:</p>
<ul class="simple">
<li>Перейти в <code class="docutils literal"><span class="pre">меню->настройки->диспетчер</span></code> настроек <a class="reference external" href="http://www.xfce.org/">Xfce</a> 4</li>
<li>Выбрать раздел “окна”</li>
<li>В разделе “Расположения кнопок” мышкой перенести кнопки</li>
</ul>
<img alt="_static/2011/xfce_left_button_menu.png" class="align-center" src="_static/2011/xfce_left_button_menu.png" />
</div>