tag:blogger.com,1999:blog-21424610567655459122024-03-13T07:23:14.882+03:00Python-блогIshayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.comBlogger130125tag:blogger.com,1999:blog-2142461056765545912.post-1208080096841217562014-01-06T14:38:00.004+04:002014-01-06T14:38:39.852+04:00Перевод документации к модулю inspect<h2>
<a href="http://python-lab.ru/documentation/27/stdlib/inspect.html" target="_blank">inspect — Инспекция “живых” объектов</a></h2>
Ishayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com0tag:blogger.com,1999:blog-2142461056765545912.post-37688371248497356602013-09-03T17:03:00.001+04:002013-09-03T17:03:20.918+04:002.x/stdlib - parser. Документация<h1 style="background-color: #f2f2f2; border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #20435c; font-family: 'Trebuchet MS', sans-serif; font-size: 32px; font-weight: normal; margin: 0px -20px 10px; padding: 3px 0px 3px 10px;">
<a href="http://python-lab.ru/documentation/27/stdlib/parser.html" target="_blank"><tt class="xref py py-mod docutils literal" style="background-color: transparent; color: #355f7c; font-size: 0.95em; font-weight: bold; padding: 0px 1px; text-decoration: none;"><span class="pre">parser</span></tt> — Доступ к распарсенным деревьям Python<a name='more'></a></a><a class="headerlink" href="http://python-lab.ru/documentation/27/stdlib/parser.html#module-parser" style="color: #c60f0f; font-size: 0.8em; padding: 0px 4px; text-decoration: none; visibility: hidden;" title="Permalink to this headline"></a></h1>
<div id="index-0" style="background-color: white; font-family: sans-serif; font-size: 16px; line-height: 20px; text-align: justify;">
Модуль <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#module-parser" style="color: #355f7c; text-decoration: none;" title="parser: Access parse trees for Python source code."><tt class="xref py py-mod docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">parser</span></tt></a> предоставляет интерфейс для внутреннего парсера Python и компилятора байт-кода. Основная цель этого интерфейса - позволить коду на Python редактировать дерево выражений Python и создавать из него выполняемый код. Это лучше чем пытаться разобрать и модифицировать произвольный фрагмент кода на Python because parsing is performed in a manner identical to the code forming the application. Кроме того, это быстрее.</div>
<div class="admonition note" style="background-color: #eeeeee; border: 1px solid rgb(204, 204, 204); font-family: sans-serif; font-size: 16px; margin-bottom: 10px; margin-top: 10px; padding: 7px;">
<div class="first admonition-title" style="display: inline; font-weight: bold; line-height: 20px; margin-bottom: 5px; margin-right: 10px; text-align: justify;">
Note</div>
<div style="display: inline; line-height: 20px; margin-bottom: 5px; text-align: justify;">
Начиная с 2.5, более удобно влезть в этапы генерации Abstract Syntax Tree (AST) и компиляции, при помощи подуля <a class="reference external" href="http://docs.python.org/library/ast.html#ast" style="color: #355f7c; text-decoration: none;" title="(in Python v2.7)"><tt class="xref py py-mod docutils literal" style="background-color: #d6d6d6; background-position: initial initial; background-repeat: initial initial; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">ast</span></tt></a>.</div>
<div class="last" style="line-height: 20px; margin-bottom: 5px; text-align: justify;">
Модуль <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#module-parser" style="color: #355f7c; text-decoration: none;" title="parser: Access parse trees for Python source code."><tt class="xref py py-mod docutils literal" style="background-color: #d6d6d6; background-position: initial initial; background-repeat: initial initial; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">parser</span></tt></a> экспортирует имена, документированные тут, заменяя “st” на “ast”; это наследие ещё тех времён, когда не было другого AST и никак не связано с AST из Python 2.5. Кроме того, это ещё и причина того, что именованные аргументы функций называются <em>ast</em>, а не <em>st</em>. Функции “ast” убраны в Python 3.</div>
</div>
<div style="background-color: white; font-family: sans-serif; font-size: 16px; line-height: 20px; text-align: justify;">
Есть несколько вещей, которые надо иметь ввиду при работе с этим модулем. Данная документация не является руководством по редактированию распарсенного дерева кода Python, но некоторые примеры использования модуля <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#module-parser" style="color: #355f7c; text-decoration: none;" title="parser: Access parse trees for Python source code."><tt class="xref py py-mod docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">parser</span></tt></a> Вы тут встретите.</div>
<div style="background-color: white; font-family: sans-serif; font-size: 16px; line-height: 20px; text-align: justify;">
Особенно важно хорошее понимание обработки грамматики Python внутренним парсером. Более подробная информация о синтаксисе языка находится в <a class="reference external" href="http://docs.python.org/reference/index.html#reference-index" style="color: #355f7c; text-decoration: none;" title="(in Python v2.7)"><em>The Python Language Reference</em></a>. Сам парсер создаётся из грамматических спецификаций, определённых в файле<tt class="file docutils literal" style="background-color: #ecf0f3; font-size: 0.95em; padding: 0px 1px;"><span class="pre">Grammar/Grammar</span></tt> в стандартной постановке Python. Распарсенные деревья сохранённые в объектах ST, создаваемых этим модулем, являются актуальным выводом внутреннего парсера, когда они создаются функциями <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.expr" style="color: #355f7c; text-decoration: none;" title="parser.expr"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">expr()</span></tt></a> или <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.suite" style="color: #355f7c; text-decoration: none;" title="parser.suite"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">suite()</span></tt></a>, описанными ниже. Объекты ST создаваемые функцией <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.sequence2st" style="color: #355f7c; text-decoration: none;" title="parser.sequence2st"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">sequence2st()</span></tt></a> имеют схожую структуру. Имейте ввиду, что значения последовательностей, которые “корректны” могут отличаться для разных версий Python, если отличается формальная грамматика языка. Однако, перенос кода из одной версии Python в другую всегда будет создавать корректное распарсенное дерево для данной версии, с тем лишь ограничением, что переход на более старую версию не будет поддерживать более новые конструкции языка. Распарсенные деревья, обычно, не совместимы меду разными версиями, тогда как для исходного кода гарантируется <em class="xref std std-term">forward-compatible</em>.</div>
<div style="background-color: white; font-family: sans-serif; font-size: 16px; line-height: 20px; text-align: justify;">
Каждый элемент последовательности, возвращаемый функциями <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.st2list" style="color: #355f7c; text-decoration: none;" title="parser.st2list"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">st2list()</span></tt></a> или <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.st2tuple" style="color: #355f7c; text-decoration: none;" title="parser.st2tuple"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">st2tuple()</span></tt></a> имеет простую форму. Последоватльность, представляющая нетерминальные элементы грамматики всегда имеет длину больше одного. Первый элементом является число, которое идентифицирует выражение грамматики. Эти числа имеют символические имена, определённые в заголовочном файле C<tt class="file docutils literal" style="background-color: #ecf0f3; font-size: 0.95em; padding: 0px 1px;"><span class="pre">Include/graminit.h</span></tt> и в модуле Python <a class="reference external" href="http://docs.python.org/library/symbol.html#symbol" style="color: #355f7c; text-decoration: none;" title="(in Python v2.7)"><tt class="xref py py-mod docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">symbol</span></tt></a>. Каждый дополнительные элемент последовательности представляет компонент выражения, который был распознан в исходной строке: они всегда являются последовательносями той же формы, что и родительская последовательность. Важный аспект этой структуры, который надо иметь ввиду, что ключевые слова, используемые для идентификации типа родительского узла, такое как <a class="reference external" href="http://docs.python.org/reference/compound_stmts.html#if" style="color: #355f7c; text-decoration: none;" title="(in Python v2.7)"><tt class="xref std std-keyword docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">if</span></tt></a> в <tt class="xref py py-const docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">if_stmt</span></tt>, включается в узел дерева без дополнительной трактовки. Например, ключевое слово <a class="reference external" href="http://docs.python.org/reference/compound_stmts.html#if" style="color: #355f7c; text-decoration: none;" title="(in Python v2.7)"><tt class="xref std std-keyword docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">if</span></tt></a> представляется кортежем <tt class="docutils literal" style="background-color: #ecf0f3; font-size: 0.95em; padding: 0px 1px;"><span class="pre">(1,</span> <span class="pre">'if')</span></tt>, где <tt class="docutils literal" style="background-color: #ecf0f3; font-size: 0.95em; padding: 0px 1px;"><span class="pre">1</span></tt> - числовое значение, ассоциированное с токеном <tt class="xref py py-const docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">NAME</span></tt>, который также включает переменные и функции, определённые пользователем. В альтернативной возвращаемой форме, когда требуется информация о номере строки, тот же самый токен может быть представлен как <tt class="docutils literal" style="background-color: #ecf0f3; font-size: 0.95em; padding: 0px 1px;"><span class="pre">(1,</span> <span class="pre">'if',</span> <span class="pre">12)</span></tt>, где <tt class="docutils literal" style="background-color: #ecf0f3; font-size: 0.95em; padding: 0px 1px;"><span class="pre">12</span></tt> - номер строки, в которой был найден терминальный символ.</div>
<div style="background-color: white; font-family: sans-serif; font-size: 16px; line-height: 20px; text-align: justify;">
Терминальные элементы представляются похожим образом, но без дочерних элементов и без дополнений в виде исходного кода, который был идентифицирован. Опять же смотрите выше пример для ключевого слова <a class="reference external" href="http://docs.python.org/reference/compound_stmts.html#if" style="color: #355f7c; text-decoration: none;" title="(in Python v2.7)"><tt class="xref std std-keyword docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">if</span></tt></a>. Различные типы терминальных символов определены в заголовочном файле C <tt class="file docutils literal" style="background-color: #ecf0f3; font-size: 0.95em; padding: 0px 1px;"><span class="pre">Include/token.h</span></tt> и модуле Python <a class="reference external" href="http://docs.python.org/library/token.html#token" style="color: #355f7c; text-decoration: none;" title="(in Python v2.7)"><tt class="xref py py-mod docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">token</span></tt></a>.</div>
<div style="background-color: white; font-family: sans-serif; font-size: 16px; line-height: 20px; text-align: justify;">
Объекты ST не требуются для поддержки функциональности этого модуля, но они используются для трёх целей: чтобы позволить приложению снизить стоимость обработки сложных распарсенных деревьев, чтобы предоставить представление распарсенного дерева, которое потребляет меньше памяти, чем представление при помощи списков или кортежей, и для того, чтобы проще сождавать дополнительные модули на С, которые манипулируют этими деревьями. Простой класс обёртка может быть создан в Python для того, чтобы скрыть использование объектов ST.</div>
<div style="background-color: white; font-family: sans-serif; font-size: 16px; line-height: 20px; text-align: justify;">
Модель <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#module-parser" style="color: #355f7c; text-decoration: none;" title="parser: Access parse trees for Python source code."><tt class="xref py py-mod docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">parser</span></tt></a> определяет функции для нескольких различных целей. Наиболее важная цель - создание ST объектов и предобразования этих объектов в другие представления, такие как распарсенные деревья и компилированные объекты кода, однако есть ещё и функции, которые служат для запросов типа дерева, представленного объектом ST.</div>
<div class="admonition seealso" style="background-color: #ffffcc; border: 1px solid rgb(255, 255, 102); font-family: sans-serif; font-size: 16px; margin-bottom: 10px; margin-top: 10px; padding: 7px;">
<div class="first admonition-title" style="display: inline; font-weight: bold; line-height: 20px; margin-bottom: 5px; margin-right: 10px; text-align: justify;">
See also</div>
<dl class="last docutils" style="margin-bottom: 0px;">
<dt style="font-weight: bold;">Module <a class="reference external" href="http://docs.python.org/library/symbol.html#symbol" style="color: #355f7c; text-decoration: none;" title="(in Python v2.7)"><tt class="xref py py-mod docutils literal" style="background-color: transparent; font-size: 0.95em; padding: 0px 1px;"><span class="pre">symbol</span></tt></a></dt>
<dd style="line-height: 20px; margin-bottom: 10px; margin-left: 30px; margin-top: 3px; text-align: justify;">Полезные константы представляющие внутренние узлы распарсенног дерева.</dd>
<dt style="font-weight: bold;">Module <a class="reference external" href="http://docs.python.org/library/token.html#token" style="color: #355f7c; text-decoration: none;" title="(in Python v2.7)"><tt class="xref py py-mod docutils literal" style="background-color: transparent; font-size: 0.95em; padding: 0px 1px;"><span class="pre">token</span></tt></a></dt>
<dd style="line-height: 20px; margin-bottom: 10px; margin-left: 30px; margin-top: 3px; text-align: justify;">
<dl class="first last docutils" style="margin-bottom: 0px; margin-top: 0px !important;">
<dt style="font-weight: bold;">Полезные константы, представляющие листью узлов распарсенного дерева и функции для</dt>
<dd style="margin-bottom: 10px; margin-left: 30px; margin-top: 3px;">проверки значений узлов.</dd></dl>
</dd></dl>
</div>
<div class="section" id="st" style="background-color: white; font-family: sans-serif; font-size: 16px;">
<span id="creating-sts"></span><h2 style="background-color: #f2f2f2; border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #20435c; font-family: 'Trebuchet MS', sans-serif; font-size: 26px; font-weight: normal; margin: 20px -20px 10px; padding: 3px 0px 3px 10px;">
Создание объектов ST<a class="headerlink" href="http://python-lab.ru/documentation/27/stdlib/parser.html#st" style="color: #c60f0f; font-size: 0.8em; padding: 0px 4px; text-decoration: none; visibility: hidden;" title="Permalink to this headline"></a></h2>
<div style="line-height: 20px; text-align: justify;">
Объекты ST могут быть созданы из исходного кода или из распарсенного дерева. Когда объект ST создаётся из исходного кода, то для создания форм <tt class="docutils literal" style="background-color: #ecf0f3; font-size: 0.95em; padding: 0px 1px;"><span class="pre">'eval'</span></tt> и <tt class="docutils literal" style="background-color: #ecf0f3; font-size: 0.95em; padding: 0px 1px;"><span class="pre">'exec'</span></tt> используются различные функции.</div>
<dl class="function" style="margin-bottom: 15px;">
<dt id="parser.expr"><tt class="descclassname" style="background-color: transparent; font-size: 0.95em; padding: 0px 1px;">parser.</tt><tt class="descname" style="background-color: transparent; font-size: 1.2em; font-weight: bold; padding: 0px 1px;">expr</tt><big>(</big><em>source</em><big>)</big><a class="headerlink" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.expr" style="color: #c60f0f; font-size: 0.8em; padding: 0px 4px; text-decoration: none; visibility: hidden;" title="Permalink to this definition"></a></dt>
<dd style="line-height: 20px; margin-bottom: 10px; margin-left: 30px; margin-top: 3px; text-align: justify;">Функция <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.expr" style="color: #355f7c; text-decoration: none;" title="parser.expr"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">expr()</span></tt></a> парсит параметр <em>source</em>, как если бы это был ввод для <tt class="docutils literal" style="background-color: #ecf0f3; font-size: 0.95em; padding: 0px 1px;"><span class="pre">compile(source,</span> <span class="pre">'file.py',</span> <span class="pre">'eval')</span></tt>. Если парсинг проходит успешно, то создаётся ST объект, котрый содержит внутреннее представление распарсенного дерева; в противном случае вызывается соответствующее исключение.</dd></dl>
<dl class="function" style="margin-bottom: 15px;">
<dt id="parser.suite"><tt class="descclassname" style="background-color: transparent; font-size: 0.95em; padding: 0px 1px;">parser.</tt><tt class="descname" style="background-color: transparent; font-size: 1.2em; font-weight: bold; padding: 0px 1px;">suite</tt><big>(</big><em>source</em><big>)</big><a class="headerlink" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.suite" style="color: #c60f0f; font-size: 0.8em; padding: 0px 4px; text-decoration: none; visibility: hidden;" title="Permalink to this definition"></a></dt>
<dd style="line-height: 20px; margin-bottom: 10px; margin-left: 30px; margin-top: 3px; text-align: justify;">Фукция <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.suite" style="color: #355f7c; text-decoration: none;" title="parser.suite"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">suite()</span></tt></a> парсит параметр <em>source</em>, как если бы это был ввод для <tt class="docutils literal" style="background-color: #ecf0f3; font-size: 0.95em; padding: 0px 1px;"><span class="pre">compile(source,</span> <span class="pre">'file.py',</span> <span class="pre">'exec')</span></tt>. Если парсинг проходит успешно, то создаётся ST объект, котрый содержит внутреннее представление распарсенного дерева; в противном случае вызывается соответствующее исключение.</dd></dl>
<dl class="function" style="margin-bottom: 15px;">
<dt id="parser.sequence2st"><tt class="descclassname" style="background-color: transparent; font-size: 0.95em; padding: 0px 1px;">parser.</tt><tt class="descname" style="background-color: transparent; font-size: 1.2em; font-weight: bold; padding: 0px 1px;">sequence2st</tt><big>(</big><em>sequence</em><big>)</big><a class="headerlink" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.sequence2st" style="color: #c60f0f; font-size: 0.8em; padding: 0px 4px; text-decoration: none; visibility: hidden;" title="Permalink to this definition"></a></dt>
<dd style="line-height: 20px; margin-bottom: 10px; margin-left: 30px; margin-top: 3px; text-align: justify;">Эта функция принимает представление распарсенного дерева в качестве последовательности и создаёт внутреннее представление, если это возможно. Если можно проверить, что дерево соответствует грамматике Python и все узлы являются корректным типом узлов в данной версии Pythonб то из внутреннего представления создаётся объект ST и он возвращается функцией. Если возникает проблема с созданием внутреннего представления или дерево не может быть проверено, вызывается исключение <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.ParserError" style="color: #355f7c; text-decoration: none;" title="parser.ParserError"><tt class="xref py py-exc docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">ParserError</span></tt></a>. Объект ST, создаваемый таким образом, не обязательно будет корректно компилироваться; обычные исключения, которые возникают при компиляции всё ещё могут возникать, когда ST объект передаётся в <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.compilest" style="color: #355f7c; text-decoration: none;" title="parser.compilest"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">compilest()</span></tt></a>. Это может означать наличие проблем, которые не связаны с синтакисом (такие как исключение <tt class="xref py py-exc docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">MemoryError</span></tt>), но могут быть вызваны конструкциями типа <tt class="docutils literal" style="background-color: #ecf0f3; font-size: 0.95em; padding: 0px 1px;"><span class="pre">del</span> <span class="pre">f(0)</span></tt>, которые проходят парсер Python, но при этом проверяются компилятором байт-кода.<br />
Последовательности, представляющие терминальные токены, могут быть представлены либо как двух-элементный список формы<tt class="docutils literal" style="background-color: #ecf0f3; font-size: 0.95em; padding: 0px 1px;"><span class="pre">(1,</span> <span class="pre">'name')</span></tt> или трёх-элементный спискок вида <tt class="docutils literal" style="background-color: #ecf0f3; font-size: 0.95em; padding: 0px 1px;"><span class="pre">(1,</span> <span class="pre">'name',</span> <span class="pre">56)</span></tt>. Если есть третий элемент, то это должен быть корректный номер строки. Номер строки может быть определён для любого набора терминальных символов во входном дереве.</dd></dl>
<dl class="function" style="margin-bottom: 15px;">
<dt id="parser.tuple2st"><tt class="descclassname" style="background-color: transparent; font-size: 0.95em; padding: 0px 1px;">parser.</tt><tt class="descname" style="background-color: transparent; font-size: 1.2em; font-weight: bold; padding: 0px 1px;">tuple2st</tt><big>(</big><em>sequence</em><big>)</big><a class="headerlink" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.tuple2st" style="color: #c60f0f; font-size: 0.8em; padding: 0px 4px; text-decoration: none; visibility: hidden;" title="Permalink to this definition"></a></dt>
<dd style="line-height: 20px; margin-bottom: 10px; margin-left: 30px; margin-top: 3px; text-align: justify;">Та же самая функция, что и <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.sequence2st" style="color: #355f7c; text-decoration: none;" title="parser.sequence2st"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">sequence2st()</span></tt></a>. Эта точка входа существует для обеспечения обратной совместимости.</dd></dl>
</div>
<div class="section" id="converting-sts" style="background-color: white; font-family: sans-serif; font-size: 16px;">
<span id="id1"></span><h2 style="background-color: #f2f2f2; border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #20435c; font-family: 'Trebuchet MS', sans-serif; font-size: 26px; font-weight: normal; margin: 20px -20px 10px; padding: 3px 0px 3px 10px;">
Преобразование объектов ST<a class="headerlink" href="http://python-lab.ru/documentation/27/stdlib/parser.html#converting-sts" style="color: #c60f0f; font-size: 0.8em; padding: 0px 4px; text-decoration: none; visibility: hidden;" title="Permalink to this headline"></a></h2>
<div style="line-height: 20px; text-align: justify;">
ST объекты, вне зависимости от исходных данных, на основе которых они созданы, могут быть преобразованы в представление распарсенных деревьев в виде деревьев списков или кортежей, или же могут быть скомпилированы в исполняемые объекты кода. Распарсенные деревья могут быть извлечены с или без информацией о номере строк.</div>
<dl class="function" style="margin-bottom: 15px;">
<dt id="parser.st2list"><tt class="descclassname" style="background-color: transparent; font-size: 0.95em; padding: 0px 1px;">parser.</tt><tt class="descname" style="background-color: transparent; font-size: 1.2em; font-weight: bold; padding: 0px 1px;">st2list</tt><big>(</big><em>ast</em><span class="optional" style="font-size: 1.3em;">[</span>, <em>line_info</em><span class="optional" style="font-size: 1.3em;">]</span><big>)</big><a class="headerlink" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.st2list" style="color: #c60f0f; font-size: 0.8em; padding: 0px 4px; text-decoration: none; visibility: hidden;" title="Permalink to this definition"></a></dt>
<dd style="line-height: 20px; margin-bottom: 10px; margin-left: 30px; margin-top: 3px; text-align: justify;">Эта функция принимает объект ST, полученный вызовом <em>ast</em> и возвращает список Python представляющий аналогичное распарсенное дерево. Результирующий список может быть использован для изучения или создания нового распарсенного дерева в форме списка. Эта функция работает пока есть достаточно памяти для построения спискового представления. Если полученное дерево будет использовано только для изучения, то надо использовать функцию <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.st2tuple" style="color: #355f7c; text-decoration: none;" title="parser.st2tuple"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">st2tuple()</span></tt></a> для сокращения потребления памяти и уменьшения фрагментации. Когда требуется списковое представление, то эта функция работает гораздо быстрее, чем получение представления в виде кортежа и преобразования его в список.<br />
Если <em>line_info=True</em>, то для всех терминальных токенов будет добавлен номер строки в качестве третьего элемента списка. Обратите внимание, что номер строки определяется строкой, на которой токен <em>заканчивается</em>. Эта информация не указывается если флаг установлен в false или вообще не передан.</dd></dl>
<dl class="function" style="margin-bottom: 15px;">
<dt id="parser.st2tuple"><tt class="descclassname" style="background-color: transparent; font-size: 0.95em; padding: 0px 1px;">parser.</tt><tt class="descname" style="background-color: transparent; font-size: 1.2em; font-weight: bold; padding: 0px 1px;">st2tuple</tt><big>(</big><em>ast</em><span class="optional" style="font-size: 1.3em;">[</span>, <em>line_info</em><span class="optional" style="font-size: 1.3em;">]</span><big>)</big><a class="headerlink" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.st2tuple" style="color: #c60f0f; font-size: 0.8em; padding: 0px 4px; text-decoration: none; visibility: hidden;" title="Permalink to this definition"></a></dt>
<dd style="line-height: 20px; margin-bottom: 10px; margin-left: 30px; margin-top: 3px; text-align: justify;">Эта функция принимает объект ST, полученный вызовом <em>ast</em> и возвращает кортеж Python, представляющий соответсвующее распарсенное дерево. Кроме того, что эта функция возвращает кортеж, а не список, в остальном она идентична функции <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.st2list" style="color: #355f7c; text-decoration: none;" title="parser.st2list"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">st2list()</span></tt></a>.<br />
Если <em>line_info=True</em>, то для всех терминальных токенов будет добавлен номер строки в качестве третьего элемента спискового представления. Эта информация не указывается если флаг установлен в false или вообще не передан.</dd></dl>
<dl class="function" style="margin-bottom: 15px;">
<dt id="parser.compilest"><tt class="descclassname" style="background-color: transparent; font-size: 0.95em; padding: 0px 1px;">parser.</tt><tt class="descname" style="background-color: transparent; font-size: 1.2em; font-weight: bold; padding: 0px 1px;">compilest</tt><big>(</big><em>ast</em>, <em>filename='<syntax-tree>'</em><big>)</big><a class="headerlink" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.compilest" style="color: #c60f0f; font-size: 0.8em; padding: 0px 4px; text-decoration: none; visibility: hidden;" title="Permalink to this definition"></a></dt>
<dd style="line-height: 20px; margin-bottom: 10px; margin-left: 30px; margin-top: 3px; text-align: justify;"><div id="index-1">
Компилятор байт-кода Python может быть вызван для объекта ST чтобы создать объект кода, который может быть использован как часть выражения <a class="reference external" href="http://docs.python.org/reference/simple_stmts.html#exec" style="color: #355f7c; text-decoration: none;" title="(in Python v2.7)"><tt class="xref std std-keyword docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">exec</span></tt></a> или быть вызван через функцию <a class="reference external" href="http://docs.python.org/library/functions.html#eval" style="color: #355f7c; text-decoration: none;" title="(in Python v2.7)"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">eval()</span></tt></a>. Эта функция предоставляет интерфейс для компилятора, передавая внутреннее распарсенное дерево из <em>ast</em> в парсер при помощи имени исходного файла, определённого в параметре<em>filename</em>. Значение по умолчанию <em>filename</em> означает, что источником является объект ST.</div>
Компиляция объекта ST может привести к исключению, связанному с компиляцией; примером может быть <tt class="xref py py-exc docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">SyntaxError</span></tt>, вызванный для выражения <tt class="docutils literal" style="background-color: #ecf0f3; font-size: 0.95em; padding: 0px 1px;"><span class="pre">del</span> <span class="pre">f(0)</span></tt> в дереве: это выражение корректно с точки зрения формальной грамматики Python, но при этом не является корретной конструкцией языка. <tt class="xref py py-exc docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">SyntaxError</span></tt>, которое будет вызвано в таком случае, генерируется компилятором байт-кода, поэтому оно генерируется в модуле <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#module-parser" style="color: #355f7c; text-decoration: none;" title="parser: Access parse trees for Python source code."><tt class="xref py py-mod docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">parser</span></tt></a>. Большая часть ошибок компиляции может быть обнаружена программным образом при изучении распарсенного дерева.</dd></dl>
</div>
<div class="section" id="querying-sts" style="background-color: white; font-family: sans-serif; font-size: 16px;">
<span id="id2"></span><h2 style="background-color: #f2f2f2; border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #20435c; font-family: 'Trebuchet MS', sans-serif; font-size: 26px; font-weight: normal; margin: 20px -20px 10px; padding: 3px 0px 3px 10px;">
Запросы к объектам ST<a class="headerlink" href="http://python-lab.ru/documentation/27/stdlib/parser.html#querying-sts" style="color: #c60f0f; font-size: 0.8em; padding: 0px 4px; text-decoration: none; visibility: hidden;" title="Permalink to this headline"></a></h2>
<div style="line-height: 20px; text-align: justify;">
Кроме того, есть две функции, которые позволяют приложению определить, был ли ST объект создан как выражение или как suite. Ни одна из этих функций не может быть использована для определения того, был этот объект создан из исходного кода при помощи <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.expr" style="color: #355f7c; text-decoration: none;" title="parser.expr"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">expr()</span></tt></a>или <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.suite" style="color: #355f7c; text-decoration: none;" title="parser.suite"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">suite()</span></tt></a> или из распарсенного дерева при помощи <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.sequence2st" style="color: #355f7c; text-decoration: none;" title="parser.sequence2st"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">sequence2st()</span></tt></a>.</div>
<dl class="function" style="margin-bottom: 15px;">
<dt id="parser.isexpr"><tt class="descclassname" style="background-color: transparent; font-size: 0.95em; padding: 0px 1px;">parser.</tt><tt class="descname" style="background-color: transparent; font-size: 1.2em; font-weight: bold; padding: 0px 1px;">isexpr</tt><big>(</big><em>ast</em><big>)</big><a class="headerlink" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.isexpr" style="color: #c60f0f; font-size: 0.8em; padding: 0px 4px; text-decoration: none; visibility: hidden;" title="Permalink to this definition"></a></dt>
<dd style="line-height: 20px; margin-bottom: 10px; margin-left: 30px; margin-top: 3px; text-align: justify;"><div id="index-2">
Когда <em>ast</em> находится в форме <tt class="docutils literal" style="background-color: #ecf0f3; font-size: 0.95em; padding: 0px 1px;"><span class="pre">'eval'</span></tt>, эта функция возвращает true, в противном случае - false. Это полезно, так как объект кода не может быть запрошен об этой информации при помощи встроенных функций. Обратите внимание, что объект кода, создаваемый функцией <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.compilest" style="color: #355f7c; text-decoration: none;" title="parser.compilest"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">compilest()</span></tt></a> не может быть запрошен об этом и он идентичен созданному при помощи встроенной функции <a class="reference external" href="http://docs.python.org/library/functions.html#compile" style="color: #355f7c; text-decoration: none;" title="(in Python v2.7)"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">compile()</span></tt></a>.</div>
</dd></dl>
<dl class="function" style="margin-bottom: 15px;">
<dt id="parser.issuite"><tt class="descclassname" style="background-color: transparent; font-size: 0.95em; padding: 0px 1px;">parser.</tt><tt class="descname" style="background-color: transparent; font-size: 1.2em; font-weight: bold; padding: 0px 1px;">issuite</tt><big>(</big><em>ast</em><big>)</big><a class="headerlink" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.issuite" style="color: #c60f0f; font-size: 0.8em; padding: 0px 4px; text-decoration: none; visibility: hidden;" title="Permalink to this definition"></a></dt>
<dd style="line-height: 20px; margin-bottom: 10px; margin-left: 30px; margin-top: 3px; text-align: justify;">Эта функция аналогична <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.isexpr" style="color: #355f7c; text-decoration: none;" title="parser.isexpr"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">isexpr()</span></tt></a> в том, что она сообщает, является ли объект ST представлением формы <tt class="docutils literal" style="background-color: #ecf0f3; font-size: 0.95em; padding: 0px 1px;"><span class="pre">'exec'</span></tt>, обычно известным как “suite.” Не стоит предполагать, что эта функция аналогична <tt class="docutils literal" style="background-color: #ecf0f3; font-size: 0.95em; padding: 0px 1px;"><span class="pre">not</span> <span class="pre">isexpr(ast)</span></tt>, так как дополнительные синтаксические фрагменты могут поддерживаться в будущем.</dd></dl>
</div>
<div class="section" id="st-errors" style="background-color: white; font-family: sans-serif; font-size: 16px;">
<span id="id3"></span><h2 style="background-color: #f2f2f2; border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #20435c; font-family: 'Trebuchet MS', sans-serif; font-size: 26px; font-weight: normal; margin: 20px -20px 10px; padding: 3px 0px 3px 10px;">
Исключения и обработка ошибок<a class="headerlink" href="http://python-lab.ru/documentation/27/stdlib/parser.html#st-errors" style="color: #c60f0f; font-size: 0.8em; padding: 0px 4px; text-decoration: none; visibility: hidden;" title="Permalink to this headline"></a></h2>
<div style="line-height: 20px; text-align: justify;">
Модуль <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#module-parser" style="color: #355f7c; text-decoration: none;" title="parser: Access parse trees for Python source code."><tt class="xref py py-mod docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">parser</span></tt></a> определяет единственное исключение, но он может передавать другие встроенные исключения из других частей Python runtime environment. Смотрите документацию по каждой функции в поисках информации, какие исключения она может вызывать.</div>
<dl class="exception" style="margin-bottom: 15px;">
<dt id="parser.ParserError"><em class="property">exception </em><tt class="descclassname" style="background-color: transparent; font-size: 0.95em; padding: 0px 1px;">parser.</tt><tt class="descname" style="background-color: transparent; font-size: 1.2em; font-weight: bold; padding: 0px 1px;">ParserError</tt><a class="headerlink" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.ParserError" style="color: #c60f0f; font-size: 0.8em; padding: 0px 4px; text-decoration: none; visibility: hidden;" title="Permalink to this definition"></a></dt>
<dd style="line-height: 20px; margin-bottom: 10px; margin-left: 30px; margin-top: 3px; text-align: justify;">Исключение, которое вызывается при появлении ошибки в модуле <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#module-parser" style="color: #355f7c; text-decoration: none;" title="parser: Access parse trees for Python source code."><tt class="xref py py-mod docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">parser</span></tt></a>. В основном он вызывается при ошибках валидации, тогда как встроенное исключение <tt class="xref py py-exc docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">SyntaxError</span></tt> вызывается во время нормального парсинга. Аргументом исключения является строка, описывающая причину оишбки, или кортеж, содержащий последовательность из распарсенного дерева, переданного в<a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.sequence2st" style="color: #355f7c; text-decoration: none;" title="parser.sequence2st"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">sequence2st()</span></tt></a>, которая привела к ошибке и объясняющую строку. Вызов <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.sequence2st" style="color: #355f7c; text-decoration: none;" title="parser.sequence2st"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">sequence2st()</span></tt></a> должен уметь обрабатывать оба типа исключений, тогда как вызовы других функций в модуле должны обрабатывать только строковые значения исключений.</dd></dl>
<div style="line-height: 20px; text-align: justify;">
Обратите внимание, что функции <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.compilest" style="color: #355f7c; text-decoration: none;" title="parser.compilest"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">compilest()</span></tt></a>, <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.expr" style="color: #355f7c; text-decoration: none;" title="parser.expr"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">expr()</span></tt></a>, и <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.suite" style="color: #355f7c; text-decoration: none;" title="parser.suite"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">suite()</span></tt></a> могут вызывать исключения, которые обычно вызываются при парсинге и компиляции. Это включает в себя <tt class="xref py py-exc docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">MemoryError</span></tt>, <tt class="xref py py-exc docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">OverflowError</span></tt>, <tt class="xref py py-exc docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">SyntaxError</span></tt>, и <tt class="xref py py-exc docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">SystemError</span></tt>. В этих случаях, эти исключения надо трактовать так же как в любом другом случае. Подробнее это описано в соответствующем разделе документации.</div>
</div>
<div class="section" id="st-objects" style="background-color: white; font-family: sans-serif; font-size: 16px;">
<span id="id4"></span><h2 style="background-color: #f2f2f2; border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #20435c; font-family: 'Trebuchet MS', sans-serif; font-size: 26px; font-weight: normal; margin: 20px -20px 10px; padding: 3px 0px 3px 10px;">
Объекты ST<a class="headerlink" href="http://python-lab.ru/documentation/27/stdlib/parser.html#st-objects" style="color: #c60f0f; font-size: 0.8em; padding: 0px 4px; text-decoration: none; visibility: hidden;" title="Permalink to this headline"></a></h2>
<div style="line-height: 20px; text-align: justify;">
Упорядочивание и сравнение на равенство доступно для объектов ST. Кроме того их можно обрабатыать модулем <a class="reference external" href="http://docs.python.org/library/pickle.html#pickle" style="color: #355f7c; text-decoration: none;" title="(in Python v2.7)"><tt class="xref py py-mod docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">pickle</span></tt></a>.</div>
<dl class="data" style="margin-bottom: 15px;">
<dt id="parser.STType"><tt class="descclassname" style="background-color: transparent; font-size: 0.95em; padding: 0px 1px;">parser.</tt><tt class="descname" style="background-color: transparent; font-size: 1.2em; font-weight: bold; padding: 0px 1px;">STType</tt><a class="headerlink" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.STType" style="color: #c60f0f; font-size: 0.8em; padding: 0px 4px; text-decoration: none; visibility: hidden;" title="Permalink to this definition"></a></dt>
<dd style="line-height: 20px; margin-bottom: 10px; margin-left: 30px; margin-top: 3px; text-align: justify;">Тип объектов, возвращаемых <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.expr" style="color: #355f7c; text-decoration: none;" title="parser.expr"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">expr()</span></tt></a>, <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.suite" style="color: #355f7c; text-decoration: none;" title="parser.suite"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">suite()</span></tt></a> и <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.sequence2st" style="color: #355f7c; text-decoration: none;" title="parser.sequence2st"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">sequence2st()</span></tt></a>.</dd></dl>
<div style="line-height: 20px; text-align: justify;">
ST объекты имеют следующие методы:</div>
<dl class="method" style="margin-bottom: 15px;">
<dt id="parser.ST.compile"><tt class="descclassname" style="background-color: transparent; font-size: 0.95em; padding: 0px 1px;">ST.</tt><tt class="descname" style="background-color: transparent; font-size: 1.2em; font-weight: bold; padding: 0px 1px;">compile</tt><big>(</big><span class="optional" style="font-size: 1.3em;">[</span><em>filename</em><span class="optional" style="font-size: 1.3em;">]</span><big>)</big><a class="headerlink" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.ST.compile" style="color: #c60f0f; font-size: 0.8em; padding: 0px 4px; text-decoration: none; visibility: hidden;" title="Permalink to this definition"></a></dt>
<dd style="line-height: 20px; margin-bottom: 10px; margin-left: 30px; margin-top: 3px; text-align: justify;">Аналогичен <tt class="docutils literal" style="background-color: #ecf0f3; font-size: 0.95em; padding: 0px 1px;"><span class="pre">compilest(st,</span> <span class="pre">filename)</span></tt>.</dd></dl>
<dl class="method" style="margin-bottom: 15px;">
<dt id="parser.ST.isexpr"><tt class="descclassname" style="background-color: transparent; font-size: 0.95em; padding: 0px 1px;">ST.</tt><tt class="descname" style="background-color: transparent; font-size: 1.2em; font-weight: bold; padding: 0px 1px;">isexpr</tt><big>(</big><big>)</big><a class="headerlink" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.ST.isexpr" style="color: #c60f0f; font-size: 0.8em; padding: 0px 4px; text-decoration: none; visibility: hidden;" title="Permalink to this definition"></a></dt>
<dd style="line-height: 20px; margin-bottom: 10px; margin-left: 30px; margin-top: 3px; text-align: justify;">Аналогичен <tt class="docutils literal" style="background-color: #ecf0f3; font-size: 0.95em; padding: 0px 1px;"><span class="pre">isexpr(st)</span></tt>.</dd></dl>
<dl class="method" style="margin-bottom: 15px;">
<dt id="parser.ST.issuite"><tt class="descclassname" style="background-color: transparent; font-size: 0.95em; padding: 0px 1px;">ST.</tt><tt class="descname" style="background-color: transparent; font-size: 1.2em; font-weight: bold; padding: 0px 1px;">issuite</tt><big>(</big><big>)</big><a class="headerlink" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.ST.issuite" style="color: #c60f0f; font-size: 0.8em; padding: 0px 4px; text-decoration: none; visibility: hidden;" title="Permalink to this definition"></a></dt>
<dd style="line-height: 20px; margin-bottom: 10px; margin-left: 30px; margin-top: 3px; text-align: justify;">Аналогичен <tt class="docutils literal" style="background-color: #ecf0f3; font-size: 0.95em; padding: 0px 1px;"><span class="pre">issuite(st)</span></tt>.</dd></dl>
<dl class="method" style="margin-bottom: 15px;">
<dt id="parser.ST.tolist"><tt class="descclassname" style="background-color: transparent; font-size: 0.95em; padding: 0px 1px;">ST.</tt><tt class="descname" style="background-color: transparent; font-size: 1.2em; font-weight: bold; padding: 0px 1px;">tolist</tt><big>(</big><span class="optional" style="font-size: 1.3em;">[</span><em>line_info</em><span class="optional" style="font-size: 1.3em;">]</span><big>)</big><a class="headerlink" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.ST.tolist" style="color: #c60f0f; font-size: 0.8em; padding: 0px 4px; text-decoration: none; visibility: hidden;" title="Permalink to this definition"></a></dt>
<dd style="line-height: 20px; margin-bottom: 10px; margin-left: 30px; margin-top: 3px; text-align: justify;">Аналогичен <tt class="docutils literal" style="background-color: #ecf0f3; font-size: 0.95em; padding: 0px 1px;"><span class="pre">st2list(st,</span> <span class="pre">line_info)</span></tt>.</dd></dl>
<dl class="method" style="margin-bottom: 15px;">
<dt id="parser.ST.totuple"><tt class="descclassname" style="background-color: transparent; font-size: 0.95em; padding: 0px 1px;">ST.</tt><tt class="descname" style="background-color: transparent; font-size: 1.2em; font-weight: bold; padding: 0px 1px;">totuple</tt><big>(</big><span class="optional" style="font-size: 1.3em;">[</span><em>line_info</em><span class="optional" style="font-size: 1.3em;">]</span><big>)</big><a class="headerlink" href="http://python-lab.ru/documentation/27/stdlib/parser.html#parser.ST.totuple" style="color: #c60f0f; font-size: 0.8em; padding: 0px 4px; text-decoration: none; visibility: hidden;" title="Permalink to this definition"></a></dt>
<dd style="line-height: 20px; margin-bottom: 10px; margin-left: 30px; margin-top: 3px; text-align: justify;">Аналогичен <tt class="docutils literal" style="background-color: #ecf0f3; font-size: 0.95em; padding: 0px 1px;"><span class="pre">st2tuple(st,</span> <span class="pre">line_info)</span></tt>.</dd></dl>
</div>
<div class="section" id="compile" style="background-color: white; font-family: sans-serif; font-size: 16px;">
<h2 style="background-color: #f2f2f2; border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #20435c; font-family: 'Trebuchet MS', sans-serif; font-size: 26px; font-weight: normal; margin: 20px -20px 10px; padding: 3px 0px 3px 10px;">
Пример: эмуляция <a class="reference external" href="http://docs.python.org/library/functions.html#compile" style="color: #355f7c; text-decoration: none;" title="(in Python v2.7)"><tt class="xref py py-func docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">compile()</span></tt></a><a class="headerlink" href="http://python-lab.ru/documentation/27/stdlib/parser.html#compile" style="color: #c60f0f; font-size: 0.8em; padding: 0px 4px; text-decoration: none; visibility: hidden;" title="Permalink to this headline"></a></h2>
<div style="line-height: 20px; text-align: justify;">
Так как многие полезные операции могут быть выполнены между парсингом и созданием байт-кода, простейшая операция - не делать ничего. Для этой цели, использование модуля ;mod:<cite>parser</cite> для создания промежуточной структуры данных эквивалентно следующему коду:</div>
<div class="highlight-python">
<div class="highlight" style="background-color: #eeffcc; background-position: initial initial; background-repeat: initial initial;">
<pre style="border-bottom-color: rgb(170, 204, 153); border-bottom-width: 1px; border-style: solid none; border-top-color: rgb(170, 204, 153); border-top-width: 1px; color: #333333; line-height: 15px; overflow-x: auto; overflow-y: hidden; padding: 5px;"><span class="gp" style="color: #c65d09; font-weight: bold;">>>> </span><span class="n">code</span> <span class="o" style="color: #666666;">=</span> <span class="nb" style="color: #007020;">compile</span><span class="p">(</span><span class="s" style="color: #4070a0;">'a + 5'</span><span class="p">,</span> <span class="s" style="color: #4070a0;">'file.py'</span><span class="p">,</span> <span class="s" style="color: #4070a0;">'eval'</span><span class="p">)</span>
<span class="gp" style="color: #c65d09; font-weight: bold;">>>> </span><span class="n">a</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #208050;">5</span>
<span class="gp" style="color: #c65d09; font-weight: bold;">>>> </span><span class="nb" style="color: #007020;">eval</span><span class="p">(</span><span class="n">code</span><span class="p">)</span>
<span class="go">10</span>
</pre>
</div>
</div>
<div style="line-height: 20px; text-align: justify;">
Эквивалентрая операция при помощи модуля <a class="reference internal" href="http://python-lab.ru/documentation/27/stdlib/parser.html#module-parser" style="color: #355f7c; text-decoration: none;" title="parser: Access parse trees for Python source code."><tt class="xref py py-mod docutils literal" style="background-color: transparent; font-size: 0.95em; font-weight: bold; padding: 0px 1px;"><span class="pre">parser</span></tt></a> немного длиннее и позволяет получить распарсенное дерево в виде объекта ST:</div>
<div class="highlight-python">
<div class="highlight" style="background-color: #eeffcc; background-position: initial initial; background-repeat: initial initial;">
<pre style="border-bottom-color: rgb(170, 204, 153); border-bottom-width: 1px; border-style: solid none; border-top-color: rgb(170, 204, 153); border-top-width: 1px; color: #333333; line-height: 15px; overflow-x: auto; overflow-y: hidden; padding: 5px;"><span class="gp" style="color: #c65d09; font-weight: bold;">>>> </span><span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">parser</span>
<span class="gp" style="color: #c65d09; font-weight: bold;">>>> </span><span class="n">st</span> <span class="o" style="color: #666666;">=</span> <span class="n">parser</span><span class="o" style="color: #666666;">.</span><span class="n">expr</span><span class="p">(</span><span class="s" style="color: #4070a0;">'a + 5'</span><span class="p">)</span>
<span class="gp" style="color: #c65d09; font-weight: bold;">>>> </span><span class="n">code</span> <span class="o" style="color: #666666;">=</span> <span class="n">st</span><span class="o" style="color: #666666;">.</span><span class="n">compile</span><span class="p">(</span><span class="s" style="color: #4070a0;">'file.py'</span><span class="p">)</span>
<span class="gp" style="color: #c65d09; font-weight: bold;">>>> </span><span class="n">a</span> <span class="o" style="color: #666666;">=</span> <span class="mi" style="color: #208050;">5</span>
<span class="gp" style="color: #c65d09; font-weight: bold;">>>> </span><span class="nb" style="color: #007020;">eval</span><span class="p">(</span><span class="n">code</span><span class="p">)</span>
<span class="go">10</span>
</pre>
</div>
</div>
<div style="line-height: 20px; text-align: justify;">
Приложение, которому нужны и объект ST и объект кода, может “запаковать” этот код в легко доступные функции:</div>
<div class="highlight-python">
<div class="highlight" style="background-color: #eeffcc; background-position: initial initial; background-repeat: initial initial;">
<pre style="border-bottom-color: rgb(170, 204, 153); border-bottom-width: 1px; border-style: solid none; border-top-color: rgb(170, 204, 153); border-top-width: 1px; color: #333333; line-height: 15px; overflow-x: auto; overflow-y: hidden; padding: 5px;"><span class="kn" style="color: #007020; font-weight: bold;">import</span> <span class="nn" style="color: #0e84b5; font-weight: bold;">parser</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">load_suite</span><span class="p">(</span><span class="n">source_string</span><span class="p">):</span>
<span class="n">st</span> <span class="o" style="color: #666666;">=</span> <span class="n">parser</span><span class="o" style="color: #666666;">.</span><span class="n">suite</span><span class="p">(</span><span class="n">source_string</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">st</span><span class="p">,</span> <span class="n">st</span><span class="o" style="color: #666666;">.</span><span class="n">compile</span><span class="p">()</span>
<span class="k" style="color: #007020; font-weight: bold;">def</span> <span class="nf" style="color: #06287e;">load_expression</span><span class="p">(</span><span class="n">source_string</span><span class="p">):</span>
<span class="n">st</span> <span class="o" style="color: #666666;">=</span> <span class="n">parser</span><span class="o" style="color: #666666;">.</span><span class="n">expr</span><span class="p">(</span><span class="n">source_string</span><span class="p">)</span>
<span class="k" style="color: #007020; font-weight: bold;">return</span> <span class="n">st</span><span class="p">,</span> <span class="n">st</span><span class="o" style="color: #666666;">.</span><span class="n">compile</span><span class="p">()</span></pre>
</div>
</div>
</div>
Ishayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com2tag:blogger.com,1999:blog-2142461056765545912.post-6257490328642598982013-08-14T18:49:00.002+04:002013-08-14T18:49:41.769+04:00Перевод документации Sphinx. Разметка уровня параграфа + Вставка кода<ul style="background-color: white; font-family: sans-serif; font-size: 16px;">
<li class="toctree-l1" style="line-height: 20px; text-align: justify;"><a class="reference internal" href="http://python-lab.ru/packages/sphinx/para.html" style="color: #355f7c; text-decoration: none;">Разметка уровня параграфа</a></li>
<li class="toctree-l1" style="line-height: 20px; text-align: justify;"><a class="reference internal" href="http://python-lab.ru/packages/sphinx/para.html#id2" style="color: #355f7c; text-decoration: none;">Разметка содержания</a></li>
<li class="toctree-l1" style="line-height: 20px; text-align: justify;"><a class="reference internal" href="http://python-lab.ru/packages/sphinx/para.html#id5" style="color: #355f7c; text-decoration: none;">Словарь</a></li>
<li class="toctree-l1" style="line-height: 20px; text-align: justify;"><a class="reference internal" href="http://python-lab.ru/packages/sphinx/para.html#id6" style="color: #355f7c; text-decoration: none;">Отображение формальной грамматики</a></li>
<li class="toctree-l1" style="line-height: 20px; text-align: justify;"><a class="reference internal" href="http://python-lab.ru/packages/sphinx/code.html" style="color: #355f7c; text-decoration: none;">Показ примеров кода</a><ul>
<li class="toctree-l2" style="text-align: justify;"><a class="reference internal" href="http://python-lab.ru/packages/sphinx/code.html#id6" style="color: #355f7c; text-decoration: none;">Номера строк</a></li>
<li class="toctree-l2" style="text-align: justify;"><a class="reference internal" href="http://python-lab.ru/packages/sphinx/code.html#id7" style="color: #355f7c; text-decoration: none;">Включения</a></li>
</ul>
</li>
</ul>
Ishayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com0tag:blogger.com,1999:blog-2142461056765545912.post-37798114790682632122013-08-04T13:51:00.001+04:002013-08-04T13:51:40.748+04:00Доступный перевод по Sphinx<ul style="background-color: white; font-family: sans-serif; font-size: 16px;">
<li class="toctree-l1" style="line-height: 20px; text-align: justify;"><a class="reference internal" href="http://python-lab.ru/packages/sphinx/invocation.html" style="color: #355f7c;">Вызов sphinx-build</a><ul>
<li class="toctree-l2" style="text-align: justify;"><a class="reference internal" href="http://python-lab.ru/packages/sphinx/invocation.html#makefile" style="color: #355f7c; text-decoration: none;">Опции Makefile</a></li>
</ul>
</li>
<li class="toctree-l1" style="line-height: 20px; text-align: justify;"><a class="reference internal" href="http://python-lab.ru/packages/sphinx/invocation.html#sphinx-apidoc" style="color: #355f7c; text-decoration: none;">Вызов sphinx-apidoc</a></li>
<li class="toctree-l1" style="line-height: 20px; text-align: justify;"><a class="reference internal" href="http://python-lab.ru/packages/sphinx/toctree-directive.html" style="color: #355f7c; text-decoration: none;">Содержание (TOC tree)</a><ul>
<li class="toctree-l2" style="text-align: justify;"><a class="reference internal" href="http://python-lab.ru/packages/sphinx/toctree-directive.html#id11" style="color: #355f7c; text-decoration: none;">Специальные имена</a></li>
</ul>
</li>
</ul>
Ishayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com0tag:blogger.com,1999:blog-2142461056765545912.post-25587963563606133812013-08-02T01:05:00.002+04:002013-08-02T01:05:52.074+04:00ПереездПоскольку большинство документации написано для Sphinx, то и переводить её удобнее в reST. В связи с этим, а так же с тем, что у меня появился хостинг, тексты я буду класть на <a href="http://python-lab.ru/">python-lab.ru</a>, а сюда вывешивать только обновления.<br />
Сейчас там появилось описание библиотеки <a href="http://python-lab.ru/documentation/27/stdlib/json.html" target="_blank">json</a> и скоро начнёт появляться документация для SphinxIshayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com2tag:blogger.com,1999:blog-2142461056765545912.post-68101719191049323932013-05-12T17:49:00.001+04:002013-05-12T17:49:46.909+04:00Скачивание файла с Google Docs и преобразование ods в csv<div style="text-align: justify;">
Возникла передо мной такая задача: мы храним таблицу соответсвия мака, ip и имени ПК в гуглодоксе, она и поддерживается в актуальном состоянии. DHCP сервер работает на FreeBSD, соответственно файл с настройками сервера вполне себе текстовый. И чтобы не обновлять данные и там и там был сделан скриптик. Наверняка можно было бы сделать проще, в некоторых случаях даже понятно как (например в функции csv2dhcp), но для небольшой таблицы я заморачиваться не стал.</div>
<div style="text-align: justify;">
Для работы понадобится <a href="http://www.freshports.org/www/py-pyquery/" target="_blank">pyquery</a> и второй питон (считаем, что это у Вас уже есть). Кроме того, нам нужна библиотека для доступа к Google API.</div>
<a name='more'></a><br />
<div style="text-align: justify;">
Итак, по порядку:</div>
<ol style="text-align: justify;">
<li>Заходим на <a href="https://developers.google.com/api-client-library/python/start/installation" target="_blank">страницу</a></li>
<li>Выбираем Drive API и Python/Command Line</li>
<li>Нажимаем на Настроить проект</li>
<li>Вводим имя проекта, Далее</li>
<li>По двум появившимся ссылкам скачиваем starter application и client secret, которым заменяем такой же файл в распакованном архиве</li>
<li>Редактируем файл sample.py</li>
</ol>
<div style="text-align: justify;">
Ниже будет код. Функцию csv2dhcp писал сам, ods2csv взял <a href="http://python-example.blogspot.ru/2012/10/how-to-convert-ods-to-csv.html" target="_blank">отсюда</a>, остальное из документации по Google API. Немножно моих комментариев в коде.</div>
<div style="text-align: justify;">
Если будут комментарии/улучшения - буду благодарен </div>
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;"># -*- coding: utf-8 -*-<br />#<br /># Copyright (C) 2012 Google Inc.<br />#<br /># Licensed under the Apache License, Version 2.0 (the "License");<br /># you may not use this file except in compliance with the License.<br /># You may obtain a copy of the License at<br />#<br /># http://www.apache.org/licenses/LICENSE-2.0<br />#<br /># Unless required by applicable law or agreed to in writing, software<br /># distributed under the License is distributed on an "AS IS" BASIS,<br /># WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.<br /># See the License for the specific language governing permissions and<br /># limitations under the License.<br /><br /><br />"""Command-line skeleton application for Drive API.<br />Usage:<br /> $ python sample.py<br /><br />You can also get help on all the command-line flags the program understands<br />by running:<br /><br /> $ python sample.py --help<br /><br />To get detailed log output run:<br /><br /> $ python sample.py --logging_level=DEBUG<br /> <br />Для работы надо поставить gdata:<br /> <br /> #$ pip install gdata<br /> $ pip install pyquery<br /> <br />Подключение API:<br /><br /> https://developers.google.com/drive/quickstart-python<br />"""<br /><br />import gflags<br />import httplib2<br />import logging<br />import os<br />import sys<br /><br />from apiclient.discovery import build<br />from oauth2client.file import Storage<br />from oauth2client.client import AccessTokenRefreshError<br />from oauth2client.client import flow_from_clientsecrets<br />from oauth2client.tools import run<br />from apiclient import errors<br /><br />FLAGS = gflags.FLAGS<br /><br /># CLIENT_SECRETS, name of a file containing the OAuth 2.0 information for this<br /># application, including client_id and client_secret.<br /># You can see the Client ID and Client secret on the API Access tab on the<br /># Google APIs Console <https://code.google.com/apis/console><br />CLIENT_SECRETS = 'client_secrets.json'<br /><br /># Helpful message to display if the CLIENT_SECRETS file is missing.<br />MISSING_CLIENT_SECRETS_MESSAGE = """<br />WARNING: Please configure OAuth 2.0<br /><br />To make this sample run you will need to download the client_secrets.json file<br />and save it at:<br /><br /> %s<br /><br />""" % os.path.join(os.path.dirname(__file__), CLIENT_SECRETS)<br /><span style="font-size: x-small;"># Временные <span style="font-size: x-small;">файлы</span></span>, <span style="font-size: x-small;">куда сохраняется скачаный файл и ко<span style="font-size: x-small;">нвертированый в <span style="font-size: x-small;">csv</span></span></span><br />TEMP_FILE = '/home/ishayahu/IP range.ods'<br />TEMP_FILE2 = '/home/ishayahu/IP range.csv'</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;"># <span style="font-size: x-small;">Имя итогового файла<span style="font-size: x-small;"></span></span><br />dhcp_file_name = '/home/ishayahu/dhcp'<br /># Set up a Flow object to be used for authentication.<br /># Add one or more of the following scopes. PLEASE ONLY ADD THE SCOPES YOU<br /># NEED. For more information on using scopes please see<br /># <https://developers.google.com/+/best-practices>.<br />FLOW = flow_from_clientsecrets(CLIENT_SECRETS,<br /> scope=[<br /> 'https://www.googleapis.com/auth/drive',<br /> 'https://www.googleapis.com/auth/drive.apps.readonly',<br /> 'https://www.googleapis.com/auth/drive.metadata.readonly',<br /> 'https://www.googleapis.com/auth/drive.file',<br /> 'https://www.googleapis.com/auth/drive.scripts',<br /> 'https://www.googleapis.com/auth/drive.readonly',<br /> ],<br /> message=MISSING_CLIENT_SECRETS_MESSAGE)<br /><br /><br /># The gflags module makes defining command-line options easy for<br /># applications. Run this program with the '--help' argument to see<br /># all the flags that it understands.<br />gflags.DEFINE_enum('logging_level', 'ERROR',<br /> ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'],<br /> 'Set the level of logging detail.')<br /><br />def retrieve_all_files(service):<br /> """Retrieve a list of File resources.<br /><br /> Args:<br /> service: Drive API service instance.<br /> Returns:<br /> List of File resources.<br /> """<br /> result = []<br /> page_token = None<br /> while True:<br /> try:<br /> param = {}<br /> if page_token:<br /> param['pageToken'] = page_token<br /> files = service.files().list(**param).execute()<br /><br /> result.extend(files['items'])<br /> page_token = files.get('nextPageToken')<br /> if not page_token:<br /> break<br /> except errors.HttpError, error:<br /> print 'An error occurred: %s' % error<br /> break<br /> return result<br /><br /><br /><br />def download_file(service, drive_file):<br /> """Download a file's content.<br /><br /> Args:<br /> service: Drive API service instance.<br /> drive_file: Drive File instance.<br /><br /> Returns:<br /> File's content if successful, None otherwise.<br /> """<br /> #download_url = drive_file.get('downloadUrl')</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"> # Так как файл в родом формате для гугла, то скачать<span style="font-size: x-small;"> его нельзя и</span></span></span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: x-small;"><span style="font-size: x-small;"><span style="font-size: x-small;"> # <span style="font-size: x-small;">downloadUrl <span style="font-size: x-small;">просто отсутствует. Поэтому используем ссылки для экс<span style="font-size: x-small;">порта</span></span></span></span></span></span><br /> download_url = drive_file[u'exportLinks'][u'application/x-vnd.oasis.opendocument.spreadsheet']<br /> if download_url:<br /> resp, content = service._http.request(download_url)<br /> if resp.status == 200:<br /> #print 'Status: %s' % resp<br /> return content<br /> else:<br /> print 'An error occurred: %s' % resp<br /> return None<br /> else:<br /> # The file doesn't have any content stored on Drive.<br /> return None<br /><br />def ods2csv(filepath): <br /> <span style="font-size: x-small;"># <span style="font-size: x-small;">комментарии тут: http://python-example.blogspot.ru/2012/10/how-to-convert-ods-to-csv.html</span></span><br /> import sys,zipfile,re,os,csv <br /> from pyquery import PyQuery as pq <br /> from lxml.cssselect import CSSSelector <br /> <br /> xml = zipfile.ZipFile(filepath).read('content.xml') <br /> <br /> def rep_repl(match): <br /> return '<table:table-cell>%s' %match.group(2) * int(match.group(1)) <br /> def repl_empt(match): <br /> n = int(match.group(1)) <br /> pat = '<table:table-cell/>' <br /> return pat*n if (n<100) else pat <br /> <br /> p_repl = re.compile(r'<table:table-cell [^>]*?repeated="(\d+)[^/>]*>(.+?table-cell>)') <br /> p_empt = re.compile(r'<table:table-cell [^>]*?repeated="(\d+)[^>]*>') <br /> xml = re.sub(p_repl, rep_repl, xml) <br /> xml = re.sub(p_empt, repl_empt, xml) <br /> <br /> d = pq(xml, parser='xml') <br /> ns={'table': 'urn:oasis:names:tc:opendocument:xmlns:table:1.0'} <br /> selr = CSSSelector('table|table-row', namespaces=ns) <br /> selc = CSSSelector('table|table-cell', namespaces=ns) <br /> rowxs = pq(selr(d[0])) <br /> data = [] <br /> for ir,rowx in enumerate(rowxs): <br /> cells = pq(selc(rowx)) <br /> if cells.text(): <br /> data.append([cells.eq(ic).text().encode('utf-8') for ic in range(len(cells))]) <br /> <br /> root,ext=os.path.splitext(filepath) <br /> with open(''.join([root,'.csv']),'wb') as f: <br /> for row in data: <br /> dw = csv.writer(f) <br /> dw.writerow(row) <br /> <br />def csv2dhcp(filepath):<br /> dhcp_file=open(dhcp_file_name,'w')<br /> for line in open(filepath,'r'):</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;"> if len(line.strip().split(','))>=6 and line.strip().split(',')[2]:<br /> dhcp_file.write("host %s { hardware ethernet %s; fixed-address 192.168.1.%s; }\n" % (line.strip().split(',')[5],line.strip().split(',')[2],line.strip().split(',')[1]))<br /> dhcp_file.close()<br /> <br />def main(argv):<br /> # Let the gflags module process the command-line arguments<br /> try:<br /> argv = FLAGS(argv)<br /> except gflags.FlagsError, e:<br /> print '%s\\nUsage: %s ARGS\\n%s' % (e, argv[0], FLAGS)<br /> sys.exit(1)<br /><br /> # Set the logging according to the command-line flag<br /> logging.getLogger().setLevel(getattr(logging, FLAGS.logging_level))<br /><br /> # If the Credentials don't exist or are invalid, run through the native<br /> # client flow. The Storage object will ensure that if successful the good<br /> # Credentials will get written back to a file.<br /> storage = Storage('sample.dat')<br /> credentials = storage.get()<br /><br /> if credentials is None or credentials.invalid:<br /> credentials = run(FLOW, storage)<br /><br /> # Create an httplib2.Http object to handle our HTTP requests and authorize it<br /> # with our good Credentials.<br /> http = httplib2.Http()<br /> http = credentials.authorize(http)<br /><br /> service = build('drive', 'v2', http=http)<br /><br /> try:<br /> print "Login success! Starting to work."<br /> for entry in retrieve_all_files(service):</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;"> <span style="font-size: x-small;"># <span style="font-size: x-small;">Пролистываем список всех файлов (как ещё получить <span style="font-size: x-small;"><span style="font-size: x-small;">нужный не знаю<span style="font-size: x-small;"></span></span></span>)</span></span></span></span><br />
<span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;"> <span style="font-size: x-small;"># IP range - <span style="font-size: x-small;">имя <span style="font-size: x-small;">нужно<span style="font-size: x-small;">го мне файла</span></span></span></span><br /> if entry[u'title']=='IP range':<br /> print "Writing content to %s" % TEMP_FILE<br /> open(TEMP_FILE,'w').write(download_file(service, entry))<br /> print "Converting ods to csv"<br /> ods2csv(TEMP_FILE)<br /> csv2dhcp(TEMP_FILE2)<br /> os.remove(TEMP_FILE)<br /> os.remove(TEMP_FILE2)<br /> # For more information on the Drive API API you can visit:<br /> #<br /> # https://developers.google.com/drive/<br /> #<br /> # For more information on the Drive API API python library surface you<br /> # can visit:<br /> #<br /> # https://google-api-client-libraries.appspot.com/documentation/drive/v2/python/latest/<br /> #<br /> # For information on the Python Client Library visit:<br /> #<br /> # https://developers.google.com/api-client-library/python/start/get_started<br /><br /> except AccessTokenRefreshError:<br /> print ("The credentials have been revoked or expired, please re-run"<br /> "the application to re-authorize")<br /><br />if __name__ == '__main__':<br /> main(sys.argv)</span></span><br />Ishayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com0tag:blogger.com,1999:blog-2142461056765545912.post-35525376858531531682013-05-08T15:15:00.000+04:002013-05-08T15:15:09.138+04:00Запуск MoinMoin2.0 под Apache22 на FreeBSD9<div style="text-align: justify;">
<i>Предполагается, что moin2 расположен в /home/ishayahu/moin-2.0</i> </div>
<div style="text-align: justify;">
Для начала нам надо установить сам апач и mod_wsgi, чтобы он мог работать с Flask (я использую для этого portmaster (/usr/ports/ports-mgmt/portmaster)): </div>
<div style="text-align: justify;">
#portmaster www/apache22 www/mod_wsgi</div>
<div style="text-align: justify;">
Далее создаём файл moin-2.0/moinmoin2.wsgi, чтобы апач мог запускать Flask приложение:</div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;"><span style="font-family: courier new,courier;">#для работы mod_wsgi, так как он блокирует sys.stdout</span></span></div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;">import sys</span></div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;">sys.stdout=sys.stderr</span></div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;"># Собственно для Flask</span></div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;">from MoinMoin.app import create_app</span></div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;">application = create_app('/home/ishayahu/moin-2.0/wikiconfig.py')</span></div>
Теперь будем настроивать апач. Создадим конфигурацию виртульного хоста: файл /usr/local/etc/apache22/Includes/wiki.local.conf
<div style="text-align: left;">
<span style="font-family: courier new,courier;"><VirtualHost *:80></span></div>
<div style="text-align: left;">
<span style="font-family: courier new,courier;"> ServerAdmin <a href="mailto:meoc-it@mail.ru" id="" shape="rect" target="_blank">meoc-it@mail.ru</a></span></div>
<div style="text-align: left;">
<span style="font-family: courier new,courier;"> DocumentRoot /home/ishayahu/moin-2.0</span></div>
<div style="text-align: left;">
<span style="font-family: courier new,courier;"> ServerName wiki.local</span></div>
<div style="text-align: left;">
<span style="font-family: courier new,courier;"> ServerAlias <a href="http://www.wiki.local/" id="" shape="rect" target="_blank">www.wiki.local</a></span></div>
<div style="text-align: left;">
<span style="font-family: courier new,courier;"> ErrorLog /home/ishayahu/wiki.local-error_log</span></div>
<div style="text-align: left;">
<span style="font-family: courier new,courier;"> CustomLog /home/ishayahu/wiki.local-access_log combined</span></div>
<div style="text-align: left;">
<span style="font-family: courier new,courier;"> WSGIDaemonProcess moinmoin2 user=ishayahu group=ishayahu threads=5</span></div>
<div style="text-align: left;">
<span style="font-family: courier new,courier;"> WSGIScriptAlias / /home/ishayahu/moin-2.0/moinmoin2.wsgi</span></div>
<div style="text-align: left;">
<span style="font-family: courier new,courier;"> <Directory /home/ishayahu/moin-2.0></span></div>
<div style="text-align: left;">
<span style="font-family: courier new,courier;"> WSGIProcessGroup moinmoin2</span></div>
<div style="text-align: left;">
<span style="font-family: courier new,courier;"> WSGIApplicationGroup %{GLOBAL}</span></div>
<div style="text-align: left;">
<span style="font-family: courier new,courier;"> Order deny,allow</span></div>
<div style="text-align: left;">
<span style="font-family: courier new,courier;"> Allow from all</span></div>
<div style="text-align: left;">
<span style="font-family: courier new,courier;"> </Directory></span></div>
<div style="text-align: left;">
<span style="font-family: courier new,courier;"></VirtualHost></span></div>
<div style="text-align: justify;">
Настроиваем запуск вики как сервиса. Создаём файл для запуска апача в
виртуальном окружении (нужно виртуальное окнужение для работы moin; не забыть <span style="font-family: "Courier New",Courier,monospace;">chmod +x /root/start_wiki</span>)
/root/start_wiki:</div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;">#!/bin/bash</span></div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;">source /home/ishayahu/moin-2.0/env/bin/activate</span></div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;">/usr/local/etc/rc.d/apache22 onestart</span></div>
<div style="text-align: justify;">
Создаём файл для регистрации вики как сервиса /etc/rc.d/wiki (не забыть <span style="font-family: "Courier New",Courier,monospace;">chmod +x /etc/rc.d/wiki</span>):</div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;">#!/bin/sh</span></div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;">#</span></div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;"># PROVIDE: wiki</span></div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;"># REQUIRE: LOGIN</span></div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;"># KEYWORD: shutdown</span></div>
<div style="text-align: justify;">
<br clear="none" /></div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;">. /etc/rc.subr</span></div>
<div style="text-align: justify;">
<br clear="none" /></div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;">name="wiki"</span></div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;">start_cmd="${name}_start"</span></div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;">stop_cmd="/usr/local/etc/rc.d/apache22 stop"</span></div>
<div style="text-align: justify;">
<br clear="none" /></div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;">wiki_start()</span></div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;">{</span></div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;"> /bin/bash /root/start_wiki</span></div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;">}</span></div>
<div style="text-align: justify;">
<br clear="none" /></div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;">load_rc_config $name</span></div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;">run_rc_command "$1"</span></div>
<div style="text-align: justify;">
И в /etc/rc.conf:</div>
<div style="text-align: justify;">
<span style="font-family: courier new,courier;">wiki_enable="YES"</span></div>
<div style="text-align: justify;">
<br clear="none" /></div>
Ishayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com0tag:blogger.com,1999:blog-2142461056765545912.post-38622874383856767172013-04-25T23:44:00.003+04:002013-04-25T23:44:35.524+04:00Flask. Документация. Предисловие для опытных программистов<div style="text-align: justify;">
Один из дизайнерских подходов Flask - что простые задачи должны быть простыми, не требовать большого количества кода и при этом не должны ограничивать Вас. Поэтому Flask реализует некоторые решения, которые некоторые могут счесть внезапными или не ортодоксальными. Например, Flask использует локальные для потоков объекты, так что Вы не должны передавать объекты из функции в функцию в пределах запроса чтобы избежать проблем с потоками. Это общепринятый подход, но он требует корректного контекста запроса для внедрения зависимостей или если Вы хотите повторно использовать код, который использует значения, привязанные к запросу. Flask гордится этим, не скрывает этого и заявляет об этом и в коде и в докуменации.</div>
<h3>
Осторожная разработка для веба</h3>
<div style="text-align: justify;">
Всегда, когда Вы создаёте веб-приложение, помните о безопасности.</div>
<div style="text-align: justify;">
Если Вы пишете веб-приложение, Вы, скорее всего, разрешаете пользователям регистрироваться и оставлять данные на вашем сервере. Пользователи доверяют Вам свои данные. И даже если Вы единственный, кто хранит данные в вашем приложении, Вы всё равно хотите чтобы ваши данные надёжно хранились.</div>
<div style="text-align: justify;">
К сожалению, есть множество способов скомпроментировать безопасность веб-приложений. Flask защитит Вас от наиболее популярных проблем современных веб-приложений: cross-site scripting (XSS). Пока Вы намеренно не пометите небезопасный HTML как безопасный, Flask, и работающий с ним движок шаблонов Jinja2, будут Вас прикрывать. Но всё равно у Вас ещё остаётся куча способов оставить дыры в приложении.<br />
Документация будет предупреждать Вас о тех аспектах веб-разработки, которые требуют особого внимания к обеспечению безопасности. Некоторые из них гораздо сложнее, чем Вы могли бы подумать, и все мы иногда недооцениваем возможность эксплуатации уязвимости, пока какой-нибудь сообразительный парень не найдёт способ это сделать. И не думайте, что ваше приложение слишком малоценно, чтобы заинтересовать атакующего. В зависимости от типа атаки, есть вероятность того, что боты автоматически постараются заполнить вашу БД спамом, ссылками на вирусное ПО и т.п.<br />
Flask не отличается от других фреймворков в том плане, что Вы, как разработчик, должны быть осторожны, учитывая возможные векторы атаки.<br />
<h3>
Статус Python 3</h3>
<div>
На данный момент сообщество Python работает над тем, чтобы библиотеки поддерживали новую версию Python. Хотя ситуация улучшается, тем не менее всё ещё есть несколько проблем, которые не позволяют нам до сих пор переключиться на Python3. Частично эти проблемы связаны изменениями в языке, которые слишком долго остаются не пересмотренными, частично из-за того, что мы не до конца понимаем, как должно измениться API для учёта изменения подхода к юникоду в Python 3.</div>
<div>
Werkzeug и Flask будут портированны на Python 3 как только будет надено решение этих проблем и мы предоставим советы по переходу на новую версию языка. До тех пор мы строго рекомендуем использовать Python 2.6 и 2.7 со включёнными предупреждениями Python 3 при разработке. Если Вы планируете переход на Python 3 в ближайшем будущем, мы крайне рекомендуем Вам прочитать "<a href="http://lucumr.pocoo.org/2011/1/22/forwards-compatible-python/" target="_blank">Как писать совместимый с будущим код Python</a>"7<br />
Продолжением является либо <a href="http://flask.pocoo.org/docs/installation/#installation" target="_blank">Установка</a>, либо <a href="http://flask.pocoo.org/docs/quickstart/#quickstart" target="_blank">Быстрый старт</a></div>
</div>
Ishayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com0tag:blogger.com,1999:blog-2142461056765545912.post-53868023365595459982013-04-25T21:44:00.004+04:002013-04-25T23:45:14.314+04:00Flask. Документация. Предисловие<br />
<div style="text-align: justify;">
Прочитайте это перед тем, как Вы начнёте работать с Flask. Это наверняка ответит на некоторые ваши вопросы о целях этого проекта и поможет Вам понять, когда его стоит использовать, а когда нет.</div>
<h3>
Что означает "микро"?</h3>
<div style="text-align: justify;">
Микро <u>не</u> означает, что всё ваше веб-приложение уместиться в один файл Python, хотя это и возможно. Кроме того, это не означает, что Flask не хватает какой-то функциональности. "Микро" в слове "микрофреймворк" означает, что Flask старается держать своё ядро простым, но расширяемым. Flask не будет принимать какие-то решения за Вас, например, какую БД использовать. Те решения, которые он делает, например, использование конкретного движка шаблонов, очень легко можно изменить. Всё остальное зависит полностью от Вас, так что Flask может быть всем, что Вам нужно и не быть тем, чем не нужен.</div>
<div style="text-align: justify;">
По умолчанию, Flask не включает слой абстракции БД, валидации форм или что-либо ещё, что может сделать другая существующая библиотека. Вместо этого Flask поддерживает расширения, которые позволяют добавить эту функциональность к вашему приложению, как если бы это было реализовано в самом Flask. Некоторые расширения предоставляют интеграцию с БД, валидацию форм, обработку загрузок, различные открытые технологии аутентификации и так далее. Flask может быть "микро", но готов к использованию в различных целях.</div>
<h3>
Конфигурация и допущения</h3>
<div>
<div style="text-align: justify;">
Flask имеет много конфигурационных значений, с адекватными значениями по умолчанию, и использует некоторые допущения. В частности, предполагается, что шаблоны и статические файлы хранятся в подкаталогах в дереве приложения Python с именами <i>templates</i> и <i>static</i> соответственно. Хотя это и можно изменить, скорее всего Вы не будете это делать, особенно в самом начале.</div>
<h3>
Двигаемся дальше</h3>
</div>
<div style="text-align: justify;">
После того, как Вы начали пользоваться Flask, Вы обнаружите большое количество доступных расширений, которые Вы можете интегрировать в ваш проект. Команда Flask просматривает эти расширения и следит за тем, чтобы их можно было использовать в новых релизах.</div>
<div style="text-align: justify;">
По мере роста вашего кода Вы можете выбрать любой дизайн кода, который Вам больше нравится. Flask продолжит предоставлять Вам лучшее, что может предоставить Python. Вы можете реализовать продвинутые шаблоны в SQLAlchemy или другом инструменте работы с БД, хранить данные не в релиационном хранилище и использовать преимущества инструментов, разработанных для WSGI - Python веб-интерфейса.</div>
<div style="text-align: justify;">
Flask включает множество хуков для настройки его поведения. Если Вам нужна более тонкая настройка, класс Flask может быть использован для создания подклассов. Если Вам это интересно, обратитесь к главе <a href="http://flask.pocoo.org/docs/becomingbig/#becomingbig" target="_blank">Becoming Big</a>. Если Вам любопытны принципы дизайна Flask, обращайтесь к разделу <a href="http://flask.pocoo.org/docs/design/#design" target="_blank">Дизайнерские решения в Flask</a>.</div>
<div style="text-align: justify;">
Дальнейший ваш путь лежит к <a href="http://flask.pocoo.org/docs/installation/#installation" target="_blank">Установке</a>, <a href="http://flask.pocoo.org/docs/quickstart/#quickstart" target="_blank">Быстрому старту</a> или <a href="http://python-lab.blogspot.ru/2013/04/flask_25.html" target="_blank">Предисловие для опытных программистов</a>.</div>
Ishayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com0tag:blogger.com,1999:blog-2142461056765545912.post-69003434623868830312013-04-25T17:36:00.002+04:002013-04-25T17:36:55.155+04:00Обнаружение пакетов и доступ к ресурсам при помощи pkg_resources<br />
<div style="text-align: justify;">
</div>
<br />
<br />
<div style="text-align: justify;">
Модуль pkg_resouces, распространяемый с setuptools, предоставляет API для библиотек Python для доступа к их файлам ресурсов и для предоставления возможности приложениям и фреймворкам автоматически обнаруживать плагины. Кроме того, он предоставляет поддержку времени выполнения для использования расширений C, находящихся в zip файле формата egg, поддержки слияния пакетов, которые имеют отдельно распространяемые модули или подпакеты, API для управления текущим "рабочим набором" активных пакетов Python.</div>
<br />
<h2 style="text-align: justify;">
Обзор</h2>
<div style="text-align: justify;">
"Яйца" - это формат распространения модулей Python, похожий на jar в Java или gem в Ruby. Они отличаются от предыдщуего формата распространения Python тем, что он импортируемый (то есть, они могут быть добавлены в sys.path) и они "отыскиваемые", то есть, они содержат метаданные, которые однозначно идентифицируют их содержимое и зависимости, и потому могут быть <i>автоматически</i> обнаружены и добавлены в sys.path в ответ на простой запрос вроде "дайте мне всё, что мне нужно для использования поддержки PDF в docutils".</div>
<div style="text-align: justify;">
Модуль pkg_resources предоставляет средства времени выполнения для поиска, исследования (интроспекции), активирования и использования яиц и других "подключаемых" форматов распространения. Поскольку это новые концепции для Python (и не настолько хорошо проработаны и в других языках), неплохо бы сперва обозначить несколько специальных терминов для обсуждения "яиц" и того, как они могут быть использованы:<br />
<ul>
<li><b>проект</b> - библиотека, фреймворк, скрипт, плагин, приложение или набор данных или других ресурсов, или любая комбинация этих элементов. Предполагается, что проекты имеют уникальные имена, т.е. имена, зарегистрированные в PyPI.<b> </b></li>
<li><b>релиз</b> - снапшот проекта на некий момент времени, определяемый идентификатором версии<b> </b></li>
<li><b>дистрибутив</b> - файл или файлы, представляющие конкретный релиз<b> </b></li>
<li><b>импортируемый дистрибутив</b> - файл или катаолг, который, если его поместить в sys.path, позволяет Python'y импортировать любые модули, расположенные в нём</li>
<li><b>дистрибутив-плагин - </b>импортируемый дистрибутив, где имена файлов однозначно определяют их релиз (т.е. проект и версию), и чьё содержимое однозначно определяет какие релизы других проектов ему необходимы для работы.</li>
<li><b>экстра</b> - необязательные возможности релиза, которые могут налагать дополнительные требования в процессе выполнения. Например, если поддержка pdf в docutils требует библиотеку поддержки pdf, docutils может объявить поддержку pdf как экстра и указать, какие ещё релизы проектов нужны для обеспечения этой функциональности</li>
<li><b>окружение</b> - набор дистрибутивов потенциально доступный для импорта, но не обязательно активных. В окружении может присутствовать более одного дистрибутива (т.е. релиза) для данного проекта.</li>
<li><b>рабочий набор</b> - набор дистрибутивов актуально доступных для импорта из sys.path. Максимум один дистрибутив (релиз) данного проекта может присутствовать в рабочем наборе, иначе нет однозначности того, что импортировать.</li>
<li><b>яйца</b> - яйца - это дистибутив-плагин в одном из трёх форматов, поддерживаемых на данный момент pkg_resources. Есть собранные яйца, разрабатываемые яйца и яйца-ссылки. Собранные яйца - это каталоги или zip файлы с имененм, заканчивающимся на .egg и соответствующим договорённости об имени яиц, и содержащих подкаталог EGG-INFO. Разрабатываемые яйца - обычные каталоги кода Python c одним или более подкаталогом ИмяПроекта.egg-info. Яйца-ссылки - это файлы .egg-link, которые содержат имя собранного яйца или разрабатываемого яйца для того, чтобы обеспечить функционал символических ссылок на платформах, где нет встроенной поддержки такой функциональности.</li>
</ul>
(Более подробно эти термины и концепты описаны в <a href="http://mail.python.org/pipermail/distutils-sig/2005-June/004652.html" target="_blank">обзоре архитектуры</a> pkg_resources и Python Eggs).<br />
<h2>
Руководство разработчика</h2>
Этот раздел ещё не написан. Планируемое содержание:<br />
<ul>
<li> Accessing Resources</li>
<li>Finding and Activating Package Distributions</li>
<ul>
<li>get_provider()</li>
<li>require()</li>
<li>WorkingSet</li>
<li>iter_distributions</li>
</ul>
<li>Running Scripts</li>
<li>Configuration</li>
<li>Namespace Packages</li>
<li>Extensible Applications and Frameworks</li>
<ul>
<li>Locating entry points</li>
<li>Activation listeners</li>
<li>Metadata access</li>
<li>Extended Discovery and Installation</li>
</ul>
<li>Supporting Custom PEP 302 Implementations</li>
</ul>
На данный момент пока обращайтесь к Руководству по API </div>
<div style="text-align: justify;">
<h2>
Руководство по API</h2>
<h3>
Поддержка пакета пространства имён</h3>
Пакет пространства имён - это пакет, который содержит только другие пакеты и модули, без своего собственного содержимого. Такие пакеты могут быть разделены между множественными, отдельно упакованными дистрибутивами. Обычно Вам не требуется напрямую использовать API пакетов пространств имён; вместо этого Вы должны предоставить аргумент namespace_package функции setup() в файле setup.py вашего проекта. Более подробно это описано в <a href="http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages" target="_blank">документации setuptools о пакетах пространства имён</a>.<br />
Тем не менее, если по какой-то причине Вам нужно работать с пакетами пространства имён или напрямую изменить sys.path в процессе выполнения, Вам может помочь следющие API:<br />
<b>declare_namespace(name)</b> - объявляет, что точечное имя пакета name является пакетом пространства имён и пакеты и модули, содержащиеся в нём, могут быть распространены между различными дистрибутивами. __path__ этого пакета будет расширен для добавления соответствующих пакетов из всех дистрибутивов sys.path'a, которые содержат пакет с этим именем. (Более точно, если импортер find_module(name) возвращает загрузчик, тогда он тоже будет исследован в поисках содержимого пакета.) Всякий раз, когда вызван ли метод activate(), проверяется наличие пакета пространства имён и обновляется его __path__.<br />
<b>fixup_namespace_backages(path_item)</b> - объявляет, что path_item является новым добавленым элементом в sys.path, который может быть необходимо использовать для обновления существующего пакета пространства имён. Обычно он вызывается для вас при автоматическом добавлении яйца в sys.path, но если ваше приложение изменяет sys.path для добавления мест, которые могут содержать части пакетов пространства имён, Вам может потребоваться вызвать эту функцию чтобы убедиться, что они добавлены в существующий пакет пространства имён.<br />
Хотя по умолчанию pkg_resources поддерживает пакеты пространства имён только для импортёров файловой системы и zip файлов, Вы можете расширить его для поддержки других импортёров, совместимых с PEP 302 при помощи функции register_namespace_handler(). См ниже раздел "Поддержка пользовательских импортёров".<br />
<h3>
Объект WorkingSet (рабочий набор)</h3>
Класс WorkingSet предоставляет доступ к коллекции активных дистрибутивов. В общем есть только один осмысленный экземпляр WorkingSet - тот, который представляет дистрибутивы, которые на данный момент активны в sys.path. Этот глобальный экземпляр доступен по имени working_set в модуле pkg_resources. Тем не менее, специализированные инструменты могут манитулировать рабочими наборами, которые не отвечают sys.path и потому создавать другие экземпляры WorkingSet.<br />
Важно помнить, что глобальный объект working_set инициализируется из sys.path при первом импорте pkg_resources, а при всех последующих манипуляциях с sys.path ghb помощи API pkg_resources он лишь обновляется. Если Вы вручную изменяете sys.path, Вы должны вызвать соответствующий метод экземпляра working_set для его синхронизации. К сожалению, Python не предоставляет способа обнаружения произвольных изменений в объектах списка, вроде sys.path, так что pkg_resources не может автоматически обновить working_set на основании изменений в sys.path.<br />
<b>WorkingSet(entries=None)</b> - создаёт WorkingSet из итерируемого аргумента entries. Если entries не передан, то по умолчанию используется значение sys.path при вызове конструктора.<br />
Обратите внимание, что обычно Вы не будете создавать экземпляры WorkingSet, вместо этого Вы будете явно или неявно использовать глобальный экземпляр working_set. По большей части API pkg_resources разработан так, что working_set используется по умолчанию, так что Вам не нужно явно обращаться к нему большую часть времени.<br />
<h4>
Основные методы WorkingSet</h4>
Следующие методы объектов WorkingSet доступны так же в качестве функций уровня модуля в pkg_resources и они применяются к экземпляру по умолчанию working_set. Таким образом Вы можете, например, вызвать pkg_resources.require() как более короткую версию pkg_resources.working_set.require().<br />
<b>require(*requirements)</b> - проверяет, что дистрибутивы, соответствующие requirements активны.<br />
requirements должно быть строкой или (с возможностью вложения) последовательностью строк, определяющих требуемые дистрибутивы и версии. Возвращаемым значением является последовательность дистрибутивов, которые необходимо активировать для удволетворения требований; все относящиеся дистрибутивы включены, даже если они уже активированы в этом рабочем наборе.<br />
Относительно синтаксиса передачи требуемых дистрибутивов смотрите раздел ниже "Парсинг требований".<br />
В общем Вам не должно понадобиться использовать этот метод напрямую. Он больше предназначен для использования в быстрых скриптах и интерактивных интерпретаторах, чем для промышленного использования. Если Вы создаёте библиотеку или приложение, крайне рекомендуется, чтобы Вы создали скрипт setup.py, использующий setuptools, и объявили в нём все ваши требования. В этом случае такие инструменты, как EasyInstall, смогут автоматически определить требования вашего пакета и соответственно их обработать.<br />
Обратите внимание, что вызов <b>require('SomePackage')</b> не установит SomePackage, если он отсутствует в системе. Если Вам нужно это сделать, Вы должны использовать метод <b>resolve()</b>, который позволяет Вам передать коллбек <i>installer</i>, который будет вызван в случае, если ye;ysq дистрибуетив не будет найден на локальной машине. Этот коллбэк может затем отобразить вопрос на продолжение операции, автоматически загрузить нужный дистрибутив или сделать ещё что-нибудь. Более подробно это описано в документакции метода <b>resolve() </b>и <b>obtain()</b> объекта <b>Environment.</b><br />
<b>run_script(requires, script_name)</b> - обнаруживает дистрибутивы, указаные в <i>requires</i> и затем запускает скрипт <i>script_name</i>. <i>requires</i> должно быть строкой, содержащей спецификаторы требований (подробнее - смотрите раздел ниже "Парсинг требований")<br />
Скрипт, если он найден, будет выполнен в глобальном окружении вызывающего. Причина этого в том, что этот метод предназанчен для вызова из обёртывающего скрипта, который работает как прокси для "настоящего" скрипта в дистрибутиве. Скрипт-обёртка обычно не должен делать ничего, кроме вызова этой функции с корректными аргументами.<br />
Если Вам нужно больше контроля над окружением выполнения скрипта, Вы, возможно, захотите использовать метод <b>run_script()</b> из <b>Metadata API</b> объекта <b>Distribution.</b><br />
<b>iter_entry_points(group, name=None)</b> - <b> </b> выдаёт (yield) точки входа из <i>group</i>, соответствующие <i>name.</i><br />
Если <i>name=None</i>, выдаются все точки входа в <i>group</i> из всех<i> </i>дистрибутивов в рабочем наборе; в противном случае будут выданы только те, которые соответствуют и <i>group</i> и <i>name.</i> Точки входа выдаётся из активнрых дистрибутивов в том порядке, в котором эти дистрибутивы возникают в рабочем наборе. Для глобального <i>working_set</i> это должно быть тем же самым порядком, в котором они перечислены в <i>sys.path.</i> Обратите внимание, что точки входа, предоставляемые индивидуальными дистрибутивами, не имеют конкретного порядка.<br />
Более подробно смотрите ниже, в разделе "Точки входа"<br />
<h4>
Методы и атрибуты WorkingSet</h4>
Эти методы используются для запросов или управления содержимым конкретного рабочего набора, так что они должны быть вызваны для конкретного экземпляра WorkingSet.<br />
<b>add_entry(entry)</b> - добавляет путь к <i>entries</i>, находя там все дистрибутивы. Вы должны использовать его когда Вы добавляете элементы к <i>sys.path</i> и хотите, чтобы глобальный <i>working_set</i> отражал эти изменения. Этот метод так же вызывается конструкотором WorkingSet().<br />
Этот метод использует <b>find_distributions(entry, True)</b> для поиска дистрибутивов, которые соответствуют элементу пути, а, затем, добавляют их вызовом <b>add().</b> <i>entry</i> всегда добавляется к атрибуту <i>entries</i>, даже если он уже присутствует там (причина этого в том, что <i>sys.path</i> может содержать одно и то же значение несколько раз, и атрибут <i>entries </i>должен быть способным отображать это)<br />
<b>__contains__(dist)</b> - True, если <i>dist</i> активен в этом рабочем наборе. Обратите внимание, что только один дистрибутив для данного проекта может быть активен в данном WorkingSet.<br />
<b>__iter__()</b> - выдаёт дистрибутивы для неповторяющихся проектов в рабочем наборе. Порядок выдачи соответствует порядку, в котором пути элементов были добавлены в рабочий набор.<br />
<b>find(req) </b>- обнаруживает дистрибутивы, соответсвующие <i>req</i> (экземпляру класса<i> </i><b>Requirement</b>). Если это активный дистрибутив для запрашиваемого проекта, то он будет возвращён, если он соответствует версии, определённой в <i>req.</i> Но если есть активный дистрибутив для проекта, который <b>не</b> соответствует требованиям <i>req</i>, будет вызвано исключение <b>VersionConflict</b>. Если нет активного дистрибутива для этого проекта, то будет возвращено <b>None.</b><br />
<b>resolve(requirements,</b> <b>env=None, installer=None)</b> - список дистрибутивов, необходимых для (рекурсивного) соответствия <i>requirements.</i><br />
<i>requirements</i> должен быть последовательностью объектов <b>Requirement.</b> <i>env</i>, если предоставлен, должен быть экземпляром <b>Environment.</b><i> </i>Если он не передан, <b>Environment </b>создаётся из <i>entries </i>рабочего каталога. <i>installer</i>, если передан, будет вызван для каждого требования, которое не удволетворено уже установленными дистрибутивами; он должен возвращать <b>Distribution</b> или <b>None.</b> (Смотрите метод <b>obtain()</b> объекта <b>Environment</b>, где более подробно рассказано об аргументе <i>installer</i>)<br />
<b>add(dist, entry=None)</b> - добавляет <i>dist</i> в рабочий набор, ассоциированный с <i>entry. </i>Если <i>entry </i>не определён, по умолчанию будет использован <i>dist.location. </i>При выходе из этой процедуры, <i>entry </i>добавляется в конец <i>.entries</i> рабочего набора (если его там ещё нет).<br />
<i>dist</i> добавляется в рабочий набор только если это касается проекта, у которого ещё нет этого активного дистрибутива в рабочем наборе. Если он успешно добавлен, все коллбэки, зарегистрированные методом <b>subscritbe()</b>, будут вызваны. (См "Получение оповещений об изменениях" ниже)<br />
Примечание: <b>add() </b>автоматически вызывается для Вас методом <b>require(), </b>так что обычно Вам не потребуется вызывать этот метод напрямую.<br />
<b>entries</b> - этот атрибут представляет "тень" <i>sys.path</i>, в первую очередь полезную для отладки. Если Вы столкнулись с проблемами импорта, проверьте <i>entries </i>глобального объекта <i>working_set </i>и сравните его с <i>sys.path. </i>Если они не совпадают, значит какая-то часть вашей программы работает с <i>sys.path</i> не обновляя соответственно <i>working_set</i>. <u>Важное замечание:</u> не изменяйте напрямую этот атрибут! Установка его эквивалентным <i>sys.path</i> решит вашу проблему не лучше, чем замазывание аварийки починит вашу машину. Если этот атрибут не соответствует <i>sys.path</i>, то это <u>сигнал</u> о проблеме, а не её причина.<br />
<h4>
Получение оповещений об изменениях</h4>
Расширяемые приложения и фреймворки могут иметь потребность в получении оповещений, когда новые дистрибутивы (например, плагины) добавляются в рабочий набор. Для этого предназначены метод <b>subscribe() </b>и функция <b>add_activation_listener().</b><br />
<b>subscribe(callback)</b> - вызывает <b>callback(distribution) </b>один раз для каждого активного дистрибутива, который уже находится в наборе или будет добавлен позже. Так как коллбэк вызывается и для уже активных дистрибутивов, Вам не нужно делать цикл по рабочему набору, чтобы обработать существующие элементы; просто зарегистрируйте коллбэк и будьте готовы к тому, что он будет немендленно вызван этим методом.<br />
Обратите внимание, что коллбэки <u>не должны</u> позволять исключениям распространяться, иначе они наложатся на операции других коллбэков, что, возможно, приведёт к противоречивому состоянию рабочего набора. Коллбэки должны использовать блоки try/except чтобы игнорировать, логировать или как-либо ещё обрабатывать ошибки, особенно с учётом того, что код, вызвавший коллбэк скорее всего не сможет обработать ошибки лушче, чем сам коллбэк.<br />
<b>pkg_resources.add_activation_listener() </b>является альтернативой <b>pkg_resources.working_set.subscribe().</b><br />
<h4>
<b>Обнаружение плагинов</b></h4>
Расширяемые<b> </b>приложения иногда имеют что-то вроде "каталога плагинов" или набора таких каталогов, откуда они хотят загрузить точки входа или другие метаданные. Метод <b>find_plugins()</b> позволяет Вам сделать это, сканируя окружения в поисках новых версий каждого проекта, которые могут быть безопасно загружены без конфликтов или невыполненных требований.<br />
<b>find_plugins(plugin_env, full_env=None, fallback=True)</b> - сканирует <i>plugin_env</i> и определяет, какие дистрибутивы могут быть добавлены в этот рабочий набор без конфликта версий или невыполненных требований.<br />
<u>Пример использования:</u><br />
<br />
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">distributions, errors = working_set.find_plugins(</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> Environment(plugin_dirlist)</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> )</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">map(working_set.add, distributions) # добавляем плагины</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> # и библиотеки в <i>sys.path</i></span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">print "Не получилось загрузить", errors<i> </i># показать ошибки</span></div>
<br />
<i>plugin_env</i> должен быть экземпляром <b>Environment</b>, который содержит только те дистрибутивы, которые находятся в каталоге плагинов проекта. <i>full_env</i>, если указан, должен быть экземпляром <b>Environment</b>, который содержит все текущие доступные дистрибутивы.<br />
Если <i>full_env</i> не задан, он создаётся автоматически из <b>WorkingSet</b>, на котором вызывается этот метод, что обычно означает, что каждый каталог в <i>sys.path</i> будет просканирован в поисках дистрибутивов.<br />
Этот метод возвращает два кортежа: ('distributions', 'error_info'), где <i>distributions</i> - список дистрибутивов, найденых в <i>plugin_env</i>, которые были загружаемы, вместе с другими дистрибутивами, которые были нужны для разврешения их зависимостей. <i>error_info</i> - это словарь, который отображает незагружаемые дистрибутивы плагинов на экземпляры исключений, которые произошли. Обычно это будут экземпляры классов <b>DistributionNotFound </b>или <b>VersionConflict.</b><br />
Большая<b> </b>часть приложений обычно использует этот метод на экземпляре <i>working_set</i>, а, затем, тут же добавляет возвращённые дистрибутивы в рабочий набор, так что они будут доступны в <i>sys.path. </i>Таким образом, оказывается возможным найти все точки вода и позволяет отслеживать другие метаданные и активировать хуки.<br />
Алгоритм разрешения используемый <b>find_plugins()</b> таков. Сперва имена проектов дистрибутивов, находящихся в <i>plugin_env</i>, сортируются. Затем, проверяется яйцо каждого проекта в порядке уменьшения версии (то есть, начиная с более новой версии проекта).<br />
Производится попытка разрешить зависимости каждого яйца. Если попытка успешна, яйцо и его зависимости добавляются в список вывода и во временную копию рабочего набора. Процесс разрешения продолжается на следующем имени проекта и более старые яйца для этого проекта даже не затрагиваются.<br />
Если попытка разрешения не удаётся, ошибка добавляется в словарь ошибок. Если флаг <i>fallback=True</i>, пробуется более старая версия плагина, до тех пор, пока не будет найдена работающая версия. Если <i>False</i>, то процесс разрешения продолжается для следующего имени проекта.<br />
Некоторые приложения могут иметь более строгие требования к "отступлению (fallback)", чем другие. Например, приложение, у которого есть схема БД или постоянные объекты, может быть не может так просто провести доунгрейд версии пакета. Другие приложения могут хотеть быть уверенными, что новая конфигурация плагинов либо на 100% хороша, либо откатиться к другой гарантированно работающей конфигруации. (То есть, они могут хотеть откатиться к гарантированно работающей конфигурации если значение <i>error_info</i> не пустое.)<br />
Обратите внимание, что этот алгоритм даёт преимущество при удволетворении зависимостей в алфавитном порядке имён проектов в случае конфликта версий. Если два проекта с именами AaronsPlugin и ZekesPlugin оба требуют разные версии TomsLibrary, в таком случае AaronsPlugin получит своё, а ZekesPlugin нет из-за конфликта версий.<br />
<h3>
Объекты Environment</h3>
<b>environment</b> - колекция объектов <b>Distribution</b>, обычно тех, которые присутствуют и потенциально импортируемы на текущей платформе. Объекты <b>Environment</b> используются <b>pkg_resources</b> для индексирования доступных дистрибутивов в процессе разрешения зависимостей.<br />
<b>Environment(search_paht=None, platform=get_supported_platform(), python=PY_MAJOR)</b> - создаёт снимок окружения сканируя <i>search_path</i> в поисках дистрибутивов, совместимых с <i>platform </i>и <i>python.</i> <i>search_path</i> должен быть последовательностью строк, которая могла бы использоваться для <i>sys.paht</i>. Если <i>search_path</i> не указан, будет использоваться <i>sys.path.</i><br />
<i>platform </i>- опциональная строка, определяющая имя платформы, с которой должны быть совместимы не кроссплатформенные дистрибутивы. Если он не указан, то будет использоваться текущая платформа. <i>python</i> - опциональная строка, указывающая на версию Python (например, "2.4"); по умолчанию - это текущая запущенная версия.<br />
Вы можете принудительно установить <i>platform</i> (и/или <i>python</i>) в <i>None</i>, если Вы хотите включить <u>все</u> дистрибутивы, не только совместимые с текущей платформой или версией.<br />
Обратите внимани, что <i>search_path</i> немендленно сканируется в поисках дистрибутивов и результирующий <b>Environment</b> является снимком найденных дистрибутивов. Он не обновляется автоматически если состояние системы изменяется в следствии, например, установки или удаления дистрибутивов.<br />
<b>__getitem__(project_name)</b> - возвращает список дистрибутивов для данного имени проекта, упорядоченный от более новых к более старым версиям. (Этот формат даёт приоритет для дистрибутивов, которые содержат ту же версию проекта). Если дистрибутивов для проекта не найдено, возвращается пустой список.<br />
<b>__iter__()</b> - выдёт уникальные имена проектов дистрибутивов в этом окружении. Выдаваемые имена всё время в низком регистре.<br />
<b>add(dist)</b> - добавляет <i>dist</i> в окружение, если он соответствует платформе и версии python, определённой на момент создания, и только если дистрибутив ещё не был добавлен (то есть, добавть один дистрибутив более одного раза не получится).<br />
<b>remove(dist)</b> - удаляет <i>dist</i> из окружения.<br />
<b>can_add(dist)</b> - проверяет, приемлем ли <i>dist</i> для этого окружения. Если он не совместим с платформой или версией Python, определёнными при создании окружения, возвращается <i>false.</i><br />
<b>__add__(dist_or_env)</b> <b>(оператор +) </b>- добавляет дистрибутив или окружение в экземпляр <b>Environment</b>, возвращая <u>новый</u> объект окружения, который содержит все дистрибутивы, содежавшиеся в предыдущих объектах. Новое окружение будет иметь <i>platform </i>и <i>python</i> равным <i>None</i>, что означает, что никакие дистрибутивы не будут отклонены при попытке добавить их; всё, что будет добавляться будет добавлено. Если Вы хотите, чтобы добавляемые дистрибутивы отфильтровывались по платформе или версии, или Вы хотите добавить их в <u>тот же</u> экземпляр окружения, в таком случае Вы должны использовать оператор +=<br />
<b>__iadd__(dist_or_env) (оператор +=)</b> - добавляет дистрибутивы или окружение в экземпляр <b>Environment</b> "на месте", обновляя существующий экземпляр и возвращая его. Дистрибутивы фильтруются по платформе и версии Python.<br />
<b>best_match(req, working_set, installer=None)</b> - находит дистрибутивы, лучше всего удволетворяющие <i>req </i>и которые можно использовать в <i>working_set</i>.<br />
Он вызывает метод<i> </i><b>find(req) </b>на <i>working_set</i>, чтобы увидеть, активирован ли подходящий дистрибутив. (Это может вызвать исключение <b>VersionConflict</b>, если неподходящая версия проекта уже активирована в заданом <i>working_set</i>). Если нужный дистрибутив не активирован, этот метод возвращает новейший дистрибутив в окружении, который отвечает <b>Requirement </b>в <i>req. </i>Если подходящего дистрибутива не найдено и указан <i>installer</i>, тогда возвращается результат вызова метода <b>obtain(req, installer) </b>окружения.<br />
<b>obtain(requirement, installer=None)</b> - получает дистрибутив, который отвечает требованиям (например, загружая его). В базовом классе <b>Environment</b> эта процедура лишь возвращает <b>installer(requirement)</b>, а если <i>installer=None</i>, возвращается <i>None</i>. Этот метод является "ловушкой", которая позволяет субклассу попробовать другие пути получения дистрибутива до того, как откатиться до аргумента <i>installer.</i><br />
<b>scan(search_path=None) </b>- сканирует <i>search_path</i> в поисках дистрибутивов, которые можно использовать на <i>platform.</i><br />
Все найденные дистрибутивы добавляются в окружение. <i>search_path</i> должен быть последовательностью строк, которую можно было бы использовать в качестве <i>sys.path.</i> Если этот аргумент не передан, то используется <i>sys.path. </i>Добавляются только дистрибутивы, подходящие для платформы и версии Python, указанной при инициализации. Этот метод является сокращением для функции <b>find_distributions()</b>, чтобы найти дистрибутивы для каждого элемента в <i>search_path</i> и затем вызвать <b>add()</b> для добавления каждого дистрибутива в окружение.<br />
<h3>
Объекты Requirement</h3>
Объекты <b>Requirement</b> выражают какая версия проекта подходит для каких целей. Эти объекты (или их строковая форма) используются разными API <b>pkg_resources</b> для обнаружения дистрибутивов, которые нужны скрипту или другим дистрибутивам.<br />
<h4>
Парсинг требований</h4>
<b>parse_requirements(s)</b> - выдаёт объекты <b>Requirement </b>для строк или итерируемых строк. Каждое требование должно начинаться с новой строки. См ниже описание синтаксиса.<br />
<b>Requirement.parse(s)</b> - создаёт объект <b>Requirement</b> и строки или интерируемых строк. Исключение <b>ValueError</b> возбуждается, если строка или строки не содержат корректного определителя требований или содержат более одного определителя. (Для обработки нескольких определителей из строки или итерируемого набора строк используйте parse_requirements().)<br />
Синтаксис определителей требований может быть определён в <a href="http://ru.wikipedia.org/wiki/%D0%A0%D0%B0%D1%81%D1%88%D0%B8%D1%80%D0%B5%D0%BD%D0%BD%D0%B0%D1%8F_%D1%84%D0%BE%D1%80%D0%BC%D0%B0_%D0%91%D1%8D%D0%BA%D1%83%D1%81%D0%B0_%E2%80%94_%D0%9D%D0%B0%D1%83%D1%80%D0%B0" target="_blank">РБНФ</a> таким образом:<br />
<br />
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">version ::= [-A-Za-z0-9_.]+</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">identifier ::= [-A-Za-z0-9_]+</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">project_name ::= identifier</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">extralist ::= identifier (',' identifier)*</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">extras ::= '[' extralist? ']'</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">comparison ::= '<' | '<=' | '!=' | '==' | '>=' | '>'</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">versionspec ::=comparison version (',' comparison version)*</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">requirement ::=project_name versionspec? extras?</span></div>
<br />
Токены могут быть разделены пробелами, а требования могут быть расположены на нескольких строках при помощи бэкслеша (\\). Комментарии в конце строки (с символом #) тоже можно использовать.<br />
Вот несколько примеров корректных определителей требований:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">FooProject >= 1.2</span><br />
<span style="font-family: "Courier New",Courier,monospace;">Fizzy [foo,bar]</span><br />
<span style="font-family: "Courier New",Courier,monospace;">PickyThing<1.6,>1.9,!=1.9.6,<2.0a0,==2.4c1</span><br />
<span style="font-family: "Courier New",Courier,monospace;">SomethingWhoseVersionIDontCareAbout</span><br />
<br />
Имя проекта - единственная требуемая часть строки, и если оно указано, то требованию будет отвечать любая версия этого проекта.<br />
<i>extras</i> в требовании используется для запроса опциональных функций проекта, что может требовать дополнительных дистрибутивов для работы. Например, если гипотетический проект Report-O-Rama предлагает опциональную поддержку PDF, он может требовать дополнительную библиотеку для предоставления этой возможности. Таким образом проект, использующий Report-O-Rama c поддержкой PDF должен использовать требование <i>Report-O-Rama[PDF]</i> для того, чтобы запросить установку или активацию и Report-O-Rama и всех необходимых библиотек, которые ему нужны для поддержки PDF. Например, Вы можете использовать<br />
<span style="font-family: "Courier New",Courier,monospace;">easy_install.py Report-O-Rama[PDF]</span><br />
для установки необходимых пакетов с помощью программы EasyInstall, или вызвать <b>pkg_resources.require('Report-O-Rama[PDF]')</b> для добавления нужных дистрибутивов в <i>sys.path</i> в процессе выполнения.<br />
<h4>
Методы и аргументы класса Requirement</h4>
<b>__contains__(dist_or_version)</b> - возвращает <i>true</i> если <i>dist_or_version</i> отвечает этому требованию. Если <i>dist_or_version</i> является объектом <b>Distribution</b>, то его имя проекта должно соответствовать имени требуемого проекта, а версия - требованию версии. Если <i>dist_or_version</i> является строкой, то она разбирается при помощи функции <b>parse_version().</b> В противном случае ожидается, что это будет уже разобранная строка.<br />
Спецификаторы версии <b>Requirement</b> (.specs) сортируются в возрастающем порядке и используются для определения интервалов приемлимых версий. Соседние избыточные условия эффективно объединяются (например, ">1, >2" дадут тот же эффект, что и ">1", a "<2,<3" дадут тот же результат, что и "<3"). "!=" исключает указанные версии из доступных. Версии, прошедшие проверку на приемлимость, затем проходят проверку на присутствие в доступном интервале. (Обратите внимание, что предоставление конфликтующих условий для одной и той же версии (например, "<2,>=2" или "==2,!=2") бессмасленно и потому может выдать причудливый результат при проверке с актуальным номером версии.)<br />
<b>__eq__(other_requirement)</b> - требование считается равным другому требованию если у них одинаковые, независимо от регистра, имена проектов, спецификаторы версии и <i>extras</i>. (Порядок <i>extras</i> и спецификаторов версий не учитывается.) Равные требования так же имеют равные хеши, так что это требование может использоваься в наборах или как ключ словаря.<br />
<b>__str__()</b> - строковая форма <b>Requirement</b> это строка, которую, если передать в <b>Requirement.parse()</b> вернёт равный объект <b>Requirement.</b><br />
<b>project_name</b> - имя запрашиваемого проекта<br />
<b>key</b> - версия <b>project_name </b>в нижнем регистре. Полезна для сравнения или индексирования.<br />
<b>extras</b> - кортеж имён <i>extras</i> для которых вызывается это требование. (Они будут в нижнем регистре и нормализованы при помощи функции <b>safe_extra()</b>, так что они могут быть не совсем равными <i>extras</i>, c которыми было создано требование)<br />
<b>specs</b> - список кортежей (<i>op,version</i>), отсортированный в возрастающем порядке версий. <i>op</i> в каждом кортеже является оператором сравнения, представленным в виде строки. <i>version</i> - это (не обработанный) номер версии. Относительный порядок кортедежей, содержащих тот же номер версии не определён, так как наличие более одного оператора для одной версии либо избыточно, либо противоречиво.<br />
<h3>
Точки входа</h3>
Точки входа - простой способ для дистрибутива объявить объекты Python (такие, как функции или классы) для использования другими дистрибутивами. Расширяемые приложения или фреймворки могут искать точки входа с определённым именем или группой или в конкретном дистрибутиве, или во всех активных дистрибутивах в <i>sys.path</i>, а затем исследовать или загрузить эти объекты.<br />
Точки входа принадлежат "группам", с точечным названием, аналогичным названиям пакетов или модулей Python. Например, пакет <i>setuptools</i> использует точку входа <i>distutils.commands</i> для того, чтобы найти команды, определённые расширением <i>distutils. setuptools</i> трактует имена точке входа, определённые в этой группе, как допустимые команды для скрипта настройки.<br />
Похожим образом другие пакеты могут определять свои собственные группы точек входа, используя либо динамические имена в группе (как <i>distutils.commands</i>), или используя предопределённые имена. Например, фреймворк блогов, которые предоставляет различные до- и постпубликационные "ловушки" может определить группу точек входа и искать точки входа с именами <i>pre_process</i> и <i>post_process</i> в этой группе.<br />
Для того, чтобы объявить точку входа, проект должен использовать <i>setuptools</i> и предоставить аргумент <i>entry_points</i> функции <b>setup()</b> в своём настроечном скрипте, так что эти точки входа будут добавлены в метаданные дистрибутива. Более подробно смотрите в документации <i>setuptools.</i><br />
Дистрибутив<i> </i>каждого проекта может объявить максимум одну точку входа определённого имени в определённой группе точек входа. Например, расширение <i>distutils</i> может объявить две разные точки входа <i>distutils.commands</i>, если у них разные имена. Но это не мешает <u>разным</u> проектам объявить точки входа с одинаковыми именами в одинаковых группах. В некоторых случаях это нежелательно, так как приложение или фреймворк, которое использует эти точки входа, может вызывать их как "ловушки" или ещё каким-то образом комбинировать их. Приложение или фреймворк само должно решать, что делать, если разные дистрибутивы объявляют одинаковые точки входа. Например, можно использовать обе точки входа, отобразить сообщение об ошибке, использовать первое найденное и т.д.<br />
<h4>
API</h4>
В следующих функциях аргумент <i>dist</i> может быть экземпляром <b>Distribution,</b> <b>Requirement</b> или строкой, определяющей требования (например, имя проекта, версию и т.д.). Если аргументом является строка или <b>Requirement</b>, ищется определяемый им дистрибутив (и добавляется в <i>sys.path</i>, если его там ещё нет). В случае, если подходящего дистрибутива нет, будет возбуждено исключение.<br />
Аргумент <i>group</i> должен быть строкой, содержащей точечный идентификатор, идентифицирующий группу точек входа. Если Вы определяете группу точек входа, Вы должны включить часть имени вашего пакета в имя группы, чтобы избежать коллизий с группами точек входа других пакетов.<br />
<b>load_entry_point(dist, group, name</b>) - загружает именованную точку входа из заданного дистрибутива или возбуждает <b>ImportError.</b><br />
<b>get_entry_info</b><b>(dist, group, name)</b> - возвращает объект <b>EnrtyPoint</b> для указанной <i>group </i>и <i>name</i> из выбранного дистрибутива. Возвращает <i>None</i>, если дистрибутив не объявил подходящей точки входа.<br />
<b>get_entry_map(dist, group=None)</b> - возвращает карту точек входа дистрибутива для <i>group</i>, или всё карту для дистрибутива. Эта функция возвращает словарь, даже если дистрибутив не объявляет точек входа. Если указана <i>group</i>, словарь отображает имена точек входа на соответствующие объекты <b>EntryPoint.</b> Если <i>group=None</i>, то словарь отображает имена групп на словри, которые отображают имена точек входа на соответствующие экзмемпляры <b>EntryPoint </b>в этой группе.<br />
<b>iter_entry_points(group, name=None) </b>- выдаёт объекты точек входа из <i>group</i> подходящие по <i>name.</i><br />
Если <i>name=None</i>, выдаются все точки входа в <i>group</i> из всех дистрибутивов в рабочем наборе из <i>sys.path</i>, иначе выдаются только те, которые соответствуют и <i>group</i> и <i>name</i>. Точки входа выдаются из активных дистрибутивов в том порядке, как эти дистрибутивы расположены в <i>sys.path</i> (Однако для конкретного дистрибутива нет какого-либо порядка точек входа.)<br />
(Этот API является методом глобального объекта <i>working_set</i>, более подробно о нём говорится в разделе "Основные методы <b>WorkingSet</b>")<br />
<h4>
Созднаие и парсинг</h4>
<b>EntryPoint(name</b>, <b>module_name, attrs=(), extras=(), dist=None)</b> - создаёт экземпляр <b>EntryPoint</b>. <i>name</i> - имя точки входа. <i>module_name</i> - точечное имя модуля, содержадещго объявляемый объект. <i>attrs</i> - опциональный кортеж имён, которые будут искать в модуле для получения объявленного объекта. Например, <i>attrs=("foo","bar") </i>и <i>module_name="baz" </i>будут означать, что объявляемый объект может быть получен следущим кодом:<br />
<span style="font-family: "Courier New",Courier,monospace;">import baz</span><br />
<span style="font-family: "Courier New",Courier,monospace;">advertized_object=baz.foo.bar</span><br />
<i>extras</i> - опциональный кортеж имён "дополнительных возможностей", которые дистрибутив требует для обеспечения этой точки вохода. Когда точка входа загружается, эти дополнительные возможности отыскиваются в аргументе <i>dist</i>, чтобы понять, какие ещё дистрибутивы должны быть активированы в <i>sys.path; </i>подробнее об этом смотри в методе <b>load()</b>. Аргумент <i>extras</i> имеет смысл только при наличии аргумента <i>dist, </i>который должен быть экземпляром <b>Distribution.</b><br />
<b>EntryPoint.parse(src, dist=None) (classmethod) </b>- парсит одну точку входа из строки <i>src. </i>Синтаксис точки входа следует форме:<br />
<span style="font-family: "Courier New",Courier,monospace;">name = some.module:some.attr [extra1, extra2]</span><br />
Имя точки входа и модуля обязательны, а <i>attrs </i>и <i>[extras]</i> не обязательны, как и пробелы между элементами. Аргумент <i>dist</i> передаётся в конструктор <b>EntryPoint()</b> вместе со значениями, полученными из <i>src.</i><br />
<b>EntryPoint.parse_group(group, lines, dist=None) (classmethod)</b> - парсит стрики или последовательность строк <i>lines</i> для создания словаря, отображающего имена точек входа на объекты <b>EntryPoint</b>. <b>ValueError</b> возбуждается если имена точек входа повторяются, если <i>group</i> не является корректным именем группы, или если есть ошибки в синтаксисе. (Обратите внимание: параметр <i>group</i> используется только для проверки и для создания более информативных сообщений об ошибке.) Если указан параметр <i>dist</i>, он будет использоваться для установки атрибута <i>dist</i> создаваемых объектов <b>EntryPoint.</b><br />
<b>EntryPoint.parse_map(data, dist=None) (classmethod)</b> - парсит <i>data</i> в словарь, отображающий имена точек входа на объекты <b>EntryPoint.</b> Если <i>data</i> является словарём, точка ключи будут использоваться как имена групп и значения передаётся в <i>parse_group() </i>в качестве аргумента <i>lines.</i> Если <i>data</i> - стока или последовательность строк, то она сперва делится на .ini-подобные разделы (при помощи функции <b>split_sections()</b>) и имена секций используются как имена групп. В любом случае аргумент <i>dist</i> передётся в<i> </i><b>parse_group()</b>, так что точки входа будут связаны с определённым дистрибутивом.<br />
<h4>
Объекты EntryPoint</h4>
Для простоты анализа, объекты <b>EntryPoint</b> имеют атрибуты, которые точно отвечают аргументам конструктора: <i>name,module_name, attrs, extras </i>и <i>dist. </i>Кроме того присутствуют следующие методы:<br />
<b>load(require=True, env=None, installer=None)</b> - загружает точку входа, возвращает объявленный объект Python, или возбуждает <b>ImportError, </b>если точка входа не может быть получена. Если <i>require=True</i>, тогда до попытки импорта вызывается <b>require(env, installer).</b><br />
<b>require(env=None, installer=None)</b> - убеждается, что все <i>extras</i>, которые нужны точке входа доступны в <i>sys.path.</i> <b>UnknownExtra</b> возбуждается, если <b>EntryPoint</b> имеет <i>extras</i>, но при этом не имеет <i>dist</i>, или если имена <i>extras</i> не определены дистрибутивом. Елси указан <i>env</i>, это должно быть экземпляром <b>Environment</b>, и он будет использован для поиска нужных дистрибутивов, если они ещё не присутствуют в <i>sys.path.</i> Если указан <i>installer</i>, он должен быть вызываемым и принимать экземпляр <b>Requirement</b> и возвращать подходящий импортируемый экземпляр <b>Distribution</b> или <b>None.</b><br />
<b>__str__()</b> - строковая форма <b>EntryPoint</b>; строка, которую можно передать в <b>EntryPoint.parse()</b> для получения эквивалентной <b>EntryPoint.</b><br />
<h3>
<b>Объекты Distribution</b></h3>
Объекты <b>Distribution</b> представляют<b> </b>коллекцию кода Python, который может быть импортирован и может иметь ассоциированные с ним метаданные и ресурсы. Их метаданные могут включать информацию, такую как от каких дистрибутивов он зависит, какие точки объявляет и так далее.<br />
<h4>
Получение или создание Distribution</h4>
Чаще всего Вы получаете объекты <b>Distribution</b> из <b>WorkingSet</b> или из <b>Environment.</b> (Смотрите ниже раздел об объектах <b>WorkingSet</b> и <b>Environment</b>, которые являются контейнерами для активных дистрибутивов и доступных дистрибутивов соответственно.) Кроме того, Вы можете получить объекты <b>Distribution</b> из этих API верхнего уровня:<br />
<b>find_distributions(path_item, only=False)</b> - выдёт дистрибутивы, доступные через <i>path_item.</i> Если <i>only=True,</i> выдаёт только дистрибутивы, чьё расположение равно <i>path_item. </i>Другими словами, если <i>only=True</i>, то будут выдаваться только дистрибутивы, которые можно импортировать если <i>sys.path=path_item.</i> В противном случае будут выданы дистрибутивы, которые находятся "в" или "под" <i>path_item</i>, но они не будут доступны для импорта, пока их расположение не будет добавлено в <i>sys.path.</i><br />
<b>get_distribution(dist_spec)</b> - возвращает объект <b>Distribution</b> для данного <b>Requirement</b> или строки.<i> </i>Если <i>dist_spec</i> уже является экземпляром <b>Distribution</b>, то он и возвращается. Если это объект <b>Requirement</b> или строка, которая может быть преобразована в этот объект, то он используется для поиска и активации подходящего дистрибутива, который затем и возвращается.<br />
Кроме того, если Вы создаёте специальный инструмент для работы с дистрибутивами или создаёте новый формат дистрибутива, Вам может потребоваться создать объект <b>Distribution</b> напрямую при помощи однго из трёх конструкоторов, указаных ниже.<br />
Все эти конструкторы принимают опциональный аргумент <i>metadata</i>, который используется для доступа к любым ресурсам или метаданным, ассоциированным с дистрибутивом. <i>metadata</i> должен быть объектом, реализующим интерфейс <b>IResourceProvider</b> или <b>None</b>. Если это <b>None</b>, то вместо него используется <b>EmptyProvider</b>. Объекты <b>Distribution</b> реализуют и методы <b>IResourceProvider </b>и <b>IMetadataProvider</b>, делегируя их объекту <b>metadata.</b><br />
<b>Distribution.from_location(location, basename, metadata=None, **kw) (classmethod)</b> - создаёт<b> </b>дистрибутив для <i>location</i>, который должен быть строкой вроде URL, имени файла или любой другой строкой, которую можно использовать в <i>sys.path.</i> Если <i>basename</i> заканчивается на .egg, тогда имя проекта, версия, версия Python и платформа извлекаются из имена файла и используются для задания соответствующих свойств создаваемого дистрибутива. Все дополнительные именованные аргументы направляются конструктору <b>Distribution().</b><br />
<b>Distribution.from_filename(filename, metadata=None, **kw) (classmethod)</b> - <b> </b>создаёт дистрибутив, распарсив локальное имя файла. Это более простой способ, аналогичный <b>Distribution.from_location( normalize_path(filename), os.path.basename(filename), methadata)</b>. Другими словами, это создаёт дистрибутив с расположением, полученным нормализацией имени файла, где имя и версия получаются из расширения файла. Все дополнительные аргументы передаётся в конструктор <b>Distribution()</b>.<br />
<b>Distribution(location, metadata,</b> <b>project_name, version, py_version, platform, precedence)</b> - создаёт дистрибутив на основе переданных параметров. Все аргументы опциональные и по умолчанию равны <b>None</b>, кроме <i>py_version</i> (который по умолчанию имеет значение текущей версии Python) и <i>precedence</i> (которое по умолчанию равно <b>EGG_DIST</b>; подробнее смотрите раздел "precedence" в "Атрибуты Distribution" ниже). Обратите внимание, что чаще используются конструкторы from_filename() или from_location().<br />
<h4>
Атрибуты Distribution</h4>
<b>location</b> - строка, определяющая место расположения дистрибутива. Для импортируемых дистрибутивов эта строка будет добавлена в <i>sys.path</i>, чтобы его можно было реально импортировать. Для не импортируемых дистрибутивов это просто имя файла, URL, или другой указатель места нахождения дистрибутива.<br />
<b>project_name</b> - строка, обозначающая проект этого дистрибутива. Имена проектов определяются в скрипте установки проектов и они используются для идентификации проектов в PyPI. Когда конструируется <b>Distribution</b>, аргумент <i>project_name</i> передаётся через функцию <b>safe_name()</b> чтобы отфильтровать все неподходящие символы.<br />
<b>key</b> - <b>dist.key </b>это сокращение <b>dist.project_name.lower().</b> Он используется для сравнений без учёта регистра и индексации дистрибутивов по имени проекта.<br />
<b>extras</b> - список строк, содержащих имена дополнительных возможностей, определённых списком зависимости проекта (аргумент <i>extra_require</i> определённый в скрипте установки проекта)<br />
<b>version</b> - строка, определяющая релиз проекта, который содержится в этом дистрибутиве. Когда конструируется <b>Distribution</b>, аргумент <i>version</i> передаётся через функцию <b>safe_version()</b> для того чтобы отфильтровать все неподходящие символы. Если <i>version</i> yt задан, тогда при обращении к этому атрибуту будет произведена попытка определить значение этого аргумента прочитывая файл метаданных <i>PKG-INFO</i>. Если <i>PKG-INFO</i> yt доступен или не может быть обработан, будет вызвано исключение <b>ValueError.</b><br />
<b>parsed_version</b> - <b> </b>кортеж, представляющи "отпарсенную" форму <i>version</i>. <b>dist.parsed_version</b> является более коротким аналогом <b>parse_version(dist.version)</b>. Он используется для сравнения или сортировки дистрибутивов согласно номеру версии. (Смотрите раздел "Утилиты для парсинга" ниже.) Обратите внимание что обращение к <b>parsed_version</b> может вызвать исключение <b>ValueError</b>, если <b>Distribution</b> был создан без <i>version</i> и без метаданных, которые могли бы указать версию дистрибутива.<br />
<b>py_version</b> - Мажорная/минорная версия Python, которую поддерживает данный дистрибутив; строка. Например, "2.3" или "2.4". По умолчанию - текущая версия Python.<br />
<b>platform</b> - строка, представляющая платформу, для которой предназначен данный дистрибутив, или <b>None</b>бесли дистрибутив предназначен для "чистого" Python и потому кросс-платформен. Смотрите "Утилиты платформ", где об этом говорится подробнее.<br />
<b>precedence</b> - используется для определения относительного порядка двух дистрибутивов с одинаковыми <i>project_name </i>и <i>parsed_version</i>. По умолчанию - <i>pkg_resources.EGG_DIST</i>, обладающий высшим приоритетом (то есть, наиболее предпочтителен). Полный список в сторону уменьшения предпочтнеия, таков: <i>EGG_DIST, BINARY_DIST, SOURCE_DIST, CHECKOUT_DIST, DEVELOP_DIST</i>. Обычно другой порядок используется только в модуле setuptools.package_index, когда сортируются дистрибутивы, найденные в индексе пакетов для определения их пригодности для установки. "Яйца" <i>System</i> и <i>Development</i> (то есть те, которые используют формат <i>.egg-info</i>) автоматически получают уровень прироритета <i>DEVELOP_DIST.</i><br />
<h4>
Методы<i> </i>Distribution</h4>
<b>activate(path=None)</b> - проверяет, что дистрибутив можно импортировать через <i>path. </i>Если <i>path=None</i>, то используется <i>sys.path</i>. Проверяется, что <i>location</i> дистрибутива находится в списке <i>path</i> и так же производятся все необходимые исправления пространства имён или объявлений. (То есть, если дистрибутив содержит пакеты пространств имён, этот метод проверяет, что они объявлены и что содержимое этих пакетов слито с содержимым, предоставляемым другими активными дистрибутивами. Смотрите раздел "Поддержка пакетов пространства имён")<br />
<i>pkg_resources</i> добавляет каллбэк оповещения в глобальный <i>working_set</i>, который проверяет, что этот метод вызывается когда к нему добавляется дистрибутив. Поэтому обычно Вам не нужно вызывать этот метод вручную. (Обратите внимание, что это означает, что пакеты имён в <i>sys.path</i> всегда импортируются <i>pkg_resources</i>, что является ещё одной причиной почему пакеты пространства имён не должны содержать никакого кода или выражений импорта)<br />
<b>as_requirement()</b> - возвращает экземпляр <b>Requirement</b>, который соответствует имени проекта дистрибутива и версии.<br />
<b>requires(extras=())</b> - список объектов <b>Requirement</b>, которые определяют зависимости дистрибутивов. Если <i>extras</i> определён, то это должна быть последовательность имён <i>extras</i>, определённых дистрибутивом и в таком случае возвращаемый список будет содержать все необходимые зависимости, которые нужны для обеспечения этих <i>extras.</i><br />
<b>clone(**kw)</b> - <i> </i>создаёт копию дистрибутива. Все переданные именованные аргументы переопределяют соответствующие аргументы конструктора <b>Distribution()</b>, позволяя Вам изменить некоторые атрибуты копируемого дистрибутива.<br />
<b>egg_name()</b> - возвращает стандартное имя файла, которое должно было бы быть у этого дистрибутива, без расширения <i>.egg</i>. Например, дистрибутив проекта Foo версии 1.2, который предназначен для Python 2.3 под Windows вернёт <i>Foo-1.2-py2.3-win32</i>. Все тире в имени или версии будут заменены на нижние подчёркивания. (<b>Distribution.from_location() </b>выполняет обратное преобразование, выполняя парсинг имени файла)<br />
<b>__cmp__(other), __hash__()</b> - объекты <b>Distribution</b> хешируемы и их можно сравнивать на основе их версий, приоритетов, ключей (имени проекта в нижнем регистре), месте расположения, версии Python и платформе.<br />
<br />
Следующие методы использутся для доступа к объектам <b>EntryPoint</b>, объявленных в дистрибутивах. Более подробно смотрите об этом в разделе, посвященном этому классу.<br />
<b>get_entry_info(group, name)</b> - возвращает объект <b>EntryPoint</b> для данных <i>group</i> и <i>name</i>, или <i>None</i> если такой точки не объявленно в этом дистрибутиве.<br />
<b>get_entry_map(group=None)</b> - возвращает карту точек входа для <i>group</i>. Если <i>group=None,</i> возвращается словарь, отображающий имена груп на карты точек входа для всех групп. (Карта точек входа - это словарь, отображающий имена точек входа на объекты <b>EntryPoint</b>)<br />
<b>load_entry_point(group, name)</b> - более короткий вариант <b>get_entry_info(group, name).load()</b>. Возвращает объект, объявленный этой точкой входа, или возбуждает исключение <b>ImportError</b>, если эта точка входа не объявлена в этом дистрибутиве или есть ещё какие-то проблемы.<br />
<br />
Кроме этих методов объекты <b>Distribution</b> так же реализуют методы <b>IResourceProvider </b>и <b>IMetadataProvider </b>(описаны ниже в этом разделе)5<br />
<ul>
<li><b>has_metadata(name)</b></li>
<li><b>metadata_isdir(name)</b></li>
<li><b>metadata_listdir(name)</b></li>
<li><b>get_metadata(name)</b></li>
<li><b>get_metadata_lines(name)</b></li>
<li><b>run_script(script_name, namespace)</b></li>
<li><b>get_resource_filename(manager, resource_name)</b></li>
<li><b>get_resource_stream(manager, resource_name)</b></li>
<li><b>get_resource_string(namager, resource_name)</b></li>
<li><b>has_resource(resource_name)</b></li>
<li><b>resource_isdir(resource_name)</b></li>
<li><b>resource_listdir(resource_name) </b></li>
</ul>
Если дистрибутив был создан с аргументом <i>metadata</i>, то эти методы доступа к ресурсам и метаданным делегируются провайдеру <b>metadata</b>. Иначе они делегируются <b>EmptyProvider</b>, так что у дистрибутива не будет ни ресурсов ни метаданных. Такой подход к делегации используется для того, чтобы обеспечение поддержки пользовательских импортеров или новых форматов дистрибутивов сводилось к простому созданию соответствующей реализации <b>IResourceProvider</b>. Смотрите раздел "Поддержка пользовательских импортёров" ниже.<br />
<h3>
API ResourceManager</h3>
Класс <b>ResourceManager</b> предоставляет единообразный доступ к пакету ресурсов, вне зависимости от того, существуют эти ресурсы как файлы, каталоги или архивы.<br />
Обычно Вам не нужно создавать или явно управлять экземплярами <b>ResourceManager</b>, так как модуль <b>pkg_resources</b> создаёт для Вас глобальный экземпляр и делает большинство его методов доступными для Вас как имена верхнего уровня в пространстве имён <i>pkg_resources</i>. Так, например, этот код вызывает метод <b>resource_string()</b> глобального <b>ResourceManager</b>:<br />
<span style="font-family: "Courier New",Courier,monospace;"><br /></span>
<span style="font-family: "Courier New",Courier,monospace;">import pkg_resources</span><br />
<span style="font-family: "Courier New",Courier,monospace;">my_data=pkg_resources.resource_string(__name__, "foo.dat")</span><br />
<br />
Таким образом, Вы можете использовать описанное ниже API без нужды в явном экземпляре <b>ResourceManager</b>; просто импортируйте модуль и используйте при необходимости.<br />
<h4>
Базовый доступ к ресурсам</h4>
В следующих методах аргумент <i>package_or_requirement</i> может быть либо именем модуля/пакета Python (например, <i>foo.bar</i>) или экземпляром <b>Requirement</b>. Если это имя пакета или модуля, то этот модуль должен быть импортируемым (то есть путь к нему должен быть в <i>sys.path</i>), а аргумент <i>resource_name</i> интерпретируется как относительный путь к пакету. (Обратите внимание, что если используется имя модуля, тогда имя ресурса трактуется относительно пакета, содержащего этот модуль. Кроме того, Вы не должны использовать пакеты пространств имён, так как эти пакеты могут быть разделяемыми между различными дистрибутивами, и потому возникает двусмысленность в том, в каком дистрибутиве искать требуемый ресурс.)<br />
Если же этот аргумент является экземпляром <b>Requirement</b>, в таком случае эти требования автоматически разрешаются (используя текущий <b>Environment</b> при необходимости) и подходящие дистрибутивы добавляются в <b>WorkingSet</b> и <i>sys.path</i>, если его там ещё нет. (Если же подходящего дистрибутива нет, то вызывается исключение.) Аргумент <i>resource_name</i> затем интерпретируется относительно корня выявленного дистрибутива; то есть первый сегмент пути будет трактоваться как верхняя часть модуля или пакета.<br />
Обратите внимание, что имена ресурсов должны иметь пути с разделителями / и не могут быть абсолютными (то есть начинаться с /) или содержать относительные имена вроде "..". <b>Не</b> используйте <i>os.path</i> для управления путём к ресурсам, так как они предоставляют <b>не</b> пути файловой системы.<br />
<b>resource_exists(package_or_requirement, resource_name) </b>- существует ли искомый ресурс? Возвращает <b>True </b>или <b>False.</b><br />
<b>resource_stream(package_or_requirement, resource_name)</b> - возвращает читаемый файлоподобный объект для указанного ресурса; это может быть собственно файл, <b>StringIO</b> или что-то вроде этого. Поток находится в "двоичном режиме" в том смысле, что все байты будут считаны так, как они есть.<br />
<b>resource_string(package_or_requirement, resource_name)</b> - возвращает искомый ресурс как строку. Ресурс читается в двоичном режиме, так что строка содержит те же байты, что и искомый ресурс.<br />
<b>resource_isdir(package_or_requirement, resource_name)</b> - является ли искомый ресурс каталогом? Возращает <b>True</b> или <b>False</b><br />
<b>resource_listdir(package_or_requirement, resource_name)</b> - возвращает список содержимого указанного каталога ресурсов, как <i>os.listdir</i> за исключением того, что работает даже если ресурсы находятся в zip файле.<br />
<b> </b><br />
Обратите<b></b> внимание, что только <b>resource_exists() </b>и <b>resource_isdir()</b> не учитывают тип ресурса. Вы не можете использовать <b>resource_listdir()</b> применительно к файлу или <b>resource_string() </b>или <b>resource_stream()</b> к каталогу. Использование неподходящего метода может привести к исключению или неопределённому поведению в зависимости от платформы и формата дистрибутива.<br />
<h4>
Извлечение ресурсов</h4>
<b>resource_filename(package_or_requirement, resource_name)</b> - иногда, когда не достаточно получить ресурс в форме потока или строки, нужно имя файла с ресурсом. В этом случае Вы можете использовать этот метод (или функцию уровня модуля) для получения имени файла этого ресурса. Если ресурс находится в архивированном дистрибутиве (например зазипованном яйце), то он будет извлечён оттуда в кэш-каталог и будет возвращено имя файла в этом кэше. Если запрошенный ресурс - каталог, тогда извлекаются и всё ресурсы из этого каталога (включая подкаталоги). Если этот ресурс - С расширение или "eager resource" (более подробно в документации setuptools), тогда все расширения С и eager русурсы тоже будут извлечены.<br />
Заархивированные ресурсы извлекаются в кэш-каталог, который управляеся двумя методами:<br />
<b>set_extraction_path(path)</b> - задаёт место, куда должны быть извлечены ресурсы.<br />
Если Вы не вызывали этот метод перед извлечением, то по умолчанию значением является результат вызова функции <b>get_default_cache() </b>(основанное на переменной окружения <i>PYTHON_EGG_CACHE</i>, что зависит от конкретной системы. Подробнее об этом - в документации к этой функции)<br />
Ресурсы извлекаются в подкаталоги этого пути, основываясь на информации, получаемый из провайдера ресурсов. Вы можете указать в качестве этой точки временный каталог, но затем Вы должны будете вызвать <b>cleanup_resources()</b> чтобы удалить извлечённые файлы, когда они Вам будут не нужны. Нет никакой гарантии того, что <b>cleanup_resources()</b> удалит все извлечённые файлы. (Например, под Windows Вы не сможете удалить файлы .pyd или .dll, которые на данный момент используются.)<br />
Обратите внимание, что Вы не должны менять путь для извлечения ресурсов, если Вы уже туда что-то извлекали, если перед этим Вы не вызвали <b>cleanup_resources().</b><br />
<b>cleanup_resources(force=False)</b> - удаляет все извлечённые файлы ресурсов и каталоги, возвращая список имён файлов или каталогов, удалить которые не получилось. Эта функция не имеет защиты для параллельного выполнения, так что её надо вызывать только в случаях, когда путь для извлечения используется только одним процессом. Этот метод не вызывается автоматически; вы должны либо вызвать его явно, либо зарегистрировать его как функцию <i>atexit</i>6 если Вы хотите быть уверенными, что временные файлы будут удалены.<br />
<h4>
Интерфейс Provider</h4>
Если Вы реализуете <b>IResourceProvider </b>и / или <b>IMetadataProvider</b> для нового формата дистриутивов, Вам могут понадобиться следующие методы <b>IResourceManager </b>для управления извлечением ресурсов в соответствующий каталог. Если Вы не реализуете архивный формат, Вам эти методы не понадобятся. В отличие от других методов, перечисленных выше, они <b>не </b>доступны как функции уровня модуля, привязанные к глобальному <b>ResourceManager</b>; для работы с ними у Вас должен быть явный экземпляр <b>ResourceManager.</b><br />
<b>get_cache_path(archive_name, names=())</b> - возвращает абсолютный genm в кэше для <i>archive_name </i>и <i>names</i>.<br />
Родительский каталог возвращаемого пути будет создан, если он ещё не существует. <i>archive_name</i> должно быть именем файла объемлющего яйца (что может не совпадать с имеем объемлющего архивного файла!), включая его расширение <i>.egg</i>. Если указан <i>names</i>, то это должно быть последовательностью путей <i>в</i> пути извлечения яйца.<br />
Этот метод должен быть вызван провайдером ресурсов, который должен обслуживать место извлечения и только для тех имён, которые он должен извлечь, так как он хранит полученные имена для дальнейшего удаления временных файлов.<br />
<b>extraction_error()</b> - возбуждает исключение <b>ExtractionError</b>, describing the active exception as interfering with the extraction process. Вы должны вызвать его если Вы встречаетесь с ошибками ОС при извлечении файлов в кэш; он отформатирует для Вас исключение ОС и добавит информацию в экземпляр <b>ExtractionError</b>, который может понадобиться программам, желающим самим обернуть или обработать ошибку.<br />
<b>postprocess(tempname, filename)</b> - обеспечивает постобработку зависящую от платформы для <i>tempname</i>. Провайдеры ресурсов должны вызывать этот метод <b>только</b> после успешного извлечения сжатых ресурсов. Он <b>не</b> должен вызываться для ресурсов, которые уже находятся в файловой системе.<br />
<i>tempname</i> - текущее (временное) имя файла, а <i>filename</i> - имя, в которое он будет переименован после завершения функции.<br />
<h3>
Metadata API</h3>
API метаданных используется для доступа к метаданным ресурсов, постовляемых в комплекте с подключаемыми (pluggable) дистрибутивами. Ресурсы метаданнх - это виртуальные файлы или каталоги, содержащие информацию о дистрибутиве, который может быть использован расширяемым приложением или фреймворком для подключения "плагинов". Как и другие ресурсы, имена метаданных разделены / и не должны содержать .. или начинаться с /. Вы не должны использовать <i>os.path</i> для работы с путём ресурсов.<br />
API метаданных предоставляется объектами, реализующими интерфейс <b>IMetadataProvider</b> или <b>IResourceProvider</b>. Объекты <b>Distribution</b> реализуют этот интерфейс, как и объекты, возвращаемые функцией <b>get_provider()</b>:<br />
<b>get_provider(package_or_requirement)</b> - если указано имя пакета, то возвращается <b>IResourceProvider </b>для пакета. Если же передан объект <b>Requirement</b>, то возвращается подходящий <b>Distribution</b> из текущего рабочего набора (при необходимости производится поиск в текущем <b>Environment</b> и найденный <b>Distribution</b> добавляется в рабочий набор). Если именованный пакет не может быть импортирован или <b>Requirement</b> не могут быть удволетворены, возбуждается исключение.<br />
<u>Примечание:</u> если Вы используете имя пакета, а не <b>Requirement</b>, то объект, который Вы получете может не быть подключемым дистрибутивом, в зависимости от метода, которым был установлен этот пакет. В частности, "development" пакеты и "single-version externally-managed" пакеты не могут быть отражены из имени пакета на подходящие метаданные. Не пишите код, который передаёт имена пакетов в <b>get_provider()</b> а затем пытается получить метаданные проекта из возвращённого объекта. Это может сработать, если указанный пакет будет <i>.egg</i> файлом или каталогом, но в других случаях Вы получите ошибку. Если Вам нужны метаданные проекта, Вы должны искать <i>проект</i>, а не <i>пакет</i>.<br />
<h4>
Методы IMetadataProvider</h4>
Методы, предоставляемые объектами (такими, как экземпляры <b>Distribution</b>), которые реализуют интерфейсы <b>IMetadataProvider</b> или <b>IResourceProvider</b>:<br />
<b>has_metadata(name)</b> - существуют ли именованные ресурсы метаданных?<br />
<b>metadata_isdir(name)</b> - запрашиваемые ресурсы метаданных являются каталогом?<br />
<b>metadata_listdir(name)</b> - список имён метаданных в каталоге (похоже на <i>os.listdir()</i>)<br />
<b>get_metadata(name)</b> - возвращает именованный ресурс метаданных в качестве строки. Данные считываются в двоичной форме, то есть возвращаются байты ресурса так, как они есть.<br />
<b>get_metadata_lines(name)</b> - выдёт (yield) ресурсы метаданных в виде списка не пустых и не закомментированных строк. Это более короткая версия вызова <b>yield_lines(provider.get_metadata(name))</b>. Смотрите раздел <b>yield_lines()</b> ниже, где более подробно рассказано о его синтаксисе.<br />
<b>run_script(script_name, namespace)</b> - выполняет указанный скрипт в словаре пространства имён. Возбуждает исключение <b>ResolutionError</b> если нет скрипта с таким именем в каталоге <i>scripts</i> метаданных. <i>namespace</i> должен быть словарём Python, обычно это словарь модуля, если скрипт запускается как модуль.<br />
<h3>
Исключения</h3>
<b>pkg_resources</b> предоставляет простую иерархию исключений для проблем, которые могут возникнуть при обработке запроса для обнаружения и активации пакетов:<br />
....ResoulutionError<br />
........DistributionNotFound<br />
........VersionConflict<br />
........UnknownExtra<br />
....ExtractionError<br />
<b>ResolutionError</b> - этот класс используется как базовый класс для других трёх исключений, так что Вы можете поймать всех их одним выражением <b>except</b>.Оно так же возбуждается непосредственно при возникновении различных проблем разрешения требований, как попытка запустить скрипт, который не существует в запрашиваемом дистрибутиве.<br />
<b>DistributionNotFound</b> - дистрибутив, удволетворяющий требованиям не может быть найден.<br />
<b>VersionConflict</b> - запрашиваемая версия проекта конфликтует с уже активной версией этого же проекта.<br />
<b>UnknownExtra</b> - один из запрошенных <i>extra</i> не был опознан дистрибутивом, где его искали.<br />
<b>ExtractionError</b> - проблема возникла при извлечении ресурса в кэш яиц Python. Следующие атрибуты доступны для экземпляров этого исключения:<br />
<i>manager</i> - менеджер ресурсов, который вызвал исключение<br />
<i>chache_path</i> - корневой каталог для извлечения ресурсов<br />
<i>original_error</i> - экземпляр исключения, который привёл к ошибке извлечения<br />
<h3>
Поддержка пользовательских импортёров (раздел будет доработан позже, когда разберусь с PEP302)</h3>
По умолчанию <b>pkg_resources</b> поддерживает нормальные импортёры файлововй системы и <i>zipimport</i>. Если Вы хотите использовать возможности <b>pkg_resources</b> вместе с другими (PEP 302 совместимыми) импортёрами или загрузчиками модулей, Вам может потребоваться зарегистрировать различные обработчики и вспомогательные функции при помощи следующих API:<br />
<b>register_finder(importer_type, distribution_finder) </b>- регистрирует <i>distribution_finder</i> чтобы найти дистрибутивы в элементах <i>sys.path</i>. <i>importer_type</i> - тип или класс PEP 302 <b>Importer </b>(обработчик элемента <i>sys.path</i>) и <i>distribution_finder</i> вызывается, когда <br />
<br />
<br />
<br /></div>
<pre>Supporting Custom Importers
===========================
``register_finder(importer_type, distribution_finder)``
Register `distribution_finder` to find distributions in ``sys.path`` items.
`importer_type` is the type or class of a PEP 302 "Importer" (``sys.path``
item handler), and `distribution_finder` is a callable that, when passed a
path item, the importer instance, and an `only` flag, yields
``Distribution`` instances found under that path item. (The `only` flag,
if true, means the finder should yield only ``Distribution`` objects whose
``location`` is equal to the path item provided.)
See the source of the ``pkg_resources.find_on_path`` function for an
example finder function.
``register_loader_type(loader_type, provider_factory)``
Register `provider_factory` to make ``IResourceProvider`` objects for
`loader_type`. `loader_type` is the type or class of a PEP 302
``module.__loader__``, and `provider_factory` is a function that, when
passed a module object, returns an `IResourceProvider`_ for that module,
allowing it to be used with the `ResourceManager API`_.
``register_namespace_handler(importer_type, namespace_handler)``
Register `namespace_handler` to declare namespace packages for the given
`importer_type`. `importer_type` is the type or class of a PEP 302
"importer" (sys.path item handler), and `namespace_handler` is a callable
with a signature like this::
def namespace_handler(importer, path_entry, moduleName, module):
# return a path_entry to use for child packages
Namespace handlers are only called if the relevant importer object has
already agreed that it can handle the relevant path item. The handler
should only return a subpath if the module ``__path__`` does not already
contain an equivalent subpath. Otherwise, it should return None.
For an example namespace handler, see the source of the
``pkg_resources.file_ns_handler`` function, which is used for both zipfile
importing and regular importing.
IResourceProvider
-----------------
``IResourceProvider`` is an abstract class that documents what methods are
required of objects returned by a `provider_factory` registered with
``register_loader_type()``. ``IResourceProvider`` is a subclass of
``IMetadataProvider``, so objects that implement this interface must also
implement all of the `IMetadataProvider Methods`_ as well as the methods
shown here. The `manager` argument to the methods below must be an object
that supports the full `ResourceManager API`_ documented above.
``get_resource_filename(manager, resource_name)``
Return a true filesystem path for `resource_name`, co-ordinating the
extraction with `manager`, if the resource must be unpacked to the
filesystem.
``get_resource_stream(manager, resource_name)``
Return a readable file-like object for `resource_name`.
``get_resource_string(manager, resource_name)``
Return a string containing the contents of `resource_name`.
``has_resource(resource_name)``
Does the package contain the named resource?
``resource_isdir(resource_name)``
Is the named resource a directory? Return a false value if the resource
does not exist or is not a directory.
``resource_listdir(resource_name)``
Return a list of the contents of the resource directory, ala
``os.listdir()``. Requesting the contents of a non-existent directory may
raise an exception.
Note, by the way, that your provider classes need not (and should not) subclass
``IResourceProvider`` or ``IMetadataProvider``! These classes exist solely
for documentation purposes and do not provide any useful implementation code.
You may instead wish to subclass one of the `built-in resource providers`_.
Built-in Resource Providers
---------------------------
``pkg_resources`` includes several provider classes that are automatically used
where appropriate. Their inheritance tree looks like this::
NullProvider
EggProvider
DefaultProvider
PathMetadata
ZipProvider
EggMetadata
EmptyProvider
FileMetadata
``NullProvider``
This provider class is just an abstract base that provides for common
provider behaviors (such as running scripts), given a definition for just
a few abstract methods.
``EggProvider``
This provider class adds in some egg-specific features that are common
to zipped and unzipped eggs.
``DefaultProvider``
This provider class is used for unpacked eggs and "plain old Python"
filesystem modules.
``ZipProvider``
This provider class is used for all zipped modules, whether they are eggs
or not.
``EmptyProvider``
This provider class always returns answers consistent with a provider that
has no metadata or resources. ``Distribution`` objects created without
a ``metadata`` argument use an instance of this provider class instead.
Since all ``EmptyProvider`` instances are equivalent, there is no need
to have more than one instance. ``pkg_resources`` therefore creates a
global instance of this class under the name ``empty_provider``, and you
may use it if you have need of an ``EmptyProvider`` instance.
``PathMetadata(path, egg_info)``
Create an ``IResourceProvider`` for a filesystem-based distribution, where
`path` is the filesystem location of the importable modules, and `egg_info`
is the filesystem location of the distribution's metadata directory.
`egg_info` should usually be the ``EGG-INFO`` subdirectory of `path` for an
"unpacked egg", and a ``ProjectName.egg-info`` subdirectory of `path` for
a "development egg". However, other uses are possible for custom purposes.
``EggMetadata(zipimporter)``
Create an ``IResourceProvider`` for a zipfile-based distribution. The
`zipimporter` should be a ``zipimport.zipimporter`` instance, and may
represent a "basket" (a zipfile containing multiple ".egg" subdirectories)
a specific egg *within* a basket, or a zipfile egg (where the zipfile
itself is a ".egg"). It can also be a combination, such as a zipfile egg
that also contains other eggs.
``FileMetadata(path_to_pkg_info)``
Create an ``IResourceProvider`` that provides exactly one metadata
resource: ``PKG-INFO``. The supplied path should be a distutils PKG-INFO
file. This is basically the same as an ``EmptyProvider``, except that
requests for ``PKG-INFO`` will be answered using the contents of the
designated file. (This provider is used to wrap ``.egg-info`` files
installed by vendor-supplied system packages.)
Utility Functions
=================
In addition to its high-level APIs, ``pkg_resources`` also includes several
generally-useful utility routines. These routines are used to implement the
high-level APIs, but can also be quite useful by themselves.
Parsing Utilities
-----------------
``parse_version(version)``
Parse a project's version string, returning a value that can be used to
compare versions by chronological order. Semantically, the format is a
rough cross between distutils' ``StrictVersion`` and ``LooseVersion``
classes; if you give it versions that would work with ``StrictVersion``,
then they will compare the same way. Otherwise, comparisons are more like
a "smarter" form of ``LooseVersion``. It is *possible* to create
pathological version coding schemes that will fool this parser, but they
should be very rare in practice.
The returned value will be a tuple of strings. Numeric portions of the
version are padded to 8 digits so they will compare numerically, but
without relying on how numbers compare relative to strings. Dots are
dropped, but dashes are retained. Trailing zeros between alpha segments
or dashes are suppressed, so that e.g. "2.4.0" is considered the same as
"2.4". Alphanumeric parts are lower-cased.
The algorithm assumes that strings like "-" and any alpha string that
alphabetically follows "final" represents a "patch level". So, "2.4-1"
is assumed to be a branch or patch of "2.4", and therefore "2.4.1" is
considered newer than "2.4-1", which in turn is newer than "2.4".
Strings like "a", "b", "c", "alpha", "beta", "candidate" and so on (that
come before "final" alphabetically) are assumed to be pre-release versions,
so that the version "2.4" is considered newer than "2.4a1". Any "-"
characters preceding a pre-release indicator are removed. (In versions of
setuptools prior to 0.6a9, "-" characters were not removed, leading to the
unintuitive result that "0.2-rc1" was considered a newer version than
"0.2".)
Finally, to handle miscellaneous cases, the strings "pre", "preview", and
"rc" are treated as if they were "c", i.e. as though they were release
candidates, and therefore are not as new as a version string that does not
contain them. And the string "dev" is treated as if it were an "@" sign;
that is, a version coming before even "a" or "alpha".
.. _yield_lines():
``yield_lines(strs)``
Yield non-empty/non-comment lines from a string/unicode or a possibly-
nested sequence thereof. If `strs` is an instance of ``basestring``, it
is split into lines, and each non-blank, non-comment line is yielded after
stripping leading and trailing whitespace. (Lines whose first non-blank
character is ``#`` are considered comment lines.)
If `strs` is not an instance of ``basestring``, it is iterated over, and
each item is passed recursively to ``yield_lines()``, so that an arbitarily
nested sequence of strings, or sequences of sequences of strings can be
flattened out to the lines contained therein. So for example, passing
a file object or a list of strings to ``yield_lines`` will both work.
(Note that between each string in a sequence of strings there is assumed to
be an implicit line break, so lines cannot bridge two strings in a
sequence.)
This routine is used extensively by ``pkg_resources`` to parse metadata
and file formats of various kinds, and most other ``pkg_resources``
parsing functions that yield multiple values will use it to break up their
input. However, this routine is idempotent, so calling ``yield_lines()``
on the output of another call to ``yield_lines()`` is completely harmless.
``split_sections(strs)``
Split a string (or possibly-nested iterable thereof), yielding ``(section,
content)`` pairs found using an ``.ini``-like syntax. Each ``section`` is
a whitespace-stripped version of the section name ("``[section]``")
and each ``content`` is a list of stripped lines excluding blank lines and
comment-only lines. If there are any non-blank, non-comment lines before
the first section header, they're yielded in a first ``section`` of
``None``.
This routine uses ``yield_lines()`` as its front end, so you can pass in
anything that ``yield_lines()`` accepts, such as an open text file, string,
or sequence of strings. ``ValueError`` is raised if a malformed section
header is found (i.e. a line starting with ``[`` but not ending with
``]``).
Note that this simplistic parser assumes that any line whose first nonblank
character is ``[`` is a section heading, so it can't support .ini format
variations that allow ``[`` as the first nonblank character on other lines.
``safe_name(name)``
Return a "safe" form of a project's name, suitable for use in a
``Requirement`` string, as a distribution name, or a PyPI project name.
All non-alphanumeric runs are condensed to single "-" characters, such that
a name like "The $$$ Tree" becomes "The-Tree". Note that if you are
generating a filename from this value you should combine it with a call to
``to_filename()`` so all dashes ("-") are replaced by underscores ("_").
See ``to_filename()``.
``safe_version(version)``
Similar to ``safe_name()`` except that spaces in the input become dots, and
dots are allowed to exist in the output. As with ``safe_name()``, if you
are generating a filename from this you should replace any "-" characters
in the output with underscores.
``safe_extra(extra)``
Return a "safe" form of an extra's name, suitable for use in a requirement
string or a setup script's ``extras_require`` keyword. This routine is
similar to ``safe_name()`` except that non-alphanumeric runs are replaced
by a single underbar (``_``), and the result is lowercased.
``to_filename(name_or_version)``
Escape a name or version string so it can be used in a dash-separated
filename (or ``#egg=name-version`` tag) without ambiguity. You
should only pass in values that were returned by ``safe_name()`` or
``safe_version()``.
Platform Utilities
------------------
``get_build_platform()``
Return this platform's identifier string. For Windows, the return value
is ``"win32"``, and for Mac OS X it is a string of the form
``"macosx-10.4-ppc"``. All other platforms return the same uname-based
string that the ``distutils.util.get_platform()`` function returns.
This string is the minimum platform version required by distributions built
on the local machine. (Backward compatibility note: setuptools versions
prior to 0.6b1 called this function ``get_platform()``, and the function is
still available under that name for backward compatibility reasons.)
``get_supported_platform()`` (New in 0.6b1)
This is the similar to ``get_build_platform()``, but is the maximum
platform version that the local machine supports. You will usually want
to use this value as the ``provided`` argument to the
``compatible_platforms()`` function.
``compatible_platforms(provided, required)``
Return true if a distribution built on the `provided` platform may be used
on the `required` platform. If either platform value is ``None``, it is
considered a wildcard, and the platforms are therefore compatible.
Likewise, if the platform strings are equal, they're also considered
compatible, and ``True`` is returned. Currently, the only non-equal
platform strings that are considered compatible are Mac OS X platform
strings with the same hardware type (e.g. ``ppc``) and major version
(e.g. ``10``) with the `provided` platform's minor version being less than
or equal to the `required` platform's minor version.
``get_default_cache()``
Determine the default cache location for extracting resources from zipped
eggs. This routine returns the ``PYTHON_EGG_CACHE`` environment variable,
if set. Otherwise, on Windows, it returns a "Python-Eggs" subdirectory of
the user's "Application Data" directory. On all other systems, it returns
``os.path.expanduser("~/.python-eggs")`` if ``PYTHON_EGG_CACHE`` is not
set.
PEP 302 Utilities
-----------------
``get_importer(path_item)``
Retrieve a PEP 302 "importer" for the given path item (which need not
actually be on ``sys.path``). This routine simulates the PEP 302 protocol
for obtaining an "importer" object. It first checks for an importer for
the path item in ``sys.path_importer_cache``, and if not found it calls
each of the ``sys.path_hooks`` and caches the result if a good importer is
found. If no importer is found, this routine returns an ``ImpWrapper``
instance that wraps the builtin import machinery as a PEP 302-compliant
"importer" object. This ``ImpWrapper`` is *not* cached; instead a new
instance is returned each time.
(Note: When run under Python 2.5, this function is simply an alias for
``pkgutil.get_importer()``, and instead of ``pkg_resources.ImpWrapper``
instances, it may return ``pkgutil.ImpImporter`` instances.)
File/Path Utilities
-------------------
``ensure_directory(path)``
Ensure that the parent directory (``os.path.dirname``) of `path` actually
exists, using ``os.makedirs()`` if necessary.
``normalize_path(path)``
Return a "normalized" version of `path`, such that two paths represent
the same filesystem location if they have equal ``normalized_path()``
values. Specifically, this is a shortcut for calling ``os.path.realpath``
and ``os.path.normcase`` on `path`. Unfortunately, on certain platforms
(notably Cygwin and Mac OS X) the ``normcase`` function does not accurately
reflect the platform's case-sensitivity, so there is always the possibility
of two apparently-different paths being equal on such platforms.
</pre>
Ishayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com0tag:blogger.com,1999:blog-2142461056765545912.post-60227858017354811172013-04-16T17:09:00.000+04:002013-04-16T17:09:48.528+04:00South. Документация. Конвертирование приложения<h2 style="text-align: justify;">
Конвертирование приложения</h2>
<div style="text-align: justify;">
Конвертировать приложение для использования South очень легко:</div>
<ul style="text-align: justify;">
<li>Отредактируйте ваш settings.py и укажите south в INSTALLED_APPS (мы предполагаем, что Вы установили south туда, куда нужно)</li>
<li>Запустите ./manage.py syncdb для того, чтобы загрузить таблицу South в БД. Обратите внимание, что теперь syncdb не такой как раньше - South его изменил</li>
<li>Запустите ./manage.py convert_to_south myapp - South автоматически подготовит и выполнит первую миграцию</li>
</ul>
<div style="text-align: justify;">
Обратите внимание, что Вы должны конвертировать приложение <b>до</b> того, как Вы сделаете изменения; South обнаруживает изменения по сравнению с замороженным состоянием последней миграции, так что он не сможет обнаружить изменения, сделанные до конвертирования в South. </div>
<h3 style="text-align: justify;">
Конвертирование других установок и серверов</h3>
<div style="text-align: justify;">
Команда convert_to_south рабоатет целиком на первой машине, на которой Вы его запустите. После того, как Вы подтвердите начальную миграцию, которую он сделал, в системе управления версиями, Вы должны запустить ./manage.py migrate myapp 0001 --fake на всех машинах, которые содержат копию кода (убедитесь, что они имеют обновлённый код и схему).</div>
<div style="text-align: justify;">
(Для тех, кому интересно, это нужно поскольку начальная миграция, которую делает convert_to_south, проверит и создат все существующие таблицы; вместо этого Вы говорите South, что это уже сделано при помощи --fake, так что следующие миграции будут применены корректно).</div>
<div style="text-align: justify;">
Помните, что новые установки кода после этого не потребуют этих шагов, Вам нужно будет лишь сделать syncdb а, затем, провести нормальную миграцию.</div>
Ishayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com0tag:blogger.com,1999:blog-2142461056765545912.post-68082504319895402252013-03-25T01:42:00.001+04:002013-03-25T01:42:18.729+04:00Документация South - Перевод. Часть 4: Пользовательские поля<div style="text-align: justify;">
В South 0.7 появилось радикальное отличие от предыдущих версий. До сих пор, если у Вас было пользовательское поле, South пытался использовать <a href="http://lurkmore.to/%D0%AD%D1%82%D0%BE_%D0%BE%D1%87%D0%B5%D0%BD%D1%8C_%D1%81%D0%B8%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D0%BA%D0%BE%D0%BB%D0%B4%D1%83%D0%BD%D1%81%D1%82%D0%B2%D0%BE" target="_blank">очень сильное колдунство</a> для того, чтобы определить, как "замораживать" это поле,так что оно могло быть отклонено в миграции (и это было не очень красивое колдунство - комбинация регулярных выражений и модуля parser).</div>
<div style="text-align: justify;">
Хотя это, как ни странно, работало хорошо у большинства пользователей, тем не менее в некоторых случаях что-то шло не так, и Вы даже не знали об этом, пока не проходило несколько недель... В целях большей вменяемости и меньшей магии теперь Вы должны указать South как замораживать ваши пользовательские поля.</div>
<div style="text-align: justify;">
Не волнуйтесь, это достаточно просто и Вам надо сделать это лишь раз для каждого поля.</div>
<a name='more'></a><br />
<h4>
Наше поле</h4>
<div style="text-align: justify;">
В этом примере мы будем использовать пользовательское поле, которое хранит список тегов в БД. Мы будем просто хранить их в TEXT колонке с некоторым разделителем (по умолчанию мы будем использовать |, но можно использовать и любой другой символ - просто передайте его как именованный аргумент).</div>
<div style="text-align: justify;">
Вот класс этого поля. Я разместил его в appname/fields.py (более подробно о создании собственных полей смотрите <a href="http://docs.djangoproject.com/en/dev/howto/custom-model-fields/" target="_blank">документацию Django</a>):</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> from django.db import models
class TagField(models.TextField):
description = "Stores tags in a single database column."
__metaclass__ = models.SubfieldBase
def __init__(self, delimiter="|", *args, **kwargs):
self.delimiter = delimiter
super(TagField, self).__init__(*args, **kwargs)
def to_python(self, value):
# If it's already a list, leave it
if isinstance(value, list):
return value
# Otherwise, split by delimiter
return value.split(self.delimiter)
def get_prep_value(self, value):
return self.delimiter.join(value)</pre>
</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Для того, чтобы рассказать South об этом поле, Вам нужно сообщить две вещи: что этот класс можно использовать и как получить именованный аргумент из экземпляра поля.</div>
<h4>
Именованные аргументы</h4>
<div style="text-align: justify;">
South замораживает поля сохраняя их имя класса и модуль (таким образом можно получить сам класс поля) и именованные аргументы, которые Вы используете для конкретного экземпляра класса (например, CharField(max_lengh=50) не то же самое, что CharField(max_lengh=150)).</div>
<div style="text-align: justify;">
Так как Python не хранит именованные аргументы, переданные конструктору класса, South должен восстановить их уже из полученного экземпляра класса. Например, мы знаем что значение именованного аргумента max_length класса CharField хранится в атрибуте self.max_lenght, тогда как ForeignKeys хранят свои именованные аргументы to (определяющие модель, на которую они указывают, так же первый позиционный аргумент) как self.rel.to.<br />
South знает все эти правила для стандартных полей Django, но Вам необходимо объяснить все это касательно своих полей. Хорошая новость состоит в том, что South может отследить цепочку наследования, так что о полях, определённых в родительских классах говорить заново в дочерних классах не надо (или надо сообщить только о тех дополнительных именованных аргументах, которых не было в родительском классе).<br />
В нашем примере мы определяем только один дополнительный именованный аргумент - delimiter. Вот код, который мы добавляем для того, чтобы South мог обработать наше новое поле. Чуть позже мы его объясним:<br />
<br />
<br />
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> from south.modelsinspector import add_introspection_rules
add_introspection_rules([
(
[TagField], # Класс(ы) к которым это применимо
[], # позиционные аргументы (не используется)
{ # именованные аргументы
"delimiter": ["delimiter", {"default": "|"}],
},
),
], ["^southtut\.fields\.TagField"])</pre>
<br />
<br />
Как Вы можете видеть, для того, чтобы рассказать South о вашем новом поле Вам нужно вызвать функцию south.modelsinspector.add_introspection_rules. Вы должны разместить этот код рядом с определением вашего поля. Так как последнее, что Вы хотели бы - это импортировать поле, но чтобы этот код не был выполнен.<br />
add_introspection_rules принимает два аргумента: список правил и список регулярных выражений. Список регулярных выражений используется South для того чтобы понять, можно ли исследовать это поле. Просто иметь правило, которое подходит для поля недостаточно, так как наследование правил подразумевает, что любой пользовательский класс поля будет иметь хотя бы одно правило, под которое он подпадает (опять - "<i>(as they will inherit from ``Field``, if not something more specificlike ``CharField``), and some custom fields can get by with only those
inherited rules (more on that shortly)</i>").<br />
Первый аргумент - список правил. Каждое правило - это кортеж (или список) с тремя элементами:<br />
<br />
<ol>
<li>Список классов к которым применимы эти правила. Практически наверняка у Вас будет тут только одно поле, например, то, про которое мы сейчас говорим.</li>
<li>Спецификация позиционных аргументов. Практически наверняка будет пустым списком - []</li>
<li>Спецификация именованных аргументов: это словарь, где ключ - имя аргумента, а значение - список или кортеж (имя_аргумента, опции)</li>
</ol>
<div>
Имя аргумента определяет место, где может быть найдено значение именованного аргумента - в нашем случае это delimiter, так как значение именованного аргумента мы храним в self.delimiter. (Если бы это было правило ForeignKey, то тут бы стояло rel.to)</div>
<div>
Опции- это словарь. Вы можете безопасно оставить этот аргумент пустым, но можно и использовать его для определения значения по умолчанию и если South обнаружит значение, соответствующее этому, то он не будет указывать это ключевое слово в определении заморозки, что позволит это определение сделать более простым и читаемым.<br />
<h4>
Простые наследования</h4>
</div>
<div>
Если ваше поле наследуется напрямую из другого поля Django, например, CharField, и не добавляет других именованных аргументов, то Вам не нужно добавлять какие-либо правила в add_introspection_rules. Вы можете просто сказать South, что с этим полем всё в порядке:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> class UpperCaseField(models.TextField):
"Убеждаемся, что содержимое всегда в верхнем регистре."
def to_python(self, value):
return value.upper()
def get_prep_value(self, value):
return value.upper()
from south.modelsinspector import add_introspection_rules
add_introspection_rules([], ["^southtut\.fields\.UpperCaseField"])</pre>
</div>
<h4>
Больше информации</h4>
<div>
Более подробную документацию на эту тему можно обнаружить в разделе <a href="http://south.readthedocs.org/en/latest/customfields.html#extending-introspection" target="_blank">Extending introspection</a>.</div>
</div>
Ishayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com0tag:blogger.com,1999:blog-2142461056765545912.post-1110233140276615492013-03-11T12:48:00.004+04:002013-03-11T12:48:50.995+04:00MoinMoin2. Документация. Индексы<h2>
Общая информация</h2>
<div style="text-align: justify;">
MoinMoin полагается на индексы, которые ускоряют доступ к метаданным элемента и данным; кроме того, он позволяет иметь более простые бэкэенды, так как самую тяжёлую работу делает слой индекса.</div>
<div style="text-align: justify;">
Внутри индексы используются для многих операций, таких как поиск элемента, история, итерирование по элементам, поиск, интерактивный поиск и т.д.</div>
<div style="text-align: justify;">
MoinMoin не сможет стартовать с повреждённым, недоступным или несуществующим индексом. Поэтому Вы должны сперва настроить и корректно инициализировать индексы.</div>
<div style="text-align: justify;">
moin автоматически обновляет индексы при создании, обновлении, удалении, разрушении или переименовании элементов посредством api хранилища moin, слоя индесов или выше.</div>
<a name='more'></a><br />
<h2 style="text-align: justify;">
Настройка</h2>
<div style="text-align: justify;">
В вашем конфиге вики должен быть элемент index_storage.</div>
<div style="text-align: justify;">
Мы используем whoosh для индексирования, и, так как whoosh поддерживает различные бэкэнды хранилища, этот элемент обеспечивает потенциальную поддержку всех этих бэкэндов.</div>
<div style="text-align: justify;">
В общем эта запись имеет такую форму:</div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">index_storage=kind,(p1,p2,...),{kw1=...,kw2=...,...}</span></div>
<div style="text-align: justify;">
На данный момент мы поддерживаем только тип FileStorage хранилища индесов, который имеет только один параметр - каталог индекса:</div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">index_storage='FileStorage',("/path/to/moin-2.0/wiki/index",),{}</span></div>
<div style="text-align: justify;">
<b>Примечания</b> <b>для FileStorage:</b></div>
<ul>
<li>путь должен быть абсолютным, доступным для записи и должен бытьна быстрой, локальной файловой системе</li>
<li>Moin <b></b>будет использовать каталог index.temp, если Вы строите индекс во "временном месте" (temporary location)</li>
</ul>
<h2>
Руководство по moin index скрипту</h2>
Вы можете исользовать группу скриптов "moin index-*" для управления индексами.<br />
<div style="text-align: justify;">
Большая часть скриптов для управления индексами поддерживает опцию --tmp для использования временного расположения индексов. Это полезно в случае, если Вы хотите проводить операции с индексами параллельно с работающей вики, которая использует нормальное расположение индексов.</div>
<h3 style="text-align: justify;">
moin index-create</h3>
<div style="text-align: justify;">
Создаёт пустой валидный индекс.</div>
<div style="text-align: justify;">
<b>Примечание</b>: приложению WSGI moin требуется индекс для успешного запуска. Так как скрипты moin index-* тоже базируются на приложении WSGI moin, это приводит к пробеме курицы и яйца. Для решения этой проблемы команда moin имеет опцию -i (--index-create), которая создаёт индекс при запуске.</div>
<div style="text-align: justify;">
Кроме того, если ещё не существует хранилище, Вам может понадобиться опция -s (--storage-create) для создания при запуске пустого хранилища.</div>
<h3 style="text-align: justify;">
moin index-build</h3>
<div style="text-align: justify;">
Обрабатывает все ревизии вики и добавляет индексируемые документы в индекс.</div>
<div style="text-align: justify;">
<b>Примечание:</b></div>
<ul style="text-align: justify;">
<li>Для больших вики, это может занять много времени. Подумайте об использовании --tmp<b> </b></li>
<li>index-build НЕ очищает сперва индекс</li>
<li>index-build не проверяет текущее содержимое вики. Поэтому Вы не должны запускать index-build несколько раз для тех же данных или той же вики</li>
</ul>
<h3>
moin index-update</h3>
<div style="text-align: justify;">
Сравнивает индекс с текущим содержимым хранилища и обновляет по необходимости индекс (добавляет, удаляет, обновляет) для соответствия текущему содержимому.</div>
<div style="text-align: justify;">
<b>Примечание</b>: Вы можете использовать это после создания индекса во временной локации для добавления изменений, которые произошли в процессе построения индекса. index-update можно запускать несколько раз для обработки новых данных.</div>
<h3 style="text-align: justify;">
moin index-destroy</h3>
<div style="text-align: justify;">
Уничтожает индекс так, что от него ничего не остаётся</div>
<h3 style="text-align: justify;">
moin index-move</h3>
<div style="text-align: justify;">
Перемещает индекс из временной локации в место постоянного расположения</div>
<h3 style="text-align: justify;">
moin index-optimize</h3>
<div style="text-align: justify;">
Оптимизирует индекс. См документацию whoosh.</div>
<h3 style="text-align: justify;">
moin index-dump</h3>
<div style="text-align: justify;">
Выводит содержимое индекса в читаемом виде, например, для отладки.</div>
<div style="text-align: justify;">
<b>Примечание:</b> только поля с атрибутом stored=True могут быть отображены.</div>
<h2 style="text-align: justify;">
Создание индекса для единичной вики</h2>
<h3 style="text-align: justify;">
Если ваша вики свеженькая и пустая</h3>
<div style="text-align: justify;">
Использование:</div>
<span style="font-family: "Courier New",Courier,monospace;"> moin index-create --storage-create --index-create</span><br />
<span style="font-family: "Courier New",Courier,monospace;">moin index-create -s -i # тоже, но короче</span><br />
<div style="text-align: justify;">
Теперь хранилище и индексы инициализированы и пусты.</div>
<div style="text-align: justify;">
Если Вы добавите информацию в вики, индекс будет автоматически обновлён. </div>
<h3 style="text-align: justify;">
Если ваша вики уже содержит данные и выключена</h3>
<div style="text-align: justify;">
Если индекс по какой-то причине должен быть пересроен, например, он потерян или повреждён, используйте:</div>
<div style="text-align: justify;">
moin index-create -i</div>
<div style="text-align: justify;">
moin index-build # может занять много времени</div>
<h3 style="text-align: justify;">
Если ваша вики уже содержит данные и должна оставаться включённой</h3>
<div style="text-align: justify;">
Используйте:</div>
<span style="font-family: "Courier New",Courier,monospace;"> moin index-create -i --tmp</span><br />
<span style="font-family: "Courier New",Courier,monospace;">moin index-build --tmp # может занять время</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"># должно работать быстро, у нас уже готово почти 99.x%</span> </span><br />
<span style="font-family: "Courier New",Courier,monospace;">moin index-update --tmp </span><br />
<span style="font-family: "Courier New",Courier,monospace;"># теперь лучше выключить вики или, по крайней мере,</span><br />
<span style="font-family: "Courier New",Courier,monospace;"># убедиться, что она не изменяется</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"># убеждаемся, что у нас проиндексирован весь контект,</span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"># должно быть очень быстрым</span> </span><br />
<span style="font-family: "Courier New",Courier,monospace;">moin index-update --tmp </span><br />
<span style="font-family: "Courier New",Courier,monospace;">moin index-move # мгновенно</span><br />
<span style="font-family: "Courier New",Courier,monospace;"># снова запускаем вики или разрешаем измененеия</span><br />
<div style="text-align: justify;">
<b>Примечание:</b> индексированиеа загружает ваш сервер, так что если Вы регулярно перестраиваете индекс, запланируйте это на то время, когда ваш сервер не очень занят.</div>
<h2 style="text-align: justify;">
Создаём индекс для фермы вики</h2>
<div style="text-align: justify;">
Если Вы запускаете ферму вики (несколько связанных вики), Вы можете разделить индекс между разными вики, так что пользователи могут искать в одной вики, а видеть результаты и из других.</div>
<div style="text-align: justify;">
До того, как Вы начнёте, Вы должны подготовить конфиг вашей вики. Например, для компании, использующей две вики, например Sales и Engineering, то их конфиги будут выглядеть соответсвтенно так:</div>
<div style="text-align: justify;">
Sales:</div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">interwikiname = u"Sales"</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">index_storage = 'FileStorage', ("/path/to/moin-2.0/wiki/index",),{}</span></div>
<div style="text-align: justify;">
Engineering:</div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">interwikiname = u"Engineering"</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">index_storage = 'FileStorage', ("/path/to/moin-2.0/wiki/index",),{}</span></div>
<div style="text-align: justify;">
Теперь построим индекс:</div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">moin index-create -i # создаём пустой индекс</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"># теперь добавляем индексы в обе вики</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">moin index-build # c конфигурацией для вики Sales</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">moin index-build # c конфигурацией для вики Engineering</span></div>
<div style="text-align: justify;">
Теперь у Вас должны быть общие индексы для всех вики.</div>
<div style="text-align: justify;">
<b>Примечание: </b>не стройте индексы для нескольких вики параллельно. Это не поддерживается.</div>
Ishayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com0tag:blogger.com,1999:blog-2142461056765545912.post-8218206138779851932013-03-10T19:36:00.003+04:002013-03-10T19:36:45.963+04:00MoinMoin2. Документация. Резервное копирование и восстановление.<h2>
Полная резервная копия / восстановление</h2>
<div style="text-align: justify;">
Лучший способ избежать полной потери данных - иметь <b>полную</b> резервную копию на вашей машине. С этой резервной копией Вы можете легко вернуть вашу машину в рабочее состояние.</div>
<div style="text-align: justify;">
Процедура ниже описывает как провести и выборочное резервное копирование файлов вашей установки MoinMoin. Поскольку нет нужды обслуживать и полное и частичное резервное копирование, иметь одну из них строго рекомендуется.</div>
<h2 style="text-align: justify;">
Частичное резервное копирование</h2>
<div style="text-align: justify;">
Если Вы хотите сделать резервную копию MoinMoin и ваших данных, тогда сделайте резервную копию следующего:</div>
<ul style="text-align: justify;">
<li>ваши данные</li>
<li>конфигурация moin, то есть wikiconfig.py</li>
<li>конфигурация логирования, то есть logging.conf</li>
<li>скрипт moin, то есть moin.wsgi</li>
<li>конфигурация веб-сервера, то есть конфигурация виртуального хоста apache</li>
<li>по желанию: код moin и зависимости; как минимум Вам нужно знать версию moin, c которой Вы работаете, чтобы Вы смогли её установить.</li>
</ul>
<div style="text-align: justify;">
Для того, чтобы создать дамп всех данных, сохранённых в moinmoin (элементы вики, профили пользователей), запустите следующую команду:</div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">moin save --all-backends --file backup.moin</span></div>
<div style="text-align: justify;">
Пожалуйста, обратите внимание,что этот файл содержит чувствительные данные, такие как профили пользователей, содержимое вики, так что храните его в безопасном месте, куда неавторизованные пользователи не смогут получить доступ.</div>
<h2 style="text-align: justify;">
Выборочное восстановление</h2>
<div style="text-align: justify;">
Для того, чтобы восстановить всё ПО и конфигурационные файлы в их исходное место, сперва создайте пустую вики:</div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">moin moin -s -i # -s создаёт новое хранилище</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"> # -i создаёт новый индекс</span></div>
<div style="text-align: justify;">
Для загрузки резервной копии в пустую вики выполните:</div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">moin load --file backup.moin</span></div>
<div style="text-align: justify;">
Затем постройте индекс загруженных данных:</div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">moin index-build</span></div>
Ishayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com0tag:blogger.com,1999:blog-2142461056765545912.post-56382135244500141582013-03-10T18:12:00.000+04:002013-05-07T13:41:29.764+04:00MoinMoin2. Документация. Введение в настройку MoinMoin<h3>
Типы конфигурационных файлов</h3>
<div style="text-align: justify;">
Для изменения того, как moinmoin себя ведёт и выглядит, Вы можете настроить его, редактируя конфигурационные файлы:</div>
<ul>
<li>Конфигурация движка Wiki</li>
<ul>
<li>файл чаще всего называется wikiconfig.py, но может иметь и другое имя</li>
<li>в этом файле находятся классы конфига движка вики</li>
<li>он написан на Python</li>
</ul>
<li>Конфигурация фреймворка</li>
<ul>
<li>расположена в том же файле, что и конфигурация движка вики</li>
<li>содержит некоторые настройки в ВЕРХНЕМ РЕГИСТРЕ в конце файла. Это конфигурация фреймворка (Flask и его расширений)</li>
<li>он написан на Python</li>
</ul>
<li>Конфигурация логирования</li>
<ul>
<li>опциональна; если Вы не хотите настраивать логирование - будут использованы встроенные настройки</li>
<li>это отдельный файл, назвается чаще всего logging.conf</li>
<li>имеет .ini подобный формат файла<a name='more'></a></li>
</ul>
</ul>
<h4>
Меняйте понемногу и храните резервные копии</h4>
<div style="text-align: justify;">
Начните с простого конфига, поставляемого с moin и меняйте его понемногу и каждый раз проверяйте работоспособность.</div>
<div style="text-align: justify;">
Если Вы не знакомы с форматом файла конфигурации, храните копию последнего работающего конфига на случай, если Вы вдруг сделаете трудно отлавливаемую ошибку.</div>
<h4 style="text-align: justify;">
Редактирование файлов Python</h4>
<div style="text-align: justify;">
Когда Вы редактируете файлы Python, будьте осторожны с отступами, используйте лишь отступы, кратные 4 пробелам и не используйте табуляцию.</div>
<div style="text-align: justify;">
Кроме того, будьте внимательны к синтаксису вообще; это должен быть корректный код на Python, иначе Вы получите ошибку при попытке загрузки конфигурации. В таком случае прочитайте внимательно сообщение об ошибке, в нём скорее всего будет содержаться номер строки и описание проблемы. Если у Вас не получается решить проблему - восстановите из резервной копии последний рабочий конфиг.</div>
<h4 style="text-align: justify;">
Зачем использовать Python для конфигурации?</h4>
<div style="text-align: justify;">
Вы, конечно, можете удивиться, почему мы используем код Python для конфигурации. Одна из причин в том, что это очень мощный язык. Moinmoin сам по себе разработан на Python и использование чего-либо другого потребовало бы больше времени для введения новой функциональности.</div>
<h3 style="text-align: justify;">
wikiconfig.py</h3>
<div style="text-align: justify;">
wikiconf.py выглядит таким образом:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"># -*- coding: utf-8 -*-</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">from MoinMoin.config.default import DefaultConfig</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"><br /></span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">class Config(DefaultConfig):</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"> # некоторый комментарий</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"> sometext = u'your value'</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"> somelist = [1, 2, 3]</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"><br /></span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">MOINCFG = Config # Flask любит только верхний регистр</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">SOMETHING_FLASKY = 'foobar'</span></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Давайте разберём это строка за строкой:</div>
<ol start="0">
<li style="text-align: justify;"> Мы объявляем кодировку конфигурационного файла; убедитесь, что ваш редактор использует ту же самую кодировку, особенно, если Вы используете не ASCII символы</li>
<li style="text-align: justify;">импортируем класс DefaultConfig из кода moin; в нём содержатся значения по умолчанию для всех настроек, что экономит ваш труд, так как Вы должны указать тут только те параметры, которые Вы хотите переопределить</li>
<li style="text-align: justify;">пустая строка для лучшего восприятия</li>
<li style="text-align: justify;">определяем новый класс Config, дочерний классу DefaultConfig. Это и есть настройки движка вики и он переопределяет значения из DefaultConfig.</li>
<li style="text-align: justify;">знак # указывает на комментарий в вашем конфиге. Эта строка, как и последующие строки в пределах Config имет отступ в 4 пробела, так как Python определяет блоки по отступам</li>
<li style="text-align: justify;">определяем атрибует Config'a c именем sometext и значением u'your value', где "u" указывает на то, что это строка юникода</li>
<li style="text-align: justify;">определяем атрибует Config'a c именем somelist и значением [1, 2, 3], это список с эементами 1, 2 и 3</li>
<li style="text-align: justify;">пустая строка для лучшего восприятия</li>
<li style="text-align: justify;">специальная строка "MOINCFG = Config" должна иметь именно такой вид по техническим причинам</li>
<li style="text-align: justify;">код в верхнем регистре находится в конце файла, вне класса Config и является настройкой фреймворка; обычно это что-то для Flask'a или его расширений</li>
</ol>
Реальный пример wikiconfig.py можно найти в каталоге docs/examples/config/<br />
<h2>
Настройка движка вики</h2>
<h3>
Настройка интерфейса пользователя</h3>
<h4>
Использование собственного шаблона snippets.html</h4>
<div style="text-align: justify;">
Пользовательский интерфейс или html элементы, которые чаще всего требуют настройки, определены как макрос в файле шаблона snippets.html.</div>
<div style="text-align: justify;">
Если Вы хотите настроить какие-то части, Вы должны сделать копию встроеннго файла MoinMoin/templates/snippets.html и настроить moin, чтобы он использовал вашу копию вместо встроенного файла.</div>
<div style="text-align: justify;">
Это делается передачей листа каталога с шаблонами, где moin будет искать шаблоны в первую очередь:</div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">template_dirs = ['path/to/my/templates',]</span></div>
<div style="text-align: justify;">
Для того<span style="font-family: "Courier New", Courier, monospace;">, <span style="font-family: inherit;">чтобы настроить что-то, обычно Вы должны добавить ваш код между {% macro ... %} и {% endmacro %}. Ниже об этом сказано более подробно.</span></span></div>
<h4 style="text-align: justify;">
<span style="font-family: "Courier New", Courier, monospace;"><span style="font-family: inherit;">Лого</span></span></h4>
<div style="text-align: justify;">
<span style="font-family: "Courier New", Courier, monospace;"><span style="font-family: inherit;">Для </span></span><span style="font-family: inherit;">замены логотипа MoinMoin на ваш логотип используйте следующий код:</span></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-family: inherit;">{% </span>macro logo() -%}</div>
<div style="text-align: justify;">
<img src=http://wiki.example.org/logos/my_logo.png" id="moin-img-logo" alt=Example logo"></div>
<div style="text-align: justify;">
{%- endmacro %}</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Рекомендуется так сделать, чтобы ваши пользователи могли легко распознать вики, на которой они сейчас находятся.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<i>Статические файлы (в том числе и логотипы) хранятся по адресу MoinMoin/static (логотипы хранятся в MoinMoin/static/logos)</i></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Кроме того, совсем не обязательно, чтобы в качестве логотипа у Вас было изображение - это может быть и просто текст.</div>
<div style="text-align: justify;">
Будьте уверены, что размер вашего изображения или текста соответствует теме, которую используют ваши пользователи вики. </div>
<div style="text-align: justify;">
<br /></div>
<h4 style="text-align: justify;">
Отображение информации о лицензии</h4>
<div style="text-align: justify;">
Если Вам нужно отобразить что-то вроде лицензионной информации вашего контента, используйте макрос:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">{# Лицензионная информация в нижнем колонтитуле #}</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">{% macro license_info() -%}</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">Всё содержимое вики находится под лицензией WTFPL.</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">{%- endmacro %}</span></div>
<div style="text-align: justify;">
<br /></div>
<h4 style="text-align: justify;">
Добавление кусков HTML</h4>
<div style="text-align: justify;">
В некоторых местах Вы можете добавить свои куски html в заголовок или тело темы:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">{# Дополнительные HTML теги в <head> #}</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">{% macro head() -%}</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">{%- endmacro %}</span></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">{# Дополнительные HTML теги перед #moin-header #}</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">{% macro before_header() -%}</span></div>
<span style="font-family: "Courier New",Courier,monospace;">{%- endmacro %}</span><br />
<br />
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">{# Дополнительные HTML теги после #moin-header #}</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">{% macro after_header() -%}</span></div>
<span style="font-family: "Courier New",Courier,monospace;">{%- endmacro %}</span><br />
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">{# Дополнительные HTML теги перед #moin-footer #}</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">{% macro before_footer() -%}</span></div>
<span style="font-family: "Courier New",Courier,monospace;">{%- endmacro %}</span><br />
<br />
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">{# Дополнительные HTML теги после #moin-footer #}</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">{% macro after_footer() -%}</span></div>
<span style="font-family: "Courier New",Courier,monospace;">{%- endmacro %}</span><br />
<br />
<h4>
Авторы и логотипы</h4>
<div style="text-align: justify;">
В конце вашей страницы вики обычно расположен какой-то текст и изображения, показывающие, что вики использует MoinMoin, Python, что MoinMoin лицензируется под GPL и т.д.</div>
<div style="text-align: justify;">
Если Вы запускаете публичный сайт, используя MoinMoin, мы будем благодарны, если Вы <i>сохраните</i> эти ссылки, особенно "MoinMoin powered".</div>
<div style="text-align: justify;">
Однако, если по какой-то причине Вы не можете этого сделать, можете спокойно изменить эти макросы для отображения чего-то другого:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">{# Ссылки на изображения в нижнем колонтитуле #}</span></div>
<span style="font-family: "Courier New",Courier,monospace;">{% macro creditlogos(start='<ul id="moin-creditlogos"><li>'|safe, end='</li></ul>'|safe, sep='</li><li>'|safe) %}</span><br />
<span style="font-family: "Courier New",Courier,monospace;">{{ start }}</span><br />
<span style="font-family: "Courier New",Courier,monospace;">{{ creditlogo('http://moinmo.in/', url_for('.static', filename='logos/moinmoin_powered.png'),
'MoinMoin powered', 'This site uses the MoinMoin Wiki software.') }}</span><br />
<span style="font-family: "Courier New",Courier,monospace;">{{ sep }}</span><br />
<span style="font-family: "Courier New",Courier,monospace;">{{ creditlogo('http://moinmo.in/Python', url_for('.static', filename='logos/python_powered.png'),
'Python powered', 'MoinMoin is written in Python.') }}</span><br />
<span style="font-family: "Courier New",Courier,monospace;">{{ end }}</span><br />
<span style="font-family: "Courier New",Courier,monospace;">{% endmacro %}</span><br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">{# Текстовые ссылки в нижнем колонтитуле #}</span><br />
<span style="font-family: "Courier New",Courier,monospace;">{% macro credits(start='<p id="moin-credits">'|safe, end='</p>'|safe, sep='<span>&bull;</span>'|safe) %}</span><br />
<span style="font-family: "Courier New",Courier,monospace;">{{ start }}</span><br />
<span style="font-family: "Courier New",Courier,monospace;">{{ credit('http://moinmo.in/', 'MoinMoin Powered', 'This site uses the MoinMoin Wiki software.') }}</span><br />
<span style="font-family: "Courier New",Courier,monospace;">{{ sep }}</span><br />
<span style="font-family: "Courier New",Courier,monospace;">{{ credit('http://moinmo.in/Python', 'Python Powered', 'MoinMoin is written in Python.') }}</span><br />
<span style="font-family: "Courier New",Courier,monospace;">{{ sep }}</span><br />
<span style="font-family: "Courier New",Courier,monospace;">{{ credit('http://moinmo.in/GPL', 'GPL licensed', 'MoinMoin is GPL licensed.') }}</span><br />
<span style="font-family: "Courier New",Courier,monospace;">{{ sep }}</span><br />
<span style="font-family: "Courier New",Courier,monospace;">{{ credit('http://validator.w3.org/check?uri=referer', 'Valid HTML 5', 'Click here to validate this page.') }}</span><br />
<span style="font-family: "Courier New",Courier,monospace;">{{ end }}</span><br />
<span style="font-family: "Courier New",Courier,monospace;">{% endmacro %}</span><br />
<br />
<h4>
Добавляем скрипты</h4>
Вы можете добавлять скрипты:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">{# Дополнительный Javascript #}</span><br />
<span style="font-family: "Courier New",Courier,monospace;">{% macro scripts() -%}</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><script type="text/javascript" src="http://example.org/cool.js"></script></span><br />
<span style="font-family: "Courier New",Courier,monospace;">{% endmacro %}</span><br />
<br />
<h4>
Добавляем CSS</h4>
Для того, чтобы применить изменения стилей, добавьте собственные css и переопределите стили, которые Вам не нравятся в основной теме:<br />
<span style="font-family: "Courier New",Courier,monospace;">{# Дополнительны Stylesheets (после theme css, до user css #}</span><br />
<span style="font-family: "Courier New",Courier,monospace;">{% macro stylesheets() -%}</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> <link media="screen" href="http://wiki.example.org/static/company.css" title="Company CSS" rel="stylesheet" /></span><br />
<span style="font-family: "Courier New",Courier,monospace;"> <link media="screen" href="http://wiki.example.org/static/red.css" title="Red Style" rel="alternate stylesheet" /></span><br />
<span style="font-family: "Courier New",Courier,monospace;"> <link media="screen" href="http://wiki.example.org/static/green.css" title="Green Style" rel="alternate stylesheet" /></span><br />
<span style="font-family: "Courier New",Courier,monospace;">{%- endmacro %}</span><br />
<br />
<div style="text-align: justify;">
Вы можете либо добавить обычные css, либо добавить выбор альтернативных css.</div>
Смотри:<br />
<ul>
<li><a href="http://www.w3.org/TR/CSS2/media.html" target="_blank">CSS media types</a></li>
<li><a href="http://www.alistapart.com/articles/alternate/" target="_blank">Альтернативные CSS</a></li>
</ul>
<div style="text-align: justify;">
Хороший способ протестировать стили - сперва использовать их как пользовательские CSS перед использованием их для широкой публики.</div>
<div style="text-align: justify;">
Обратите внимание, стили будут включены вне зависимости от того, какую тему выбрал пользователь, так что либо примените стили ко всем доступным темам, либо заставьте всех пользователей использовать одну и ту же тему, чтобы ваш CSS отображался корректно.</div>
<h4 style="text-align: justify;">
Отображение аватаров пользователей</h4>
<div style="text-align: justify;">
При желании moin может отображать аватары пользователей при помощи gravatar.com. Для того, чтобы это активировать используйте:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">user_use_gravatar = True</span></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Обратите внимание, что использование gravatar'a сопряжено с некоторыми проблемами личных данных:</div>
<ul style="text-align: justify;">
<li>для того, чтобы связать аватар с вашим e-mail на gravatar.com, Вы должны предоставить им свой e-mail адрес, который должен быть такой же, как указан в профиле пользователя вики</li>
<li>когда вики отображает аватар, URL будет использовать как ссылка на провайдер сервиса аватаров, так что они могут приблиительно знать, какие пользователи какой вики пользуются </li>
</ul>
<h3>
XStatic пакеты</h3>
<div style="text-align: justify;">
<a href="https://xstatic.readthedocs.org/en/latest/" target="_blank">XStatic</a> - стандарт пакетов для упаковки внешних статических файлов в качестве пакетов Python, чаще всего от сторонних производителей. Таким образом их можно будет легко использовать на разных ОС, не важно, имеют ли они систему управлени пакетами, или нет.</div>
<div style="text-align: justify;">
Во многих случаях эти внешние статические файлы обслуживаются кем-то другим (как jQuery библиотекой или другой js библиотекой) и мы определённо не хотим сливать их с нашим проектом.</div>
<div style="text-align: justify;">
Для MoinMoin нам требуются следующие XStatic пакеты в setup.py:</div>
<ul>
<li><a href="http://pypi.python.org/pypi/XStatic-jQuery" target="_blank">jquery</a> для jquery функциональности, загружаемой в файл шаблона base.html</li>
<li><a href="http://pypi.python.org/pypi/XStatic-jQuery-File-Upload" target="_blank">jquery_file_upload</a>, загружаемой в файл шаблона представления index. Она позволяет загружать несколько файлов одновременно.</li>
<li><a href="http://pypi.python.org/pypi/XStatic-CKEditor" target="_blank">ckeditor</a> используется в файле шаблона modify_text_html. WYSIWYG редактор, похожий на обычный текстовый процессор</li>
<li><a href="http://pypi.python.org/pypi/XStatic-svgweb" target="_blank">svgweb </a>используется в base.html для обеспечения SVG поддержки в большинстве браузеров</li>
<li><a href="http://pypi.python.org/pypi/XStatic-svg-edit-moin" target="_blank">svgedit_moin</a> загружается в modify_svg-edit. Это быстрый, основанный на javascript SVG редактор</li>
<li><a href="http://pypi.python.org/pypi/XStatic-TWikiDraw-moin" target="_blank">twikidraw_moin</a> - Java аплет, загружаемый из файла шаблона или modify_twikidraw. Это простой редактор изображений</li>
<li><a href="http://pypi.python.org/pypi/XStatic-AnyWikiDraw" target="_blank">anywikidraw</a> - Java аплет, загружаемый из файла шаблона или modify_anywikidraw. Он может быть использован для редактирования рисунков и диаграм на элементах.</li>
<li><a href="http://pypi.python.org/pypi/XStatic-multiDownload" target="_blank">jquery_multi_download</a> используется в шаблонах или представлении index для множественных параллельных загрузок.</li>
</ul>
Эти пакеты импортируются в wikiconfig: <br />
<span style="font-family: "Courier New",Courier,monospace;">from xstatic.main import XStatic</span><br />
<span style="font-family: "Courier New",Courier,monospace;">mod_names = ['jquery', 'jquery_file_upload',</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> 'ckeditor',
'svgweb', 'svgedit_moin',</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> 'twikidraw_moin',
'anywikidraw',</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> 'jquery_multi_download', ]</span><br />
<span style="font-family: "Courier New",Courier,monospace;">pkg = __import__('xstatic.pkg', fromlist=mod_names)</span><br />
<span style="font-family: "Courier New",Courier,monospace;">for mod_name in mod_names:</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> mod = getattr(pkg, mod_name)</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> xs = XStatic(mod, root_url='/static', provider='local', protocol='http')</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> serve_files.update([(xs.name, xs.base_dir)])</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><br /></span>
<br />
<div style="text-align: justify;">
В файле шаблона Вы можете получить доступ к файлам пакета по имени их модуля<span style="font-family: "Courier New",Courier,monospace;">:</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"><br /></span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">url_for('serve.files', name='имя модуля', filename='имя файла для загрузки')</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"><br /></span></div>
<h3 style="text-align: justify;">
Добавление <span style="font-family: "Courier New",Courier,monospace;">XStatic пакетов</span></h3>
<div style="text-align: justify;">
Следующий пример<span style="font-family: "Courier New",Courier,monospace;"></span> показывает как Вы можете активировать дополнительный пакет <a href="http://pypi.python.org/pypi/XStatic-MathJax" target="_blank">XStatic-MathJax</a>, который используется для mathml или формул latex в содержимом элемента.</div>
<div style="text-align: justify;">
Для этого:</div>
<ul>
<li>сперва выполните<br /><span style="font-family: "Courier New",Courier,monospace;">pip install xstatic-mathjax</span></li>
<li>добавьте mathjax в mod_names в файл wikiconfig</li>
<li>добавьте нужный фрагмент в base.html</li>
</ul>
<span style="font-family: "Courier New",Courier,monospace;"><script type="text/x-mathjax-config"></span><br />
<span style="font-family: "Courier New",Courier,monospace;">MathJax.Hub.Config({</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> extensions: ["tex2jax.js"],</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> jax: ["input/TeX","output/HTML-CSS"],</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> tex2jax: {inlineMath: [["$",</span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;">"$"</span>],["\\(","\\)"]]}</span><br />
<span style="font-family: "Courier New",Courier,monospace;">});</span><br />
<span style="font-family: "Courier New",Courier,monospace;"></script></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><script src="{{ url_for('serve.files', name='mathjax', filename='MathJax.js') }}"></script></span><br />
<h3>
Пользовательские темы</h3>
В случае, если Вы хотите сделать большие изменения в том, как MoinMoin отображает свои страницы, Вы можете также просто написать свою новую тему.<br />
<b>Предупреждение:</b> разработка своей собственный темы подразумевает что Вам придётся ещё и обслуживать её и обновлять её, что обычно подразумевает затраты времени.<br />
<i>Надо добавить подробностей про пользовательские темы</i><br />
<h3>
Аутентификация<i> </i></h3>
<div style="text-align: justify;">
MoinMoin использует настраиваемый список аутентификаторов auth, так что администратор может настроить кому он хочет дать возможность аутентифицироваться. Moin обрабатывает этот список слева направо.</div>
<div style="text-align: justify;">
Каждый аутентификатор является экземпляром определённого класса, настройка которого обычно происходит при помощи передаваемых именованных аргументов. Большинство из них имеют разумные настройки по умолчанию.</div>
<h4 style="text-align: justify;">
MoinAuth</h4>
<div style="text-align: justify;">
Это аутентификатор используемый moin по умолчанию, если Вы не хотите ничего больше настраивать. Пользователь входит заполняя форму входа, вводя имя пользователя и пароль, moin сравнивает хеш пароля с тем, который хранится в профиле пользователя, и если всё совпадает - пользователь аутентифицирован:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">from MoinMoin.auth import MoinAuth</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">auth = [MoinAuth()] # это значение по умолчанию!</span></div>
<h4 style="text-align: justify;">
HTTPAuthMoin</h4>
<div style="text-align: justify;">
При помощи HTTPAuthMoin moin обеспечивает базовую аутентификацию без помощи веб-сервера:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">from MoinMoin.auth.http import HTTPAuthMoin</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">auth = [HTTPAuthMoin(autocreate=True)]</span></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
При похожей настройке moin будет требовать аутентификации при помощи http заголовков. После этого браузер обычно показвает пользователю диалог входа, где у пользователя запрашивается имя пользователя и пароль. Оба передаются moin и сравниваются с хешем пароля, хранимым в профиле пользователя.</div>
<div style="text-align: justify;">
<b>Примечание: </b>при использовании HTTPAuthMoin браузер будет показывать диалог входа, так что пользователю придётся войти в вики перед её использованием.</div>
<h4 style="text-align: justify;">
GivenAuth</h4>
<div style="text-align: justify;">
При иcпользовании GivenAuth moin полагается на вебсервер, который производит аутентификацию пользователя а результат возвращает moin, обычно при помощи переменной окружения REMOTE_USER:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">from MoinMoin.auth import GivenAuth</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">auth = [GivenAuth(autocreate=True, coding='utf-8')]</span></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Использование этого метода имеет свои за и против:</div>
<ul style="text-align: justify;">
<li>Вы можете использовать только те расширения аутентификации, которые доступны для вашего веб-сервера</li>
<li>единственная информация, получаемая moin через REMOTE_USER - имя аутентифицированного пользователя, ничего больше. Так, например, для LDAP/AD Вы не получите дополнитульную информацию, хранящуюся в LDAP</li>
<li>Вы должны будете сами сохранить всё, что нужно, вручую, например, адрес электронной почты и т.п.</li>
</ul>
<div style="text-align: justify;">
Пожалуйста, обратите внимание, что Вы должны передать правильную кодовую страницу, чтобы moin мог декодировать имя пользователя в юникод при необходимости. Для переменной окружения, например, REMOTE_USER, кодировка может зависеть от вашей ОС 5</div>
<div style="text-align: justify;">
Если Вы не знаете правильную кодировку, попробуйте 'utf-8', 'iso-8859-1', и так далее</div>
<div style="text-align: justify;">
<i>Сделать: добавить стандартные кодировки для некоторых платформ, например, windows)</i></div>
<div style="text-align: justify;">
Чтобы это опробовать, измените конфигурацию, перезапустите moin и затем воспользуйтесь не ASCII именем пользователя (умлауты и т.д.). Если moin не рухнет (с ошибкой Unicode Error в логе) - значит Вы нашли правильную кодировку.</div>
<div style="text-align: justify;">
Для пользователей, настраивающих GivenAuth на Apache, пример файла настройки виртуального хоста можно посмотреть в docs/examples/deployment/moin-http-basic-auth.conf</div>
<h4 style="text-align: justify;">
OpenID</h4>
<div style="text-align: justify;">
Благодаря OpenID moin может использовать аутентификацию, проводимую некоторыми OpenID провайдерами (такими как Google, Yahoo, Microsoft и другими):</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">from MoinMoin.auth.openidrp import OpenIDAuth</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">auth = [OpenIDAuth()]</span></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
По умолчанию OpenID аутентификация принимает всех OpenID провайдеров. Если хотите, Вы можете настроить список провайдеров, которым хотите позволить проводить аутентификцию (т.е. тех из них, которым Вы доверяете), передав их URL'ы через именованый аргумент trusted_providers. Если оставить его пустым, moin будет принимать авторизацию от всех провайдеров:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"># Разрешаем только профили google:</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">auth = [OpenIDAuth(trusted_providers=['https://www.google.com/accounts/o8/ud?source=profiles'])]</span></div>
<div style="text-align: justify;">
Для того, чтобы пользователь мог воспользоваться OpenID, его OpenID должен быть сохранён в его профиле.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<i>Примечание: Если Вы собираетесь использовать эту аутентификацию, то Вам потребуются пакеты python-openid и python-ldap. Оба они у меня под FreeBSD 9.1 через pip не установились. Но их можно установить из портов: <a href="http://www.freshports.org/security/py-openid/" target="_blank">py-openid</a> и <a href="http://www.freshports.org/net/py-ldap2/" target="_blank">py-ldap2</a>. Единственная проблема в том, что создаваемое виртуальное окружение по умолчанию имеет флаг --no-site-packages, из-за чего виртуальное окружение не буедт использовать пакеты из стандартной установки. Для того, чтобы это исправить надо удалить или переименвать файл env/lib/python2.7/</i><i>no-global-site-packages.txt.</i></div>
<h4 style="text-align: justify;">
LDAPAuth</h4>
<div style="text-align: justify;">
При помощи LDAPAuth<i> </i>Вы можете проводить аутентификацию при помощи LDAP или Active Directory</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b>LDAPAuth c одним LDAP сервером</b></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Этот пример показывает как использовать LDAPAuth c одним LDAP/AD сервером:</div>
<div style="text-align: justify;">
<b> </b></div>
<div style="text-align: justify;">
<b> </b></div>
<span style="font-family: "Courier New",Courier,monospace;">from MoinMoin.auth.ldap_login import LDAPAuth</span><br />
<span style="font-family: "Courier New",Courier,monospace;">ldap_common_arguments = dict(</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # значения, приведённые ниже - значения по умолчанию</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # Вы можете удалить их, если они Вам не нравятся</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # примеры, приведённые в комментариях стандартны для</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # Active Directory или OpenLDAP</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> bind_dn='', # Мы можем использовать фиксированный пароль для</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # подключения к LDAP. Будьте осторожны если Вам нужно</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # использовать % в этих настройках, так как они </span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # используется как форматируемые строки. Вместо</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # этого используйте %%.</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> #bind_dn = 'binduser@example.org' # (AD)</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> #bind_dn = 'cn=admin,dc=example,dc=org' # (OpenLDAP)</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> #bind_pw = 'secret'</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # или мы можем использовать имя пользователя и</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # пароль, полученные от пользователя:</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> #bind_dn = '%(username)s@example.org'</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # DN, который мы используем для первого подключения (AD)</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> #bind_pw = '%(password)s'</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # пароль, который мы используем для первог подключения</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # или мы можем подключиться анонимно</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # (если это поддерживается вашим каталогом)</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # В любом случае, bind_dn и bind_pw должны быть определены</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> bind_pw='',</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> base_dn='', # base DN, который мы используем для поиска</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> #base_dn = 'ou=SOMEUNIT,dc=example,dc=org'</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> scope=2, # диапазон поиска (2 == ldap.SCOPE_SUBTREE)</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> referrals=0, # LDAP REFERRALS (0 для AD)</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> search_filter='(uid=%(username)s)',</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # ldap фильтр для поиска:</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> #search_filter = '(sAMAccountName=%(username)s)' # (AD)</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> #search_filter = '(uid=%(username)s)' # (OpenLDAP)</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # можно использовать и более сложные фильтры:</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # "(&(cn=%(username)s(memberOf=CN=WikiUsers,OU=Groups,DC=example,DC=org))"</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # некоторые имена атрибутов, которые мы будем использовать</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # для извлечения информации из LDAP (если не None,</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # если None, то атрибуты не будут извлечены из LDAP):</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> </span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"># зачастую 'givenName' - ldap атрибут имени</span> </span><br />
<span style="font-family: "Courier New",Courier,monospace;"> givenname_attribute=None,</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> # 'sn' - ldap атрибут фамилии</span> </span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span>surname_attribute=None, </span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"># 'displayName' - ldap атрибут псевдонима (aliasname)</span> </span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span>aliasname_attribute=None, </span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"># 'mail' - ldap атрибут email</span> </span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span>email_attribute=None, </span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"># callback функция вызывается для обработки email адреса</span> </span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span>email_callback=None, </span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"># кодировка, используемая для запросов и ответов ldap</span> </span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span>coding='utf-8', </span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span>timeout=10, # как долго ждём ответ от сервера [сек]</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"># использование Transport Layer Security:</span></span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> # 0 = Не используем, 1 = Пробуем, 2 = Обязательно</span> </span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span>start_tls=0, </span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span>tls_cacertdir=None,</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span>tls_cacertfile=None,</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span>tls_certfile=None,</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span>tls_keyfile=None,</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> # 0 == ldap.OPT_X_TLS_NEVER</span></span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> # (нужно для самоподписанных сертификатов)</span> </span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span>tls_require_cert=0, </span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"># установите в True для только одного подключения - </span></span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> # полезно если настроена для подключения под пользователем</span></span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> # при первой попытке</span> </span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span>bind_once=False, </span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> # задайте в True для автоматического создания / обновления</span></span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> # профилей пользователей</span> </span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span>autocreate=True, </span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"># отправлять сообщение "invalid username or password"</span></span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> # ("неверное имя пользователя или пароль") при входе в</span></span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> # систему или нет</span> </span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span>report_invalid_credentials=True, </span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span>)</span><br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"></span>ldap_authenticator1 = LDAPAuth(</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"># </span></span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;">URI </span></span></span>сервера </span></span></span>ldap / active directory</span></span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"></span> </span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span>server_uri='ldap://localhost', </span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span># используйте ldaps://server:636 url для ldaps,</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span># ldap://server для ldap без tls (и задайте set start_tls=0),</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span># ldap://server для ldap с tls (и задайте start_tls=1 или 2).</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> <span style="font-family: "Courier New",Courier,monospace;"></span># уникальное имя для ldap сервера, например</span></span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> # 'ldap_pdc' и 'ldap_bdc' (или 'ldap1' и 'ldap2')</span> </span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span>name='ldap1',</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"></span>**ldap_common_arguments # разложение общих аргументов</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span>)</span><br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"># в этом списке Вы можете указать несколько ldap аутентификаторов</span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"># или другие аутентификаторы </span></span><br />
<span style="font-family: "Courier New",Courier,monospace;">auth = [ldap_authenticator1, ] </span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"></span><br /></span>
<span style="font-family: "Courier New",Courier,monospace;"># используйте настройки пользователей (по желанию, см</span><br />
<span style="font-family: "Courier New",Courier,monospace;"># MoinMoin/config/multiconfig для значений по умолчанию)</span><br />
<span style="font-family: "Courier New",Courier,monospace;"># Возможно Вы захотите использовать user_checkbox_remove,</span><br />
<span style="font-family: "Courier New",Courier,monospace;"># user_checkbox_defaults, user_form_defaults,</span><br />
<span style="font-family: "Courier New",Courier,monospace;"># user_form_disable, user_form_remove. </span><br />
<span style="font-family: "Courier New",Courier,monospace;"><br /></span>
<br />
<div style="text-align: justify;">
<b> </b></div>
<div style="text-align: justify;">
<b>LDAPAuth</b> <b>c двумя LDAP серверами</b></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Этот пример показывает как использовать LDAPAuth c двумя LDAP/AD серверами, например, в случае когда у Вас есть основной и резервный сервера:</div>
<div style="text-align: justify;">
<br /></div>
<span style="font-family: "Courier New",Courier,monospace;"># ... всё как для одного сервера (до строки "auth =") ...</span><br />
<span style="font-family: "Courier New",Courier,monospace;">ldap_authenticator2 = LDAPAuth(</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> </span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"># URI сервера ldap / active для второго сервера</span> </span><br />
<span style="font-family: "Courier New",Courier,monospace;"> server_uri='ldap://otherldap', </span><br />
<span style="font-family: "Courier New",Courier,monospace;"> name='ldap2',</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> **ldap_common_arguments</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> )</span><br />
<span style="font-family: "Courier New",Courier,monospace;">auth = [ldap_authenticator1, ldap_authenticator2, ]</span><br />
<div style="text-align: justify;">
<br /></div>
<h4 style="text-align: justify;">
AuthLog</h4>
<div style="text-align: justify;">
AuthLog не является реальным аутертификатором в том смысле, что люди не могут через него залогиниться или выйти. Он лишь логирует информацию для отладки аутентификации:<br />
<span style="font-family: "Courier New",Courier,monospace;"><br />from MoinMoin.auth import MoinAuth<br />from MoinMoin.auth.log import AuthLog<br />auth = [MoinAuth(), AuthLog(),]</span><br />
<br />
Вот пример итогового лога:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">2011-02-05 16:35:00,229 INFO MoinMoin.auth.log:22 login: user_obj=<MoinMoin.user.User at 0x90a0f0c name:u'ThomasWaldmann' valid:1> kw={'username': u'ThomasWaldmann', 'openid': None, 'attended': True, 'multistage': None, 'login_password': u'secret', 'login_username': u'ThomasWaldmann', 'password': u'secret', 'login_submit': u''}<br /> 2011-02-05 16:35:04,716 INFO MoinMoin.auth.log:22 session: user_obj=<MoinMoin.user.User at 0x90a0f6c name:u'ThomasWaldmann' valid:1> kw={}<br /> 2011-02-05 16:35:06,294 INFO MoinMoin.auth.log:22 logout: user_obj=<MoinMoin.user.User at 0x92b5d4c name:u'ThomasWaldmann' valid:False> kw={}<br /> 2011-02-05 16:35:06,328 INFO MoinMoin.auth.log:22 session: user_obj=None kw={}</span><br />
<br />
Примечание: тут содержится важная информация, такая как имена пользователей и пароли. Убедитесь, что Вы используете это только для тестирования / отладки и удаляете после этого логи.<br />
<h4>
SMBMount</h4>
SMBMount не является реальным аутертификатором в том смысле, что люди не могут через него залогиниться или выйти. Вместо этого он получает имя пользователя и пароль и использует его для подключения SMB шар под этим пользователем.<br />
SMBMount полезен только для очень специфических приложений, например, в комбинации с хранилищем на файловом сервере:<br />
<br />
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">from MoinMoin.auth.smb_mount import SMBMount</span></div>
</div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">smbmounter = SMBMount(</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> # Вы можете удалить значения по умолчанию, если они Вам</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> # не нравятся. Смотрите более детально man mount.cifs</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> </span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"># (не умолчание) mount.cifs //server/share</span> </span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> server='smb.example.org', </span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> share='FILESHARE', # (не умолчание) mount.cifs //server/share</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> # (не умолчание) функция от имени пользователя</span></span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> # для определения точки монтирования</span> </span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> mountpoint_fn=lambda username: u'/mnt/wiki/%s' % username, </span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> </span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"># (не умолчание) имя пользователя для получения</span></span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> # uid, который используется для mount.cifs -o uid=...</span> </span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> dir_user='www-data', </span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> domain='DOMAIN', # (</span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;">не умолчание</span></span>) mount.cifs -o domain=...</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> dir_mode='0700', # (</span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;">умолчание</span></span></span>) mount.cifs -o dir_mode=...</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> file_mode='0600', # (</span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;">умолчание</span></span></span>) mount.cifs -o file_mode=...</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> iocharset='utf-8', # (</span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;">умолчание</span></span></span>) mount.cifs -o iocharset=...</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> #(попробуйте 'iso8859-1'</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> # если значение по умолчанию не работает)</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> coding='utf-8', # (</span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;">умолчание</span></span></span>) кодировка, которая</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> # используется для имени пользователя/пароля/командной</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> # строки (</span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;">попробуйте 'iso8859-1'</span></span><br />
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> # если значение по умолчанию не работает</span><span style="font-family: "Courier New",Courier,monospace;">)</span></div>
</div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> log='/dev/null', # (</span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;">умолчание</span></span></span>) файл лога для mount.cifs</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> )</span></div>
<div style="text-align: left;">
</div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">auth = [....., smbmounter] # Вам нужен реальный</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> # аутентификатор в этом списке перед smbmounter</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">smb_display_prefix = u"S:" # куда будет монтироваться</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> # //server/share для пользователей windows</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> # (только для целей отображения)</span></div>
<div style="text-align: justify;">
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"></span></div>
<br />
<i>Сделать: проверить, работает ли SMBMount как это описано</i><br />
<h3>
Безопасность передачи</h3>
<h4>
Личные данные</h4>
Некоторые из описаных методов аутентификации передают аутентификационные данные, такие как имя пользователя и пароль, в незашифрованной форме:<br />
<ul>
<li>MoinAuth: кода данные формы входа передаются moin, они содержат имя пользователя и пароль в незашифрованном виде</li>
<li>HTTPAuthMoin: ваш браузер передаёт имя пользователя и пароль в закодированной (но НЕ зашифрованной) форме при КАЖДОМ запросе</li>
<li>GivenAuth: проверьте потенциальные проблемы безопасности метода аутентификации, используемого вашим веб-сервером.</li>
<li>OpenID: проверьте сами</li>
</ul>
<h4>
Содержимое</h4>
http передаёт всё в открытом виде без какого либо шифрования<br />
<h4>
Шифрование</h4>
Передача незашифрованных данных может создать кучу проблем в разных случаях. Мы рекомендуем Вам использовать зашифрованные подключения, такие как https, VPN или ssh тунель.<br />
Для публичных вики с очень низкими потребностями безопасности может быть не нужно шифровать передаваемые данные, но всё равно ещё остаётся потребность шифрования личных данных.<br />
При использовании незашифрованных подключений пользователи вики должны использовать уникальный пароль, а не использовать пароли, которые он использует для других целей.<br />
<h3>
Безопасность пароля</h3>
<h4>
Сила пароля</h4>
Как Вы можете знать, многие пользователи не умеют выбирать хорошие пароли, а многие ещё и используют очень лёгкие для взлома пароли. Чтобы помочь пользователям выбрать хороший пароль moin имеет встроенную функцию проверки пароля, активированная по умолчанию, которая проверяет качество пароля, чтобы пользователи не могли выбрать лёгкий для взлома пароль.<br />
Если у Вашего сайта низкие требования к безопасности, то эту функцию можно отключить:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">password_checker = None # не производить проверку пароля</span><br />
<br />
Обратите внимание, что встроенная функция делает лишь базовые проверки, то есть не использует словарь плохих паролей.<br />
<h4>
Хранение паролей</h4>
Moin никогда не хранит пароли пользователей вики в открытом виде, вместо этого использует криптографические хеши паролей, получаемы при помощи библиоткеки <a href="http://packages.python.org/passlib/" target="_blank">passlib</a>. Документация passlib рекомендует 3 схемы хеширования, обеспечивающие хороший уровень безопасности: sha512_crypt, pbkdf2_sha512 и bcrypt (bcrypt требует ещё дополнительные бинарные пакеты, смотрите библиотеку passlib).<br />
По умолчанию мы используем sha512_crypt хеши со значениями по умолчанию (это тот же алгоритм, который использется в moin>=1.9.7)<br />
В случае если вход в систему занимает слишком много времени или Вы по другой причине хотите заменить генератор хешей, обращайтесь к документации passlib. Moin позволяет Вам настроить параметр CryptContext библиотеки passlib в конфиге вики (вот пример по умолчанию)5<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">passlib_crypt_context = dict(</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> schemes=["sha512_crypt",],</span><br />
<span style="font-family: "Courier New",Courier,monospace;">)</span><br />
<br />
<h3>
Авторизация</h3>
Moin использует списки контроля доступа (ACL) для определения того, кто что может делать.<br />
Обратите внимание, что вики обычно часто используют так назыаемую "мягкую безопасность", что означает, что они с одной стороны дают полную свободу пользователям, но в то же время предоставляют возможность отменить любой приченённый ущерб.<br />
"Жёсткая безопасность" подразумевает, что какие-то элементы можно заблокировать, предотвратив приченение ущерба.<br />
Конфигурация moin по умолчанию старается сочетать как "мягкую", так и "жёсткую" безопасность. Однако Вам могут потребоваться другие настройки, в зависимости от ситуации, с которой столкнулись администратор, хозяин или пользователи вики.<br />
Так что помните:<br />
<ul>
<li>если ваша вики довольно открыта, Вы можете разрешить пользователям легко вносить в неё информацию, например, исправлять опечатки. Однако, некоторые пользователи могут использовать вашу вики для размешения спама, хотя Вы и сможете отменить его добавление позже.</li>
<li>если ваша вики скорее закрыта, то есть Вы требуетет от пользователей сперва создать себе аккаунт, для того, чтобы он мог вносить в неё изменения, то Вы будете получать меньший вклад от пользователей, но и зато меньше спама.</li>
</ul>
<h4>
ACL для функций </h4>
Этот ACL управляет доступом к некоторым специфическим функциям / представлениям moin:<br />
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"># значение по умолчанию функции acl_rights_functions приведено</span></div>
</div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"># тут для справки, Вам, скорее всего, не потребуется его менять:</span></div>
<div style="text-align: justify;">
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">#acl_rights_functions = ['superuser', 'notextcha', ]
acl_functions=u'+YourName:superuser TrustedEditorGroup:notextcha'</span></div>
<br />
Поддерживаемые возможности (права):<br />
<ul>
<li>superuser - пользователь с функциями администратора. Давайте такие права только доверенным пользователям</li>
<li>notextcha - если у Вас активирован TextChas, пользователи с notextcha не будут получать вопрос. Давайте такие права только доверенным пользователям, которые регулярно вносят правки в вашу вики</li>
</ul>
<i>Примечание: то есть, для того, чтобы дать кому-то какие-то права (суперпользоателя или notextcha)</i>, <i>Вы должнны вручную в файл конфигурации добавить строку acl_functions, где указать нужные имена пользователей.</i><br />
<ul>
</ul>
<h4>
ACL контента</h4>
Эти ACL управляют доступом к контенту, который хранится в вики; они настраиваются для каждого хранилища (см соответствующую документацию) и, по желанию, для метаданных:<br />
<br />
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"># значение acl_rights_contents тут для справки</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"># Вам, скорее всего, не потребуется его менять:</span></div>
</div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">#acl_rights_contents = ['read', 'write', 'create', 'destroy', 'admin', ]</span></div>
<div style="text-align: justify;">
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">... backend configuration ...</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">... before=u'YourName:read,write,create,destroy,admin',</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">... default=u'All:read,write,create',</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">... after=u'',</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">... hierarchic=False,</span></div>
<br />
Обычно у Вас будут before, on item, default и after, которые обрабатываются именно в таком порядке. ACL default используется только в случае, если в метаданных не определено другого ACL для этого элемента (<a href="https://moin-20.readthedocs.org/en/latest/_images/graphviz-879e1883f1a5d3e966f5395ca5370733a7f16200.png" target="_blank">диаграмма по ссылке</a>).<br />
Как использовать brfore/default/after:<br />
<ul>
<li>before обычно используется для принуждения чего-либо, например, если Вы хотите какому-то администратору все права</li>
<li>default используется в случае, если не задан специальный ACL в метаданных элемента</li>
<li>after используется реже, обычно в случае когда надо "не забыть что-то, если только что-то другое не определено"</li>
</ul>
При настройке ACL контента, Вы можете выбрать между "плоской", станадрной обработке ACL и иерархической обработкой ACL. Иерархическая обработка подразумевает, что подэлементы наследуют ACL от родительских элементов, если ACL не определён для них самих.<br />
Обратите внимание, что хотя иерархическая обработка обычно более удобна в некоторых случаях, тем не менее, она делает систему гораздо сложнее. Вы должны быть очень внимательны с изменениями ACL, которые происходят в результате изменения иерархии, когда Вы создаёте, переименовываете или удаляете элементы.<br />
Поддерживаемые возможности (права):<br />
<ul>
<li>read - чтение информации</li>
<li>write - запись (редактирование) информации</li>
<li>create - создание новых элементов</li>
<li>destroy - полное уничножение элемента, должно быть разрешено только пользователям, которым Вы на <b>100% доверяете</b></li>
<li>admin - изменение (создание, удаление)<b> </b>ACL для элементов, должно быть разрешено только пользователям, которым Вы на <b>100% доверяете</b></li>
</ul>
<h4>
ACL - <b> </b>специальные группы</h4>
В дополнение к группам, поставляемым group backend, есть некоторые имена групп, доступные в ACL:<br />
<ul>
<li>All - виртуальная группа, содержащая всех пользователей</li>
<li>Known - виртуальная группа, содержащая всех залогинившихся пользователей</li>
<li>Trusted - виртуальная группа, содержащая всех залогинившихся пользователей, которые произвели вход "доверенным" методом аунтентификации</li>
</ul>
<h4>
ACL - базовый синтаксис</h4>
ACL - это строка юникода с одной или более записью контроля доступа, с разделителями пробелами.<br />
Каждая запись - набор, разделённый двоеточиями, двух значений:<br />
<ul>
<li>слева находится разделённый запятыми список пользователей / групп</li>
<li>справа находится разделённый запятыми список прав для этих пользователей / групп</li>
</ul>
ACL обрабатываются слева направа, где учитывается первое совпадение слева. Например:</div>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">u"SuperMan:read,write,create,destroy,admin All:read,write"</span></div>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
Если SuperMan на данный момент вошёл в систему и moin обрабатывает даный ACL, то он обнаружит совпадение уже с первым элементом. Если moin хочет знать, может ли этот пользователь уничтожить элемент, то ответ будет "да", так как destroy - одно из прав, которые перечислены в правой части этого элемента.</div>
<div style="text-align: justify;">
Если JoeDoe на данный момент вошёл в систему и moin обрабатывает этот ACL, то с первым элементом совпадения не произойдёт, так что moin двинется дальше вправо и посмотрит на вторую запись. Тут у нас указано имя группы All (a JoeDoe очевидно является членом этой группы), так что этот элемент нам подходит.</div>
<div style="text-align: justify;">
Если moin хочет знать, может ли этот польователь уничтожать элементы, ответом будет "нет", так как это право не указано среди доступных прав для этой группы. Если moin хочет знать, имеет ли этот пользователь право на запись - ответ будет "да".</div>
<div style="text-align: justify;">
<b>Примечания:</b></div>
<div style="text-align: justify;">
<ul>
<li>Как следствие обработки слева направо и поиска первого совпадения, Вы должны расположить ваши элементы ACL начиная с более детальных, заканчивая более общими. Обычно этот будет такой порядок:</li>
<ul>
<li>имя пользователя</li>
<li>специальные группы</li>
<li>более общие группы</li>
<li>Trusted</li>
<li>Known</li>
<li>All</li>
</ul>
<li>Не размещайте пробелы внутри элемента ACL, если только это не является частью имени пользователя или группы</li>
<li>Право, не заданное явно - не выдано</li>
<li>Для большинства ACL есть встроенные значения по умолчанию, которые дают ограниченные права</li>
</ul>
<h4>
ACL - префиксы элементов</h4>
Для того, чтобы сделать систему более гибкой, есть два способа изменить элементы ACL: префиксы + и -.<br />
Если Вы используете один из двух префиксов, MoinMoin будет искать и имя пользователя и пароль, и должны будут совпасть и то и другое, или moin перейдёт к следующему элементу.<br />
+ означает, что MoinMoin должен выдать разрешение(я), заданные справа<br />
- означает, что MoinMoin не выдаёт разрешение(я), заданные справа<br />
Например:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">u"+SuperMan:create,destroy,admin -Idiot:write All:read,write"</span><br />
<br />
Если SuperMan на данный момент вошёл в систему и moin хочет узнать, имеет ли он право на уничтожение элемента, то он найдёт совпадение с перым элементом, так как совпадут имя пользователя <b>и</b> искомое разрешение. Так как префиксом является +, то ответом будет "да". Если moin хочет знать, имеет ли он право на запись, то первый элемент нам не подойдёт, так как нет совпадения со стороны прав, и moin перейдёт к следующему элементу. Он тоже не подойдёт и moin перейдёт к третьему элементу. Конечно, SuperMan является членом группы All, так что тут совпадение будет. Так как право write указано среди выданных прав, ответом будет "да".<br />
Если Idiot на данный момент вошёл в систему и moin хочет знать, имеет ли он право на запись, то совпадение произойдёт со вторым элементом. Так как префиксом является -, то ответом будет "нет" и третий элемент даже не будет рассматриваться.<br />
<b>Примечания:</b><br />
<ul>
<li>Обычно Вы будете использовать эти модификаторы в случае, если большая часть прав для данного пользователя должна быть определена позже, но некая группа или пользователь должны иметь права, несколько отличающиеся от этих прав</li>
</ul>
<h4>
<b>ACL - записи по умолчанию</b></h4>
Есть специальная ACL запись, default, которая используется в качестве ACL по умолчанию.<br />
Это полезно в случае если Вы хотите использовать по большей части ACL по умолчанию, но с некоторыми модификациями, однако Вы не хотите указывать эту ACL каждый раз и Вы так же хотите иметь возможность изменить ACL по умолчанию, не редактируя её во многих элементах.<br />
Пример:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">u"-NotThisGuy:write Default"</span><br />
<br />
Это будет работать как обычно, за исключением того, что NotThisGuy никогда не получит прав на зпись.<br />
<h3>
Анти-спам</h3>
<h4>
TextChas</h4>
TextCHA - текстовая альтернатива капче. MoinMoin использует её для предотвращения спама в вики и её эффективность вполне доказана.<br />
Возможности:<br />
<ul>
<li>когда регистрируется новый пользователь или сохраняется элемент она может задать случайный вопрос для проверки антибот</li>
<li>moin сравнивает полученный ответ с регулярным выражением</li>
<li>вопросы и ответы можно настроить в конфиге вики</li>
<li>поддерка нескольких языков: пользователь получает вопрос на своём языке или на английском по умолчанию, в зависимоитс от доступности вопросов и ответов на языке пользователя.</li>
</ul>
<h4>
Настройка TextCha</h4>
Советы для настройки:<br />
<ul>
<li>имейте один числовой, один буквенный ответ</li>
<li>задавайте вопрос, на который сможет ответить типичный пользователь вашей вики</li>
<li>Не задавайте слишком сложные вопросы</li>
<li>Не задавайте "вычисляемые" вопросы, типа "1+1" или "2+2"</li>
<li>Не задавайте слишком очевидные вопросы</li>
<li>Не делитесь вопросами с другими сайтами и не копируйте их оттуда (или спамеры смогут под это подстроиться)</li>
<li>Вы должны как минимум задать textcha для английского языка или вашего языка пользователя, если это не английский, так как иначе возникнет ошибка, если MoinMoin не найдёт textcha на языке пользователя.</li>
</ul>
В вашем конфиге вики используйте что-то вроде этого:</div>
<div style="text-align: justify;">
</div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">textchas = {</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> 'en': { # ukegst английские примеры textchas</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> # (не исользуйте их!)</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> u"Enter the first 9 digits of Pi.": ur"3\.14159265",</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> u"What is the opposite of 'day'?": ur"(night|nite)",</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> # ...</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> },</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> 'de': { # немецкие textchas</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> u"Gib die ersten 9 Stellen von Pi ein.": ur"3\.14159265",</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> u"Was ist das Gegenteil von 'Tag'?": ur"nacht",</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> # ...</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> },</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> # Вы можете добавить и другие языки</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">}</span></div>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
Обратите внимание, что пользователи с notextcha ACL не будут получать эти вопросы.</div>
<div style="text-align: justify;">
<h3>
Секреты</h3>
Moin использует секреты для шифрования или подписывания чего-то вроде:<br />
<ul>
<li>textchas</li>
<li>билеты (tickets)</li>
</ul>
Секреты - длинные случайные строки, которые <b>не</b> используются для ваших паролей. <b>Не</b> используйте строки из примера, так как они не являются секретными, ведь они - часть документации moin. Создайте свои собственные секреты:</div>
<div style="text-align: justify;">
<br /></div>
<span style="font-family: "Courier New",Courier,monospace;"> secrets = {</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> 'security/textcha': 'kjenrfiefbeiaosx5ianxouanamYrnfeorf',</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> 'security/ticket': 'asdasdvarebtZertbaoihnownbrrergfqe3r',</span><br />
<span style="font-family: "Courier New",Courier,monospace;">}</span><br />
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Если Вы не настроите эти секреты, moin это обнаружит и будет использовать SECRET_KEY Flask'a вместо них.</div>
<div style="text-align: justify;">
<h3>
Группы и словари</h3>
Moin может получить информацию групп и словарей из поддерживаемого хранилища, такого как конфигурация вики или элементов вики.<br />
Группа - это список имён в юникоде. Она может использоваться для разных целей: какое-нибудь приложение может поределить группы пользователей для использования в ACL.<br />
Словарь отображает юникодовые ключи на юникодовые значения. Он тоже может использоваться для разных приложений. На данный момент он не используется самим moin.<br />
<h4>
Конфигурация бэкэнда групп</h4>
Бэкэнд WikiGroups получает группы из элементов ваики и используется по умолчанию:<br />
<span style="font-family: "Courier New",Courier,monospace;"><br /></span><span style="font-family: "Courier New",Courier,monospace;">def groups(self, request):</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> from MoinMoin.datastruct import WikiGroups</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> return WikiGroups(request)</span><br />
<br />
<br />
Бэкэнд ConfigGroups использует группы, определённые в конфигурационном файле:<br />
<br />
<div style="text-align: left;">
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> def groups(self, request):</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> from MoinMoin.datastruct import ConfigGroups</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> # Группы определяются тут.</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> groups = {u'EditorGroup': [</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> u'AdminGroup', u'John', u'JoeDoe', u'Editor1'],</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> u'AdminGroup': [u'Admin1', u'Admin2', u'John']</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> }</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">return ConfigGroups(request, groups)</span></div>
</div>
<br />
CompositeGroups может использовать, в большей части, любую комбинацию бэкэндов. Вот пример использования комбинаци WikiGroups и ConfigGroups:<br />
<br />
<br />
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> def groups(self, request):</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"><tt> </tt>from MoinMoin.datastruct import ConfigGroups, WikiGroups, CompositeGroups</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> groups = {u'EditorGroup': [</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> u'AdminGroup', u'John', u'JoeDoe', u'Editor1'],</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> u'AdminGroup': [</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> u'Admin1', u'Admin2', u'John']}</span></div>
<div style="text-align: left;">
</div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"># Тут используется конфигурация ConfigGroups и WikiGroups.</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"># Обратите внимание на важность порядка! Так как ConfigGroups</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"># упомянут первым, EditorGroup будет получен из него, не из</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"># WikiGroups.</span></div>
<div style="text-align: left;">
</div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">return CompositeGroups(request,</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> ConfigGroups(request, groups),</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> WikiGroups(request))</span></div>
<h4>
Конфигурация бэкэнда Dict</h4>
WikiDicts бэкэнд получает словари из элементов вики и использует их по умолчанию:<br />
<br />
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> def dicts(self, request):</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> from MoinMoin.datastruct import WikiDicts</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> return WikiDicts(request)</span></div>
<br />
<br />
ConfigDicts бэкэнд использует словари, определённые в конфигурационном файле<br />
<br />
<br />
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> def dicts(self, request):</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> from MoinMoin.datastruct import ConfigDicts</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> dicts = {u'OneDict': {u'first_key': u'first item',</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> u'second_key': u'second item'},</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> u'NumbersDict': {u'1': 'One',
u'2': 'Two'}</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> }</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> return ConfigDicts(request, dicts)</span></div>
<br />
<br />
CompositeDicts бэкэнд может использовать комбинацию бэкэндов. Вот пример:<br />
<br />
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">def dicts(self, request):</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> from MoinMoin.datastruct import ConfigDicts, WikiDicts, CompositeDicts</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> dicts = {u'OneDict': {u'first_key': u'first item',</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> u'second_key': u'second item'},</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> u'NumbersDict': {u'1': 'One',
u'2': 'Two'}}</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> return CompositeDicts(request,</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> ConfigDicts(request, dicts),</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> WikiDicts(request))</span></div>
<br />
<br />
<h3>
Хранилище</h3>
MoinMoin поддерживает бэкэнд хранилищ как разные способы хранения элементов вики. Настройка хранилищ сложна и многослойна и включает:<br />
<ul>
<li>router middleware, который отправляет часть пространства имён соответствующему бэкэнду</li>
<li>middleware проверки ACL, который позволяет нам убедиться, что никто не получит доступ к тому, к чему не надо</li>
<li>примесь индексирования (index mixin), которая индексирует некоторые данные автоматически при записи, так что эти элементы можно быстрее получить</li>
<li>бэкэнд хранения, который хранит элементы вики</li>
</ul>
<h4>
create_simple_mapping</h4>
Это вспомогательная функция, которая облегчает настройку хранения. Она помогает:<br />
<ul>
<li>Создать простую настройку, которая использует 3 бэкэнда хранения для следующих частей пространства имён:</li>
<ul>
<li>содержание</li>
<li>профили пользователей</li>
</ul>
<li>настроить ACL, защищающая эти части пространства имён</li>
<li>настроить router middleware, который направляет к этим частям пространства имён</li>
<li>настраивает примесь индексирования</li>
</ul>
Вызвать её можно так:<br />
<br />
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">from MoinMoin.storage import create_simple_mapping</span></div>
<div style="text-align: left;">
</div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">namespace_mapping, acl_mapping = create_simple_mapping(</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> uri=...,</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> content_acl=dict(before=...,</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> default=...,</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> after=...,</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> hierarchic=..., ),</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> user_profile_acl=dict(before=...,)</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> default=...,</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"> after=..., ),</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">)</span></div>
<br />
uri зависит от типа бэкэнда хранилища и хранит то, что Вы хотите использовать, см. ниже. Обычно это URL подобная строка такой формы:</div>
<div style="text-align: justify;">
<ul>
</ul>
</div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">stores:fs:/srv/mywiki/%(nsname)s/%(kind)s</span></div>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
stores - имя бэкэнда, за которым идёт двоеточие, за которым идёт спецификация хранилища. fs - имя хранилища, за которым идёт спецификация, актуальная для fs хранилища (файловой системы), то есть путь с подстановками.</div>
<div style="text-align: justify;">
%(nsname)s будет замещено content или userprofiles для соответствующего бэкэнда. %(kind)s будет замещено meta или data.</div>
<div style="text-align: justify;">
В нашем случае созданное отображение будет выглядеть так:</div>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
<pre>+----------------+-----------------------------+
| Namespace part | Filesystem path for storage |
+----------------+-----------------------------+
| / | /srv/mywiki/content/ |
+----------------+-----------------------------+
| /UserProfiles/ | /srv/mywiki/userprofiles/ |
+----------------+-----------------------------+</pre>
</div>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
content_acl и user_profile_acl - это словари, определяющие ACL для этой части пространства имён (содержимое, профиль пользователя). См документацию про ACL.</div>
<div style="text-align: justify;">
<h4>
</h4>
<h4>
protecting middleware</h4>
Возможности:<br />
<ul>
<li>защищает доступ к нижним слоям хранилища ACL'ем</li>
<li>позволяет убедиться, что не возникнет проблем с безопасностью ACL, даже если есть проблемы с верхними уровнями</li>
<li>Если Вы используете create_simple_mapping, Вы всего лишь передаёте ACL параметры; middleware будет автоматически настроен moin</li>
</ul>
<h4>
routing middleware</h4>
Возможности:<br />
<ul>
<li>перенаправляет доступ к различным бэкэндам в зависимости от имени элемента</li>
<li>в терминах POSIX это что-то вроде fstab/mount</li>
<li>если Вы используете create_simple_mapping, router middleware будет автоматически настроен moin</li>
</ul>
<h4>
indexing middleware</h4>
Возможности:<br />
<ul>
<li>обслуживает индекс для важных значений метаданных</li>
<li>ускоряет поиск / выборку элементов</li>
<li>упрощает возможность организации нижних слоёв</li>
<li>indexing middleware будет настроен автоматически moin</li>
</ul>
<h4>
stores backend</h4>
Это бэкэнд, который связывает вместе 2 хранилища в бэкэнд: один для метаданных, другой для данных<br />
<h4>
хранилище fs</h4>
Возможности:<br />
<ul>
<li>хранение в файловой системе</li>
<li>хранение метаданных и данных в разных файлах/каталогах</li>
</ul>
Настройка:</div>
<br />
<span style="font-family: "Courier New",Courier,monospace;">from MoinMoin.storage import create_simple_mapping</span><br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">data_dir = '/srv/mywiki/data'</span><br />
<span style="font-family: "Courier New",Courier,monospace;">namespace_mapping, acl_mapping = create_simple_mapping(</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> uri='stores:fs:{0}/%(nsname)s/%(kind)s'.format(data_dir),</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> content_acl=dict(</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> before=u'WikiAdmin:read,write,create,destroy',</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> default=u'All:read,write,create',</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> after=u'', ),</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> user_profile_acl=dict(</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> before=u'WikiAdmin:read,write,create,destroy',</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> default=u'',</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> after=u'', ),</span><br />
<span style="font-family: "Courier New",Courier,monospace;">)</span><br />
<pre></pre>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
<h4>
хранилище sqla </h4>
Возможности:<br />
<ul>
<li>хранение данных в (SQL) БД/таблице</li>
<li>может либо использовать 1 БД на хранилище или 1 таблицу на хранилище, в этом случае Вы должны дать таблицам разные имена</li>
<li>использует sqlalchemy (без ORM) для абстракции БД</li>
<li>поддерживает множество типов БД, например:</li>
<ul>
<li>sqlite (по умолчанию, встроена в Python)</li>
<li>postgresql</li>
<li>mysql</li>
<li>и другие, смотри документацию sqlalchemy</li>
</ul>
</ul>
uri для create_simple_mapping выглядит как-то так:<br />
<div style="text-align: left;">
</div>
<div style="text-align: left;">
<span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;">stores:sqla:sqlite:////srv/mywiki/data/mywiki_%(nsname)s_%(kind).db</span></span></div>
</div>
<div style="text-align: left;">
<span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;">stores:sqla:sqlite:////srv/mywiki/data/mywiki_%(nsname)s.db::%(kind)s</span></span></div>
<div style="text-align: left;">
<span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;">stores:sqla:mysql://myuser:mypassword@localhost/mywiki_%(nsname)s::%(kind)s</span></span></div>
<div style="text-align: left;">
<span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;">stores:sqla:postgres://myuser:mypassword@localhost/mywiki_%(nsname)s::%(kind)s</span></span></div>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
<br />
uri после sqla имеет следующую форму: DBURI::TABLENAME<br />
Пожалуйста, обратитесь к документации sqlalchemy на тему части DBURI.<br />
Передайте пользователю myuser (c паролем mypassword) полный доступ к этим БД.<br />
<h4>
хранилище sqlite</h4>
Возможности:<br />
<ul>
<li>напрямую общается с sqlite, без использования sqlalchemy</li>
<li>хранит данные в sqlite БД, то есть в одном файле</li>
<li>может либо использовать 1 БД на хранилище или 1 таблицу на хранилище, в этом случае Вы должны дать таблицам разные имена</li>
<li>может по желанию сжимать данные при помощи zlib. По умолчанию уровень сжатия 0, то есть данные не сжимаются.</li>
</ul>
uri для create_simple_mapping будет выглядеть следующим образом:</div>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">stores:sqlite:/srv/mywiki/data/mywiki_%(nsname)s_%(kind)s.db</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">stores:sqlite:/srv/mywiki/data/mywiki_%(nsname)s.db::%(kind)s</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">stores:sqlite:/srv/mywiki/data/mywiki_%(nsname)s.db::%(kind)s::1</span></div>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
uri часть после "sqlite:" имеет следующую форму: PATH::TABLENAME::COMPRESSION. В качестве разделителя используется ::, чтобы обеспечить поддержку windows, где : может использоваться в пути после имени диска.</div>
<div style="text-align: justify;">
<h4>
хранилище kc </h4>
Возможности:<br />
<ul>
<li>использует Kyoto Cabinet файл для хранения данных</li>
<li>очень быстрое</li>
<li>однопроцессное и локальное</li>
</ul>
uri для create_simple_mapping выглядит так:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">stores:kc:/srv/mywiki/data/%(nsname)s_%(kind)s.kch</span></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Обратитесь к документации kyoto cabinet на тему того, что должно быть после kc:.</div>
<div style="text-align: justify;">
Если Вы используете kc для встроенного сервера moin, Вы не можете использовать перезагрузчик (reloader). Отключите эту опцию в командной строке:</div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">moin moin -r</span></div>
<div style="text-align: justify;">
<h4>
хранилище kt</h4>
Возможности:<br />
<ul>
<li>использует Kyoto Tycoon сервер для хранения</li>
<li>быстрый</li>
<li>многопроцессорный, локальный или удалённый</li>
</ul>
<i>Сделать: добавить пример конфигурации хранилища</i></div>
<div style="text-align: justify;">
<h4>
хранилище в памяти</h4>
Возможности:<br />
<ul>
<li>держит всё в ОЗУ</li>
<li>если ваша система или moin падает, все данные будут потеряны, так что определённо не стоит использовать это для продакшена</li>
<li>лучше всего предназначено для тестирования</li>
<li>только один процесс</li>
</ul>
<i>Сделать: добавить пример конфигурации хранилища</i></div>
<div style="text-align: justify;">
<h4>
бэкэнд файлового сервера</h4>
Возможности:<br />
<ul>
<li>предоставляет часть файловой системы как хранилище только для чтения элементов вики:</li>
<ul>
<li>файлы отображаются как элементы вики</li>
<ul>
<li>с одной ревизией</li>
<li>с таким количеством метаданных, сколько может быть сохранено в метаданных AC</li>
</ul>
<li>каталоги будут отображаться как элементы индекса, содержащие ссылки на их содержимое</li>
</ul>
<li>может быть полезно вместе с псевдо-аутентификатором SMBMount</li>
</ul>
<h3>
Настройка почты</h3>
<h4>
отправка почты</h4>
Moin может по желанию отправлять e-mail. Возможные использования:<br />
<ul>
<li>отправка уведомлений об изменениях элементов</li>
<li>позволяет восстановить забытый пароль</li>
</ul>
Вам нужно задать несколько настроек для того, чтобы можно было отправлять почту:</div>
<span style="font-family: "Courier New",Courier,monospace;"><br /> <br /> # адрес "from:" [Unicode]</span><br />
<span style="font-family: "Courier New",Courier,monospace;">mail_from = u"wiki <wiki@example.org>"</span><br />
<span style="font-family: "Courier New",Courier,monospace;"># a) использование SMTP сервера, например, "mail.provider.com"</span><br />
<span style="font-family: "Courier New",Courier,monospace;"># (None чтобы отключить отправку почты)</span><br />
<span style="font-family: "Courier New",Courier,monospace;">mail_smarthost = "smtp.example.org"</span><br />
<span style="font-family: "Courier New",Courier,monospace;"># если Вы используете SMTP AUTH на вашем mail_smarthost:</span><br />
<span style="font-family: "Courier New",Courier,monospace;">#mail_username = "smtp_username"</span><br />
<span style="font-family: "Courier New",Courier,monospace;">#mail_password = "smtp_password"</span><br />
<span style="font-family: "Courier New",Courier,monospace;"># b) альтернативно использованию SMTP,</span><br />
<span style="font-family: "Courier New",Courier,monospace;"># Вы можете использовать инструмент командной строки sendmail:</span><br />
<span style="font-family: "Courier New",Courier,monospace;">#mail_sendmail = "/usr/sbin/sendmail -t -i"</span><br />
<ul>
</ul>
<div style="text-align: justify;">
<i>Сделать: описать настройку более подробно</i></div>
<div style="text-align: justify;">
<h4>
</h4>
<h4>
Верификация e-mail адреса</h4>
Во время создания аккаунта Moin может потребовать от нового пользователя подтвердить свой адрес электронной почты, нажав на ссылку в отправленном по этому адресу письме.<br />
Убедитесь, что Moin может отправлять электронную почту (см предыдущий раздел) и добавьте следующую строку в ваш конфигурационный ффайл:<br />
<span style="font-family: "Courier New",Courier,monospace;">user_email_verification = True</span><br />
<h2>
Настройка фреймоворка </h2>
Вот, что Вы можете захотеть настроить для Flask и его расширений (более подробно это описано в их документации):<br />
<br />
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"># для Flask</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">SECRET_KEY = 'вы должны изменить эту строку на что-то секретное'</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"># используйте True только для разработки, не для публичных сайтов</span></span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">DEBUG = False</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">#TESTING = False</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">#SESSION_COOKIE_NAME = 'session'</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">#PERMANENT_SESSION_LIFETIME = timedelta(days=31)</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">#USE_X_SENDFILE = False</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">#LOGGER_NAME = 'MoinMoin'</span></div>
<div style="text-align: left;">
</div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;"># для Flask-Cache:</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">#CACHE_TYPE = 'filesystem'</span></div>
<div style="text-align: left;">
<span style="font-family: "Courier New",Courier,monospace;">#CACHE_DIR = '/path/to/flask-cache-dir'</span></div>
<h2>
Настройка логирования</h2>
По умолчанию логирование настроено на отправку вывода в stderr. Это будет хорошо работать для встроенного сервера (где вывод будет отображаться в консоли) или для Apache2 и т.п. (где лог будет выведен в error.log)<br />
Логирование настраиваемое и гибкое благодаря использованию модуля logging стандартной библиотеки. <br />
Формат файла настройки описан по <a href="http://docs.python.org/2/library/logging.html#configuring-logging" target="_blank">ссылке</a>.<br />
Кроме того, примеры настройки можно найти в каталоге docs/examples/config/logging/.<br />
Настройку логирования нужно произвести как можно раньше, обычно это делается ещё в скрипте-адапторе, то есть moin.wsgi:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">from MoinMoin import log</span><br />
<span style="font-family: "Courier New",Courier,monospace;">log.load_config('wiki/config/logging/logfile')</span><br />
<br />
Вы должны указать путь к файлу настройки, который отвечает вашим потребностям.<br />
Пожалуйста обратите внимание, что файл конфигурации логирования должен быть отдельным файлом, так что не пытайтесь добавить это в файл настройки вики<br />
<i>Примечание: </i> <i>для изменения конфигурации логирования можно использовать переменную окужения MOINLOGGINGCONF</i>, <i>которая должна содержать путь к файлу с конфигурацией логирования. Для задания переменой используйте:</i><br />
<i>export MOINLOGGINGCONF=/path/to/config</i><br />
<i>для удаления переменной:</i><br />
<i>unset MOINLOGGINGCONF </i></div>
Ishayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com0tag:blogger.com,1999:blog-2142461056765545912.post-82263398900783737472013-03-06T17:37:00.000+04:002013-03-06T17:37:09.832+04:00MoinMoin2. Документация. Опции сервера<h2>
Встроенный веб-серер (для простого использования)</h2>
<div style="text-align: justify;">
Moin поставляется с простым, встроенным веб-сервером, основанным на Werkzeug, удобным для разработки, отладки, персонального использования и для небольших групп.</div>
<div style="text-align: justify;">
Он <b>не</b> предназначен для обслуживания больших нагрузок, но его легко использовать.</div>
<div style="text-align: justify;">
Пожалуйста, обратите внимание, что встроенный сервер использует порт 8080. Так как он больше, чем 1024, Вам не требуется права администратора и потому мы крайне рекомендуем Вам использовать непревилигированный аккаунт. Если Вы используете его для вики на вашем ПК или разрабатываете moin, тогда Вы, скорее всего, используете нормальный аккаунт пользователя.</div>
<h3 style="text-align: justify;">
Запуск встроенного сервера</h3>
<div style="text-align: justify;">
Для запуска встроенного веб-сервера используйте следующую команду:</div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"># просто для отладки (один процесс и один поток)</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">moin</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"># требуется для некоторых браузеров, таких, как IE9 или Chrome в режиме</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"># инкогнито (попробуйте это в случае если браузер подвисает или сервер</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"># не отвечает)</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">moin moin --threaded</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"># или, если Вам нужен другой IP/порт</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">moin moin --config /path/to/wikiconfig.py --host 1.2.3.4 --port 7777</span></div>
<div style="text-align: justify;">
После того, как сервер запущен, Вы увидете вывод лога, например:</div>
<div style="text-align: justify;">
2011-03-06 23:35:11,445 INFO werkzeug:116 * Running on http://127.0.0.1:8080/</div>
<div style="text-align: justify;">
Откройте в браузере этот URL и ваша вики работает!</div>
<h3 style="text-align: justify;">
Остановка встроенного сервера</h3>
<div style="text-align: justify;">
Для того, чтобы остановить сервер, либо используйте Ctrl-C, либо закройте окно терминала.</div>
<h2 style="text-align: justify;">
Внешний веб-сервер (для продвинутого использования) </h2>
<div style="text-align: justify;">
Мы не хотим вдаваться в детали того, как использовать moin c внешним веб-сервером, так как все веб-сервера отличаются друг от друга и у каждого есть своя документация, так что обращайтесь туда. Кроме того, в общем, управление сервром требует достаточного опыта работы с ОС, правами доступа, обеспечением безопасности, серверным ПО и т.д.</div>
<div style="text-align: justify;">
Для того, чтобы использовать MoinMoin c другим веб-сервером, убедитесь, что сервер может общаться с moin, что можно сделать следующим кодом:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">from MoinMoin.app import create_app</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">application = create_app('/path/to/config/wikiconfig.py')</span></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
MoinMoin - это приложение Flask, микрофреймворка для WSGI приложения, так что мы рекомендуем Вам почитать документацию по Flask.</div>
<div style="text-align: justify;">
Убедитесь, что Вы используете create_app(), как в примере выше, для создания приложения, так как Вы не можете импортировать приложение из MoinMoin.</div>
<div style="text-align: justify;">
Подробнее читайте дальше по ссылке <a href="http://flask.pocoo.org/docs/deploying">http://flask.pocoo.org/docs/deploying</a></div>
<div style="text-align: justify;">
В случае, если Вы столкнётесь с проблемами при разворачивании main WSGI приложения, Вы можете попробовать начать с простого WSGI приложения. Смотрите docs/examples/deployment/test.wsgi.</div>
<div style="text-align: justify;">
Если и test.wsgi не работает, значит проблема не с moin, а либо с веб-сервером, либо с вашим методом развёртывания WSGI приложения.</div>
<div style="text-align: justify;">
Если тестовое приложение выдаёт что-то кроме Server Error 500, обратитесь к настройке приложения MoinMoin.</div>
<div style="text-align: justify;">
В противном случае смотрите логи ошибок вашего веб-сервера для решения проблем.</div>
Ishayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com0tag:blogger.com,1999:blog-2142461056765545912.post-75873928087319785992013-03-06T16:36:00.000+04:002013-03-06T16:36:29.877+04:00MoinMoin2. Документация. Загрузка и установка<div style="text-align: justify;">
<blockquote class="tr_bq">
<i>Примечание, курсивом выделены вставки, сделанные мной на личном опыте</i><br />
<a name='more'></a><br /></blockquote>
</div>
<h3>
Загрузка</h3>
<div style="text-align: justify;">
Для moin2 пакеты пока не доступны, так что Вы должны получить его из репозитория. Вы можете использовать один или два URLa репозиториев и либо использовать Mercurial для поддержки кода в актуальном состоянии, или же скачать файлы в архие tar.gz:</div>
<ul>
<li>Использование Mercurial для клонирования одного из репозиториев:<br /><span style="font-family: "Courier New",Courier,monospace;">hg clone http://hg.moinmo.in/moin/2.0 moin-2.0</span><br />или<br /><span style="font-family: "Courier New",Courier,monospace;">hg clone http://bitbucket.org/thomaswaldmann/moin-2.0 moin-2.0</span><br />после этого убедитесь, что ваша рабочая директория использует ветку default:<br /><i><span style="font-family: "Courier New",Courier,monospace;">cd moin-2.0</span></i><br /><span style="font-family: "Courier New",Courier,monospace;">hg up -C default</span></li>
<li>В качестве альтернативы посетите http://hg.moinmo.in/moin/2.0 и скачайте архив (обычно, для ветки default) и распакуйте его</li>
</ul>
<h3>
Установка</h3>
Перед тем, как Вы запустите moin, Вы должны его установить:<br />
<h3>
Установка разработчика</h3>
<h4>
Использование стандартной установки Python или каталога virtualenv</h4>
Пожалуйста, убедитесь, что у Вас установлен virtualenv, который включает в себя pip.<br />
<div style="text-align: justify;">
Если вы всего лишь хотите запускать moin из рабочего каталога mercurial со стандартной установкой Python, выполните следующую комманду в этом каталоге. Вы не должны выполнять её как администратор машины, используйте стандартный аккаунт пользователя:</div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">./quickinstall # для Linux и других POSIX OS</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"># или</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">quickinstall.bat # для Windows</span></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<i>На FreeBSD 9.1 bash не установлен по умолчанию, а он нужен для работы этого скрипта. Так что сперва Вам нужно установить bash:</i></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"><i>cd /usr/ports/shells/bash/ && make install clean</i></span></div>
<div style="text-align: justify;">
<i>после чего надо будет отредактировать первую строку скрипта, указав путь к bash:</i></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"><i>#!/usr/local/bin/bash </i></span></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Эта команда использует virtualenv для создания каталога env/ в текущем рабочем каталоге, создаёт виртуальное окружение для MoinMoin и затем устанавливает moin2 со всеми зависимостями в этот каталог. pip автоматически скачает все зависимости из PyPI и установит их, так что это может занять некоторое время. Кроме того, будут скомпилированы все переводы (файлы *.po) в бинарные файлы *.mo.</div>
<div style="text-align: justify;">
Просмотрите вывод скрипта quickinstall и проверьте отсутствие ошибок.</div>
<div style="text-align: justify;">
Если у Вас плохое подключение к сети из-за чего скачивание прерывается, Вы можете попробовать выполнить шаги из quickinstall вручную.</div>
<div style="text-align: justify;">
Кроме того, quickinstall создаст скрипт moin для вашей платформы, который Вы сможете использовать для запуска встроенного сервера или команды moin.</div>
<div style="text-align: justify;">
После того, как Вы активируете виртуальное окружение<i> (sourcer bin/activate выполненый в bash)</i>, встроенный серверный скрипт с именем moin будет находиться в вашем стандартном пути, так что Вы можете просто запустить команду moin из вашей командной строки.</div>
<div style="text-align: justify;">
<b>Примечание:</b> в этом специальном режиме MoinMoin код не будет скопирован в каталог env/, всё будет запускаться из вашей рабочей директории, так что Вы можете напрямую править код и смотреть, что получается. Процедуру установки надо выполнить только один раз.</div>
<h4 style="text-align: justify;">
Использование другого Python или другого каталога virtualenv</h4>
<div style="text-align: justify;">
Например, если Вы хотите использовать PyPy и хотите, чтобы каталог для virtualenv назывался env-pypy, выполните команду:</div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"># для Linux</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">DIR=env-pypy</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">PYTHON=/opt/pypy/bin/pypy</span></div>
<div style="text-align: justify;">
Таким образом, Вы можете проверить разные версии Python в разных каталогах вашего рабочего каталога.</div>
<h3 style="text-align: justify;">
Активирование виртуального окружения</h3>
<div style="text-align: justify;">
ВАЖНО: Вы всегда должны активировать ваше виртуальное окружение перед запуском чего-либо, что будет выполнять код moin! Иначе не будет найдена ни команда moin, ни код moin, ни необходимые библиотеки. Кроме того, если Вы хотите установить дополнительное ПО в виртуальное окружение, активируйте его перед запуском pip!</div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">source env/bin/activete # для Linux или других POSIX OS</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"># или</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">env\Scripts\activate.bat # для Windows</span></div>
<div style="text-align: justify;">
После того, как Вы активировали виртуальное окружение, команда moin будет в вашем пути, так что Вы сможете выполнить её.</div>
<h3 style="text-align: justify;">
Помогаем moin найти конфигурацию wiki</h3>
<div style="text-align: justify;">
moin так же должен обнаружить конфигурацию wiki. Если Вы хотите запустить moin самым простым способом, без передачи параметров команде moin, проще всего это будет сделать из каталога с конфигурационными файлами, т.е. wikiconfig.py.</div>
<div style="text-align: justify;">
Если Вы работаете в рабочем каталоге репозитория, то Вам нужен каталог верхнего уровня, где есть уже готовый к использованию wikiconfig.py.</div>
<div style="text-align: justify;">
В случае, если Вы хотите указать путь к файлу с конфигурацией, используйте <b>абсолютный путь. </b>moin будет искать конфигурационный файл в таком порядке:</div>
<ol>
<li>аргумент командной строки --config /path/to/wikiconfig.py</li>
<li>переменная окружения MOINCFG=/path/to/wikiconfig.py</li>
<li>текущий каталог, файл wikiconfig_local.py</li>
<li>текущий каталог, файл wikiconfig.py</li>
</ol>
<h3>
Инициализация индекса и/или хранилища</h3>
<div style="text-align: justify;">
Если у Вас уже есть хранилищи И индекс (для содержимого этого хранилища и для этой версии moin), Вы можете пропустить этот раздел.</div>
<div style="text-align: justify;">
Если Вы начинаете с самого начала, то есть ни хранилища ни индекса ещё не создано, то Вам нужно создать пустое хранилище и пустой индекс:</div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"># создаём хранилище и индекс:</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">moin index-create -s -i</span></div>
<h3 style="text-align: justify;">
Загружаем некоторые элемента</h3>
<div style="text-align: justify;">
Если Вы не хотите получить совсем пустую вики, Вы можете, по желанию, загрузить в хранилище некоторые примеры, например:</div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">moin load --file contrib/serialized/items.moin</span></div>
<h3 style="text-align: justify;">
Строим индекс</h3>
<div style="text-align: justify;">
Если у Вас уже есть некоторые элементы в хранилище, но индекса ещё нет, то его нужно построить:</div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">moin index-build</span></div>
<h3 style="text-align: justify;">
Установка PIL</h3>
<div style="text-align: justify;">
Для некоторых функций обработки изображений, котоыре использует MoinMoin, например, изменение размера или поворот, Вам нужен PIL - Python Imaging Library.</div>
<div style="text-align: justify;">
Пользователи Windows, которые хотят установить PIL должны пропустить этот раздел и перейти к <b>Решение проблем - Установка PIL под Windows.</b></div>
<div style="text-align: justify;">
Если Вы устанавливаете PIL при помощи pip, тогда pip постарается найти библиотеку поддержки jpeg <b> </b>и ассоциированные заголовки разработки в вашей системе, и если у Вас их нет - то Вы не получите поддержки jpeg в PIL. Так что если Вы хотите обеспечить эту поддержку, убедитесь, что у Вас есть jpeg библиотеки и заголовки:</div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"># установка jpeg библиотеки и заголовков разработки</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">sudo apt-get install libjpeg62-dev # Ubuntu/Debian</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">yum install libjpeg-turbo-devel #Fedora/Redhat</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"><i>cd /usr/ports/graphics/jpeg/ && make install clean # FreeBSD</i> </span></div>
<div style="text-align: justify;">
После этого активируйте виртуальное окружение и установите PIL:</div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">pip install pil</span></div>
<h2 style="text-align: justify;">
Решение проблем</h2>
<h3 style="text-align: justify;">
PyPI не работает</h3>
<div style="text-align: justify;">
Всегда может быть так, что PyPI окажется недоступен. В этом случае можно использовать зеркала b.pypi.python.org, c.pypi.python.org, d.pypi.python.org. Вам только нужно сказать об этом pip:</div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"># разместите это в ~/.pip/pip.conf</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">[global]</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">index-url = http://c.pypi.python.org/simple</span></div>
<div style="text-align: justify;">
В случае, если и это не будет работать, попробуйте mini pypi, где должны быть все необходимые для moin пакеты:</div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"># разместите это в ~/.pip/pip.conf</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">[global]</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">index-url = http://pypi.moinmo.in/simple</span></div>
<h3 style="text-align: justify;">
Проблемы с сетью</h3>
<div style="text-align: justify;">
Если у Вас плохое или ограниченное подключение к сети, у Вас могут возникнуть проблемы с командами, выполняемыми скриптом quickinstall. Вы можете увидеть трассировку pip, ошибки таймаута и т.д. Обратите внимание на эти сообщения.</div>
<div style="text-align: justify;">
В этом случае попробуйте сделать это вручную:</div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"># перейдите в виртуальное окружение:</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">source env/bin/activate</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;"># убедитесь в проблемах, запустив</span></div>
<div style="text-align: justify;">
<span style="font-family: "Courier New",Courier,monospace;">pip install -e .</span></div>
<div style="text-align: justify;">
После этого установите каждый пакет в ваше виртуальное окружение вручную:</div>
<ul>
<li> Найдите все нужные пакеты, перечисленные в install_requires из файла setup.py</li>
<li>Загрузите все нужные пакеты из http://pypi.python.org/</li>
<li>Установите все эти пакеты:<br /><span style="font-family: "Courier New",Courier,monospace;">pip install package.tar</span></li>
<li>Теперь попробуйте ещё раз:<br /><span style="font-family: "Courier New",Courier,monospace;">pip install -e .</span></li>
</ul>
Повторите эти шаги, пока не прекратится появление ошибок.<br />
<h3>
Установка PIP под Windows</h3>
<div style="text-align: justify;">
PIL версии 1.1.7 не устанавливается корректно командой pip install pil на Windows. Некоторым пользователям удалось сделать это при помощи pip install pillow, установив форк PIL'a, устранающего эту проблему. Другие установили PIL 1.1.6 в каталог установки Python, скачав его с http://www.pythonware.com/products/pil/
</div>
Ishayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com0tag:blogger.com,1999:blog-2142461056765545912.post-38872657736607068322013-03-06T13:48:00.002+04:002013-03-06T13:48:52.640+04:00MoinMoin2 документация. Требования<div style="text-align: justify;">
MoinMoin требует Python >= 2.6 и < 3.0. Мы обычно тестируем работу на CPython и рекомендуем использовать его. Кроме того, можно попробовать PyPy >= 1.6</div>
<h4 style="text-align: justify;">
Сервера</h4>
<div style="text-align: justify;">
Для moin можно использовать любой сервер, совместимый с WSGI:</div>
<ul>
<li>встроенный сервер "moin" рекомендуется для однопользовательских wiki, тестирования, отладки, разработки и т.п.</li>
<li>Apache c mod_wsgi рекомендуется для больших/популярных вики</li>
<li>Другие WSGI совместимые сервера или middleware</li>
<li>Для cgi, fastcgi, ajp и т.д. можно использовать middleware <a href="http://trac.saddi.com/flup" target="_blank">flup</a></li>
<li>IIS со шлюзом <a href="http://code.google.com/p/isapi-wsgi/" target="_blank">ISAPI-WSGI</a> тоже можно использовать</li>
</ul>
<br />
<h4>
Зависимости</h4>
Зависимости перечислены в setup.py.<br />
<div style="text-align: justify;">
Если Вы используете easy_install, pip или наш скрипт quickinstall, тогда зависимости должны установиться автоматически.</div>
<h4 style="text-align: justify;">
Клиенты</h4>
<div style="text-align: justify;">
На стороне клиента Вам нужны:</div>
<ul>
<li>приличный веб-браузер, поддерживающий W3C стандарт HTML 5, CSS 2.1 и JavaScript:</li>
<ul>
<li>Любая текущая версия Firefox, Chrome, Opera, Safari, IE (9/10) должны работать</li>
<li>Использование более старых версий IE не рекомендуется и не поддерживается</li>
<li>Для Windows 7/8 MS предоставляет IE 9/10</li>
</ul>
<li>Java плагин для браузера (опционально, если Вы хотите использовать TWikiDraw или AnyWikiDraw для рисования аплетов)
</li>
</ul>
Ishayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com0tag:blogger.com,1999:blog-2142461056765545912.post-43353052313214496672013-03-06T13:22:00.001+04:002013-03-06T13:22:15.955+04:00Продвинутое руководство по логированию (Перевод)<div style="text-align: justify;">
Библиотека logging использует модульный подход и предлагает несколько категорий компонентов: loggers, handlers, filters, и formatters.
</div>
<ul class="simple" style="text-align: justify;">
<li>Logger представляет интерфейс, который использует непосредственно код приложения.</li>
<li>Handler посылает запись лога (созданную logger'ом) в соответствующее расположение.</li>
<li>Filter позволяет определить, какую запись лога выводить.</li>
<li>Formatter определяет расположение записи лога в итоговом выводе.<a name='more'></a></li>
</ul>
<div style="text-align: justify;">
Информация логирования передаётся между logger, handler, filter и
formatter в экземпляре <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.LogRecord" title="logging.LogRecord"><tt class="xref py py-class docutils literal"><span class="pre">LogRecord</span></tt></a>.</div>
<div style="text-align: justify;">
Логирование осуществляется вызовом методов экземпляра класса <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.Logger" title="logging.Logger"><tt class="xref py py-class docutils literal"><span class="pre">Logger</span></tt></a> (тут и далее он будет называться <i class="dfn">loggers</i>). Каждый экземпляр имеет своё имя и эти имена располагаются в иерархии пространства имён, используя точки в качестве разделителей. Например, logger с именем ‘scan’ является родительским logger'ом для logger'ов
‘scan.text’, ‘scan.html’ и ‘scan.pdf’. Имена logger'ов могут быть любыми, как Вы хотите, и отображают место, где было создано сообщение лога.</div>
<div style="text-align: justify;">
Общепринято использовать для имён logger'ов имена модулей:</div>
<div class="highlight-python" style="position: relative; text-align: justify;">
<div class="highlight">
<pre><span class="n">logger</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="n">__name__</span><span class="p">)</span>
</pre>
</div>
</div>
<div style="text-align: justify;">
В таком случае имя logger'a соответствует иерархии пакетов/модулей и интуитивно становится понято, где именно события логируются уже из имени logger'a.</div>
<div style="text-align: justify;">
Корень иерархии logger'ов называется root logger. Этот тот
logger, который используется функциями <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.debug" title="logging.debug"><tt class="xref py py-func docutils literal"><span class="pre">debug()</span></tt></a>, <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.info" title="logging.info"><tt class="xref py py-func docutils literal"><span class="pre">info()</span></tt></a>, <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.warning" title="logging.warning"><tt class="xref py py-func docutils literal"><span class="pre">warning()</span></tt></a>,
<a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.error" title="logging.error"><tt class="xref py py-func docutils literal"><span class="pre">error()</span></tt></a> и <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.critical" title="logging.critical"><tt class="xref py py-func docutils literal"><span class="pre">critical()</span></tt></a>, которые просто вызывают одноимённые меоды root logger'a. Функции и методы имеют одну и ту же подпись. Имя root logger’а отображается как ‘root’ в выводе логов.</div>
<div style="text-align: justify;">
Конечно же возможно логировать сообщения в разные места. Вы можете записывать сообщения в файлы, передавать по HTTP GET/POST, email'y через SMTP, сокеты или OS-специфичные механизмы логирования, такие как syslog или Windows NT event log. Место, куда отправляются логи, определяется классами
<i class="dfn">handler</i>. Вы можете создать свой собственный класс направления логов, если у Вас есть какие-то свои особые потребности.</div>
<div style="text-align: justify;">
По умолчанию место направления не задано для сообщение логов. Вы можете определить его при помощи <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.basicConfig" title="logging.basicConfig"><tt class="xref py py-func docutils literal"><span class="pre">basicConfig()</span></tt></a>, как в примерах руководства. Если Вы вызываете функции <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.debug" title="logging.debug"><tt class="xref py py-func docutils literal"><span class="pre">debug()</span></tt></a>, <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.info" title="logging.info"><tt class="xref py py-func docutils literal"><span class="pre">info()</span></tt></a>,
<a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.warning" title="logging.warning"><tt class="xref py py-func docutils literal"><span class="pre">warning()</span></tt></a>, <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.error" title="logging.error"><tt class="xref py py-func docutils literal"><span class="pre">error()</span></tt></a> и <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.critical" title="logging.critical"><tt class="xref py py-func docutils literal"><span class="pre">critical()</span></tt></a>, они будут проверять, задано ли это место, и если оно не задано, то вывод направляется в консколь (<tt class="docutils literal"><span class="pre">sys.stderr</span></tt>) и используется формат отображения сообщений по умолчанию.</div>
<div style="text-align: justify;">
Формат отображения, задаваемый по умолчанию в <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.basicConfig" title="logging.basicConfig"><tt class="xref py py-func docutils literal"><span class="pre">basicConfig()</span></tt></a> для сообщений:</div>
<div class="highlight-python" style="text-align: justify;">
<pre>severity:logger name:message</pre>
</div>
<div style="text-align: justify;">
Вы можете изменить его передав строку формата в <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.basicConfig" title="logging.basicConfig"><tt class="xref py py-func docutils literal"><span class="pre">basicConfig()</span></tt></a> в аргументе
<i>format</i>. Более подробно все опции форматирования описаны в <a class="reference internal" href="http://docs.python.org/2/library/logging.html#formatter-objects"><i>Formatter Objects</i></a>.</div>
<div class="section" id="logging-flow" style="text-align: justify;">
<h3>
Поток форматирования</h3>
<div class="separator" style="clear: both; text-align: center;">
</div>
<a href="http://min.us/lblfdKgdMHx4f0" target="_blank">иллюстрация тут</a><br />
<br />
<h3>
</h3>
Перемещение информации лога между logger'ами и handler'ами иллюстрирован диаграммой по ссылке выше.</div>
<div class="section" id="loggers" style="text-align: justify;">
<h3>
Logger'ы</h3>
Объекты <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.Logger" title="logging.Logger"><tt class="xref py py-class docutils literal"><span class="pre">Logger</span></tt></a> имеют тройную работу. Во-первых, они предоставляют методы коду приложения, так что приложение может в процессе выполнения логировать сообщения. Во-вторых, объекты logger определяют какие сообщения логов будут работать на этом уровне (объекте фильтра). В третих, объекты logger передают подходящие сообщения логов всем заинтересованным handler'ам.<br />
Чаще всего используемые методы объекта logger относятся к одной из двух категорий: настройка и отправка сообщений.<br />
Вот наиболее часто использемые методы настройки:<br />
<ul class="simple">
<li><a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.Logger.setLevel" title="logging.Logger.setLevel"><tt class="xref py py-meth docutils literal"><span class="pre">Logger.setLevel()</span></tt></a> определяет минимальный уровень сообщений, которые будут обработаны; debug - минимальный встроенный уровень, а critical - максимальный. Например, если установлен уровень INFO, logger будет обрабатывать сообщения уровня INFO, WARNING, ERROR и CRITICAL и игнорировать сообщения уровня DEBUG.</li>
<li><a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.Logger.addHandler" title="logging.Logger.addHandler"><tt class="xref py py-meth docutils literal"><span class="pre">Logger.addHandler()</span></tt></a> и <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.Logger.removeHandler" title="logging.Logger.removeHandler"><tt class="xref py py-meth docutils literal"><span class="pre">Logger.removeHandler()</span></tt></a> добавляют и удаляют объекты handler из объекта logger. Handler'ы более подробно обсуждены в <a class="reference internal" href="http://docs.python.org/2/howto/logging.html#handler-basic"><i>Handlers</i></a>.</li>
<li><a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.Logger.addFilter" title="logging.Logger.addFilter"><tt class="xref py py-meth docutils literal"><span class="pre">Logger.addFilter()</span></tt></a> и <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.Logger.removeFilter" title="logging.Logger.removeFilter"><tt class="xref py py-meth docutils literal"><span class="pre">Logger.removeFilter()</span></tt></a> добавляют и удалют объекты filter из объекта logger. Filter'ы более подробно обсуждаются в <a class="reference internal" href="http://docs.python.org/2/library/logging.html#filter"><i>Filter Objects</i></a>.</li>
</ul>
Вам не нужно вызывать эти методы каждый раз для каждого logger, который Вы создаёте. Смотрите последние два абазца этого раздела.<br />
Когда объект logger настроен, следующие методы создают сообщения логов:<br />
<ul class="simple">
<li><a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.Logger.debug" title="logging.Logger.debug"><tt class="xref py py-meth docutils literal"><span class="pre">Logger.debug()</span></tt></a>, <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.Logger.info" title="logging.Logger.info"><tt class="xref py py-meth docutils literal"><span class="pre">Logger.info()</span></tt></a>, <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.Logger.warning" title="logging.Logger.warning"><tt class="xref py py-meth docutils literal"><span class="pre">Logger.warning()</span></tt></a>,
<a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.Logger.error" title="logging.Logger.error"><tt class="xref py py-meth docutils literal"><span class="pre">Logger.error()</span></tt></a> и <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.Logger.critical" title="logging.Logger.critical"><tt class="xref py py-meth docutils literal"><span class="pre">Logger.critical()</span></tt></a> создают записи логов с сообщением и уровнем, соответствующим названию метода. Сообщение - это строка формата, которая может содержать стандартный синтаксис подстановки, такой как <tt class="xref py py-const docutils literal"><span class="pre">%s</span></tt>, <tt class="xref py py-const docutils literal"><span class="pre">%d</span></tt>, <tt class="xref py py-const docutils literal"><span class="pre">%f</span></tt>. Остальные аргументы - список объектов, которые должны быть подставлены в поля подстановки сообщения. В соответствии с <tt class="xref py py-const docutils literal"><span class="pre">**kwargs</span></tt>, методы логирования учитывают только именованый аргумент <tt class="xref py py-const docutils literal"><span class="pre">exc_info</span></tt> и использует его для того, чтобы определить, логировать ли информацию об исключении.</li>
<li><a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.Logger.exception" title="logging.Logger.exception"><tt class="xref py py-meth docutils literal"><span class="pre">Logger.exception()</span></tt></a> создаёт запись в логе, аналогичную методу
<a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.Logger.error" title="logging.Logger.error"><tt class="xref py py-meth docutils literal"><span class="pre">Logger.error()</span></tt></a>. Разница в том, что <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.Logger.exception" title="logging.Logger.exception"><tt class="xref py py-meth docutils literal"><span class="pre">Logger.exception()</span></tt></a> делает дамп трасировки стека при вызове. Вызывайте этот метод только из обработчика исключений.</li>
<li><a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.Logger.log" title="logging.Logger.log"><tt class="xref py py-meth docutils literal"><span class="pre">Logger.log()</span></tt></a> принимает уровень логирования в качестве аргумента. В этом случае приходится больше печатать, но зато это способ залогировать события пользовательского уровня.</li>
</ul>
<a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.getLogger" title="logging.getLogger"><tt class="xref py py-func docutils literal"><span class="pre">getLogger()</span></tt></a> возвращает ссылку на экземпляр logger'а с именем, если оно задано, или <tt class="docutils literal"><span class="pre">root</span></tt>, если нет. Имена представляют из себя иерархическую структуру с точками в качестве разделителей. Множественные вызовы <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.getLogger" title="logging.getLogger"><tt class="xref py py-func docutils literal"><span class="pre">getLogger()</span></tt></a> с одним и тем же имененм будут возвращать ссылку на один и тот же объект logger'а. Logger'ы, находящиеся ниже в иерархии являются дочерними для logger'ов, которые находятся выше. Например, для logger'а с имененм <tt class="docutils literal"><span class="pre">foo</span></tt> logger'ы с именами
<tt class="docutils literal"><span class="pre">foo.bar</span></tt>, <tt class="docutils literal"><span class="pre">foo.bar.baz</span></tt> и <tt class="docutils literal"><span class="pre">foo.bam</span></tt> будут дочерними.<br />
Logger'ы поддерживают концепцию <i>эффективного уровня</i>. Если для logger'а не задан уровень явно, то используется уровень его родителя. Если и его родитель не имеет заданного уровня - смотрится родитель родителя, и так далее. Корневой logger всегда имеет явно заданный уровень (по умолчанию это <tt class="docutils literal"><span class="pre">WARNING</span></tt>). При решении вопроса обрабатывать ли событи используется именно эффективный уровень.<br />
Дочерние logger'ы распространяют сообщения handler'ам, связанным с родительским logger'ом. Из-за этого нет необходимости определять и настраивать handler'ы для всех logger'ов в приложении. Но важно сконфигурировать handler'ы для logger'ов верхнего уровня и уже потом создавать при необходимости дочерние logger'ы. (Однако, распространение сообщений можно отключить, задав значением атрибута propagate logger'a равным False.)</div>
<div class="section" id="handlers" style="text-align: justify;">
<h3>
Handler'ы</h3>
Объекты <tt class="xref py py-class docutils literal"><span class="pre">Handler</span></tt> отвечают за отправку соответствующего сообщения (соответствующего уровня) к его месту назначения, определённого в handler'e. Объекты logger могут добавить себе ноль или более handler'ов при помощи метода <tt class="xref py py-func docutils literal"><span class="pre">addHandler()</span></tt>. Например, приложение может хотеть отправлять все сообщения в файл логов, сообщения уровня ошибки и выше в stdout, а все критические сообщения отправлять на почту. Этот сценарий требует три handler'a, каждый из которых отвечает за отправку сообщений определённого уровня в определённое место.<br />
Стандартная библиотека включает в себя несколько типов handler'ов (см
<a class="reference internal" href="http://docs.python.org/2/howto/logging.html#useful-handlers"><i>Useful Handlers</i></a>); это руководство по большей части использует в примерах <a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#logging.StreamHandler" title="logging.StreamHandler"><tt class="xref py py-class docutils literal"><span class="pre">StreamHandler</span></tt></a> и
<a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#logging.FileHandler" title="logging.FileHandler"><tt class="xref py py-class docutils literal"><span class="pre">FileHandler</span></tt></a>.<br />
Есть несколько методов у handler'a для разработчиков приложений, о которых стоит позаботиться. Методы, которые нужны тем, кто будет пользоваться встроенными handler'ами (то есть, не будет использовать самописные) следующие:<br />
<ul class="simple">
<li>Метод <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.Handler.setLevel" title="logging.Handler.setLevel"><tt class="xref py py-meth docutils literal"><span class="pre">Handler.setLevel()</span></tt></a> аналогичен методу объекта logger, он определяет минимальный уровень, который будет направлен в соответствующее место. Зачем нужно два метода <tt class="xref py py-func docutils literal"><span class="pre">setLevel()</span></tt>? Уровень, заданный в logger'e определяет уровень сообщений, который будет передан в handler'ы. Уровень, заданный в каждом handler'e определяет сообщения, которые этот handler будут посылать.</li>
<li><tt class="xref py py-func docutils literal"><span class="pre">setFormatter()</span></tt> определяет объект Formatter, который будет использовать этот handler.</li>
<li><tt class="xref py py-func docutils literal"><span class="pre">addFilter()</span></tt> и <tt class="xref py py-func docutils literal"><span class="pre">removeFilter()</span></tt> соответственно добавляют и удаляют объекты фильтров из handler'a.</li>
</ul>
Код приложения не должен напрямую инициализировать и использовать экземпляры
<tt class="xref py py-class docutils literal"><span class="pre">Handler</span></tt>. Вместо этого, класс <tt class="xref py py-class docutils literal"><span class="pre">Handler</span></tt> является базовым классом, который определяет интерфейс, которым должны обладать все handler'ы и определяет некоторое поведение по умолчанию, которое могут использовать дочерние классы (или переопределять их).</div>
<div class="section" id="formatters" style="text-align: justify;">
<h3>
Formatter'ы</h3>
Объекты formatter задают порядок, структуру и содержание сообщения лога. В отличие от базового класса <tt class="xref py py-class docutils literal"><span class="pre">logging.Handler</span></tt>, код приложения может сам создавать экземпляры класса, но Вы можете создавать и дочерние классы, реализующие ваши потребности. Конструктор принимает два необязательных аргумента - строку формата сообщения и строку формата даты.<br />
<dl class="method">
<dt id="logging.logging.Formatter.__init__">
<tt class="descclassname">logging.Formatter.</tt><tt class="descname">__init__</tt><big>(</big><i>fmt=None</i>, <i>datefmt=None</i><big>)</big></dt>
<dd><br /></dd></dl>
Если строка формата сообщения не указана, по умолчанию сообщение будет передано как есть. Если не указана строка формата времени, то используется следующий формат:<br />
<div class="highlight-python">
<pre>%Y-%m-%d %H:%M:%S</pre>
</div>
где миллисекунды присоединяются к концу строки.<br />
Строка формата сообщения использует стиль подстановки <tt class="docutils literal"><span class="pre">%(<dictionary</span> <span class="pre">key>)s</span></tt>; возможные ключи указаны в <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logrecord-attributes"><i>LogRecord attributes</i></a>.<br />
Следующая строка формата отобразит сообщение в виде: ЧитаемоеВремя - УровеньСообщения - СамоСообщение:<br />
<div class="highlight-python" style="position: relative;">
<div class="highlight">
<pre><span class="s">'</span><span class="si">%(asctime)s</span><span class="s"> - </span><span class="si">%(levelname)s</span><span class="s"> - </span><span class="si">%(message)s</span><span class="s">'</span>
</pre>
</div>
</div>
Formatter'ы используют настраеваемую функцию для преобразования времени создания записи в кортеж. По умолчанию используется функция<tt> </tt><a class="reference internal" href="http://docs.python.org/2/library/time.html#time.localtime" title="time.localtime"><tt class="xref py py-func docutils literal"><span class="pre">time.localtime()</span></tt></a>; для того, чтобы это изменить присвойте аттрибуту <tt class="docutils literal"><span class="pre">converter</span></tt> функцию с той же сигнатурой, что и у <a class="reference internal" href="http://docs.python.org/2/library/time.html#time.localtime" title="time.localtime"><tt class="xref py py-func docutils literal"><span class="pre">time.localtime()</span></tt></a> или
<a class="reference internal" href="http://docs.python.org/2/library/time.html#time.gmtime" title="time.gmtime"><tt class="xref py py-func docutils literal"><span class="pre">time.gmtime()</span></tt></a>. Для того, чтобы изменить это для всех formatter'ов, например, если Вы хотите, чтобы время логирования отображалось в GMT, задайте атрибут <tt class="docutils literal"><span class="pre">converter</span></tt> класса
Formatter (равным <tt class="docutils literal"><span class="pre">time.gmtime</span></tt> для отображения в GMT).</div>
<div class="section" id="configuring-logging" style="text-align: justify;">
<h3>
Настройка логирования</h3>
Программисты могут настроить логирование тремя способами:<br />
<ol class="arabic simple">
<li>Явно создать logger'ы, handler'ы, and formatter'ы при помощи кода на Python, который вызывает методы конфигурации, о которых мы говорили выше.</li>
<li>Создать файл настройки и считать его функцией <a class="reference internal" href="http://docs.python.org/2/library/logging.config.html#logging.config.fileConfig" title="logging.config.fileConfig"><tt class="xref py py-func docutils literal"><span class="pre">fileConfig()</span></tt></a>.</li>
<li>Создать словрь с информацией конфигурации и передать его функции <a class="reference internal" href="http://docs.python.org/2/library/logging.config.html#logging.config.dictConfig" title="logging.config.dictConfig"><tt class="xref py py-func docutils literal"><span class="pre">dictConfig()</span></tt></a>.</li>
</ol>
Документацию последних двух вариантов Вы можете найти в
<a class="reference internal" href="http://docs.python.org/2/library/logging.config.html#logging-config-api"><i>Configuration functions</i></a>. Следующие примеры настраивают очень простой logger, консаольный handler и простой formatter при помощи кода на Python:<br />
<br />
<div class="highlight-python" style="position: relative;">
<div class="highlight">
<pre><span class="kn">import</span> <span class="nn">logging</span>
<span class="c"># создаём logger</span>
<span class="n">logger</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="s">'simple_example'</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
<span class="c"># создаём консольный handler и задаём уровень</span>
<span class="n">ch</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">StreamHandler</span><span class="p">()</span>
<span class="n">ch</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
<span class="c"># создаём formatter</span>
<span class="n">formatter</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">Formatter</span><span class="p">(</span><span class="s">'</span><span class="si">%(asctime)s</span><span class="s"> - </span><span class="si">%(name)s</span><span class="s"> - </span><span class="si">%(levelname)s</span><span class="s"> - </span><span class="si">%(message)s</span><span class="s">'</span><span class="p">)</span>
<span class="c"># добавляем formatter в ch</span>
<span class="n">ch</span><span class="o">.</span><span class="n">setFormatter</span><span class="p">(</span><span class="n">formatter</span><span class="p">)</span>
<span class="c"># добавляем ch к logger</span>
<span class="n">logger</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">ch</span><span class="p">)</span>
<span class="c"># код "приложения"</span>
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">'debug message'</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s">'info message'</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">warn</span><span class="p">(</span><span class="s">'warn message'</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s">'error message'</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">critical</span><span class="p">(</span><span class="s">'critical message'</span><span class="p">)</span>
</pre>
</div>
</div>
<br />
Запуск этого модуля из командной строки приведёт к такому выводу:<br />
<br />
<div class="highlight-python">
<pre>$ python simple_logging_module.py
2005-03-19 15:10:26,618 - simple_example - DEBUG - debug message
2005-03-19 15:10:26,620 - simple_example - INFO - info message
2005-03-19 15:10:26,695 - simple_example - WARNING - warn message
2005-03-19 15:10:26,697 - simple_example - ERROR - error message
2005-03-19 15:10:26,773 - simple_example - CRITICAL - critical message</pre>
</div>
<br />
Следующий модуль Python создаёт logger, handler и formatter, почти аналогичные примеру выше, отличие лишь в именах объектов:<br />
<br />
<div class="highlight-python" style="position: relative;">
<div class="highlight">
<pre><span class="kn">import</span> <span class="nn">logging</span>
<span class="kn">import</span> <span class="nn">logging.config</span>
<span class="n">logging</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">fileConfig</span><span class="p">(</span><span class="s">'logging.conf'</span><span class="p">)</span>
<span class="c"># создаём logger</span>
<span class="n">logger</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="s">'simpleExample'</span><span class="p">)</span>
<span class="c"># код "приложения"</span>
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">'debug message'</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s">'info message'</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">warn</span><span class="p">(</span><span class="s">'warn message'</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s">'error message'</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">critical</span><span class="p">(</span><span class="s">'critical message'</span><span class="p">)</span> </pre>
<pre> </pre>
</div>
</div>
Вот файл logging.conf:<br />
<br />
<div class="highlight-python">
<pre>[loggers]
keys=root,simpleExample
[handlers]
keys=consoleHandler
[formatters]
keys=simpleFormatter
[logger_root]
level=DEBUG
handlers=consoleHandler
[logger_simpleExample]
level=DEBUG
handlers=consoleHandler
qualname=simpleExample
propagate=0
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)
[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=</pre>
<pre> </pre>
</div>
Результат будет похож на результат предыдущего примера:<br />
<br />
<div class="highlight-python">
<pre>$ python simple_logging_config.py
2005-03-19 15:38:55,977 - simpleExample - DEBUG - debug message
2005-03-19 15:38:55,979 - simpleExample - INFO - info message
2005-03-19 15:38:56,054 - simpleExample - WARNING - warn message
2005-03-19 15:38:56,055 - simpleExample - ERROR - error message
2005-03-19 15:38:56,130 - simpleExample - CRITICAL - critical message</pre>
<pre> </pre>
</div>
Вы можете заменить, что подход, основанный на конфигурационном файле имеет некоторое преимущество перед подходом, где всё это вносится в код, так как мы разделили код и конфигурацию и не-программисты могут легко изменить конфигурацию логирования.<br />
<div class="admonition warning">
<div class="first admonition-title">
<span style="color: red;">Предупреждение:</span></div>
<span style="color: red;">Функция <a class="reference internal" href="http://docs.python.org/2/library/logging.config.html#logging.config.fileConfig" title="logging.config.fileConfig"><tt class="xref py py-func docutils literal"><span class="pre">fileConfig()</span></tt></a> принимает параметр по умолчанию
<tt class="docutils literal"><span class="pre">disable_existing_loggers</span></tt> со значением <tt class="xref docutils literal"><span class="pre">True</span></tt> для обратной совместимости. Это может быть тем, что Вы хотите, или нет, так как из-за этого все уже существующие до вызова <a class="reference internal" href="http://docs.python.org/2/library/logging.config.html#logging.config.fileConfig" title="logging.config.fileConfig"><tt class="xref py py-func docutils literal"><span class="pre">fileConfig()</span></tt></a> logger'ы будут деактивированы, если только они не перечислены в конфигурации. Более подробно смотрите документацию и при необходимости используйте в качестве значения параметра False.</span><br />
<div class="last">
<span style="color: red;">Словарь, передаваемый в функцию <a class="reference internal" href="http://docs.python.org/2/library/logging.config.html#logging.config.dictConfig" title="logging.config.dictConfig"><tt class="xref py py-func docutils literal"><span class="pre">dictConfig()</span></tt></a> может также определить логическое значение для ключа <tt class="docutils literal"><span class="pre">disable_existing_loggers</span></tt>, который, если не определён явно в этом словаре, получает значение по умолчанию
<tt class="xref docutils literal"><span class="pre">True</span></tt>.</span></div>
</div>
Обратите внимание, что имена классов в конфигурационном файле должны быть заданы либо относительно модуля логирования или абсолютно, так, что они могут быть разрешены обычным механизмом импорта. Таким образом, Вы можете использовать либо
<a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#logging.handlers.WatchedFileHandler" title="logging.handlers.WatchedFileHandler"><tt class="xref py py-class docutils literal"><span class="pre">WatchedFileHandler</span></tt></a> (относительно модуля логирования) или
<tt class="docutils literal"><span class="pre">mypackage.mymodule.MyHandler</span></tt> (для класса, определённого в пакете <tt class="docutils literal"><span class="pre">mypackage</span></tt> и модуля <tt class="docutils literal"><span class="pre">mymodule</span></tt>, где <tt class="docutils literal"><span class="pre">mypackage</span></tt> - доступный для импорта в Python).<br />
В Python 2.7, была добавлена возможность конфигурирования логгинга с исполльзованием словаря. Это расширение функциональность подхода конфигурирования при помощи файла и он рекомендуется для новых приложений. Поскольку конфигурация хранится в словаре, а его можно заполнить разными способами, у Вас появляется множество способов настройки. Например, Вы можете использовать конфигурационный файл в формате JSON, или YAML. Или же Вы можете сконструировать словарь в коде Python, получить его через сокет в сериализованной форме (pickled), или использовать любой другой подход.<br />
Вот пример тойже самой настройки в формате YAML:<br />
<br />
<div class="highlight-python">
<pre>version: 1
formatters:
simple:
format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
handlers:
console:
class: logging.StreamHandler
level: DEBUG
formatter: simple
stream: ext://sys.stdout
loggers:
simpleExample:
level: DEBUG
handlers: [console]
propagate: no
root:
level: DEBUG
handlers: [console]</pre>
<pre> </pre>
</div>
Более подробно по поводу логирования при помощи словаря описано в
<a class="reference internal" href="http://docs.python.org/2/library/logging.config.html#logging-config-api"><i>Configuration functions</i></a>.</div>
<div class="section" id="what-happens-if-no-configuration-is-provided" style="text-align: justify;">
<h3>
Что происходит, если конфигурация не задана</h3>
Если конфигурация логировани не задана, то может сложиться ситуация, в которой сообщение должно быть обработано, но для его вывода не найден ни один handler. Поведение модуля в таком случае будет зависеть от версии Python.<br />
Для Python 2.x, поведение таково:<br />
<ul class="simple">
<li>Если <i>logging.raiseExceptions</i> = <i>False</i> (режим production), сообщение просто игнорируется.</li>
<li>Если <i>logging.raiseExceptions</i> = <i>True</i> (режим development), будет один раз выведено сообщение
‘No handlers could be found for logger X.Y.Z’.</li>
</ul>
</div>
<div class="section" id="configuring-logging-for-a-library" style="text-align: justify;">
<span id="library-config"></span><br />
<h3>
Конфигурирование логирования для библиотеки</h3>
Когда Вы разрабатываете библиотеку, которая использует логирование, Вы должны задокументировать использование logger'ов, например, указать используемые имена и конфигурацию. Если приложение не настраивает логирование, но вызывает функции логирования, то (как описано в предыдущем разделе) будет выведено сообщение об ошибке в <tt class="docutils literal"><span class="pre">sys.stderr</span></tt>.<br />
Если по какой-то причине Вы <i>не</i> хотите, чтобы это сообщение выводилось и при этом не хотите настраивать логирование, Вы можете подключить ничего не делающий handler к корневому logger вашей библиотеки. В таком случае сообщений об ошибке Вы не увидите, так как handler будет найден, но так как он ничего не делает, Вы ничего и не получите. Если пользователь, использующий вашу библиотеку настроит логирование, скорее всего он добавит и некоторые handler'ы и если уровни правильно настроены, то вывод будет осуществляться через эти hdnler'ы и всё будет хорошо.<br />
Ничего не делающий handler уже присутствует в пакете - это <a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#logging.NullHandler" title="logging.NullHandler"><tt class="xref py py-class docutils literal"><span class="pre">NullHandler</span></tt></a> (с версии Python 2.7). Экземпляр этого handler'a может быть добавлен к logger'y верхнего уровня в вашей библиотеке (<i>если</i> Вы хотите предотвратить вывод ошибочных сообщений в
<tt class="docutils literal"><span class="pre">sys.stderr</span></tt> в конфгурации). Если всё логирование в библиоткете <i>foo</i> делается logger'ами с именами ‘foo.x’, ‘foo.x.y’ и т.д., тогда код:<br />
<br />
<div class="highlight-python" style="position: relative;">
<div class="highlight">
<pre><span class="kn">import</span> <span class="nn">logging</span>
<span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s">'foo'</span><span class="p">)</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">NullHandler</span><span class="p">())</span>
</pre>
</div>
</div>
<br />
даст желаемый Вам эффект. Если ваша организация разрабатывает несколько библиотек, то именем logger'a должно быть ‘orgname.foo’, а не просто ‘foo’.<br />
<div class="admonition note">
<div class="first admonition-title">
<span style="color: #999999;">Примечание</span><br />
<span style="color: #999999;">Очень рекомендуется <i>не добавлять handler'ы</i>, отличные от </span><span style="color: #999999;"><a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#logging.NullHandler" title="logging.NullHandler"><tt class="xref py py-class docutils literal"><span class="pre">NullHandler</span></tt></a> в logger'ы вашей библиотеки по той причине, что конфигурация handler'ов является прерогативой разработчика приложения, который будет использовать вашу библиотеку. Разработчик приложения знает свою целевую аудиторию и какие handler'ы больше подходят для их целей. Если же Вы добавляете handler'ы "под капотом", Вы можете вмешаться в их способность проходить юнит-тесты и добавить им проблем.</span></div>
</div>
</div>
<div class="section" id="logging-levels" style="text-align: justify;">
<h2>
Уровни логирования</h2>
Числовые значения уровней логирования приведены ниже в таблице. В основном это интересно в случае, если Вы хотите объявить свой собственный уровень логирования и хотите придать им значения, относительно предопределённых уровней. Если Вы определите уровень с тем же числовым значением, он переопределит предопределённое значение и имя предопределённого значения будет потеряно.<br />
<table border="1" class="docutils" style="margin-left: 0px; margin-right: 0px; text-align: left;">
<colgroup>
<col width="48%"></col>
<col width="52%"></col>
</colgroup>
<thead valign="bottom">
<tr><th class="head">Уровень</th>
<th class="head">Числовое значение</th>
</tr>
</thead>
<tbody valign="top">
<tr><td><tt class="docutils literal"><span class="pre">CRITICAL</span></tt></td>
<td>50</td>
</tr>
<tr><td><tt class="docutils literal"><span class="pre">ERROR</span></tt></td>
<td>40</td>
</tr>
<tr><td><tt class="docutils literal"><span class="pre">WARNING</span></tt></td>
<td>30</td>
</tr>
<tr><td><tt class="docutils literal"><span class="pre">INFO</span></tt></td>
<td>20</td>
</tr>
<tr><td><tt class="docutils literal"><span class="pre">DEBUG</span></tt></td>
<td>10</td>
</tr>
<tr><td><tt class="docutils literal"><span class="pre">NOTSET</span></tt></td>
<td>0</td>
</tr>
</tbody>
</table>
Уровни могут быть так же ассоциированны с logger'ами, будучи заданными либо разработчиком, либо загрузкой сохранённой конфигурации. Когда вызывается метод логирования, logger сравнивает свой уровень с уровнем, асооциированным с вызовом метода. Если уровень logger'a больше, чем у метода, то сообщение игнорируется. Это основной механизм контроля подробности логирования.<br />
Сообщения кодируются экземляром класса <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.LogRecord" title="logging.LogRecord"><tt class="xref py py-class docutils literal"><span class="pre">LogRecord</span></tt></a>. Когда logger решает залогировать событие, из сообщения создаётся экземпляр
<a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.LogRecord" title="logging.LogRecord"><tt class="xref py py-class docutils literal"><span class="pre">LogRecord</span></tt></a>.<br />
Сообщения отправляются через <i class="dfn">handler'ы</i>, которые являются экземплярами подклассов класса <tt class="xref py py-class docutils literal"><span class="pre">Handler</span></tt>. Handler'ы отвечают за то, чтобы убедиться, что сообщение (в форме <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.LogRecord" title="logging.LogRecord"><tt class="xref py py-class docutils literal"><span class="pre">LogRecord</span></tt></a>) окажется в нужном месте (или наборе мест), что полезно для целевой аудиенции этого сообщения (таких как конечные пользователи, служба поддержки, системных администраторов, разработчиков). Handler'ы передают экзмепляры
<a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.LogRecord" title="logging.LogRecord"><tt class="xref py py-class docutils literal"><span class="pre">LogRecord</span></tt></a> в конктерное место назначения. Каждый logger может иметь 0 или больше ассоциированных handler'ов (при помощи метода
<a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.Logger.addHandler" title="logging.Logger.addHandler"><tt class="xref py py-meth docutils literal"><span class="pre">addHandler()</span></tt></a> класса <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.Logger" title="logging.Logger"><tt class="xref py py-class docutils literal"><span class="pre">Logger</span></tt></a>). Кроме handler'a, напрямую связанного с logger'ом, <i>все handler'ы, связанные с его предками </i>так же вызываются для отправки сообщения (если только для logger флаг <i>propagate </i>не установлен в занчение false, так как в этом случае распространение сообщения будет остановлено на этом logger'е).<br />
Как и logger'ы, handler'ы могут иметь ассоциированные с ними уровни. Уровень handler’а работает как фильтр так же, как уровень logger’а. Если handler решает переслать сообщение, то используется метод <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.Handler.emit" title="logging.Handler.emit"><tt class="xref py py-meth docutils literal"><span class="pre">emit()</span></tt></a> для отправки сообщения по адресу. Большая часть пользовательских подклассов будет переопределять этот метод.<br />
<div class="section" id="custom-levels">
<h3>
Пользовательские уровни</h3>
Можно определить свой уровень, но без нужды этого делать не стоит, так как имеющиеся уровни были выбраны на основе практического опыта. Однако, если Вы уверены, что Вам нужны собственные уровни, при их создании требуется приложить много внимания, и очень плохой идеей это может оказаться, если Вы разрабатываете свою библиотеку. Ведь если несколько библиотек определяют свои уровни, есть вариант что итоговые логи этих библиотек будет очень сложно разобрать, так как одно и то же значение уровня может иметь разный смысл для разных библиотек.</div>
</div>
<div class="section" id="useful-handlers" style="text-align: justify;">
<h2>
Полезные Handler'ы</h2>
В дополнении к базовому классу <tt class="xref py py-class docutils literal"><span class="pre">Handler</span></tt>, есть ещё много полезных дочерних классов:<br />
<ol class="arabic simple">
<li><a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#logging.StreamHandler" title="logging.StreamHandler"><tt class="xref py py-class docutils literal"><span class="pre">StreamHandler</span></tt></a> посылает сообщения в потоки (файло-подобные объекты)</li>
<li><a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#logging.FileHandler" title="logging.FileHandler"><tt class="xref py py-class docutils literal"><span class="pre">FileHandler</span></tt></a> посылает сообщения в файлы на диске.</li>
<li><tt class="xref py py-class docutils literal"><span class="pre">BaseRotatingHandler</span></tt> - базовый класс handler'ов, которые ротируют файлы логов в определённый момент. Его не надо использовать непосредственно, вместо этого используйте <a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#logging.handlers.RotatingFileHandler" title="logging.handlers.RotatingFileHandler"><tt class="xref py py-class docutils literal"><span class="pre">RotatingFileHandler</span></tt></a> или
<a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#logging.handlers.TimedRotatingFileHandler" title="logging.handlers.TimedRotatingFileHandler"><tt class="xref py py-class docutils literal"><span class="pre">TimedRotatingFileHandler</span></tt></a>.</li>
<li><a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#logging.handlers.RotatingFileHandler" title="logging.handlers.RotatingFileHandler"><tt class="xref py py-class docutils literal"><span class="pre">RotatingFileHandler</span></tt></a> посылает сообщения в файлы на диске, с поддержкой максимального размера файла логов и ротиции файлов.</li>
<li><a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#logging.handlers.TimedRotatingFileHandler" title="logging.handlers.TimedRotatingFileHandler"><tt class="xref py py-class docutils literal"><span class="pre">TimedRotatingFileHandler</span></tt></a> посылает сообщения в файл на диск и делает ротацию через некоторый временной интервал.</li>
<li><a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#logging.handlers.SocketHandler" title="logging.handlers.SocketHandler"><tt class="xref py py-class docutils literal"><span class="pre">SocketHandler</span></tt></a> посылает сообщения через сокеты TCP/IP.</li>
<li><a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#logging.handlers.DatagramHandler" title="logging.handlers.DatagramHandler"><tt class="xref py py-class docutils literal"><span class="pre">DatagramHandler</span></tt></a> посылает сообщения через UDP сокеты.</li>
<li><a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#logging.handlers.SMTPHandler" title="logging.handlers.SMTPHandler"><tt class="xref py py-class docutils literal"><span class="pre">SMTPHandler</span></tt></a> посылает сообщения на определённый адрес электронной почты.</li>
<li><a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#logging.handlers.SysLogHandler" title="logging.handlers.SysLogHandler"><tt class="xref py py-class docutils literal"><span class="pre">SysLogHandler</span></tt></a> посылает сообщения демону Unix
syslog, возможно, на удалённой машине.</li>
<li><a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#logging.handlers.NTEventLogHandler" title="logging.handlers.NTEventLogHandler"><tt class="xref py py-class docutils literal"><span class="pre">NTEventLogHandler</span></tt></a> посылает сообщения в
Windows NT/2000/XP event log.</li>
<li><a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#logging.handlers.MemoryHandler" title="logging.handlers.MemoryHandler"><tt class="xref py py-class docutils literal"><span class="pre">MemoryHandler</span></tt></a> посылает сообщения в буфер в памяти, который скидывается на диск при соответствии определённому критерию.</li>
<li><a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#logging.handlers.HTTPHandler" title="logging.handlers.HTTPHandler"><tt class="xref py py-class docutils literal"><span class="pre">HTTPHandler</span></tt></a> посылает сообщения на HTTP сервер методами <tt class="docutils literal"><span class="pre">GET</span></tt> или <tt class="docutils literal"><span class="pre">POST</span></tt>.</li>
<li><a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#logging.handlers.WatchedFileHandler" title="logging.handlers.WatchedFileHandler"><tt class="xref py py-class docutils literal"><span class="pre">WatchedFileHandler</span></tt></a> наблюдает за файлами, куда идёт логирование. Если файл изменяется, то он закрывается и открывается заново по имени файла. Полезен только на Unix-подобных системах; Windows не поддерживает нужного механизма.</li>
<li><a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#logging.NullHandler" title="logging.NullHandler"><tt class="xref py py-class docutils literal"><span class="pre">NullHandler</span></tt></a> ничего не делает с сообщениями об ошибках. Он используется разработчиками библиотек, которые хотят исопльзовать логирование, но при этом избежать сообщений ‘No
handlers could be found for logger XXX’, которые могут быть отображены, если пользователь библиотеки не настроил логирование. Более подробно смотрите в <a class="reference internal" href="http://docs.python.org/2/howto/logging.html#library-config"><i>Configuring Logging for a Library</i></a>.</li>
</ol>
<div class="versionadded">
<span class="versionmodified">Новое с версии 2.7: Класс</span> <a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#logging.NullHandler" title="logging.NullHandler"><tt class="xref py py-class docutils literal"><span class="pre">NullHandler</span></tt></a>.</div>
Классы <a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#logging.NullHandler" title="logging.NullHandler"><tt class="xref py py-class docutils literal"><span class="pre">NullHandler</span></tt></a>, <a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#logging.StreamHandler" title="logging.StreamHandler"><tt class="xref py py-class docutils literal"><span class="pre">StreamHandler</span></tt></a> и <a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#logging.FileHandler" title="logging.FileHandler"><tt class="xref py py-class docutils literal"><span class="pre">FileHandler</span></tt></a>
определены в ядре пакета логирования. Другие handler'ы определены в подмодуле <a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#module-logging.handlers" title="logging.handlers: Handlers for the logging module."><tt class="xref py py-mod docutils literal"><span class="pre">logging.handlers</span></tt></a>. (Есть ещё один подмодуль, <a class="reference internal" href="http://docs.python.org/2/library/logging.config.html#module-logging.config" title="logging.config: Configuration of the logging module."><tt class="xref py py-mod docutils literal"><span class="pre">logging.config</span></tt></a>, содержащий всё необходимое для конфигурирования.)<br />
Сообщения форматируются для отображения экземплярами класса
<a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.Formatter" title="logging.Formatter"><tt class="xref py py-class docutils literal"><span class="pre">Formatter</span></tt></a>. Для их инициализции нужна строка формата, которую можно исопльзовать с оператором % и словарём.<br />
Для форматирования нескольких сообщений сразу можно использовать экземпляры класса <tt class="xref py py-class docutils literal"><span class="pre">BufferingFormatter</span></tt>. Кроме строки формата (которая применяется к каждому сообщению в наборе) даются ещё и строки формата для заголовка и завершающего сообщения.Если фильтрование на уровне logger'a или handler'a не достаточно, можно добавить экземпляр <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.Filter" title="logging.Filter"><tt class="xref py py-class docutils literal"><span class="pre">Filter</span></tt></a> и к <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.Logger" title="logging.Logger"><tt class="xref py py-class docutils literal"><span class="pre">Logger</span></tt></a> и к
<tt class="xref py py-class docutils literal"><span class="pre">Handler</span></tt> (при помощи их метода <tt class="xref py py-meth docutils literal"><span class="pre">addFilter()</span></tt>). Перед тем, как решать, обрабатывать ли сообщение, logger'ы и handler'ы смотрят на свои фильтры для проверки разрешений. Если какой-либо фильтр возвращает значение false, то сообщение не будет обработано.<br />
Базовая функциональность <a class="reference internal" href="http://docs.python.org/2/library/logging.html#logging.Filter" title="logging.Filter"><tt class="xref py py-class docutils literal"><span class="pre">Filter</span></tt></a> позволяет отфильтровать сообщения по имени logger'а. Если это используется, то сообщения, посланные указанному logger'у или его потомкам пропускаются через фильтр, а все остальные игнорируются.</div>
<div class="section" id="exceptions-raised-during-logging" style="text-align: justify;">
<h2>
Исключения, возникающие во время логирования</h2>
Пакет логирования предназначен для поглощения исключений, которые возникают в работающем продукте. То есть, ошибки, которые возникают при обработке событий логирования, такие как проблемы с настройкой, сетью и т.п, не прерывают работу самого продукта.<br />
Исключения <tt class="xref py py-class docutils literal"><span class="pre">SystemExit</span></tt> и <tt class="xref py py-class docutils literal"><span class="pre">KeyboardInterrupt</span></tt> никогда не поглощаются. Другие исключения, возникающие в методе <tt class="xref py py-meth docutils literal"><span class="pre">emit()</span></tt> подкласса
<tt class="xref py py-class docutils literal"><span class="pre">Handler</span></tt> передаются методу <tt class="xref py py-meth docutils literal"><span class="pre">handleError()</span></tt>.<br />
Реализация по умолчанию <tt class="xref py py-meth docutils literal"><span class="pre">handleError()</span></tt> в <tt class="xref py py-class docutils literal"><span class="pre">Handler</span></tt> проверяет, задана ли переменна уровня модуля <tt class="xref py py-data docutils literal"><span class="pre">raiseExceptions</span></tt>. Если она задана, то трассировка отображается в <a class="reference internal" href="http://docs.python.org/2/library/sys.html#sys.stderr" title="sys.stderr"><tt class="xref py py-data docutils literal"><span class="pre">sys.stderr</span></tt></a>. Если нет - исключение поглощается.<br />
<div class="admonition note">
<div class="first admonition-title">
<span style="color: #999999;">Примечание</span></div>
<div class="last">
<span style="color: #999999;">Значением по умолчанию <tt class="xref py py-data docutils literal"><span class="pre">raiseExceptions</span></tt> является <tt class="xref docutils literal"><span class="pre">True</span></tt>, потому что в процессе разработки Вы скорее всего хотите знать обо всех возникающих исключениях. В работающей уже библиотеке рекомендуется установить в качестве значения <tt class="xref py py-data docutils literal"><span class="pre">raiseExceptions</span></tt> <tt class="xref docutils literal"><span class="pre">False</span></tt>.</span></div>
</div>
</div>
<div class="section" id="using-arbitrary-objects-as-messages" style="text-align: justify;">
<span style="color: #999999;"></span><br />
<h2>
Использование произвольных объектов в качестве сообщений</h2>
В предыдущих разделах и примерах мы подразумевали, что в качестве сообщения передаётся строка. Однако, можно передать любой объект, у которого будет вызван метод
<a class="reference internal" href="http://docs.python.org/2/reference/datamodel.html#object.__str__" title="object.__str__"><tt class="xref py py-meth docutils literal"><span class="pre">__str__()</span></tt></a>, когда его потребуется преобразовать в строку. На самом деле, если Вы хотите, Вы можете даже избежать перевода объекта в строковое преобразование, например,
<tt class="xref py py-class docutils literal"><span class="pre">SocketHandler</span></tt> посылает событие сериализуя его и отправляя по сети.</div>
<h2 style="text-align: justify;">
Оптимизация</h2>
<div style="text-align: justify;">
Форматирование аргументов сообщения происходит как можно позже, когда его уже нельзя избежать. Однако, вычисление аргументов, переданных методу логирования может стоить дорого и Вы можете хотеть избежать этого, особенно в случае если сообщение будет просто отброшено. Для этого Вы можете использовать метод <tt class="xref py py-meth docutils literal"><span class="pre">isEnabledFor()</span></tt>, который принимает в качестве аргумента уровень и возвращает true, если событие будет обработано logger'ом для этого уровня. Код может быть такой:<br />
</div>
<div class="highlight-python" style="position: relative; text-align: justify;">
<div class="highlight">
<pre><span class="k">if</span> <span class="n">logger</span><span class="o">.</span><span class="n">isEnabledFor</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">):</span>
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">'Message with </span><span class="si">%s</span><span class="s">, </span><span class="si">%s</span><span class="s">'</span><span class="p">,</span> <span class="n">expensive_func1</span><span class="p">(),</span>
<span class="n">expensive_func2</span><span class="p">())</span>
</pre>
</div>
</div>
<div style="text-align: justify;">
<br />
так что если порог logger’а выше, чем <tt class="docutils literal"><span class="pre">DEBUG</span></tt>, вызовы
<tt class="xref py py-func docutils literal"><span class="pre">expensive_func1()</span></tt> и <tt class="xref py py-func docutils literal"><span class="pre">expensive_func2()</span></tt> не будут произведены.</div>
<div style="text-align: justify;">
Есть и другие настройки оптимизации, которые можно применить для специфических приложений, которым нужен более полный контроль над тем, какая информация для логирования собирается. Вот список того, что Вы можете сделать, чтобы избежать логирования того, чего Вы не хотите:</div>
<table border="1" class="docutils" style="margin-left: 0px; margin-right: 0px; text-align: left;">
<colgroup>
<col width="54%"></col>
<col width="46%"></col>
</colgroup>
<thead valign="bottom">
<tr><th class="head">Чего Вы не хотите собирать</th>
<th class="head">Как этого избежать</th>
</tr>
</thead>
<tbody valign="top">
<tr><td>Информацию о том, где был сделан вызов</td>
<td><tt class="docutils literal"><span class="pre">logging._srcfile</span></tt> = <tt class="xref docutils literal"><span class="pre">None</span></tt>.</td>
</tr>
<tr><td>Информацию о потоках</td>
<td><tt class="docutils literal"><span class="pre">logging.logThreads</span></tt> = <tt class="docutils literal"><span class="pre">0</span></tt>.</td>
</tr>
<tr><td>Информацию о процессах</td>
<td><tt class="docutils literal"><span class="pre">logging.logProcesses</span></tt> = <tt class="docutils literal"><span class="pre">0</span></tt>.</td>
</tr>
</tbody>
</table>
<div style="text-align: justify;">
Обратите внимание, что ядро модуля логирования содержит только основные handler'ы. Если Вы не импортируете <a class="reference internal" href="http://docs.python.org/2/library/logging.handlers.html#module-logging.handlers" title="logging.handlers: Handlers for the logging module."><tt class="xref py py-mod docutils literal"><span class="pre">logging.handlers</span></tt></a> и <a class="reference internal" href="http://docs.python.org/2/library/logging.config.html#module-logging.config" title="logging.config: Configuration of the logging module."><tt class="xref py py-mod docutils literal"><span class="pre">logging.config</span></tt></a>, они не будут занимать память.</div>
Ishayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com7tag:blogger.com,1999:blog-2142461056765545912.post-3949932054060187572013-02-01T09:36:00.002+04:002013-02-01T09:36:20.779+04:00Fabric: Операции<div style="text-align: justify;">
Операции - функции, которые используются в fabfile и в другом "не ядерном" коде, таком как run()/sudo().</div>
<a name='more'></a><br />
<h3 style="text-align: justify;">
fabric.operations.get(remote_path, local_path = None)</h3>
<div style="text-align: justify;">
Скачивает один или более файлов с удалённого узла.</div>
<br />
<div style="text-align: justify;">
get возвращает итерируемый объект, содержащий абсолютные пути ко всем загруженным файлам, который будет пустым, если <span style="background-color: #cccccc;">local_path</span> будет объектом StringIO (ниже мы познакомимся со StringIO более подробно). Этот объект так же выставляет атрибут <span style="background-color: #cccccc;">.failed</span>, содержащий все удалённые пути, загрузка с которых не удалась, и .succeeded, эквивалентный <span style="background-color: #cccccc;">not .failed</span>.</div>
<div style="text-align: justify;">
<span style="background-color: #cccccc;">remote_path</span> - это удалённый файл или каталог для загрузки, который может использовать синтаксис подстановки оболочки, например, <span style="background-color: #cccccc;">/var/log/apache2/*.log</span>, и тильды будут замещены на удалённую домашнюю директорию. Относительные пути будут рассматриваться относительно домашнего каталога удалённого пользователя или текущего рабочего каталога, если используются в команде <u>cd</u>. Если удалённый genm указывает на каталог, то он будет рекурсивно скачан.</div>
<div style="text-align: justify;">
<span style="background-color: #cccccc;">local_path</span> - локальный путь, куда будут загружены файлы. Если путь относительный, он будет трактоваться относительно текущей рабочей директории. Он может быть построен при помощи стандартной вставки на основании словарей со следующими переменными:</div>
<div style="text-align: justify;">
<ul>
<li><span style="background-color: #cccccc;">host</span>: Значение <span style="background-color: #cccccc;">env.host_string</span>, например, <span style="background-color: #cccccc;">myhostname</span> или <span style="background-color: #cccccc;">user@myhostname-222</span> (двоеточие между именем узла и номером порта заменено на тире для увеличения совместимости с разными ФС)</li>
<li><span style="background-color: #cccccc;">dirname</span>: Часть каталога из удалённого пути, т.е. <span style="background-color: #cccccc;">src/projectname</span> в <span style="background-color: #cccccc;">/src/projectname/utils.py</span></li>
<li><span style="background-color: #cccccc;">basename</span>: Часть файла из удалённого пути, т.е. <span style="background-color: #cccccc;">utils.py</span> в <span style="background-color: #cccccc;">/src/projectname/utils.py </span></li>
<li><span style="background-color: #cccccc;">path</span>: Полный удалённый путь: <span style="background-color: #cccccc;">/src/projectname/utils.py </span></li>
</ul>
</div>
<dl class="function" style="background-color: white; margin: 1em 0px 2.5em;"><dd style="margin-bottom: 10px; margin-left: 30px; margin-top: 3px;"><div class="admonition note" style="background-color: #e9ffe9; border: 1px solid rgb(96, 144, 96); margin: 2em; padding: 0px;">
<div class="first admonition-title" style="background-color: #70a070; border-bottom-color: rgb(96, 144, 96); border-bottom-style: solid; border-bottom-width: 1px; color: white; font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 1.1em; font-weight: bold; line-height: 24px; padding: 0.1em 0px 0.1em 0.5em; text-align: justify; text-shadow: rgba(0, 0, 0, 0.498039) 0px 1px;">
Примечание</div>
<div style="margin: 0.5em 1em; padding: 0px; text-align: justify;">
<span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;">Если </span></span><tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; line-height: 24px;"><span class="pre">remote_path</span></tt><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;"> - абсолютный путь, то только подкаталоги будут </span><span style="font-size: 14.399999618530273px; line-height: 24px;">созданы</span><span style="font-size: 0.9em; line-height: 24px;"> локально и переданы в переменные выше. Так, например, </span></span><tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; line-height: 24px;"><span class="pre">get('/var/log',</span> <span class="pre">'%(path)s')</span></tt><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;"> будет записывать файлы как </span></span><tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; line-height: 24px;"><span class="pre">apache2/access.log</span></tt><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;">,</span></span><tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; line-height: 24px;"><span class="pre">postgresql/8.4/postgresql.log</span></tt><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;"> и т.д. в локальный рабочий каталог. Он <b>не</b> будет записывать файлы как</span></span><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;"> </span></span><tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; line-height: 24px;"><span class="pre">var/log/apache2/access.log</span></tt><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;">.</span></span></div>
<div style="margin: 0.5em 1em; padding: 0px; text-align: justify;">
<span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;">Кроме того, когда скачивается один файл, </span></span><tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; line-height: 24px;"><span class="pre">%(dirname)s</span></tt><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;"> и </span></span><tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; line-height: 24px;"><span class="pre">%(path)s</span></tt><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;"> не имеют особого смысла и будут, </span><span style="font-size: 14.399999618530273px; line-height: 24px;">соответственно</span><span style="font-size: 0.9em; line-height: 24px;"> иметь пустое значение и значение, равное </span></span><tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; line-height: 24px;"><span class="pre">%(basename)s</span></tt><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;">. Таким образом, вызов вроде </span></span><tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; line-height: 24px;"><span class="pre">get('/var/log/apache2/access.log',</span> <span class="pre">'%(path)s')</span></tt><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;"> сохранит локальный файл под именем </span></span><tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; line-height: 24px;"><span class="pre">access.log</span></tt><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;">, а не </span></span><tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; line-height: 24px;"><span class="pre">var/log/apache2/access.log</span></tt><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;">.</span></span></div>
<div class="last" style="margin: 0.5em 1em; padding: 0px; text-align: justify;">
<span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;">Такое поведение </span><span style="font-size: 14.399999618530273px; line-height: 24px;">предназначено</span><span style="font-size: 0.9em; line-height: 24px;"> для </span><span style="font-size: 14.399999618530273px; line-height: 24px;">соответствия</span><span style="font-size: 0.9em; line-height: 24px;"> программе командной строки </span></span><tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; line-height: 24px;"><span class="pre">scp</span></tt><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;">.</span></span></div>
</div>
<div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
Если значение не задано, то <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">local_path</span></tt> получает значение <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">"%(host)s/%(path)s"</span></tt> чтобы это было безопасно для использования на нескольких узлах.</div>
<div class="admonition warning" style="background-color: #ffe9e9; border: 1px solid rgb(144, 0, 0); font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 0.9em; line-height: 24px; margin: 2em; padding: 0px;">
<div class="first admonition-title" style="background-color: #b04040; border-bottom-color: rgb(144, 0, 0); border-bottom-style: solid; border-bottom-width: 1px; color: white; font-size: 1.1em; font-weight: bold; padding: 0.1em 0px 0.1em 0.5em; text-align: justify; text-shadow: rgba(0, 0, 0, 0.498039) 0px 1px;">
Предупреждение</div>
<div class="last" style="margin: 0.5em 1em; padding: 0px; text-align: justify;">
Если ваш аргумент <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">local_path</span></tt> не содержит <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">%(host)s</span></tt> и ваш вызов <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.get" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.get"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">get</span></tt></a> запускается на нескольких хостах, ваши локальные файлы будут перезаписаны при каждом удачном запуске!</div>
</div>
<div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
Если <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">local_path</span></tt> не использует вышеозначенные переменные (т.е. это просто явный путь) он будет действовать похоже командам <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">scp</span></tt> или <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">cp</span></tt>, перезаписывая при необходимости существующие файлы, скачивая их в нужное место (т.е. <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">get('/path/to/remote_file.txt', </span><span class="pre">'local_directory')</span></tt> создаст <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">local_directory/remote_file.txt</span></tt>) и т.п.</div>
<div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">local_path</span></tt> может быть и файлоподобным объектом, например, результатом <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">open('path',</span> <span class="pre">'w')</span></tt> или экземпляром <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">StringIO</span></tt>.</div>
<div class="admonition note" style="background-color: #e9ffe9; border: 1px solid rgb(96, 144, 96); font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 0.9em; line-height: 24px; margin: 2em; padding: 0px;">
<div class="first admonition-title" style="background-color: #70a070; border-bottom-color: rgb(96, 144, 96); border-bottom-style: solid; border-bottom-width: 1px; color: white; font-size: 1.1em; font-weight: bold; padding: 0.1em 0px 0.1em 0.5em; text-align: justify; text-shadow: rgba(0, 0, 0, 0.498039) 0px 1px;">
Примечание</div>
<div class="last" style="margin: 0.5em 1em; padding: 0px; text-align: justify;">
Попытка выполнить <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.get" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.get"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">get</span></tt></a> каталога в файлоподобный объект некорректна и вернёт ошибку.</div>
</div>
<div class="admonition note" style="background-color: #e9ffe9; border: 1px solid rgb(96, 144, 96); margin: 2em; padding: 0px;">
<div class="first admonition-title" style="background-color: #70a070; border-bottom-color: rgb(96, 144, 96); border-bottom-style: solid; border-bottom-width: 1px; color: white; font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 1.1em; font-weight: bold; line-height: 24px; padding: 0.1em 0px 0.1em 0.5em; text-align: justify; text-shadow: rgba(0, 0, 0, 0.498039) 0px 1px;">
Примечание</div>
<div class="last" style="margin: 0.5em 1em; padding: 0px; text-align: justify;">
<span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;">Эта функция будет использовать </span></span><tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; line-height: 24px;"><span class="pre">seek</span></tt><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;"> и </span></span><tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; line-height: 24px;"><span class="pre">tell</span></tt><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;"> для перезаписи всего содержимого файлоподобного объекта, чтобы это соответствовало поведению </span></span><a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.put" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 0.9em; line-height: 24px; text-decoration: initial;" title="fabric.operations.put"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">put</span></tt></a><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;"> (который тоже использует весь файл). Однако, в отличие от </span></span><a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.put" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 0.9em; line-height: 24px; text-decoration: initial;" title="fabric.operations.put"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">put</span></tt></a><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;">, указатель файла не будет </span><span style="font-size: 14.399999618530273px; line-height: 24px;">восстановлен</span><span style="font-size: 0.9em; line-height: 24px;"> в предыдущую локацию, так как это достаточно бессмысленно и/или даже не возможно.</span></span></div>
</div>
<div class="admonition note" style="background-color: #e9ffe9; border: 1px solid rgb(96, 144, 96); font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 0.9em; line-height: 24px; margin: 2em; padding: 0px;">
<div class="first admonition-title" style="background-color: #70a070; border-bottom-color: rgb(96, 144, 96); border-bottom-style: solid; border-bottom-width: 1px; color: white; font-size: 1.1em; font-weight: bold; padding: 0.1em 0px 0.1em 0.5em; text-align: justify; text-shadow: rgba(0, 0, 0, 0.498039) 0px 1px;">
Примечание</div>
<div class="last" style="margin: 0.5em 1em; padding: 0px; text-align: justify;">
Из-за того, как работают наши слои SSH, временные файлы всё равно будут записаны во временный файл на диске, даже если Вы передаёте в качестве аргумента <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">local_path</span></tt> файлоподобный объект или StringIO. Временные файлы будут удалены, но имейте это в виду и не ожидайте прямой передачи данных в память. (Мы надеемся исправить это в будущем, чтобы дать возможность прямой передачи данных в память.)</div>
</div>
<div class="admonition note" style="background-color: #e9ffe9; border: 1px solid rgb(96, 144, 96); font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 0.9em; line-height: 24px; margin: 2em; padding: 0px;">
<div class="first admonition-title" style="background-color: #70a070; border-bottom-color: rgb(96, 144, 96); border-bottom-style: solid; border-bottom-width: 1px; color: white; font-size: 1.1em; font-weight: bold; padding: 0.1em 0px 0.1em 0.5em; text-align: justify; text-shadow: rgba(0, 0, 0, 0.498039) 0px 1px;">
Примечание</div>
<div class="last" style="margin: 0.5em 1em; padding: 0px; text-align: justify;">
Если файлоподбный объект, такой как StringIO имеет атрибут <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">name</span></tt>, он будет использован в выводе Fabric, вместо простого <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre"><file</span> <span class="pre">obj></span></tt></div>
</div>
<div class="versionchanged" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Изменения в версии 1.0: </span><span class="versionmodified">Теперь есть отдельный удалённый рабочий каталог, с которым работает</span> <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/context_managers.html#fabric.context_managers.cd" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.context_managers.cd"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">cd</span></tt></a>, и локальный рабочий каталог, с которым работает <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/context_managers.html#fabric.context_managers.lcd" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.context_managers.lcd"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">lcd</span></tt></a>.</div>
<div class="versionchanged" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Изменения в версии 1.0: </span><span class="versionmodified">Теперь можно использовать файлоподобные объекты в качестве аргумента</span> <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">local_path</span></tt>.</div>
<div class="versionchanged" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Изменения в версии 1.0: </span><tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">local_path</span></tt> может теперь содержать переменные genb и узла.</div>
<div class="versionchanged" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Изменения в версии 1.0: </span><span class="versionmodified">В аргументе</span> <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">remote_path</span></tt> можно использовать каталоги, которые будут рекурсивно загружены.</div>
<div class="versionchanged" style="margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; font-style: italic; line-height: 24px;">Изменения в версии 1.0: </span><span class="versionmodified" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px;">Возвращает итерируемый объект, содержащий локальные пути, содержащий </span><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="line-height: 24px;">атрибуты </span></span><tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; line-height: 24px;"><span class="pre">.failed</span></tt><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="line-height: 24px;"> и</span></span><tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; line-height: 24px;"><span class="pre">.succeeded</span></tt><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="line-height: 24px;">.</span></span></div>
<div class="versionchanged" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Изменения в версии 1.5: </span><span class="versionmodified">Использует атрибут</span> <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">name</span></tt> файлоподобного объекта для вывода лога</div>
</dd></dl>
<dl class="function" style="background-color: white; margin: 1em 0px 2.5em;">
<dt id="fabric.operations.local" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; text-align: justify;"><tt class="descclassname" style="background-color: transparent; border: 0px; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;">fabric.operations.</tt><tt class="descname" style="background-color: transparent; border: 0px; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 1.2em; font-weight: bold; letter-spacing: 0.01em;">local</tt><big>(</big><em>command</em>, <em>capture=False</em>, <em>shell=None</em><big>)</big><a class="headerlink" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.local" style="border: none; color: #cccccc; font-size: 1em; margin-left: 6px; padding: 0px 4px; text-decoration: initial; visibility: hidden;" title="Permalink to this definition"></a></dt>
<dd style="margin-bottom: 10px; margin-left: 30px; margin-top: 3px;"><div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
Выполняет команду на локальной системе.</div>
<div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.local" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.local"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">local</span></tt></a> - это лишь оболочка вокруг использования встроенного модуля Python <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">subprocess</span></tt> с <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">shell=True</span></tt>. Если Вам надо сделать что-то особое - используйте модуль <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">subprocess</span></tt> напрямую.</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
<tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; line-height: 24px;"><span class="pre">shell</span></tt><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="line-height: 24px;"> передаётся напрямую в аргумент </span></span><tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; line-height: 24px;"><span class="pre">execute</span></tt><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="line-height: 24px;"> </span></span><a class="reference external" href="http://docs.python.org/library/subprocess.html#subprocess.Popen" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; text-decoration: initial;">subprocess.Popen</a><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="line-height: 24px;">‘а (что определяет используемую локально оболочку.) В соответствии со документацией, на Unix по умолчанию используется </span></span><tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; line-height: 24px;"><span class="pre">/bin/sh</span></tt><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="line-height: 24px;">, так что эта опция полезна для установки других значений, например, </span></span><tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; line-height: 24px;"><span class="pre">/bin/bash</span></tt><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="line-height: 24px;">.</span></span></div>
<div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.local" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.local"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">local</span></tt></a> на данный момент не способен одновременно вводить и выводить информация, в отличие от <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.run" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.run"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">run</span></tt></a>/<a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.sudo" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.sudo"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">sudo</span></tt></a>. Именованный аргумент <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">capture</span></tt> позволяет переключаться между выводом и вводом при необходимости, значение по умолчанию - <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">False</span></tt>.</div>
<div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
Когда <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">capture=False</span></tt>, локальные ввод и вывод subprocess’a направляется напрямую на ваш терминал, хотя Вы можете использовать глобальные <a class="reference internal" href="http://docs.fabfile.org/en/1.5/usage/output_controls.html" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;"><em>настройки вывода</em></a> <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">output.stdout</span></tt> и <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">output.stderr,</span></tt> чтобы спрятать один из них или оба. В этом режиме возвращаемые значения stdout/stderr всегда будут пустыми.</div>
<div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
Если <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">capture=True</span></tt>, то Вы не увидите никакого вывода на вашем терминале, но возвращаемое значение будет храниться в stdout/stderr.</div>
<div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
В любом случае, как и при запуске <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.run" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.run"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">run</span></tt></a> и <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.sudo" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.sudo"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">sudo</span></tt></a>, возвращаемое значение содержит атрибуты <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">return_code</span></tt>, <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">stderr</span></tt>, <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">failed</span></tt> и <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">succeeded</span></tt>. Более подробно это описано в <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.run" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.run"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">run</span></tt></a>.</div>
<div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.local" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.local"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">local</span></tt></a> будет учитывать менеджер контекста <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/context_managers.html#fabric.context_managers.lcd" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.context_managers.lcd"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">lcd</span></tt></a>, позволяющий Вам контролировать текущий рабочий каталог вне зависимости от удалённого каталога (которым управляет <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/context_managers.html#fabric.context_managers.cd" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.context_managers.cd"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">cd</span></tt></a>).</div>
<div class="versionchanged" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Изменения в версии 1.0: </span><span class="versionmodified">Добавлены атрибуты</span> <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">succeeded</span></tt> и <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">stderr</span></tt>.</div>
<div class="versionchanged" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Изменения в версии 1.0: </span><span class="versionmodified">Теперь учитывает менеджер контекста</span> <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/context_managers.html#fabric.context_managers.lcd" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.context_managers.lcd"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">lcd</span></tt></a>.</div>
<div class="versionchanged" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Изменения в версии 1.0: </span><span class="versionmodified">Значение по умолчанию для</span> <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">capture</span></tt> изменено с <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">True</span></tt> на <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">False</span></tt>.</div>
</dd></dl>
<dl class="function" style="background-color: white; font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin: 1em 0px 2.5em;">
<dt id="fabric.operations.open_shell" style="text-align: justify;"><tt class="descclassname" style="background-color: transparent; border: 0px; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;">fabric.operations.</tt><tt class="descname" style="background-color: transparent; border: 0px; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 1.2em; font-weight: bold; letter-spacing: 0.01em;">open_shell</tt><big>(</big><em>command=None</em><big>)</big><a class="headerlink" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.open_shell" style="border: none; color: #cccccc; font-size: 1em; margin-left: 6px; padding: 0px 4px; text-decoration: initial; visibility: hidden;" title="Permalink to this definition"></a></dt>
<dd style="margin-bottom: 10px; margin-left: 30px; margin-top: 3px;"><div style="margin-bottom: 0.5em; text-align: justify;">
Вызывает интерактивную оболочку на удалённой системе.</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
Если передан аргумент <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">command</span></tt>, то он будет передан по каналу перед тем, как передать управление пользователю.</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
Эта функция чаще всего используется когда Вам нужно взаимодействовать с серьёзными командами оболочки или набором команд, например, при отладке или когда нужно провести полностью интерактивное восстановление при ошибке удалённой программы.</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
Следует иметь ввиду, что интерактивная оболочка в середине скрипта и <i>не</i> является заменой команды <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.run" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.run"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">run</span></tt></a>, которая тоже может взаимодействовать с удалённым хостом (хотя только во время выполнения переданной команды) и подразумевает решение большего количества программных проблем, таких как обработка ошибок и захват ввода/вывода.</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
Конкретнее, <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.open_shell" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.open_shell"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">open_shell</span></tt></a> предоставляет больше интерактивности, чем <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.run" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.run"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">run</span></tt></a>, использование полноценной удалённой оболочки не позволяет Fabric определить, завершилась ли программа с ошибкой и заполняет ввод/вывод вводом/выводом оболочки, таким как заставки входа, приглашения и т.д.</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
Таким образом, эта функция не имеет возвращаемого значения и не вызывает обработку ошибок Fabric, если какая-либо удалённая программа завершилась с ошибкой.</div>
<div class="versionadded" style="margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Начиная с версии 1.0.</span></div>
</dd></dl>
<dl class="function" style="background-color: white; font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin: 1em 0px 2.5em;">
<dt id="fabric.operations.prompt" style="text-align: justify;"><tt class="descclassname" style="background-color: transparent; border: 0px; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;">fabric.operations.</tt><tt class="descname" style="background-color: transparent; border: 0px; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 1.2em; font-weight: bold; letter-spacing: 0.01em;">prompt</tt><big>(</big><em>text</em>, <em>key=None</em>, <em>default=''</em>, <em>validate=None</em><big>)</big><a class="headerlink" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.prompt" style="border: none; color: #cccccc; font-size: 1em; margin-left: 6px; padding: 0px 4px; text-decoration: initial; visibility: hidden;" title="Permalink to this definition"></a></dt>
<dd style="margin-bottom: 10px; margin-left: 30px; margin-top: 3px;"><div style="margin-bottom: 0.5em; text-align: justify;">
Выдаёт пользователю запрос с текстом <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">text</span></tt> и возвращает полученное значение (как <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">raw_input</span></tt>).</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
Для удобства к <span style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 15.199999809265137px;">text</span> будет добавлен одиночный пробел, ничего больше. Таким образом Вы можете завершить свой запрос вопросительным знаком или двоеточием, например <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">prompt("What</span> <span class="pre">hostname?")</span></tt>.</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
Если указан <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">key</span></tt>, ввод пользователя и будет сохранён как <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">env.<key></span></tt> и возвращён этой функцией <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.prompt" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.prompt"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">prompt</span></tt></a>. Если этот ключ уже существует в <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">env</span></tt>, то его значение будет перезаписано и пользователю будет выдано предупреждение.</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
Если передан параметр <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">default</span></tt>, то он будет выведен в квадратных скобках и будет использоваться в случае, если пользователь ничего не введёт (т.e. нажмёт Enter без ввода текста). По умолчанию значением <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">default</span></tt> является пустая строка. Если значением является не пустая строка, то к нему будет добавлен пробел, так что вызов <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">prompt("Каково имя узла</span><span class="pre">?",</span> <span class="pre">default="foo")</span></tt> приведёт к отображению <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">Каково имя узла</span><span class="pre">?</span> <span class="pre">[foo] </span></tt> (с пробелом после <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">[foo]</span></tt>.)</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
Опциональный именованный аргумент <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">validate</span></tt> может быть вызываемым объектом или строкой:</div>
<ul class="simple" style="margin-bottom: 10px;">
<li style="text-align: justify;">Если это вызываемый объект, то он будет вызван с полученной от пользователя строкой и должен вернуть значение для сохранения в случае успеха. При ошибке он должен вызвать исключение с сообщением, которое будет показано пользователю.</li>
<li style="text-align: justify;">Если это строка, то значение, переданное в параметре <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">validate</span></tt> используется как регулярное выражение. Поэтому рекомендуется использовать "сырые" строки. Обратите внимание, что регулярное выражение будет (<i>в любом случае?</i>) требовать полного совпадения.</li>
</ul>
<div style="margin-bottom: 0.5em; text-align: justify;">
В любом случае <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.prompt" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.prompt"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">prompt</span></tt></a> будет перезапрашивать ввод от пользователя до тех пор, пока не пройдёт валидация (или пользователь не нажмёт <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">Ctrl-C</span></tt>).</div>
<div class="admonition note" style="background-color: #e9ffe9; border: 1px solid rgb(96, 144, 96); font-size: 0.9em; margin: 2em; padding: 0px;">
<div class="first admonition-title" style="background-color: #70a070; border-bottom-color: rgb(96, 144, 96); border-bottom-style: solid; border-bottom-width: 1px; color: white; font-size: 1.1em; font-weight: bold; padding: 0.1em 0px 0.1em 0.5em; text-align: justify; text-shadow: rgba(0, 0, 0, 0.498039) 0px 1px;">
Примечание</div>
<div class="last" style="margin: 0.5em 1em; padding: 0px; text-align: justify;">
<a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.prompt" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.prompt"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">prompt</span></tt></a> учитывает <a class="reference internal" href="http://docs.fabfile.org/en/1.5/usage/env.html#abort-on-prompts" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;"><em>env.abort_on_prompts</em></a> и будет вызывать <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/utils.html#fabric.utils.abort" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.utils.abort"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">abort</span></tt></a> вместо запроса, если этот флаг установлен в <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">True</span></tt>. Если Вы хотите заблокировать ввод пользователя безусловно, но в этом случае запросить информацию у пользователя - оберните код при помощи <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/context_managers.html#fabric.context_managers.settings" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.context_managers.settings"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">settings</span></tt></a>.</div>
</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
Примеры:</div>
<div class="highlight-python">
<div class="highlight" style="background-color: transparent; background-position: initial initial; background-repeat: initial initial;">
<pre style="background-color: #eeeeee; border-bottom-left-radius: 6px; border-bottom-right-radius: 6px; border-top-left-radius: 6px; border-top-right-radius: 6px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.015em; line-height: 18px; margin: 1em 2em; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><div style="text-align: justify;">
<span style="color: #408090; font-size: 0.95em; font-style: italic; letter-spacing: 0.015em;"># Простейшая форма:</span></div>
<span class="n"><div style="text-align: justify;">
<span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">environment</span><span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="o" style="color: #666666; font-size: 0.95em; letter-spacing: 0.015em;">=</span><span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">prompt</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">(</span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">'Please specify target environment: '</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">)</span></div>
</span>
<div style="text-align: justify;">
<span style="color: #408090; font-size: 0.95em; font-style: italic; letter-spacing: 0.015em;"># Со значением по умолчанию и сохранением как env.dish:</span></div>
<span class="n"><div style="text-align: justify;">
<span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">prompt</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">(</span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">'Specify favorite dish: '</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">,</span><span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">'dish'</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">,</span><span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">default</span><span class="o" style="color: #666666; font-size: 0.95em; letter-spacing: 0.015em;">=</span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">'spam & eggs'</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">)</span></div>
</span>
<div style="text-align: justify;">
<span style="color: #408090; font-size: 0.95em; font-style: italic; letter-spacing: 0.015em;"># С валидацией, требуем ввод числа:</span></div>
<span class="n"><div style="text-align: justify;">
<span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">prompt</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">(</span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">'Please specify process nice level: '</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">,</span><span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">key</span><span class="o" style="color: #666666; font-size: 0.95em; letter-spacing: 0.015em;">=</span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">'nice'</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">,</span><span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">validate</span><span class="o" style="color: #666666; font-size: 0.95em; letter-spacing: 0.015em;">=</span><span class="nb" style="color: #007020; font-size: 0.95em; letter-spacing: 0.015em;">int</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">)</span></div>
</span>
<div style="text-align: justify;">
<span style="color: #408090; font-size: 0.95em; font-style: italic; letter-spacing: 0.015em;"># С валидацией по регулярному выражению:</span></div>
<span class="n"><div style="text-align: justify;">
<span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">release</span><span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="o" style="color: #666666; font-size: 0.95em; letter-spacing: 0.015em;">=</span><span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">prompt</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">(</span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">'Please supply a release name'</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">,</span></div>
</span><div style="text-align: justify;">
<span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">validate</span><span class="o" style="color: #666666; font-size: 0.95em; letter-spacing: 0.015em;">=</span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">r'^\w+-\d+(\.\d+)?$'</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">)</span></div>
<div style="text-align: justify;">
<span style="color: #408090; font-size: 0.95em; font-style: italic; letter-spacing: 0.015em;"># Запрос вне зависимости от глобальной настройки:</span></div>
<span class="k" style="color: #007020; font-weight: bold;"><div style="text-align: justify;">
<span class="k" style="font-size: 0.95em; letter-spacing: 0.015em;">with</span><span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">settings</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">(</span><span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">abort_on_prompts</span><span class="o" style="color: #666666; font-size: 0.95em; letter-spacing: 0.015em;">=</span><span class="bp" style="font-size: 0.95em; letter-spacing: 0.015em;">False</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">):</span></div>
</span><div style="text-align: justify;">
<span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">prompt</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">(</span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">'I seriously need an answer on this! '</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">)</span></div>
</pre>
</div>
</div>
</dd></dl>
<dl class="function" style="background-color: white; margin: 1em 0px 2.5em;">
<dt id="fabric.operations.put" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; text-align: justify;"><tt class="descclassname" style="background-color: transparent; border: 0px; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;">fabric.operations.</tt><tt class="descname" style="background-color: transparent; border: 0px; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 1.2em; font-weight: bold; letter-spacing: 0.01em;">put</tt><big>(</big><em>local_path=None</em>, <em>remote_path=None</em>, <em>use_sudo=False</em>, <em>mirror_local_mode=False</em>, <em>mode=None</em><big>)</big><a class="headerlink" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.put" style="border: none; color: #cccccc; font-size: 1em; margin-left: 6px; padding: 0px 4px; text-decoration: initial; visibility: hidden;" title="Permalink to this definition"></a></dt>
<dd style="margin-bottom: 10px; margin-left: 30px; margin-top: 3px;"><div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
Загружает один или более файлов на удалённый хост.</div>
<div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.put" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.put"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">put</span></tt></a> возвращает итерируемый объект, содержащий абсолютные пути ко всем загруженным файлам. Этот итерируемый объект содержит также атрибут <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">.failed</span></tt>, содержащий пути к локальным файлам, которые не удалось выгрузить (и потому его можно использовать для логической проверки.) Кроме того, Вы можете использовать <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">.succeeded</span></tt>, который эквивалентен <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">not</span> <span class="pre">.failed</span></tt>.</div>
<div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">local_path</span></tt> может быть как относительным, так и абсолютным путём, или даже каталогом, может содержать символы подстановки оболочки, как они используются в модуле <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">glob</span></tt>. Можно использовать и ~ (так же как в <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">os.path.expanduser</span></tt>).</div>
<div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">local_path</span></tt> может быть и файлоподобным объектом, как, например, результатом <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">open('path')</span></tt> или экземпляром <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">StringIO</span></tt>.</div>
<div class="admonition note" style="background-color: #e9ffe9; border: 1px solid rgb(96, 144, 96); margin: 2em; padding: 0px;">
<div class="first admonition-title" style="background-color: #70a070; border-bottom-color: rgb(96, 144, 96); border-bottom-style: solid; border-bottom-width: 1px; color: white; font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 1.1em; font-weight: bold; line-height: 24px; padding: 0.1em 0px 0.1em 0.5em; text-align: justify; text-shadow: rgba(0, 0, 0, 0.498039) 0px 1px;">
Примечание</div>
<div class="last" style="margin: 0.5em 1em; padding: 0px; text-align: justify;">
<span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;">В таком случае </span></span><a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.put" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 0.9em; line-height: 24px; text-decoration: initial;" title="fabric.operations.put"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">put</span></tt></a><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;"> постарается прочитать всё содержимое файлоподобного объекта, проматывая его при помощи </span></span><tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; line-height: 24px;"><span class="pre">seek</span></tt><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;"> (и будет использовать </span></span><tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; line-height: 24px;"><span class="pre">tell</span></tt><span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="font-size: 0.9em; line-height: 24px;"> для сохранения </span><span style="font-size: 14.399999618530273px; line-height: 24px;">предыдущей</span><span style="font-size: 0.9em; line-height: 24px;"> позиции файла).</span></span></div>
</div>
<div class="admonition note" style="background-color: #e9ffe9; border: 1px solid rgb(96, 144, 96); font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 0.9em; line-height: 24px; margin: 2em; padding: 0px;">
<div class="first admonition-title" style="background-color: #70a070; border-bottom-color: rgb(96, 144, 96); border-bottom-style: solid; border-bottom-width: 1px; color: white; font-size: 1.1em; font-weight: bold; padding: 0.1em 0px 0.1em 0.5em; text-align: justify; text-shadow: rgba(0, 0, 0, 0.498039) 0px 1px;">
Примечание</div>
<div class="last" style="margin: 0.5em 1em; padding: 0px; text-align: justify;">
Использование файлоподобного объекта в команде <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.put" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.put"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">put</span></tt></a> в аргументе <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">local_path</span></tt> приведёт к удалению временного файла из-за нашей реалиации слоя SSH.</div>
</div>
<div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">remote_path</span></tt> также может быть абсолютным или относительным путём, но применяется к удалённому узлу. Относительный genm трактуется относительно домашней директории удалённого пользователя, но, при необходимости, можно использовать и тильду (т.е. <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">~/.ssh/</span></tt>).</div>
<div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
Пустая строка в качестве значения любого из двух аргументов пути будет замещена на текущий рабочий каталог.</div>
<div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
Хотя протокол SFTP (который используется <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.put" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.put"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">put</span></tt></a>) не имеет возможности загрузить файл в локацию, которая не принадлежит подключившемуся пользователю, Вы можете задать <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">use_sudo=True</span></tt>, чтобы обойти это. При использовании этого параметра <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.put" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.put"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">put</span></tt></a> загружает файлы во временный каталог на удалённом хосте и затем использует <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.sudo" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.sudo"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">sudo</span></tt></a> для перемещения их в <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">remote_path</span></tt>.</div>
<div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
В некоторых случаях желательно чтобы загруженные файлы имели аналогичный режим, как и их локальные "коллеги" (например, когда Вы загружаете выполняемые скрипты). Для этого используйте <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">mirror_local_mode=True</span></tt>.</div>
<div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
В качестве альтернативы Вы можете использовать именованный аргумент <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">mode</span></tt> для того, чтобы задать режим извлечения так же как и <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">os.chmod</span></tt> или команда Unix <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">chmod</span></tt>.</div>
<div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.put" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.put"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">put</span></tt></a> учитывает результат <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/context_managers.html#fabric.context_managers.cd" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.context_managers.cd"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">cd</span></tt></a>, так что относительные пути в <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">remote_path</span></tt> будут толковаться относительно текущего удалённого рабочего каталога, если это возможно. Таким образом, например, код ниже выгрузит файл в <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">/tmp/files/test.txt</span></tt> а не в <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">~/files/test.txt</span></tt>:</div>
<div class="highlight-python" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px;">
<div class="highlight" style="background-color: transparent; background-position: initial initial; background-repeat: initial initial;">
<pre style="background-color: #eeeeee; border-bottom-left-radius: 6px; border-bottom-right-radius: 6px; border-top-left-radius: 6px; border-top-right-radius: 6px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.015em; line-height: 18px; margin: 1em 2em; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><div style="text-align: justify;">
<span class="k" style="color: #007020; font-size: 0.95em; font-weight: bold; letter-spacing: 0.015em;">with</span><span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">cd</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">(</span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">'/tmp'</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">):</span></div>
<div style="text-align: justify;">
<span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">put</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">(</span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">'/path/to/local/test.txt'</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">,</span><span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">'files'</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">)</span></div>
</pre>
</div>
</div>
<div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
Использование <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/context_managers.html#fabric.context_managers.lcd" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.context_managers.lcd"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">lcd</span></tt></a> будет влиять на <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">local_path</span></tt> аналогичным образом.</div>
<div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
Примеры:</div>
<div class="highlight-python" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px;">
<div class="highlight" style="background-color: transparent; background-position: initial initial; background-repeat: initial initial;">
<pre style="background-color: #eeeeee; border-bottom-left-radius: 6px; border-bottom-right-radius: 6px; border-top-left-radius: 6px; border-top-right-radius: 6px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.015em; line-height: 18px; margin: 1em 2em; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><div style="text-align: justify;">
<span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">put</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">(</span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">'bin/project.zip'</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">,</span><span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">'/tmp/project.zip'</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">)</span></div>
<span class="n"><div style="text-align: justify;">
<span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">put</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">(</span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">'*.py'</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">,</span><span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">'cgi-bin/'</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">)</span></div>
</span><span class="n"><div style="text-align: justify;">
<span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">put</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">(</span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">'index.html'</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">,</span><span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">'index.html'</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">,</span><span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">mode</span><span class="o" style="color: #666666; font-size: 0.95em; letter-spacing: 0.015em;">=</span><span class="mo" style="color: #208050; font-size: 0.95em; letter-spacing: 0.015em;">0755</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">)</span></div>
</span></pre>
</div>
</div>
<div class="admonition note" style="background-color: #e9ffe9; border: 1px solid rgb(96, 144, 96); font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 0.9em; line-height: 24px; margin: 2em; padding: 0px;">
<div class="first admonition-title" style="background-color: #70a070; border-bottom-color: rgb(96, 144, 96); border-bottom-style: solid; border-bottom-width: 1px; color: white; font-size: 1.1em; font-weight: bold; padding: 0.1em 0px 0.1em 0.5em; text-align: justify; text-shadow: rgba(0, 0, 0, 0.498039) 0px 1px;">
Примечание</div>
<div class="last" style="margin: 0.5em 1em; padding: 0px; text-align: justify;">
Если файлоподобный объект, такой как StringIO, имеет атрибут <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">name</span></tt>, то его значение будет использоваться в выводе Fabric, вместо стандартного <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre"><file</span> <span class="pre">obj></span></tt></div>
</div>
<div class="versionchanged" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Изменения в версии 1.0: </span><span class="versionmodified">Теперь учитывается удалённый рабочий каталог, управляемый</span> <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/context_managers.html#fabric.context_managers.cd" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.context_managers.cd"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">cd</span></tt></a>, и локальный рабочий каталог, управляемый <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/context_managers.html#fabric.context_managers.lcd" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.context_managers.lcd"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">lcd</span></tt></a>.</div>
<div class="versionchanged" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Изменения в версии 1.0: </span><span class="versionmodified">Теперь можно использовать файлоподобные объекты в аргументе</span> <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">local_path</span></tt>.</div>
<div class="versionchanged" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Изменения в версии 1.0: </span><span class="versionmodified">В аргументе</span> <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">local_path</span></tt> можно задать каталог, который будет рекурсивно выгружен на удалённый узел.</div>
<div class="versionchanged" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Изменения в версии 1.0: </span><span class="versionmodified">Возвращает итерируемый объект, содержащий удалённые пути с атрибутами</span> <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">.failed</span></tt> и<tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">.succeeded</span></tt>.</div>
<div class="versionchanged" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Изменения в версии 1.5: </span>Позволяет использовать атрибут <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">name</span></tt> файлоподобного объекта для вывода лога</div>
</dd></dl>
<dl class="function" style="background-color: white; font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin: 1em 0px 2.5em;">
<dt id="fabric.operations.reboot" style="text-align: justify;"><tt class="descclassname" style="background-color: transparent; border: 0px; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;">fabric.operations.</tt><tt class="descname" style="background-color: transparent; border: 0px; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 1.2em; font-weight: bold; letter-spacing: 0.01em;">reboot</tt><big>(</big><em>wait=120</em><big>)</big><a class="headerlink" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.reboot" style="border: none; color: #cccccc; font-size: 1em; margin-left: 6px; padding: 0px 4px; text-decoration: initial; visibility: hidden;" title="Permalink to this definition"></a></dt>
<dd style="margin-bottom: 10px; margin-left: 30px; margin-top: 3px;"><div style="margin-bottom: 0.5em; text-align: justify;">
Перезагружает удалённую систему.</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
Временно изменяет настройки переподключения (<a class="reference internal" href="http://docs.fabfile.org/en/1.5/usage/env.html#timeout" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;"><em>timeout</em></a> и <a class="reference internal" href="http://docs.fabfile.org/en/1.5/usage/env.html#connection-attempts" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;"><em>connection_attempts</em></a>) чтобы убедиться, что попытки подключения не прекратятся как минимум раньше <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">wait</span></tt> секунд.</div>
<div class="admonition note" style="background-color: #e9ffe9; border: 1px solid rgb(96, 144, 96); font-size: 0.9em; margin: 2em; padding: 0px;">
<div class="first admonition-title" style="background-color: #70a070; border-bottom-color: rgb(96, 144, 96); border-bottom-style: solid; border-bottom-width: 1px; color: white; font-size: 1.1em; font-weight: bold; padding: 0.1em 0px 0.1em 0.5em; text-align: justify; text-shadow: rgba(0, 0, 0, 0.498039) 0px 1px;">
Примечание</div>
<div style="margin: 0.5em 1em; padding: 0px; text-align: justify;">
По состоянию на Fabric 1.4, способность переподключиться в пределах сессии больше не требует использования внутреннего API. Хотя мы и не объявляем эту функцию нежелательной, тем не менее добавление к ней новых возможностей не стоит у нас в приоритетах.</div>
<div class="last" style="margin: 0.5em 1em; padding: 0px; text-align: justify;">
Пользователи, желающие получить больше возможностей должны посмотреть исходники этой функции (6 хорошо задокументированных строк) и написать свою собственную адаптацию с различными значениями timeout/attempts или дополнительной логикой.</div>
</div>
<div class="versionadded" style="margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Появился в версии 0.9.2.</span></div>
<div class="versionchanged" style="margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Изменения в версии 1.4: </span><span class="versionmodified">Изменен именованный аргумент</span> <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">wait</span></tt> - ему добавлено значение по умолчанию.</div>
</dd></dl>
<dl class="function" style="background-color: white; font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin: 1em 0px 2.5em;">
<dt id="fabric.operations.require" style="text-align: justify;"><tt class="descclassname" style="background-color: transparent; border: 0px; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;">fabric.operations.</tt><tt class="descname" style="background-color: transparent; border: 0px; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 1.2em; font-weight: bold; letter-spacing: 0.01em;">require</tt><big>(</big><em>*keys</em>, <em>**kwargs</em><big>)</big><a class="headerlink" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.require" style="border: none; color: #cccccc; font-size: 1em; margin-left: 6px; padding: 0px 4px; text-decoration: initial; visibility: hidden;" title="Permalink to this definition"></a></dt>
<dd style="margin-bottom: 10px; margin-left: 30px; margin-top: 3px;"><div style="margin-bottom: 0.5em; text-align: justify;">
Проверяет наличие переданных ключей в общем словаре окружения и прерывает выполнение, если их не находит.</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
Позиционными аргументами должны быть строки, определяющие то, какие переменные окружения должны быть проверены. Если какой-либо из этих переменных не существует, Fabric прервёт выполнение и выведен имена отсутствующих ключей.</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
Опциональный именованный аргумент <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">used_for</span></tt> может быть строкой, которая будет отправлена на стандартный вывод, чтобы сообщить пользователю, для каких целей будет использоваться отсутствующая переменная. <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">used_for</span></tt> выводится как часть строки вроде этой:</div>
<div class="highlight-python">
<div class="highlight" style="background-color: transparent; background-position: initial initial; background-repeat: initial initial;">
<pre style="background-color: #eeeeee; border-bottom-left-radius: 6px; border-bottom-right-radius: 6px; border-top-left-radius: 6px; border-top-right-radius: 6px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.015em; line-height: 18px; margin: 1em 2em; overflow-x: auto; overflow-y: hidden; padding: 0.5em; text-align: justify;"><span class="s" style="color: #4070a0;">"Th(is|ese) variable(s) (are|is) used for </span><span class="si" style="color: #70a0d0; font-style: italic;">%s</span><span class="s" style="color: #4070a0;">"</span>
</pre>
</div>
</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
Опциональный именованный аргумент <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">provided_by</span></tt> может быть списком функций или имён функций, или одной функцией или её именем, которые должны быть выполнены для того, чтобы задать эти переменные; он будет включён в сообщение об ошибке.</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
<b>Примечание</b>: Подразумевается, что именованные аргументы применяются ко всем переданным ключам как к группе. Если Вам надо, например, указать для разных ключей разные <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">used_for</span></tt>, Вы должны использовать несколько вызовов <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">require()</span></tt>.</div>
<div class="versionchanged" style="margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Изменения в версии 1.1: </span><span class="versionmodified">Позволяет использовать итерируемые значения</span> <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">provided_by</span></tt>, а не одиночные значения.</div>
</dd></dl>
<dl class="function" style="background-color: white; font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin: 1em 0px 2.5em;">
<dt id="fabric.operations.run" style="text-align: justify;"><tt class="descclassname" style="background-color: transparent; border: 0px; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;">fabric.operations.</tt><tt class="descname" style="background-color: transparent; border: 0px; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 1.2em; font-weight: bold; letter-spacing: 0.01em;">run</tt><big>(</big><em>command</em>, <em>shell=True</em>, <em>pty=True</em>, <em>combine_stderr=None</em>, <em>quiet=False</em>, <em>warn_only=False</em>, <em>stdout=None</em>,<em>stderr=None</em><big>)</big><a class="headerlink" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.run" style="border: none; color: #cccccc; font-size: 1em; margin-left: 6px; padding: 0px 4px; text-decoration: initial; visibility: hidden;" title="Permalink to this definition"></a></dt>
<dd style="margin-bottom: 10px; margin-left: 30px; margin-top: 3px;"><div style="margin-bottom: 0.5em; text-align: justify;">
Запускает команду оболочки на удалённом узле.</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
Если <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">shell=True</span></tt> (значение gj умолчанию), <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.run" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.run"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">run</span></tt></a> выполнит заданную команду через оболочку, которая определяется переменной <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">env.shell</span></tt> (в сумме получается что-то вроде <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">/bin/bash</span> <span class="pre">-l</span> <span class="pre">-c</span> <span class="pre">"<command>"</span></tt>.) Все двойные кавычки (<tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">"</span></tt>) или знаки доллара (<tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">$</span></tt>) в <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">command</span></tt> будут автоматически экранированы, если <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">shell=True</span></tt>.</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
<a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.run" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.run"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">run</span></tt></a> возвращает результирующий вывод выполнения удалённой программы в качестве одной (скорее всего состоящей из нескольких строк) строки. Эта строка будет иметь логические атрибуты <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">failed</span></tt> и <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">succeeded</span></tt>, определяющие успешно или нет была выполнена команда, а в атрибуте <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">return_code</span></tt> Вы получите код возврата команды. Более того, он содержит копии запрошенной и реальной строки команды в аргументах <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">.command</span></tt> и <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">.real_command</span></tt> соответственно.</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
Любой текст, введённый в вашем локальном терминале будет перенаправлен в удалённую программу, пока она выполняется; таким образом Вы можете взаимодействовать удалённой программой, вводя пароли и т.п. Более подробно смотрите в разделе <a class="reference internal" href="http://docs.fabfile.org/en/1.5/usage/interactivity.html" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;"><em>Взаимодействие с удалённой программой</em></a>.</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
Вы можете задать <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">pty=False</span></tt> чтобы не создавать псевдотерминал на удалённом хосте в том случае, если это создаёт проблемы для выполняемой команды. Но, таким образом, Fabric надо будет самому передавать весь ввод удалённой программе, в том числе и пароли. (Если <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">pty=True</span></tt>, удалённый псеводтерминал бдует делать всё это сам.) Подробнее об этом в разделе <a class="reference internal" href="http://docs.fabfile.org/en/1.5/usage/interactivity.html#pseudottys" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;"><em>Псевдотерминалы</em></a>.</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
Конкретнее, если Вам нужно программно проверить поток вывода ошибок удалённой программы (доступный через атрибут <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">stderr</span></tt> возвращаемого значения функции), Вы можете задать <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">combine_stderr=False</span></tt>. В этом случае есть большая вероятность получения путанного вывода на вашем терминале (хотя возвращаемая <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.run" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.run"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">run</span></tt></a> строка будет разделена надлежащим образом). Более подробно смотрите в разделе <a class="reference internal" href="http://docs.fabfile.org/en/1.5/usage/interactivity.html#combine-streams" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;"><em>Комбинирование stdout и stderr</em></a>.</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
Чтобы игнорировать ненулевой код возвращения задайте <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">warn_only=True</span></tt>. Чтобы и игнорировать ненулевое возвращаемое значение <i>и</i> принудить команду выполняться тихо, задайте <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">quiet=True</span></tt>.</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
Чтобы переопределить какие локальные потоки будут использованы для отображения удалённых stdout и/или stderr, определите <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">stdout</span></tt> или <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">stderr</span></tt>. (По умолчанию используются потоковые объекты Python <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">sys.stdout</span></tt> и <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">sys.stderr</span></tt>.)</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
Например, <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">run("command",</span> <span class="pre">stderr=sys.stdout)</span></tt> будет выводить удалённый поток ошибок в локальный поток вывода, сохраняя его как свой собственный атрибут возвращаемого значения (как выше). Или же Вы можете даже передать свой собственный потоковый объект или логировщик, например <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">myout</span> <span class="pre">=</span> <span class="pre">StringIO();</span> <span class="pre">run("command",</span> <span class="pre">stdout=myout)</span></tt>.</div>
<div style="margin-bottom: 0.5em; text-align: justify;">
Примеры:</div>
<div class="highlight-python">
<div class="highlight" style="background-color: transparent; background-position: initial initial; background-repeat: initial initial;">
<pre style="background-color: #eeeeee; border-bottom-left-radius: 6px; border-bottom-right-radius: 6px; border-top-left-radius: 6px; border-top-right-radius: 6px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.015em; line-height: 18px; margin: 1em 2em; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><div style="text-align: justify;">
<span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">run</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">(</span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">"ls /var/www/"</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">)</span></div>
<span class="n"><div style="text-align: justify;">
<span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">run</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">(</span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">"ls /home/myuser"</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">,</span><span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">shell</span><span class="o" style="color: #666666; font-size: 0.95em; letter-spacing: 0.015em;">=</span><span class="bp" style="color: #007020; font-size: 0.95em; letter-spacing: 0.015em;">False</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">)</span></div>
</span><span class="n"><div style="text-align: justify;">
<span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">output</span><span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="o" style="color: #666666; font-size: 0.95em; letter-spacing: 0.015em;">=</span><span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">run</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">(</span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">'ls /var/www/site1'</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">)</span></div>
</span></pre>
</div>
</div>
<div class="versionadded" style="margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Начиная с версии 1.0: </span><span class="versionmodified">Атрибуты</span> <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">succeeded</span></tt> и <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">stderr</span></tt> возвращаемого значения, именованный аргумент <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">combine_stderr</span></tt>, и интерактивное поведение.</div>
<div class="versionchanged" style="margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Изменения в версии 1.0: </span><span class="versionmodified">Значением по умолчанию </span><tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">pty</span></tt> теперь является <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">True</span></tt>.</div>
<div class="versionchanged" style="margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Изменения в версии 1.0.2: </span><span class="versionmodified">Значением по умолчанию </span><tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">combine_stderr</span></tt> теперь является <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">None</span></tt> вместо <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">True</span></tt>. Однако <i>поведение</i> по умолчанию не изменилось, так как глобальным значением всё ещё является <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">True</span></tt>.</div>
<div class="versionadded" style="margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Начиная с версии 1.5: </span>Именованные аргументы <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">quiet</span></tt>, <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">warn_only</span></tt>, <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">stdout</span></tt> и <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">stderr</span></tt>.</div>
<div class="versionadded" style="margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Начиная с версии 1.5: </span><span class="versionmodified">Атрибуты возвращаемого значения</span> <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">.command</span></tt> и <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">.real_command</span></tt>.</div>
</dd></dl>
<dl class="function" style="background-color: white; margin: 1em 0px 2.5em;">
<dt id="fabric.operations.sudo" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; text-align: justify;"><tt class="descclassname" style="background-color: transparent; border: 0px; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;">fabric.operations.</tt><tt class="descname" style="background-color: transparent; border: 0px; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 1.2em; font-weight: bold; letter-spacing: 0.01em;">sudo</tt><big>(</big><em>command</em>, <em>shell=True</em>, <em>pty=True</em>, <em>combine_stderr=None</em>, <em>user=None</em>, <em>quiet=False</em>, <em>warn_only=False</em>,<em>stdout=None</em>, <em>stderr=None</em>, <em>group=None</em><big>)</big><a class="headerlink" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.sudo" style="border: none; color: #cccccc; font-size: 1em; margin-left: 6px; padding: 0px 4px; text-decoration: initial; visibility: hidden;" title="Permalink to this definition"></a></dt>
<dd style="margin-bottom: 10px; margin-left: 30px; margin-top: 3px;"><div style="margin-bottom: 0.5em; text-align: justify;">
<span style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, Helvetica Neue, sans-serif;"><span style="line-height: 24px;">Запускает оболочку на удалённом хосте с привилегиями суперпользователя.</span></span></div>
<div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.sudo" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.sudo"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">sudo</span></tt></a> во всём идентично <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.run" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.run"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">run</span></tt></a>, за исключением того, что переданная <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">command</span></tt> всё время оборачивается в программу <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">sudo</span></tt> для получения прав суперпользователя.</div>
<div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.sudo" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.sudo"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">sudo</span></tt></a> принимает дополнительные аргументы <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">user</span></tt> и <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">group</span></tt>, которые передаются <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">sudo</span></tt> и позволяют запустить программу под пользователем/группой, отличных от root. На большинстве систем программа <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">sudo</span></tt> может принимать строку логин/группа или числа (uid/gid); <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">user</span></tt> и <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">group</span></tt> могут быть также строками или числами.</div>
<div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
Вы можете установить значение <a class="reference internal" href="http://docs.fabfile.org/en/1.5/usage/env.html#sudo-user" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;"><em>env.sudo_user</em></a> на уровне модуля при помощи <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/context_managers.html#fabric.context_managers.settings" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.context_managers.settings"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">settings</span></tt></a> если Вы хотите сделать несколько вызовов <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">sudo</span></tt> с одним и тем же значением <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">user</span></tt>. Конечно же аргумент <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">user</span></tt> будет переопределять глобальные настройки.</div>
<div style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
Примеры:</div>
<div class="highlight-python" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px;">
<div class="highlight" style="background-color: transparent; background-position: initial initial; background-repeat: initial initial;">
<pre style="background-color: #eeeeee; border-bottom-left-radius: 6px; border-bottom-right-radius: 6px; border-top-left-radius: 6px; border-top-right-radius: 6px; border: 1px solid rgb(204, 204, 204); font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.015em; line-height: 18px; margin: 1em 2em; overflow-x: auto; overflow-y: hidden; padding: 0.5em;"><div style="text-align: justify;">
<span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">sudo</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">(</span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">"~/install_script.py"</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">)</span></div>
<span class="n"><div style="text-align: justify;">
<span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">sudo</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">(</span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">"mkdir /var/www/new_docroot"</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">,</span><span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">user</span><span class="o" style="color: #666666; font-size: 0.95em; letter-spacing: 0.015em;">=</span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">"www-data"</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">)</span></div>
</span><span class="n"><div style="text-align: justify;">
<span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">sudo</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">(</span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">"ls /home/jdoe"</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">,</span><span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">user</span><span class="o" style="color: #666666; font-size: 0.95em; letter-spacing: 0.015em;">=</span><span class="mi" style="color: #208050; font-size: 0.95em; letter-spacing: 0.015em;">1001</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">)</span></div>
</span><span class="n"><div style="text-align: justify;">
<span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">result</span><span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="o" style="color: #666666; font-size: 0.95em; letter-spacing: 0.015em;">=</span><span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">sudo</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">(</span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">"ls /tmp/"</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">)</span></div>
</span><span class="k" style="color: #007020; font-weight: bold;"><div style="text-align: justify;">
<span class="k" style="font-size: 0.95em; letter-spacing: 0.015em;">with</span><span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">settings</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">(</span><span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">sudo_user</span><span class="o" style="color: #666666; font-size: 0.95em; letter-spacing: 0.015em;">=</span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">'mysql'</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">):</span></div>
</span><div style="text-align: justify;">
<span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="n" style="font-size: 0.95em; letter-spacing: 0.015em;">sudo</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">(</span><span class="s" style="color: #4070a0; font-size: 0.95em; letter-spacing: 0.015em;">"whoami"</span><span class="p" style="font-size: 0.95em; letter-spacing: 0.015em;">)</span><span style="font-size: 0.95em; letter-spacing: 0.015em;"> </span><span class="c" style="color: #408090; font-size: 0.95em; font-style: italic; letter-spacing: 0.015em;"># prints 'mysql'</span></div>
</pre>
</div>
</div>
<div class="versionchanged" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Изменения в версии 1.0: </span><span class="versionmodified">Те же изменения, что и для</span> <a class="reference internal" href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.run" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;" title="fabric.operations.run"><tt class="xref py py-obj docutils literal" style="background-color: transparent; background: inherit !important; border: 0px; color: inherit !important; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; font-weight: bold; letter-spacing: 0.01em;"><span class="pre">run</span></tt></a>.</div>
<div class="versionchanged" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Изменения в версии 1.5: </span><span class="versionmodified">Теперь учитывается</span> <a class="reference internal" href="http://docs.fabfile.org/en/1.5/usage/env.html#sudo-user" style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; color: #444444; text-decoration: initial;"><em>env.sudo_user</em></a>.</div>
<div class="versionadded" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Обновление в версии 1.5: </span>Именованные аргументы <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">quiet</span></tt>, <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">warn_only</span></tt>, <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">stdout</span></tt> и <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">stderr</span></tt>.</div>
<div class="versionadded" style="font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, 'Helvetica Neue', sans-serif; font-size: 16px; line-height: 24px; margin-bottom: 0.5em; text-align: justify;">
<span class="versionmodified" style="font-style: italic;">Обновление в версии 1.5: </span><span class="versionmodified">Атрибуты возвращаемого значения</span> <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">.command</span></tt> и <tt class="docutils literal" style="background-color: #f2f2f2; color: #444444; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em;"><span class="pre">.real_command</span></tt>.</div>
</dd></dl>
Ishayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com0tag:blogger.com,1999:blog-2142461056765545912.post-4139365990778973112013-01-30T16:02:00.005+04:002013-01-30T16:02:54.470+04:00Fabric: Модель выполнения<div style="text-align: justify;">
Если Вы читали <a href="http://python-lab.blogspot.ru/2013/01/fabric.html" target="_blank">руководство</a>, то Вы должны быть уже знакомы с тем, как Fabric работает (с одной задачей на одном хосте). Однако, во многих ситуациях Вы можете захотеть выполнить несколько задач и/или на нескольких хостах. Возможно, Вы захотите разделить одну большую задачу на несколько маленьких, или обойти список серверов в поисках тех, на которых надо удалить выбранного пользователя. Все эти сценарии требуют некоторых правил о том, как и когда выполняются задачи.</div>
<div style="text-align: justify;">
Этот документ описывает модель выполнения Fabric, включая главный цикл выполнения, определение списка хостов, создание подключений и т.д.<br />
<a name='more'></a></div>
<h3>
Стратегия выполнения</h3>
<div style="text-align: justify;">
По умолчанию Fabric работает в одиночном, последовательном режиме выполнения, хотя, начиная с версии 1.3, доступна параллельная модель выполнения (см <a href="http://docs.fabfile.org/en/1.5/usage/parallel.html" target="_blank">параллельное выполнение</a>). Поведение по умолчанию заключается в следующем:</div>
<div style="text-align: justify;">
<ul>
<li>Создаётся список задач. На данный момент это просто список аргументов, переданных <a href="http://docs.fabfile.org/en/1.5/usage/fab.html" target="_blank">fab'y</a>, сохраняя порядок аргументов</li>
<li>Для каждой задачи из разных источников создаётся список хостов (подробнее см "Как создаётся список хостов" ниже)</li>
<li>Проходится список задач, каждая задача запускается один раз для каждого хоста в списке</li>
<li>Задачи, для которых нет хостов в списке хостов, выполняются только локально и всегда запускаются <u>только</u> один раз</li>
</ul>
<div>
Таким образом, если у нас есть следующий fabfile:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> from fabric.api import run, env
env.hosts = ['host1', 'host2']
def taskA():
run('ls')
def taskB():
run('whoami')</pre>
</div>
<div>
и мы выполняем команду:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> $ fab taskA taskB</pre>
</div>
<div>
мы увидим, что Fabric выполнит следующее:</div>
<div>
<ul>
<li>taskA выполняется на host1</li>
<li>taskA выполняется на host2</li>
<li>taskB выполняется на host1</li>
<li>taskB выполняется на host2</li>
</ul>
</div>
<div>
Хотя это и упрощённый подход, он позволяет очевидно сопоставить задачи и хосты и (в отличие от инструментов, которые запускают задачу сразу на нескольких узлах) позволяют реализовать логику скрипта, где Вы проверяете результат выполнения предыдущей команды и на основании этого решаете что делать дальше.</div>
<h3>
Определение задач</h3>
<div>
Подробнее о том, что такое задачи Fabric и с чем их едят, смотрите "<a href="http://docs.fabfile.org/en/1.5/usage/tasks.html" target="_blank">Определение задач</a>"</div>
<h3>
Определение списка хостов</h3>
<div>
Если только Вы не используете Fabric как просто систему запуска локальных скриптов (что возможно, но не является его основной задачей), наличие задач без возможности определить хосты для их выполнения было бы малополезным. Есть несколько способов сделать это, область воздействия этих методов меняется от глобальной до "только на одну задачу" и их можно смешивать в нужных пропорциях.</div>
<h4>
Хосты</h4>
<div>
Хостами, в данном контексте, называется то, что обычно называется "строками хостов": строка, которая определяет имя пользователя, имя хоста и номер порта: `username@hostname:port`. Пользователя и порт (и, соответственно, `@` и `:`) могут быть опущены; в таком случае будет использоваться локальное имя пользователя и порт 22. Таким образом, "admin@foo.com:222", "deploy@website" и "nameserver1" могут быть использованы в качестве строк хостов.</div>
<div>
Так же поддерживается нотация IPv6, например, "::1", "[::1]:1222", "user@2001:db8::1" или "user@[2001:db8::1]:1222". Квадратные скобки нужны только для того, чтобы отделить адрес от номера порта. Если номер порта не указан, то скобки тоже можно не использовать. Кроме того, если строка хоста задаётся через командную строку, то в некоторых оболочках может потребоваться экранировать эти скобки.</div>
<div>
<b>Примечание: </b>Раздел между именем пользователя и именем хоста происходит по <i>последнему</i> найденному знаку @, так что можно вполне использовать email адрес в качестве имени пользователя.</div>
<div>
В процессе выполнения Fabric нормализует полученную строку хоста и затем сохраняет каждую часть (имя пользователя / имя хоста / порт) в словаре окружения и для их использования и для того, чтобы задачи по необходимости могли на них сослаться. Более детально смотри в "<a href="http://docs.fabfile.org/en/1.5/usage/env.html" target="_blank">Словарь окружения</a>".</div>
<h4>
Роли</h4>
<div>
Строка хоста определяют один хост, но иногда бывает полезно объединить хосты в группы. Возможно, у Вас есть несколько Web серверов за балансировщиком нагрузки, и Вы хотите обновить их все; или Вы хотите запустить задачу на "всех клиентских серверах". Роли позволяют Вам определить строки, которые будут соответствовать списку строк хостов, и их потом можно использовать вместо перечисления всех этих узлов.</div>
<div>
Такое отображение определяется как словарь, env.roledefs, который должен быть изменён fabfile перед использованием. Вот простой пример:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> from fabric.api import env
env.roledefs['webservers'] = ['www1', 'www2', 'www3']</pre>
</div>
<div>
Так как env.roledefs по умолчанию пуст, Вы можете спокойно изменить его, не боясь потерять информацию (понятно, если Вы не используете другие fabfile, которые тоже изменяют этот словарь):</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> from fabric.api import env
env.roledefs = {
'web': ['www1', 'www2', 'www3'],
'dns': ['ns1', 'ns2']
}</pre>
</div>
<div>
Значениями в env.roledefs могут быть не только итерируемыми объектами, но и вызываемыми, и потому могут быть вызваны при выполнении задачи, а не при загрузке модуля. (Например, Вы можете подключиться к удалённому серверу для того, чтобы получить определения ролей и не беспокоиться о задержке при загрузке файла при выполнении, например, fab --list.)</div>
<div>
Использование ролей вовсе не обязательно, это лишь более удобный способ работы в ситуации, когда у Вас есть группы серверов.</div>
<div>
<i>Изменение в версии 0.9.2</i> Добавлена возможность использовать вызываемые объекты в качестве значений roledefs</div>
<h4>
Как создаётся список хостов</h4>
<div>
Есть несколько способов создать список хостов, глобальный или локальный, для задачи, и обычно каждый из этих методов перезаписывает другой, вместо того, чтобы объединять полученные списки (но это может быть изменено в будущих релизах). Каждый такой метод обычно состоит из двух частей - одна для узлов, другая - для ролей.</div>
<div>
<b>Глобально, при помощи env</b></div>
<div>
Наиболее используемый метод создания списка хостов или ролей - изменение двух значений в словаре окружения <a href="http://docs.fabfile.org/en/1.5/usage/env.html" target="_blank">env</a>: hosts и roles. Значения этих переменных проверяется в процессе выполнения, когда и создаётся список хостов для каждой задачи.</div>
<div>
Таким образом, это можно сделать на уровне модуля, что возымеет эффект при импорте fabfile:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> from fabric.api import env, run
env.hosts = ['host1', 'host2']
def mytask():
run('ls /var/www')</pre>
</div>
<div>
Такой fabfile, запущенный как fab mytask, запустит mytask на host1, а, затем, на host2.</div>
<div>
Так как переменная env проверяется для <i>каждой</i> задачи, это означает, что Вы можете изменить env в одной задаче и это будет влиять на все следующие задачи:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> from fabric.api import env, run
def set_hosts():
env.hosts = ['host1', 'host2']
def mytask():
run('ls /var/www')</pre>
</div>
<div>
Когда Вы запустите fab set_hosts mytask, set_hosts является локальной задачей, так как его список хостов пуст, но mytask будет запущен уже для двух указанных узлов.</div>
<div>
<b>Примечание:</b> Этот метод раньше использовался для создания фиктивных ролей, но при возможности создать обычные роли такая потребность отпала. Но его всё ещё можно использовать в некоторых случаях.</div>
<div>
Рядом с env.hosts расположен env.roles (не путать с env.roledefs), который, если задан, используется как список имён ролей для обращения к env.roledefs.</div>
<div>
<b>Глобально, через командную строку</b></div>
<div>
Кроме изменения env.hosts, env.roles и env.exclude_hosts на уровне модуля, Вы можете задать их при помощи аргументов командной строки в виде строки с разделителем - запятой: <a href="http://docs.fabfile.org/en/1.5/usage/fab.html#cmdoption-H" target="_blank">-H/--hosts</a> и <a href="http://docs.fabfile.org/en/1.5/usage/fab.html#cmdoption-R" target="_blank">-R/--roles</a>:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;">$ fab -H host1,host2 mytask</pre>
</div>
<div>
Такой вызов эквивалентен env.hosts = ['host1','host2'].</div>
<div>
<b>Примечание:</b> Эти опции можно использовать (и часто так и делают) для указания только одного узла или роли. Fabirc просто вызывает string.split(',') над полученной строкой, так что строка без запятых превращается в список с одним элементом.</div>
<div>
Важно знать, что эти опции обрабатываются <i>до</i> того, как загружается ваш fabfile, так что все присвоения значений env.hosts или env.roles в вашем файле будут переопределять полученные аргументы.</div>
<div>
Если Вы хотите слить списки из командной строки и определённые в fabfile, убедитесь, что Вы используете env.hosts.extend():</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> from fabric.api import env, run
env.hosts.extend(['host3', 'host4'])
def mytask():
run('ls /var/www')</pre>
</div>
<div>
Когда Вы запустите этот fabfile c опциями командной строки: fab -H host1,host2 mytask, env.hosts будет содержать `['host1','host2','host3','host4']` к моменту выполнения mytask.</div>
<div>
<b>Примечание: </b>env.hosts - простой список Python, так что Вы можете использовать и env.hosts.append() или любой другой метод списков.</div>
<div>
<b>Определение хостов для конкретной задачи в командной строке</b></div>
<div>
Глобальные списки хостов полезны только если Вы хотите, чтобы все ваши задачи выполнялись на одном и том же списке узлов. Но, поскольку, это не всегда так, Fabric предоставляет несколько методов более точно указания узлов для выполнения конкретной задачи. Первый - использование аргументов задачи.</div>
<div>
Как указано в "<a href="http://docs.fabfile.org/en/1.5/usage/fab.html" target="_blank">Опции и аргументы fab</a>", возможно задать аргументы для конкретной задачи при помощи специального синтаксиса командной строки. Кроме того, чтобы передавать аргументы вашим задачам, это можно использовать и для задания "аргументов" host, hosts, role или roles, которые интерпретируются Fabric при создании списка хостов (и они удаляются из аргументов, передаваемых самой задаче.)</div>
<div>
<b>Примечание:</b> Так как запятые уже используются для разделения аргументов, в качестве разделителей строк хостов в аргументах hosts или roles должны использоваться точки с запятой. Более того, аргумент должен быть заключён в кавычки, чтобы ваши точки с запятой не были интерпретированы оболочкой.</div>
<div>
Возьмём такой fabfile, который похож на используемый ранее, но в котором не определены хосты:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> from fabric.api import run
def mytask():
run('ls /var/www')</pre>
</div>
<div>
Для того, чтобы определить узел для задачи mytask используйте такую команду:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> $ fab mytask:hosts="host1;host2"</pre>
</div>
<div>
Это переопределит все другие списки хостов и mytask всегда будет запускаться только на этих двух узлах.</div>
<div>
<b>Определение хостов для конкретной задачи при помощи декораторов</b></div>
<div>
Если данная задача всегда должна выполняться на определённом списке узлов, Вы можете захотеть определить их в самом fabfile. Это можно сделать декорируя задачу при помощи декораторов <a href="http://docs.fabfile.org/en/1.5/api/core/decorators.html#fabric.decorators.hosts" target="_blank">hosts</a> или <a href="http://docs.fabfile.org/en/1.5/api/core/decorators.html#fabric.decorators.roles" target="_blank">roles</a>. Эти декораторы принимают список аргументов:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> from fabric.api import hosts, run
@hosts('host1', 'host2')
def mytask():
run('ls /var/www')</pre>
</div>
<div>
Или один итерируемый аргумент:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> my_hosts = ('host1', 'host2')
@hosts(my_hosts)
def mytask():
# ...</pre>
</div>
<div>
Когда используются декораторы, они переопределяют все проверки env для списка хостов этой задачи (хотя сам env не изменяется - просто игнорируется). Таким образом, даже если выше в fabfile Вы определили env.hosts или вызвали <a href="http://docs.fabfile.org/en/1.5/usage/fab.html" target="_blank">fab</a> c опцией <a href="http://docs.fabfile.org/en/1.5/usage/fab.html#cmdoption-H" target="_blank">-H/--hosts</a>, mytask будет всё равно запущен на узлах host1 и host2.</div>
<div>
Тем не менее, декоратор <i>не</i> переопределяет аргумент командной строки для этой задачи, о чём говорилось в предыдущем разделе.</div>
<div>
<b>Старшинство</b></div>
<div>
Мы показали несколько методов указания хостов и сказали, какой из них какой переопределяет. Но, для пущей ясности, подведём тут краткий итог:</div>
<div>
<ul>
<li>Для конкретной задачи, список хостов, передаваемый через аргументы командной строки (fab mytask:host=host1), переопределяет вообще всё.</li>
<li>Для конкретной задачи, список хостов, определяемый в декораторе (@hosts('host1')), переопределяет переменную env.</li>
<li>Глобально определённый список узлов, заданный в fabfile (env.hosts = ['host1']) <i>может</i> переопределить список хостов из командной строки, но только если Вы специально так сделали (или же допустили ошибку)</li>
<li>Глобально определённый список узлов из командной строки (--hosts=host1) лишь инициализирует переменную env.</li>
</ul>
<div>
В будущем такой подход может измениться, чтобы быть более логичным (например, чтобы опция --hosts имела преимущество над env.hosts, так же как аргументы командной строки для конкретной задачи имеют преимущество над значениями, определёнными в коде), но только в релизах, без обратной совместимости.</div>
</div>
<h4>
Комбинация списков хостов</h4>
<div>
Списки узлов из разных источников не объединяются. Если значением env.hosts является ['host1','host2','host3'], а список хостов, определённый для задачи, например, через декоратор - ['host2','host3'], то эта задача <i>не</i> будет выполнена на host1, так как узлы, определённые в декораторе переопределяют значение из переменной окружения.</div>
<div>
Однако, для каждого источника, если определены <i>и</i> hosts <i>и</i> roles, то их значения сливаются в один список узлов. Возьмём для примера fabfile, который мы использовали для декораторов:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> from fabric.api import env, hosts, roles, run
env.roledefs = {'role1': ['b', 'c']}
@hosts('a', 'b')
@roles('role1')
def mytask():
run('ls /var/www')</pre>
</div>
<div>
Предположим, что для исполнения mytask в командной строке не указаны ни hosts ни roles. В таком случае этот fabfile выполнится на узлах ['a','b','c'] - объединении role1 и содержимого декоратора <a href="http://docs.fabfile.org/en/1.5/api/core/decorators.html#fabric.decorators.hosts" target="_blank">hosts</a>.</div>
<h4>
Дедупликация</h4>
<div>
По умолчанию, для поддержки объединения списков хостов, Fabric производит дедупликацию итогового списка, так что каждая строка хоста будет присутствовать в итоговом списке только раз. Это не допускает умышленного выполнения той же самой задачи несколько раз на одном и том же хосте, что иногда может быть полезно.</div>
<div>
Для того, чтобы отключить дедупликацию установите <a href="http://docs.fabfile.org/en/1.5/usage/env.html#dedupe-hosts" target="_blank">env.dedupe_hosts</a> в False</div>
<h4>
Удаление определённых узлов</h4>
<div>
Иногда бывает полезно исключить один или более хостов, т.е. убрать несколько плохих или по другим причинам негодных узлов, которые упоминаются в ролях или сгенерированном листе узлов.</div>
<div>
<b>Примечание: </b>В Fabric 1.4 Вы можете использовать вместо этого <a href="http://docs.fabfile.org/en/1.5/usage/env.html#skip-bad-hosts" target="_blank">skip-bad-hosts</a>, в этом случае недоступные хосты будут игнорированы</div>
<div>
Исключение узлов может быть достигнуто глобально опцией <a href="http://docs.fabfile.org/en/1.5/usage/fab.html#cmdoption-x" target="_blank">--exclude-hosts/-x</a></div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> $ fab -R myrole -x host2,host5 mytask</pre>
</div>
<div>
Если myrole определена как ['host1','host2',...,'host15'], то вызов выше выполнит задачу на списке узлов ['host1','host3','host4','host6',...,'host15'].</div>
<div>
<b>Примечание: </b>использование этой опции не модифицирует env.hosts - эти узлы лишь исключаются в процессе выполнения задачи</div>
<div>
Исключить узлы можно и для отдельной задачи при помощи именованного аргумента exclude_hosts, который используется аналогично аргументам hosts и roles. Этот пример будет иметь тот же результат, что и пример выше:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> $ fab mytask:roles=myrole,exclude_hosts="host2;host5"</pre>
</div>
<div>
Обратите внимание, что в списке в качестве разделителя опять используются точка с запятой.</div>
<h4>
Комбинация исключений</h4>
<div>
Список хостов для исключения, так же как и список хостов, не взаимодействует со списками, полученными с других уровней. Например, опция -x не будет влиять на список хостов, указанных в декораторе или в именованном аргументе, а именованный аргумент exlude_hosts не будет влиять на список, полученный через -H.</div>
<div>
Есть только одно маленькое исключение из этого правила, а именно, именованные аргументы уровня CLI (mytask:exclude_hosts=x,y) <i>будет</i> учтён в списках хостов, заданных через @hosts или @roles. Таким образом, задача, декорированная при помощи @hosts('host1','host2'), выполненное через fab taskname:exclude_hosts=host2, будет запущен только на host1.</div>
<div>
Как и в случае с объединением списков, эта функциональность на данный момент ограничена (в частности, для облегчения реализации) и может быть изменена в будущих релизах.</div>
<h3>
Интеллектуальное выполнение задач при помощи execute</h3>
<div>
<i>Добавлено в версии 1.3</i></div>
<div>
Большая часть информации, приведённой здесь, касается задач "верхнего уровня", выполняемых через <a href="http://docs.fabfile.org/en/1.5/usage/fab.html" target="_blank">fab</a>, таких как наш первый пример, где мы вызывали fab taskA taskB. Однако, часто удобно обернуть вызов нескольких задач, как в нашем примере, в свою собственную задачу meta.</div>
<div>
До Fabric 1.3 это надо было делать вручную, как об этом говорится в <a href="http://docs.fabfile.org/en/1.5/usage/library.html" target="_blank">Library Use</a>. Дизайн Fabric воздерживается от магического поведения, так что простой вызов задачи <i>не</i> принимает во внимание декораторы, такие как <a href="http://docs.fabfile.org/en/1.5/api/core/decorators.html#fabric.decorators.roles" target="_blank">roles</a>.</div>
<div>
Начиная с Fabric 1.3 вспомогательная функция <a href="http://docs.fabfile.org/en/1.5/api/core/tasks.html#fabric.tasks.execute" target="_blank">execute</a>, принимающая в качестве аргумента имя или объект задачи. Её используют так же, как и вызывают задачу из командной строки: к ним применяются все те же правила, которые мы приводили выше в разделе "как создаются списки хостов". (Именованные аргументы hosts и roles для execute аналогичны <a href="http://docs.fabfile.org/en/1.5/usage/execution.html#hosts-per-task-cli" target="_blank">аргументам CLI для задачи</a>, включая то, как они переопределяют все остальные настройки host/role.)</div>
<div>
В качестве примера возьмём fabfile, который определяет две отдельные задачи для развёртывания Web приложения:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> from fabric.api import run, roles
env.roledefs = {
'db': ['db1', 'db2'],
'web': ['web1', 'web2', 'web3'],
}
@roles('db')
def migrate():
# Database stuff here.
pass
@roles('web')
def update():
# Code updates here.
pass</pre>
</div>
<div>
В Fabric версии 1.2 и раньше, единственный способ убедиться, что migrate запускается на серверах БД, а update - на Web серверах - было вызвать обе задачи как задачи "верхнего уровня":</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> $ fab migrate update</pre>
</div>
<div>
В версиях начиная от 1.3 Вы можете использовать execute для создания мета-задачи. Обновим инструкцию import:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> from fabric.api import run, roles, execute</pre>
</div>
<div>
и добавим это в конец файла:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> def deploy():
execute(migrate)
execute(update)</pre>
</div>
<div>
Вот и всё. Декораторы будут работать, как и ожидается, в результате чего будут выполнены:</div>
<div>
<ul>
<li>migrate на db1</li>
<li>migrate на db2</li>
<li>update на web1</li>
<li>update на web2</li>
<li>update на web3</li>
</ul>
<div>
<b>Предупреждение: </b>эта техника работает так как задачи, у которых нет списка узлов (даже глобального списка) выполняются только один раз. Если это используется в "обычной" задаче, которая запускается на нескольких хостах, вызов <a href="http://docs.fabfile.org/en/1.5/api/core/tasks.html#fabric.tasks.execute" target="_blank">execute</a> также будет вызван несколько раз, в результате чего будет вызваны несколько раз подзадачи - будьте осторожны. Если Вы хотите, чтобы ваш вызов <a href="http://docs.fabfile.org/en/1.5/api/core/tasks.html#fabric.tasks.execute" target="_blank">execute</a> происходил только один раз, Вам нужно использовать декоратор <a href="http://docs.fabfile.org/en/1.5/api/core/decorators.html#fabric.decorators.runs_once" target="_blank">runs_once</a>.</div>
</div>
<div>
<b>См также: </b><a href="http://docs.fabfile.org/en/1.5/api/core/tasks.html#fabric.tasks.execute" target="_blank">execute</a>, <a href="http://docs.fabfile.org/en/1.5/api/core/decorators.html#fabric.decorators.runs_once" target="_blank">runs_once</a></div>
<h4>
Использование execute c динамически создаваемым списком хостов</h4>
<div>
Ещё одно частое применение Fabric продвинутыми пользователями - параметризация поиска списка узлов в процессе выполнения (когда использование <a href="http://docs.fabfile.org/en/1.5/usage/execution.html#execution-roles" target="_blank">ролей</a> недостаточно). execute может сильно облегчить это:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> from fabric.api import run, execute, task
# Например, код, работающий с HTTP API, или БД, или ...
from mylib import external_datastore
# Это сам алгоритм, который вообще не думает о списке узлов
def do_work():
run("something interesting on a host")
# Задача, вызываемая из командной строки
@task
def deploy(lookup_param):
# Вот то, чего Вы не добьётесь при помощи @hosts или @roles.
# Даже "ленивые" роли требуют сперва объявления доступных ролей
# Тут же нет никаких ограничений
host_list = external_datastore.query(lookup_param)
# Используем динамический список вместе с задачей
execute(do_work, hosts=host_list)</pre>
</div>
<div>
Например, если "external_datastore" просто получает список узлов по некоторому тегу и Вы хотите выполнить задачу на всех серверах, относящихся к вашему приложения, Вы можете просто сделать так:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> $ fab deploy:app</pre>
</div>
<div>
Но постойте! Что-то не так пошло на серверах БД. Давайте обновим код миграции и запустим обновление только на нужных серверах:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> $ fab deploy:db</pre>
</div>
<div>
Такое использование похоже на роли Fabric, но имеет гораздо больше возможностей и при этом не ограничен только одним аргументом. Определите задачу так, как Вам нужно, получите из вашей БД то, что Вам нужно - это лишь Python.</div>
<h4>
Альтернативный подход</h4>
<div>
Похожим на то, о чём мы только что говорили, но с использованием способности fab вызывать поочерёдно несколько задач без явного вызова - заменить env.hosts на задачу поиска списка узлов и затем вызвать do_work в той же самой сессии:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> from fabric.api import run, task
from mylib import external_datastore
# Отмечена как публично видимая задача, но о списке хостов
# пусть подумает кто-то другой
@task
def do_work():
run("something interesting on a host")
@task
def set_hosts(lookup_param):
# Обновляем env.hosts вместо вызова execute()
env.hosts = external_datastore.query(lookup_param)</pre>
</div>
<div>
Теперь мы можем сделать так:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> $ fab set_hosts:app do_work</pre>
</div>
<div>
Преимуществом этого подхода по отношению к предыдущему варианту является то, что Вы можете спокойно do_work на любую другую задачу:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> $ fab set_hosts:db snapshot
$ fab set_hosts:cassandra,cluster2 repair_ring
$ fab set_hosts:redis,environ=prod status</pre>
</div>
<h3>
Обработка ошибок</h3>
<div>
После того, как список задач составлен, Fabric начнёт выполнять его, как это описано в "Стратегии выполнения", пока все задачи не будут выполнены на всех узлах из списка для каждой задачи. По умолчанию Fabric работает по принципу "быстрой ошибки" - как только удалённая программа возвращает ненулевое значение или ваш код Python в fabfile возбуждает исключение выполнение задач тут же прекращается.</div>
<div>
Обычно это ровно то, что нужно, но, как и в каждом правиле, тут есть свои исключения, так что Fabric даёт Вам настройку env.warn_only. Значение по умолчанию False означает, что при ошибке выполнение скрипта будет тут же прервано. Если же значением является True - то при возникновении ошибки Fabric выдаст предупреждение, но выполнение скрипта будет продолжено.</div>
<h3>
Подключения</h3>
<div>
Сам по себе fab не делает никаких подключений к удалённым узлам. Вместо этого он лишь проверяет для каждого запуска задачи на каждом узле, что переменная env.host_string имеет корректное значение. Пользователи, желающие использовать Fabric как библиотеку могут вручную добиться того же эффекта (хотя в Fabric 1.3 использовать <a href="http://docs.fabfile.org/en/1.5/api/core/tasks.html#fabric.tasks.execute" target="_blank">execute</a> предпочтительнее и даёт больше возможностей.)</div>
<div>
env.host_string, как и следует из названия, текущая строка узла и её и использует Fabric для определения того, как подключиться к узлу при использовании сетевых функций. Операции вроде <a href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.run" target="_blank">run</a> или <a href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.put" target="_blank">put</a> используют env.host_string в качестве ключа поиска в общем словаре, которые отражает строки узлов на объекты подключений SSH.</div>
<div>
<b>Примечание</b>: Словарь подключений (на данный момент он расположен в fabric.state.connections) работает как кэш, возвращая уже созданные подключения, если можно, для экономии времени, или создавая новые.</div>
<h4>
"Ленивые" подключения</h4>
<div>
Так как подключения определяются конкретными операциями, Fabric не будет создавать подключения, пока они не понадобятся. Возьмём для примера задачу, которая делает что-то локально <i>до</i> того, как она начинает взаимодействовать с удалённым сервером:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> from fabric.api import *
@hosts('host1')
def clean_and_upload():
local('find assets/ -name "*.DS_Store" -exec rm '{}' \;')
local('tar czf /tmp/assets.tgz assets/')
put('/tmp/assets.tgz', '/tmp/assets.tgz')
with cd('/var/www/myapp/'):
run('tar xzf /tmp/assets.tgz')</pre>
</div>
<div>
Вот как это происходит:</div>
<div>
<ul>
<li>Два вызова <a href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.local" target="_blank">local</a> будут произведены без создания подключений</li>
<li><a href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.put" target="_blank">put</a> запросит кэш подключений в поисках подключения к host1</li>
<li>Кэш подключений не найдёт существующего подключения для этой строки хоста, так что будет создано новое SSH подключение, которое и будет возвращено операции <a href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.put" target="_blank">put</a></li>
<li><a href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.put" target="_blank">put</a> передаст файл через это подключение</li>
<li>Наконец, <a href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.run" target="_blank">run</a> запрашивает кэш в поисках подключения для той же самой строки, откуда его и получает</li>
</ul>
<div>
Таким образом, задача, которая не использует сетевых задач, вообще не будет создавать подключений (но она будет всё равно выполнена для каждого узла в списке)</div>
</div>
<h4>
Закрытие соединения</h4>
<div>
Кэш соединений Fabric сам никогда не закрывает соединения - они остаются открытыми для возможного дальнейшего использования. <a href="http://docs.fabfile.org/en/1.5/usage/fab.html" target="_blank">fab</a> делает это для Вас сам: перед завершением скрипта он обходит все открытые подключения и закрывает их (вне зависимости от результата завершения задач).</div>
<div>
Пользующиеся Fabric как библиотекой должны сами убедиться, что перед завершением скрипта все подключения будут закрыты. Сделать это можно при помощи вызова <a href="http://docs.fabfile.org/en/1.5/api/core/network.html#fabric.network.disconnect_all" target="_blank">disconnect_all</a> в конце скрипта.</div>
<div>
<b>Примечание:</b> <a href="http://docs.fabfile.org/en/1.5/api/core/network.html#fabric.network.disconnect_all" target="_blank">disconnect_all</a> может быть перемещён в более доступное место в будущем. Мы всё ещё работаем над библиотечным использованием Fabric c точки зрения его организации.</div>
<h4>
Множественные попытки подключений и игнорирование плохих узлов</h4>
<div>
Начиная с Fabric 1.4 перед тем, как завершиться с ошибкой, скрипт будет предпринимать <a href="http://docs.fabfile.org/en/1.5/usage/env.html#connection-attempts">env.connection_attempts</a> попыток подключения c таймаутом <a href="http://docs.fabfile.org/en/1.5/usage/env.html#timeout" target="_blank">env.timeout</a> секунд. (На данный момент по умолчанию это 1 попытка и 10 секунд, для соответствия предыдущему поведению, но эти значения можно спокойно поменять)</div>
<div>
Более того, даже полная невозможность подключиться к серверу уже не является абсолютным препятствием. Задайте <a href="http://docs.fabfile.org/en/1.5/usage/env.html#skip-bad-hosts" target="_blank">env.skip_bad_hosts</a> в True и в большинстве случаев (обычно в начале подключений) Fabric будет лишь предупреждать об ошибке, а не завершать выполнение задач.</div>
<div>
<i>Добавлено в версии 1.4</i></div>
<h3>
Управление паролями</h3>
<div>
Fabric работает с двухъярусным кэшем паролей, чтобы запоминать ваши логин и пароли sudo в некоторых случаях; это помогает избежать нудного повторного ввода паролей, если несколько систем используют одни и те же пароли [мы крайне рекомендуем использовать SSH <a href="http://ru.wikipedia.org/wiki/%D0%9A%D1%80%D0%B8%D0%BF%D1%82%D0%BE%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0_%D1%81_%D0%BE%D1%82%D0%BA%D1%80%D1%8B%D1%82%D1%8B%D0%BC_%D0%BA%D0%BB%D1%8E%D1%87%D0%BE%D0%BC" target="_blank">доступ по ключу</a>, а не полагаться на настройки пароля, что менее безопасно], или же конфигурация sudo на удалённой системе не имеет своего кэша.</div>
<div>
Первый слой - это либо значения по умолчанию, либо fallback кэш паролей, <a href="http://docs.fabfile.org/en/1.5/usage/env.html#password" target="_blank">env.password</a> (который можно задать либо через командную строку опцией <a href="http://docs.fabfile.org/en/1.5/usage/fab.html#cmdoption-p" target="_blank">--password</a> или <a href="http://docs.fabfile.org/en/1.5/usage/fab.html#cmdoption-I" target="_blank">--initial-password-prompt</a>). Эта переменная хранит только один пароль который (если он не пуст) будет использован в случае, когда кэш для узла не имеет значения для текущей <a href="http://docs.fabfile.org/en/1.5/usage/env.html#host-string" target="_blank">строки узла</a>.</div>
<div>
<a href="http://docs.fabfile.org/en/1.5/usage/env.html#passwords" target="_blank">env.passwords</a> (множественное число!) служит как кэш на пользователя / узел, храня недавно введённый пароль для каждой уникальной комбинации пользователь/узел/порт. Таким образом, в той же сессии подключения под разными пользователями и / или к разным узлам будут требовать только один пароль для каждого случая. (В прежних версиях Fabric использовал только один кэш пароля по умолчанию и потому требовалось каждый раз вводить пароль заново, как только хранившийся в кэше не подходил.)</div>
<div>
В зависимости от вашей конфигурации и числа узлов в сессии, к которым Вы будете подключаться, Вы можете использовать одну или обе этих переменных. В любом случае, Fabric автоматически заполняет их по необходимости без дополнительных настроек.</div>
<div>
Конкретнее, каждый раз, когда у пользователя запрашивается пароль, введённое значение используется и для обновления кэша пароля по умолчанию, и значения кэша для текущего значения строки хоста.</div>
<h4>
Использование "родных" файлов конфигурации SSH</h4>
<div>
SSH клиенты командной строки (как те, которые предоставляет <a href="http://openssh.org/" target="_blank">OpenSSH</a>) используют специальный формат конфигурации, известный как ssh_config и считывается из файла, чьё расположение зависит от платформы - $HOME/.ssh/config (или в пути, указанном в опции <a href="http://docs.fabfile.org/en/1.5/usage/fab.html#cmdoption--ssh-config-path" target="_blank">--ssh-config-path</a>/<a href="http://docs.fabfile.org/en/1.5/usage/env.html#ssh-config-path" target="_blank">env.ssh_config_path</a>). Этот файл позволяет определить различные SSH опции, такие как имя пользователя по умолчанию или для конкретного хоста, псевдонимы узлов и другие опции переключения (например, использовать ли <a href="http://docs.fabfile.org/en/1.5/usage/env.html#forward-agent" target="_blank">agent forwarding</a>)</div>
<div>
Реализация SSH Fabric позволяет загрузить набор этих опций из указанного файла конфигурации SSH, который должен существовать. По умолчанию этого не делается (для сохранения обратной совместимости), но его можно активировать при помощи настройки <a href="http://docs.fabfile.org/en/1.5/usage/env.html#use-ssh-config" target="_blank">env.use_ssh_config</a>, установив его в True в начале вашего fabfile.</div>
<div>
Если эта настройка активирована, то следующие настройки SSH будут загружены и использованы Fabric:</div>
<div>
<ul>
<li>User и Port будут использованы для соответствующих параметров подключения, если другие не указаны в таком порядке:</li>
<ul>
<li>Глобально определённые User / Port будут использованы вместо текущих значений по умолчанию (локальное имя пользователя и 22 соответственно), если соответствующие переменные окружения не заданы</li>
<li>Однако, если <a href="http://docs.fabfile.org/en/1.5/usage/env.html#user" target="_blank">env.user</a> / <a href="http://docs.fabfile.org/en/1.5/usage/env.html#port" target="_blank">env.port</a> <i>заданы, </i>они переопределяют глобальные значения User / Port.</li>
<li>Значения user/port в строке хоста (т.е. hostname:222) будут переопределять всё, включая значения из ssh_config</li>
</ul>
<li>HostName может быть использован для замещения переданного имени узла, так же как и в обычном ssh. Таким образом запись `Host foo` определяющая `HostName example.com` позволит использовать в Fabric имя узла foo, которое на момент подключения будет заменено на example.com</li>
<li>IdentityFile будет применено (но не заменит) к <a href="http://docs.fabfile.org/en/1.5/usage/env.html#key-filename" target="_blank">env.key_filename</a></li>
<li>ForwardAgent будет аргументом <a href="http://docs.fabfile.org/en/1.5/usage/env.html#forward-agent" target="_blank">env.forward_agent</a> по принципу OR: если либо значение из файла, либо значение переменной будет положительным, то тогда перенаправление агента будет активировано</li>
<li>ProxyCommand вызовет использование команды proxy для подключения к узлу, как и в обычном ssh</li>
</ul>
<div>
<b>Примечание: </b>Если Вы хотите всего лишь "отфутболить" SSH трафик от шлюза, Вы можете решить, что <a href="http://docs.fabfile.org/en/1.5/usage/env.html#gateway" target="_blank">env.gateway</a> более удобный способ подключения (и это уже настройка уровня Fabric), чем просто метод `ssh gatewayhost nc %h %p` использования ProxyCommand в качестве шлюза.</div>
</div>
<div>
<b>Примечание: </b>Если Ваш файл настроек SSH содержит директиву ProxyCommand <i>и </i>Вы установили значение <a href="http://docs.fabfile.org/en/1.5/usage/env.html#gateway" target="_blank">env.gateway</a>, отличное от None, <a href="http://docs.fabfile.org/en/1.5/usage/env.html#gateway" target="_blank">env.gateway</a> будет иметь приоритет и ProxyCommand будет проигнорирована.</div>
<div>
<b>Примечание: </b>Если Вы создали SSH файл настройки, Вам будет проще изменить env.gateway (через <a href="http://docs.fabfile.org/en/1.5/api/core/context_managers.html#fabric.context_managers.settings" target="_blank">settings</a>), чем разбираться с настройками из файла настроек.</div>
</div>
Ishayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com0tag:blogger.com,1999:blog-2142461056765545912.post-73024744872754491952013-01-28T14:23:00.001+04:002013-01-28T14:23:14.335+04:00Fabric: Обзор и руководство (Перевод)<h3>
<span style="text-align: justify;">Добро пожаловать в Fabric!</span></h3>
<pre style="text-align: justify; white-space: pre-wrap; word-wrap: break-word;">Этот документ - быстрый тур по возможностям Fabric и короткое руководство по его использованию. Дополнительная документация может быть найдена <a href="http://docs.fabfile.org/en/1.5/index.html#usage-docs" target="_blank">тут</a>.</pre>
<h3 style="text-align: justify;">
Что такое Fabric?</h3>
<pre style="text-align: justify; white-space: pre-wrap; word-wrap: break-word;">Как написано в README:</pre>
<blockquote class="tr_bq" style="text-align: justify;">
Fabric - это библиотека для Python (2.5 или выше) и инструмент командной строки для использования SSH при развёртывании приложений или выполнении административных задач.</blockquote>
<div style="text-align: justify;">
Более конкретно: </div>
<br />
<ul>
<li style="text-align: justify;">Инструмент, который позволяет Вам выполнить <i>любую функцию Python </i>при помощи <i>командной строки</i></li>
<li style="text-align: justify;">Библиотека подпрограмм (построенная на более низкоуровневой библиотеке), переназначенная для выполнения команд оболочки через SSH <i>легко</i> и <i>по-питонски.</i></li>
</ul>
<div style="text-align: justify;">
Обычно, большинство пользователей используют обе эти возможности, применяя Fabric для записи и выполнения функций Python или <i>заданий</i>, чтобы автоматизировать работу с удалённым сервером. Давайте на это посмотрим.<br />
<a name='more'></a></div>
<h3>
Hello, fab</h3>
<div style="text-align: justify;">
Это не было бы хорошим руководством без стандартного примера:</div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;">def hello():</span></div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"> print("Hello world!")</span></div>
<div style="text-align: justify;">
Если разместить эту функцию в модуле с именем fabfile.py в вашей рабочей директории, то эту функцию hello можно выполнить при помощи инструмента fab (устанавливаемого как часть Fabric) и будет делать именно то, что Вы ожидаете:</div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;">$ fab hello</span></div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;">Hello world!</span></div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;">Done.</span></div>
<div style="text-align: justify;">
Вот и всё. Таким образом Вы можете использовать Fabric как (очень) простой способ сборки даже без импорта какого либо из его API.</div>
<div style="text-align: justify;">
<b>Примечание: </b>Инструмент fab просто просто импортирует ваш fabfile и выполняет функцию или функции, которые Вы в нём определили. Тут нет никакой магии - всё, что Вы можете сделать в обычном скрипте Python, можно сделать и в fabfile.</div>
<div style="text-align: justify;">
<b>См также: </b><a href="http://docs.fabfile.org/en/1.5/usage/execution.html#execution-strategy" target="_blank">Execution strategy</a>, <a href="http://docs.fabfile.org/en/1.5/usage/tasks.html" target="_blank">Definding tasks</a>, <a href="http://docs.fabfile.org/en/1.5/usage/fab.html" target="_blank">fab options and arguments</a></div>
<h3>
Аргументы задачи</h3>
<div style="text-align: justify;">
Очень часто полезно передать параметры в процессе выполнения в вашу задачу, как Вы это можете сделать и в обычном скрипте Python. Fabric поддерживает эту возможность при помощи такой нотации: <task name>:<arg>,<kwarg>=<value>,.... Давайте расширим наш первый пример:</div>
<div>
<span style="font-family: Courier New, Courier, monospace;">def hello(name="world"):</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> print("Hello %s!" % name)</span></div>
<div style="text-align: justify;">
По умолчанию, если Вы используете команду fab hello - Вы получите тот же результат, что и в раньше; но теперь Вы можете передать и имя, кого приветствовать:</div>
<div>
<span style="font-family: Courier New, Courier, monospace;">$ fab hello:name=Jeff</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">Hello Jeff!</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">Done.</span></div>
<div style="text-align: justify;">
Те, кто уже программируют на Python, могут предположить, что то же самое можно сделать и немного по другому:</div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace;">$ fab hello:Jeff</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">Hello Jeff!</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">Done.</span></div>
</div>
<div style="text-align: justify;">
На данный момент, аргумент, который Вы передаёте, в любом случае будет передан как строка, так что Вам могут потребоваться дополнительные манипуляции с полученным значением. В более поздних версиях может быть добавлена система типов, чтобы облегчить этот процесс.</div>
<div style="text-align: justify;">
<b>См также: </b><a href="http://docs.fabfile.org/en/1.5/usage/fab.html#task-arguments" target="_blank">аргументы для задачи</a></div>
<h3>
Локальные команды</h3>
<div style="text-align: justify;">
В примере выше fab всего лишь экономит Вам несколько строк, начинающихся после `if __name__=="__main__"`. Обычно же используется API Fabric, который содержит функции (или <b>операции</b>) для выполнения команд оболочки, передачи файлов и т.д.</div>
<div style="text-align: justify;">
Давайте построим гипотетическое Web приложение fabfile. Этот сценарий делает следующее: Web приложение управляется через Git на удалённом хосте <i>vcshost. </i>На <i>localhost</i> у нас есть локальный клон web-приложения. Когда мы размещаем обновления на <i>vcshost, </i>мы хотим иметь возможность немедленно установить эти обновления на удалённых хост <i>my_server</i> в автоматическом режиме. Мы будем делать это, автоматизируя локальные и удалённые команды Git.</div>
<div style="text-align: justify;">
Fabfile обычно лучше всего работают из корня проекта:</div>
<div style="text-align: justify;">
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> .
|-- __init__.py
|-- app.wsgi
|-- fabfile.py <-- our fabfile!
|-- manage.py
`-- my_app
|-- __init__.py
|-- models.py
|-- templates
| `-- index.html
|-- tests.py
|-- urls.py
`-- views.py</pre>
</div>
<div style="text-align: justify;">
<b>Примечание:</b> мы будем использовать приложение Django, но лишь в качестве примера - Fabric не привязан к какому-то внешнему коду, используя лишь SSH библиотеку.</div>
<div style="text-align: justify;">
Для начала, возможно, мы захотим запустить наши тесты и отправить обновления на наш VCS, так что мы будем готовы к развёртыванию:</div>
<div style="text-align: justify;">
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> from fabric.api import local
def prepare_deploy():
local("./manage.py test my_app")
local("git add -p && git commit")
local("git push")</pre>
</div>
<div style="text-align: justify;">
Результат этого может быть таким:</div>
<div style="text-align: justify;">
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> $ fab prepare_deploy
[localhost] run: ./manage.py test my_app
Creating test database...
Creating tables
Creating indexes
..........................................
----------------------------------------------------------------------
Ran 42 tests in 9.138s
OK
Destroying test database...
[localhost] run: git add -p && git commit
<interactive Git add / git commit edit message session>
[localhost] run: git push
<git push session, possibly merging conflicts interactively>
Done.</pre>
</div>
<div style="text-align: justify;">
Сам код вполне понятен: мы импортируем функцию API Fabric, <a href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.local" target="_blank">local</a>, и используем её для запуска и взаимодействия с локальной оболочкой. Все остальные API Fabric аналогичны - это лишь Python.</div>
<div style="text-align: justify;">
<b>См также: </b><a href="http://docs.fabfile.org/en/1.5/api/core/operations.html" target="_blank">Операции</a>, <a href="http://docs.fabfile.org/en/1.5/usage/fabfiles.html#fabfile-discovery" target="_blank">исследование fabfile</a></div>
<h3>
Сделайте это по своему</h3>
<div style="text-align: justify;">
Так как Fabric - "всего лишь Python", Вы можете организовать свой fabfile так, как Вам это удобно. Например, часто полезно выделить некоторые вещи в подзадачи:</div>
<div style="text-align: justify;">
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> from fabric.api import local
def test():
local("./manage.py test my_app")
def commit():
local("git add -p && git commit")
def push():
local("git push")
def prepare_deploy():
test()
commit()
push()</pre>
</div>
<div style="text-align: justify;">
Задача prepare_deploy может быть вызвана как в примерах выше, но теперь Вы можете использовать и более <i>детализированные</i> подзадачи, если захотите.</div>
<h3>
Ошибки</h3>
<div style="text-align: justify;">
Всё может работать хорошо, но что будет, если наш тест завершится с ошибкой? Скорее всего, мы захотим остановить наш процесс и сперва исправить ошибку.</div>
<div style="text-align: justify;">
Fabric проверяет возвращаемое значение программы, которую он вызывает, и прерывает своё выполнение если вызванная программа завершилась как-то не так. Давайте посмотрим, что будет, если один из наших тестов завершится с ошибкой:</div>
<div style="text-align: justify;">
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> $ fab prepare_deploy
[localhost] run: ./manage.py test my_app
Creating test database...
Creating tables
Creating indexes
.............E............................
======================================================================
ERROR: testSomething (my_project.my_app.tests.MainTests)
----------------------------------------------------------------------
Traceback (most recent call last):
[...]
----------------------------------------------------------------------
Ran 42 tests in 9.138s
FAILED (errors=1)
Destroying test database...
Fatal error: local() encountered an error (return code 2) while executing './manage.py test my_app'
Aborting.</pre>
</div>
<div style="text-align: justify;">
Замечательно! Нам даже ничего не нужно делать: Fabric обнаружил ошибку и зам завершил свою работу, не дойдя до ``commit``.</div>
<div style="text-align: justify;">
<b>См также: </b><a href="http://docs.fabfile.org/en/1.5/usage/execution.html#failures" target="_blank">Обработка ошибок (документация)</a></div>
<h3>
Обработка ошибок</h3>
<div style="text-align: justify;">
Но что если мы хотим быть немного более гибкими и дать пользователю выбор? Настройка (или <b>переменная окружения</b>, обычно сокращается до <b>env var</b>) под названием <a href="http://docs.fabfile.org/en/1.5/usage/env.html#warn-only" target="_blank">warn_only</a> позволяет не прерывать выполнение, а лишь вывести предупреждение, что даёт возможность организовать гибкую обработку ошибок.</div>
<div style="text-align: justify;">
Давайте воспользуемся этой настройкой для нашей функции test и затем посмотрим на результат вызова <a href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.local" target="_blank">local</a>:<br />
<br />
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> from __future__ import with_statement
from fabric.api import local, settings, abort
from fabric.contrib.console import confirm
def test():
with settings(warn_only=True):
result = local('./manage.py test my_app', capture=True)
if result.failed and not confirm("Tests failed. Continue anyway?"):
abort("Aborting at user request.")
[...]</pre>
<br />
Кроме того, о чём мы уже сказали, мы воспользовались тут ещё несколькими новыми вещами:<br />
<br />
<ul>
<li>Импорт __future__ необходим для использования with в Python 2.5</li>
<li>Подмодуль <a href="http://docs.fabfile.org/en/1.5/api/contrib/console.html#module-fabric.contrib.console" target="_blank">contrib.console</a> содержит функцию <a href="http://docs.fabfile.org/en/1.5/api/contrib/console.html#fabric.contrib.console.confirm" target="_blank">confirm</a>, которая используется для вывода в консоль вопроса да /нет</li>
<li>Менеджер контекста <a href="http://docs.fabfile.org/en/1.5/api/core/context_managers.html#fabric.context_managers.settings" target="_blank">settings</a> используется для применения конкретных настроек к отдельному блоку кода</li>
<li>Операция запуска команд наподобие <a href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.local" target="_blank">local</a> может вернуть объекты, содержащие информацию о результате выполнения запущенной команды (например .failed или .return_code)</li>
<li>Функция <a href="http://docs.fabfile.org/en/1.5/api/core/utils.html#fabric.utils.abort" target="_blank">abort</a> используется для ручного прерывания программы</li>
</ul>
<div>
И, несмотря на некоторое усложнение, код всё ещё прост и достаточно гибок.</div>
<div>
<b>См также: </b><a href="http://docs.fabfile.org/en/1.5/api/core/context_managers.html" target="_blank">Менеджеры контекста</a>, <a href="http://docs.fabfile.org/en/1.5/usage/env.html#env-vars" target="_blank">Полный список env vars</a></div>
<h3>
Создаём подключения</h3>
<div>
Давайте улучшим наш fabfile, добавив туда задачу deploy, которая будет запускаться на удалённом сервере и проверять, что находящийся на нём код актуален:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> def deploy():
code_dir = '/srv/django/myproject'
with cd(code_dir):
run("git pull")
run("touch app.wsgi")</pre>
</div>
<div>
Опять же, тут мы используем некоторые новые возможности:</div>
<div>
<ul>
<li>Fabric это лишь Python, так что мы можем свободно использовать обычный код Python, переменные и строки</li>
<li><a href="http://docs.fabfile.org/en/1.5/api/core/context_managers.html#fabric.context_managers.cd" target="_blank">cd</a> - простой способ предварить команду вызовом cd /в/какую-либо/директорию (то есть изменить каталог перед вызовом другой команды). Это аналогично команде <a href="http://docs.fabfile.org/en/1.5/api/core/context_managers.html#fabric.context_managers.lcd" target="_blank">lcd</a>, которая делает то же самое на локальной машине</li>
<li><a href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.run" target="_blank">run</a> аналогичен <a href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.local" target="_blank">local</a>, но запускает команду удалённо, а не локально</li>
</ul>
<div>
Кроме того, мы должны быть уверены, что мы импортировали новые функции в начале файла:</div>
</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> from __future__ import with_statement
from fabric.api import local, settings, abort, run, cd
from fabric.contrib.console import confirm</pre>
</div>
<div>
Теперь со всеми этими изменениями пора приниматься за новый сервер:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> $ fab deploy
No hosts found. Please specify (single) host string for connection: my_server
[my_server] run: git pull
[my_server] out: Already up-to-date.
[my_server] out:
[my_server] run: touch app.wsgi
Done.</pre>
</div>
<div>
Но мы ещё не создали ни одного подключения, так что Fabric не знает, на каком удалённом хосте должны выполняться эти команды. В таком случае Fabric спросит это у нас в процессе выполнения задачи. Определения подключения задаётся в форме SSH подобной строки подключения, т.е. user@host:port и по умолчанию будет использовать локальное имя пользователя, так что в нашем примере достаточно указать только имя сервера - <i>my_server.</i></div>
<h3>
Взаимодействие с удалённым сервером</h3>
<div>
git pull работает хорошо если Вы уже получили исходники, но что если это первое получение кода? Неплохо было бы обработать и эту ситуацию и в таком случае запустить сперва git clone:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> def deploy():
code_dir = '/srv/django/myproject'
with settings(warn_only=True):
if run("test -d %s" % code_dir).failed:
run("git clone user@vcshost:/path/to/repo/.git %s" % code_dir)
with cd(code_dir):
run("git pull")
run("touch app.wsgi")</pre>
</div>
<div>
Как и в случае с <a href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.local" target="_blank">local</a> выше, <a href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.run" target="_blank">run</a> так же позволяет нам строить логические выражения, основанные на выполнении команд оболочки. Самая интересная часть тут - вызов git clone. Так как мы используем SSH метод Git'a для доступа к репозиторию на нашем сервере Git, это означает, что вызов <a href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.run" target="_blank">run</a> должен аутентифицировать себя.</div>
<div>
Старые версии Fabric (и схожие высокоуровневые библиотеки SSH) запускали удалённые программы в limbo и не могли подключиться к ней с локальной машины. Это проблематично, особенно когда Вам нужно ввести пароль или как-то ещё взаимодействовать с удалённо запущенной программой.</div>
<div>
Fabric 1.0 и более поздние версии решают эти проблемы и позволяют Вам связаться с программой на удалённой машине. Давайте посмотрим, что происходит, когда мы запускаем нашу задачу deploy на новом сервере:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> $ fab deploy
No hosts found. Please specify (single) host string for connection: my_server
[my_server] run: test -d /srv/django/myproject
Warning: run() encountered an error (return code 1) while executing 'test -d /srv/django/myproject'
[my_server] run: git clone user@vcshost:/path/to/repo/.git /srv/django/myproject
[my_server] out: Cloning into /srv/django/myproject...
[my_server] out: Password: <enter password>
[my_server] out: remote: Counting objects: 6698, done.
[my_server] out: remote: Compressing objects: 100% (2237/2237), done.
[my_server] out: remote: Total 6698 (delta 4633), reused 6414 (delta 4412)
[my_server] out: Receiving objects: 100% (6698/6698), 1.28 MiB, done.
[my_server] out: Resolving deltas: 100% (4633/4633), done.
[my_server] out:
[my_server] run: git pull
[my_server] out: Already up-to-date.
[my_server] out:
[my_server] run: touch app.wsgi
Done.</pre>
</div>
<div>
Обратите внимание на запрос пароля (Password) - git, запущенный на нашем сервере спрашивает у нас пароль к серверу Git. И мы можем вручную ввести его, после чего клонирование пройдёт нормально.</div>
<div>
<b>См также</b>: <a href="http://docs.fabfile.org/en/1.5/usage/interactivity.html" target="_blank">Взаимодействие с удалёнными программами</a></div>
<h3>
Как объявить подключения заранее</h3>
<div>
Указание адреса хоста для подключения во время выполнения не самое удобное решение, так что Fabric предоставляет несколько способов сделать это либо в fabfile, либо в командной строке. Мы не будем говорить обо всех этих способах здесь, но мы покажем наиболее популярный из них - установку глобального списка хостов, <a href="http://docs.fabfile.org/en/1.5/usage/env.html#hosts" target="_blank">env.hosts</a>.</div>
<div>
<a href="http://docs.fabfile.org/en/1.5/usage/env.html" target="_blank">env</a> - глобальный объект, похожий на словарь, определяющий многие из настроек Fabric, и в него можно заносить свои значения (на самом деле, <a href="http://docs.fabfile.org/en/1.5/api/core/context_managers.html#fabric.context_managers.settings" target="_blank">settings</a>, о котором мы говорили выше, всего лишь обёртка над этим объектом). Таким образом, мы можем изменить его на уровне модуля вверху fabfile:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> from __future__ import with_statement
from fabric.api import *
from fabric.contrib.console import confirm
env.hosts = ['my_server']
def test():
do_test_stuff()</pre>
</div>
<div>
Когда fab загружает наш fabfile, исполняется наша модификация env и она сохраняет наше изменение настройки. Конечный результат будет аналогичным - наша задача deploy будет запущена на сервере <i>my_server</i>.</div>
<div>
Таким образом, мы можем легко сказать Fabric выполнить задачу сразу на нескольких серверах: так как env.hosts - это список, fab проходит по нему, вызывая задачу для каждого узла.</div>
<div>
<b>См также: </b><a href="http://docs.fabfile.org/en/1.5/usage/env.html" target="_blank">Словарь окружения env</a>, <a href="http://docs.fabfile.org/en/1.5/usage/execution.html#host-lists" target="_blank">Как устроен список хостов</a></div>
<h3>
Заключение</h3>
<div>
Итак, наш fabfile всё ещё не большой, как и должно быть. Вот его содержание:</div>
<div>
<pre style="text-align: start; white-space: pre-wrap; word-wrap: break-word;"> from __future__ import with_statement
from fabric.api import *
from fabric.contrib.console import confirm
env.hosts = ['my_server']
def test():
with settings(warn_only=True):
result = local('./manage.py test my_app', capture=True)
if result.failed and not confirm("Tests failed. Continue anyway?"):
abort("Aborting at user request.")
def commit():
local("git add -p && git commit")
def push():
local("git push")
def prepare_deploy():
test()
commit()
push()
def deploy():
code_dir = '/srv/django/myproject'
with settings(warn_only=True):
if run("test -d %s" % code_dir).failed:
run("git clone user@vcshost:/path/to/repo/.git %s" % code_dir)
with cd(code_dir):
run("git pull")
run("touch app.wsgi")</pre>
</div>
<div>
Зато он использует большую часть возможностей Fabric:</div>
<div>
<ul>
<li>определяет задачи в fabfile и выполняет их при помощи <a href="http://docs.fabfile.org/en/1.5/usage/fab.html" target="_blank">fab</a></li>
<li>вызывает локальные команды оболочки при помощи <a href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.local" target="_blank">local</a></li>
<li>модифицирует переменную env при помощи <a href="http://docs.fabfile.org/en/1.5/api/core/context_managers.html#fabric.context_managers.settings" target="_blank">settings</a></li>
<li>обрабатывает ошибки выполнения команд, запрашивает ввод от пользователя и может вручную прервать выполнение</li>
<li>определяет список хостов и запускает удалённые команды на них при помощи <a href="http://docs.fabfile.org/en/1.5/api/core/operations.html#fabric.operations.run" target="_blank">run</a></li>
</ul>
<div>
Однако, есть ещё много тем, которые мы ещё не покрыли. Обратитесь к ссылкам в разделах "см также" и к <a href="http://docs.fabfile.org/en/1.5/index.html#documentation-index" target="_blank">содержанию документации</a>.</div>
<div>
Спасибо за внимание!</div>
</div>
</div>
Ishayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com0tag:blogger.com,1999:blog-2142461056765545912.post-92229687858210738632013-01-24T15:49:00.001+04:002013-01-24T15:49:19.622+04:00wxPython in Action. Глава 13. Создание списков (list control) и управление им (Перевод)В этой главе мы поговорим о:<br />
<br />
<ul>
<li>создании списков в различных стилях</li>
<li>работа с элементами в списке</li>
<li>реакции на выбор пользователем элемента из списка</li>
<li>редактирование меток и сортировка списка</li>
<li>создание большого списка (large list)</li>
</ul>
<div>
<a name='more'></a><div style="text-align: justify;">
У всех нас есть списки, которые мы хотим просмотреть, и программисты на wxPython не исключение. В wxPython есть два управляющих элемента, которые Вы можете использовать для отображения информации при помощи списков. Самый простой - list box - обычный список из одной колонки, который можно прокручивать, похожий на то, что Вы можете получить в HTML при помощи <select>. Об этом мы говорили в главе 8 (<a href="http://wiki.python.su/%D0%9A%D0%BD%D0%B8%D0%B3%D0%B8/WxPythonInAction/%D0%A0%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%20%D1%81%20%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D0%BC%D0%B8%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%B0%D0%BC%D0%B8%20%D1%83%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F#A.2BBBoEMAQ6_.2BBEEEPgQ3BDQEMARCBEw_.2BBEEEPwQ4BEEEPgQ6_.28listbox.29.3F" target="_blank">видимо, всё же имеется ввиду глава 7</a>) и больше их затрагивать не будем.</div>
</div>
<div style="text-align: justify;">
Эта глава будет говорить о более сложном способе отображения информации в форме списка - элементе управления list (list control), полноценном виджете списка. Он отображает ListCtrl с несколькими колонками информации для каждой строки, который можно отсортировать по каждой колонке и стиль отображения которого можно настроить. У Вас есть достаточно гибкости в настройке каждой части этого элемента.</div>
<h2>
13.1 Создание элемента управления list</h2>
<div>
List может быть создан в одной из 4-х форм:</div>
<div>
<ul>
<li>иконка (плитка)</li>
<li>маленькая иконка (значки)</li>
<li>список</li>
<li>отчёт</li>
</ul>
<div style="text-align: justify;">
Суть этого должна быть понятна всем, кто использует Проводник в Windows или Mac Finder - это соответствует способам отображения элементов в проводнике. Мы начнём наше исследование этого элемента с того, что посмотрим как его создать в каждой из этих форм.</div>
</div>
<h3>
13.1.1 Что такое режим "иконка"</h3>
<div style="text-align: justify;">
List выглядит как панель отображения дерева файловой системы в MS Windows Explorer. Этот элемент управления отображает информацию в одном из четырёх режимов. По умолчанию используется режим иконка, где каждый элемент списка представлен иконкой с текстом под ней. Рисунок 13.1 показывает простой пример этого режима.<br />
Код для отображения этого примера приведён в листинге 13.1. Обратите внимание, что этот код зависит от некоторых .png файлов, которые расположены в той же папке, что и наш модуль. Эти файлы можно получить с сайта этой книги.<br />
<div style="text-align: center;">
Листинг 13.1</div>
<br />
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;">import wx</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;">import sys, glob</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;">class DemoFrame(wx.Frame):</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"> def __init__(self):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">wx.Frame.__init__(self, None, -1, \</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">"wx.ListCtrl in wx.LC_ICON mode",</span><span style="font-family: 'Courier New', Courier, monospace;">size=(600,400))</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace;">il = wx.ImageList(32,32, True)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace;"># Создаём image list</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace;">for name in glob.glob("icon??.png"):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace;">bmp = wx.Bitmap(name, wx.BITMAP_TYPE_PNG)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace;">il_max = il.Add(bmp)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"># Создаём list</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list = wx.ListCtrl(self, -1</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace;">style=wx.LC_ICON | wx.LC_AUTOARRANGE)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.AssignImageList(il, wx.IMAGE_LIST_NORMAL)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace;">for x in range(25):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> # Заполняем </span><span style="font-family: 'Courier New', Courier, monospace;">list</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace;">img = x % (il_max+1)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.InsertImageStringItem(x,</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: justify;"> </span><span style="font-family: 'Courier New', Courier, monospace;">"This is item %02d" % x, img)</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;">app = wx.PySimpleApp()</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;">frame = DemoFrame()</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;">frame.Show()</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;">app.MainLoop()</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivYnDm0enadRK_5_KDQjcLzFDBYVNaYAhcTSeI91cQchrNrrbGGYTZYnQHVXuS3u8WukHEY5BTekYZ0gFUCFVhT8DWG5cDfhs4-c_NaNBe7vs34TOaqwu0LAn8lswxdfzMeS_hrkiRDB8/s1600/13-1.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivYnDm0enadRK_5_KDQjcLzFDBYVNaYAhcTSeI91cQchrNrrbGGYTZYnQHVXuS3u8WukHEY5BTekYZ0gFUCFVhT8DWG5cDfhs4-c_NaNBe7vs34TOaqwu0LAn8lswxdfzMeS_hrkiRDB8/s1600/13-1.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Рисунок 13.1 Простой список в режиме "иконка"</td></tr>
</tbody></table>
<div style="text-align: center;">
<br /></div>
В листинге 13.1 демонстрационный фрейм создаёт список изображений (image list), который содержит ссылки на изображения, которые мы будем отображать; затем мы создаём и заполняем элемент list. Список изображения мы обсудим позже в этой главе.<br />
<h3>
13.1.2 Что такое режим "маленькая иконка"</h3>
<div>
Режим "маленькая иконка" (small icon) похож на режим "иконка", только использует маленькие значки. Рисунок 13.2 приводит пример того же самого списка в режиме "маленькой иконки".</div>
<div>
Этот режим особенно полезен когда Вы хотите уместить в виджете много элементов, особенно если сами иконки не настолько детализированы, чтобы показывать их в исходном размере.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQubLUF2kb0IGtWMLxEVct5qMfRDQOp74yQ4OWMbsKteBgXEDbzyCC-wU-2E9uw9gfn3kJ4tMhQTyo4BNIxs-dg2NNYx1aCvaAn9WKsPfj-yQ1hHmEmMlRgruC5frNRtuDevJDCqmUPTM/s1600/13-2.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQubLUF2kb0IGtWMLxEVct5qMfRDQOp74yQ4OWMbsKteBgXEDbzyCC-wU-2E9uw9gfn3kJ4tMhQTyo4BNIxs-dg2NNYx1aCvaAn9WKsPfj-yQ1hHmEmMlRgruC5frNRtuDevJDCqmUPTM/s1600/13-2.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Рисунок 13.2 Простой list в режиме "маленькая иконка"</td></tr>
</tbody></table>
<br />
<br /></div>
<h3>
13.1.3 Что такое режим списка (list mode)?</h3>
<div>
В режиме списка элементы отображаются в нескольких колонках, автоматически заполняя каждую из них по очереди, как показано на рисунке 13.3</div>
<div>
Этот режим имеет те же достоинства, что и режим "маленькая иконка"; выбор между ними (т.е. между расположением в строчку или в столбик) зависит от ваших предпочтений.</div>
<div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE1EiARYN4jEzzzAX9DgDd8CvLn5VZMA4PstfCm8kafDTXahV1Yhj12xeUAapUES8WA9BhU8NuDr4rESkLOEC9XLa5oVXFx5gbdYARvXkYf1u_JIKjmfU7u-PJV7swdTgGqhjoZKwWgp8/s1600/13-3.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE1EiARYN4jEzzzAX9DgDd8CvLn5VZMA4PstfCm8kafDTXahV1Yhj12xeUAapUES8WA9BhU8NuDr4rESkLOEC9XLa5oVXFx5gbdYARvXkYf1u_JIKjmfU7u-PJV7swdTgGqhjoZKwWgp8/s1600/13-3.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Рисунок 13.3 Простой list в режиме "список"</td></tr>
</tbody></table>
<br /></div>
<h3>
13.1.4 Что такое режим отчёта (report mode)?</h3>
<div>
В режиме отчёта list отображается в формате нескольких колонок, где каждый строк может иметь любое число столбцов, связанных с ним, как показано на рисунке 13.4<br />
<br /></div>
<div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhNqWay98nofJXQdEBToQEJm_A0HDU19Qgh_tVeQZSj-_43ErAMmppPYyIFB-UzNLJvguPK_qYA0rAtKIoWEXxQRYcVVpCS0wSGk-Ygz89UPwvwxRCHu8-SUntaGNrJ4nBBaV2zXWx-04/s1600/13-4.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhNqWay98nofJXQdEBToQEJm_A0HDU19Qgh_tVeQZSj-_43ErAMmppPYyIFB-UzNLJvguPK_qYA0rAtKIoWEXxQRYcVVpCS0wSGk-Ygz89UPwvwxRCHu8-SUntaGNrJ4nBBaV2zXWx-04/s1600/13-4.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Рисунок 13.4 Простой list в режиме "отчёт"</td></tr>
</tbody></table>
Этот режим настолько отличается от режима "иконка", что стоит привести код, который нужен для создания такого отображения:<br />
<div style="text-align: center;">
Листинг 13.2 Пример создания list'a в режиме "отчёт"</div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: left;">
</div>
<span style="font-family: Courier New, Courier, monospace;">import wx</span><br />
<span style="font-family: Courier New, Courier, monospace;">import sys, glob, random</span><br />
<span style="font-family: Courier New, Courier, monospace;">import data</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">class DemoFrame(wx.Frame):</span><br />
<span style="font-family: Courier New, Courier, monospace;"> def __init__(self):</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">wx.Frame.__init__(self, None, -1,</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">"wx.ListCtrl in wx.LC_REPORT mode",</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">size=(600,400))</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">il = wx.ImageList(16,16, True)</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">for name in glob.glob("smicon??.png"):</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">bmp = wx.Bitmap(name, wx.BITMAP_TYPE_PNG)</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">il_max = il.Add(bmp)</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Создаём list</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list = wx.ListCtrl(self, -1, style=wx.LC_REPORT)</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.AssignImageList(il, wx.IMAGE_LIST_SMALL)</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Добавляем колонки</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">for col, text in enumerate(data.columns):</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.InsertColumn(col, text)</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Добавляем строки</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">for item in data.rows:</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">index = self.list.InsertStringItem(sys.maxint, item[0])</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">for col, text in enumerate(item[1:]):</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.SetStringItem(index, col+1, text)</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"># даём каждому элементу случайное изображение</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">img = random.randint(0, il_max)</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.SetItemImage(index, img, img)</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Настраиваем ширину колонок</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.SetColumnWidth(0,</span><span style="font-family: 'Courier New', Courier, monospace;"> 120)</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.SetColumnWidth(1,</span><span style="font-family: 'Courier New', Courier, monospace;"> wx.LIST_AUTOSIZE)</span><br />
<span style="font-family: 'Courier New', Courier, monospace; text-align: left;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: left;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: left;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: left;"> </span><span style="font-family: Courier New, Courier, monospace;">self.list.SetColumnWidth(2,</span><span style="font-family: 'Courier New', Courier, monospace;"> wx.LIST_AUTOSIZE)</span><br />
<span style="font-family: 'Courier New', Courier, monospace; text-align: left;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: left;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: left;"> </span><span style="font-family: 'Courier New', Courier, monospace; text-align: left;"> </span><span style="font-family: Courier New, Courier, monospace;">self.list.SetColumnWidth(3,</span><span style="font-family: 'Courier New', Courier, monospace;"> wx.LIST_AUTOSIZE_USEHEADER)</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">app = wx.PySimpleApp()</span><br />
<span style="font-family: Courier New, Courier, monospace;">frame = DemoFrame()</span><br />
<span style="font-family: Courier New, Courier, monospace;">frame.Show()</span><br />
<span style="font-family: Courier New, Courier, monospace;">app.MainLoop()</span><br />
<div>
<br /></div>
</div>
<div>
В следующем разделе мы обсудим как поместить значение в соответствующем месте. Логика отображения этого режима должна быть не так уж и сложна. Лучше всего использовать этот режим в случае, когда список содержит одну-две дополнительные колонки данных. Если же ваш список сложнее, или содержит больше данных, то тогда лучше использовать grid control, описанный в 14 главе.</div>
<div>
<h3>
13.1.5 Как я могу создать list?</h3>
</div>
<div>
Элемент list в wxPython является экземпляром класса wx.ListCtrl. Его конструктор похож на конструкторы других виджетов:</div>
<div>
<span style="font-family: Courier New, Courier, monospace;">wx.ListCtrl(parent, id, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.LC_ICON, validator=wx.DefaultValidator, name="listCtrl")</span></div>
<div>
Эти параметры содержат значения, которые мы уже видели в конструкторах других виджетов. parent - это родительский виджет, в котором будет расположен list; id - идентификатор wxPython, где -1 обозначает автоматически сгенерированное значение. Явно расположение задаётся параметрами pos и size. style задаёт режим и остальные опции отображения - об этом мы ещё поговорим в этой главе. validator используется для проверки ввода и о нём мы говорили в 9 главе. Параметр name используется достаточно редко.</div>
<div>
Флаг style - это битовая маска, которая определяет некоторые возможности этого элемента управления. Первый набор значений - это режим отображения элемента. Режим по умолчанию - wx.LC_ICON. Таблица 13.1 содержит остальные доступные режимы.</div>
<div>
<table border="1" cellpadding="2" cellspacing="2" style="text-align: left; width: 100%;">
<tbody>
<tr>
<th style="vertical-align: top;">Стиль</th>
<th style="vertical-align: top;">Описание</th>
</tr>
<tr>
<td style="vertical-align: top;">wx.LC_ICON</td>
<td style="vertical-align: top;">Режим "иконка"</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LC_LIST</td>
<td style="vertical-align: top;">Режим "список"</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LC_REPORT</td>
<td style="vertical-align: top;">Режим "отчёт"</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LC_SMALL_ICON</td>
<td style="vertical-align: top;">Режим "маленькая иконка"</td>
</tr>
</tbody>
</table>
</div>
<div>
В режимах "иконка" и "маленькая иконка" доступны ещё три флага, которые определяют расположение иконки относительно списка. Значение по умолчанию - wx.LC_ALIGN_TOP, которе выравнивает иконки по вершине списка. Для выравнивания по левой стороне используйте wx.LC_ALIGN_LEFT. Стиль LC.AUTOARRANGE заворачивает иконки по достижении ими нижнего или правого угла окна.</div>
<div>
Таблица 13.2 содержит стили отображения для режима "отчёт":</div>
<table border="1" cellpadding="2" cellspacing="2" style="text-align: left; width: 100%;">
<tbody>
<tr>
<th style="vertical-align: top;">Стиль</th>
<th style="vertical-align: top;">Значение по умолчанию</th>
</tr>
<tr>
<td style="vertical-align: top;">wx.LC_HRULES</td>
<td style="vertical-align: top;">Рисует линии между строками
list'a</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LC_NO_HEADER</td>
<td style="vertical-align: top;">Не отображает заголовки колонок</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LC_VRULES</td>
<td style="vertical-align: top;">Рисует линии между колонками
list'a</td>
</tr>
</tbody>
</table>
<div>
Флаги битовых масок могут быть скомбинированы при помощи операции <i>или. </i>Используйте wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES для того чтобы получить вид, похожий на решётку. По умолчанию все элементы list позволяют осуществлять множественный выбор. Для того, чтобы это изменить используйте флаг wx.LC_SINGLE_SEL.<br />
В отличие от остальных виджетов, которые мы видели до сих пор, list имеет ещё несколько методов, которые позволяют Вам изменить его флаги стилей уже в процессе выполнения. Метод SetSingleStyle(style, add=True) позволяет Вам добавить или удалить один флаг стиля, в зависимости от параметра add. Вызов listCtrl.SetSingleStyle(LC_HRULES, True) добавит горизонтальную линейку, тогда как listCtrl.SetSingleStyle(LC_HRULES, False) удалит её. Вызов SetWindowStyleFlag(style) позволяет Вам переустановить весь стиль, задав новые флаги, например, SetWindowsStyleFlag(LC_REPORT | LC_NO_HEADER). Эти методы полезны для изменения list'a на лету.<br />
<h2>
13.2 Управление элементами в list'e</h2>
</div>
<div>
После того, как list создан, Вы можете добавлять информацию в него. В wxPython для этой цели используются разные способы, зависящие от того, что Вы хотите добавить - текстовую информацию или изображения, ассоциированные с элементами list'a. В следующих разделах мы покажем как добавлять текст и изображения в ваш list.</div>
<h3>
13.2.1 Что такое image list и как к нему добавлять изображения</h3>
<div>
Перед тем, как мы сможем говорить о том, как информация добавляется в list, мы должны сказать несколько слов о том, как list работает с изображениями. Все изображения, используемые в этом элементе, должны быть сперва добавлены в image list, который представляет из себя проиндексированный массив изображений, сохранённых в элементе list. Когда Вы связываете изображение с определённым элементом в list, то для ссылки на изображение используется его индекс. Этот механизм позволяет быть уверенным в том, что каждое изображение загружено только один раз, вне зависимости от того, как часто оно используется в list. Что, в свою очередь, помогает сэкономить память в случаях, когда изображения используются по нескольку раз. Кроме того, это обегчает связь между несколькими версиями одного и того же изображения, что может быть полезно для различных режимов. Более подробно создание изображений и bitmap в wxPython обсуждается в главе 12.</div>
<div>
<h4>
Создание image list</h4>
image list является экземпляром wx.ImageList и для его создания используется следующий конструктор:<br />
<span style="font-family: Courier New, Courier, monospace;">wx.ImageList(width, height, mask=True, initialCount=1)</span><br />
Параметры width и height задают в пикселях размер изображения, которое будет добавлено в list. Изображения больше, чем указанный размер добавить нельзя. Если параметр mask = True, nj изображение рисуется с его маской, если она у него есть. Параметр initialCount задаёт начальный внутренний размер list'a. Если Вы знаете, что list будет большой, то указание этого размера может сэкономить память и время позже.<br />
<h4>
Добавление и удаление изображений</h4>
</div>
<div>
Вы можете добавить изображение в list при помощи метода Add(bitmap, mask=wx.NullBitmap), где bitmap и mask оба являются экземплярами wx.Bitmap. Аргумент mask является монохромным битовым изображением, которое определяет прозрачные части изображения, если они должны быть. Если битовое изображение уже имеет свою маску, то его маска и будет использоваться по умолчанию. Если маски у изображения нет и у Вас нет монохромной карты прозрачности, но Вы хотите чтобы какой-то цвет в изображении служил маской, Вы можете использовать метод AddWithColourMask(bitmap, colour), где colour - цвет wxPython (или его имя), который будет использоваться в качестве маски. Если у Вас есть объект wx.Icon, который Вы хотите добавить в image list, то используйте метод AddIcon(icon). Все методы добавления возвращают индекс изображения в list'e, который Вы можете позже использовать.</div>
<div>
Следующий отрывок кода показывает пример создания image list (похоже на листинг 13.1)</div>
<div>
<span style="font-family: Courier New, Courier, monospace;">il = wx.ImageList(32, 32, True)</span><br />
<span style="font-family: Courier New, Courier, monospace;">for name in glob.glob("icon??.png"):</span><br />
<span style="font-family: Courier New, Courier, monospace;"> bmp = wx.Bitmap(name, wx.BITMAP_TYPE_PNG)</span><br />
<span style="font-family: Courier New, Courier, monospace;"> il_max = il.Add(bmp)</span></div>
<div>
image list должен быть привязан к list при помощи следующего метода:</div>
<div>
<span style="font-family: Courier New, Courier, monospace;">self.list.AssignImageList(il, wx.IMAGE_LIST_NORMAL)</span></div>
<div>
Для того, чтобы удалить изображение из image list, воспользуйтесь методом Remove(index), где index - индекс изображения в списке. Этот метод изменяет индексы всех изображений после удалённого, что может создать проблему, если Вы ссылаетесь на конкретный индекс где-либо в ваше программе. Для того чтобы отчистить весь image list используйте RemoveAll(). Вы можете изменить изображение с заданным индексом при помощи метода Replace(index, bitmap, mask=wx.NullBitmap), где index - индекс изображения в image list, bitmap и mask имеют то же самое значение, что и в Add(). Если Вы хотите заменить иконку, то используйте метод ReplaceIcon(index, icon). Метода для замены цвета маски нет.</div>
<h4>
Использование image list</h4>
<div>
Вы можете получить длину image list при помощи метода GetImageCount(), а размер кэша конкретного изображения при помощи GetSize(), который возвращает кортеж (width, height).</div>
<div>
Хотя это и не относится к теме list'a, тем не менее Вы можете нарисовать изображение из image list на устройство контекста. Более подробно об этом говорилось в главах <a href="http://wiki.python.su/%D0%9A%D0%BD%D0%B8%D0%B3%D0%B8/WxPythonInAction/%D0%A0%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%20%D1%81%20%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D1%8B%D0%BC%D0%B8%20%D1%81%D0%BE%D1%81%D1%82%D0%B0%D0%B2%D0%BD%D1%8B%D0%BC%D0%B8%20%D0%B1%D0%BB%D0%BE%D0%BA%D0%B0%D0%BC%D0%B8" target="_blank">6</a> и <a href="http://python-lab.blogspot.com/2012/10/wxpython-in-action-12.html" target="_blank">12</a>. Для этого нужен метод Draw():</div>
<div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;">Draw(index, dc, x, y, flags=wx.IMAGELIST_DRAW_NORMAL, solidBackground=False)</span></div>
</div>
<div>
В этом случае index - индекс изображения в image list, dc - устройство контекста wx.DC. Параметры x и y - начальные координаты в устройстве контекста для отрисовки изображения. flags управляет отрисовкой изображения, а bitmask - одна или более из констант wx.IMAGELIST_DRAW_NORMAL, wx.IMAGELIST_DRAW_TRANSPARENT, wx.IMAGELIST_DRAW_SELECTED и wx.IMAGELIST_DRAW_FOCUSED. Если solidBackground=True, то метод будет использовать более быстрый алгоритм, который работает только при сплошном фоне.</div>
<div>
После того, как у Вас есть image list, Вы должны прикрепить его к list'y. Это делается одним из двух способов: AssignImage(imageList, which) или SetImage(imageList, which). Оба метода принимают идентичные параметры, первый из которых image list, а второй - числовой флаг со значением wx.IMAGE_LIST_NORMAL или wx.IMAGE_LIST_SMALL. Единственная разница между методами заключается в том, как image list управляется со стороны C++. При использовании AssignImage() image list становится частью list и уничтожается вместе с ним, а при использовании SetImage() image list продолжает жить своей жизнью и уничтожается лишь когда он сам покидает область видимости.</div>
<div>
list может иметь два image list, подключённых к себе. Обычный image list, который подключён с wx.IMAGE_LIST_NORMAL, отображается в режиме "иконки", тогда как маленький image list, подключённый с wx.IMAGE_LIST_SMALL, используется в режимах "отчёт" и "маленькие иконки". Скорее всего Вам нужен только один из них, но если Вы хотите, чтобы ваш list мог отображаться в разных режимах (то есть пользователь сможет переключаться между режимами "иконка" и "маленькая иконка"), Вам нужно подключить оба листа. Но в таком случае стоит помнить, что list знает об изображениях только их индексы в image list, так что оба image list должны иметь для идентичных изображений идентичные индексы. То есть, если иконка документа в обычном image list имеет индекс 2, то и в маленьком image list у неё должен быть индекс 2.</div>
<div>
Кроме того, у list есть метод-получатель GetImageList(which), который возвращает image list, подключённый с флагом which.</div>
<h3>
13.2.2 Как я могу добавлять и удалять элементы из list?</h3>
<div>
Перед тем, как Вы сможете отобразить list, Вы должны добавить к нему текстовую информацию. В режиме "иконка" Вы можете добавить новый элемент как иконку, строку или как то и другое. В режиме "отчёт" Вы так же можете задать информацию для различных столбцов после того, как Вы добавите иконку или строку. API и соглашения о наименовании методов для управления элементами отличаются от тех, которые мы видели до сих пор, так что даже если Вы понимаете, как управлять элементами меню и list box, Вы всё равно должны прочитать этот раздел.<br />
Добавление текстовой информации в list состоит из одного шага для режима "иконка" и из нескольких шагов для режима "отчёт". Первый шаг, общий для любого режима, это добавить первый элемент в строку. Для режима "отчёт" Вы должны будете ещё добавить столбцы и информацию для этих столбцов.<br />
<h4>
Добавление новой строки</h4>
</div>
<div>
Для того, чтобы добавить новую строку, воспользуйтесь одним из методов InsertItem(). Какой из них использовать зависит от типа элемента, который Вы добавляете. Если Вы просто хотите добавить строку в list, используйте InsertStringItem(index, label), где index - та строка в list, куда Вы добавляете элемент для отображения. Если у Вас есть только изображение, тогда используйте InsertImageItem(index, imageIndex). В этом случае первый index - строка в list, а imageIndex - индекс изображения в image list, прикреплённом к list. Перед этим image list должен быть уже создан и подключён к list'y. Если Вы указываете индекс за пределами image list, то Вы получите пустое изображение. Если Вы хотите добавить элемент с тестом и изображением, используйте InsertImageStringItem(index, label, imageIndex). Этот метод комбинирует параметры предыдущих двух, так что index - строка в list'e, label - строка для отображения, imageIndex - индекс в image list.</div>
<div>
Сам list для управления информацией о добавленных элементах использует экземпляры wx.ListItem. Мы лишь упомянем, что последний метод для добавления элемента - InsertItem(index, item), где item - это экземпляр wx.ListItem, который Вы уже создали. Мы не будем вдаваться в детали этого процесса, так как скорее всего Вы не будете с этим сталкиваться, да и сам класс не так сложен - практически только методы установки и получения. Практически все методы элемента list'a доступны посредством методов самого list'a.</div>
<h4>
Добавление столбца</h4>
<div>
Для того, чтобы добавить столбец в режим "отчёт", создайте колонку, после чего задайте данные для каждой строки. Столбец создаётся методом InsertColumn():</div>
<div>
<span style="font-family: Courier New, Courier, monospace;">InsertColumn(col, heading, format=wx.LIST_FORMAT_LEFT, width=-1)</span></div>
<div>
В этом методе параметр col - индекс нового столбца в list'e. Параметр heading - строка текста задающая заголовок столбца. format управляет выравниваем текста в колонке; для него доступны значения wx.LIST_FORMAT_CENTRE, wx.LIST_FORMAT_LEFT, wx.LIST_FORMAT_RIGHT. Параметр width - первоначальная ширина отображаемого столбца в пикселях; понятно, что пользователь может изменить её ширину позже. Для того, чтобы использовать wx.ListItem объект для задания колонки есть метод InsertColumnInfo(info), который принимает элемент list в качестве параметра.</div>
<h4>
Установка значений для list c несколькими колонками</h4>
<div>
Вы можете обратить внимание, что вставка элемента с использованием метода, описанного выше, задаёт значение только первой колонки режима "отчёт". Для того, чтобы задать значения другим колонкам используйте метод SetStringItem()</div>
<div>
<span style="font-family: Courier New, Courier, monospace;">SetStringItem(index, col, label, imageId=-1)</span></div>
<div>
Параметры index и col - индексы строки и колонки для ячейки, значение которой Вы задаёте. Для параметра col можно использовать значение 0, чтобы указать первую колонку, но index должен соответствовать строке, которая уже существует в list'e; другими словами этот метод можно использовать только для строк, которые уже добавлены. Аргумент label - это текст для отображения в ячейке, а imageId - индекс в соответствующем image list, если в ячейке Вы хотите показать изображение.</div>
<div>
Метод SetStringItem() технически является специальным случаем метода SetItem(info), который принимает экземпляр wx.ListItem. Для того, чтобы использовать этот метод задайте строку, колонку и любые другие параметры экземпляра элемента list перед его добавлением. Так же Вы можете получить экземпляр wx.ListItem в ячейке при помощи метода GetItem(index, col=0), который возвращает элемент указанной строки и переданной колонки (первой, по умолчанию).</div>
<h4>
Свойства элемента</h4>
<div>
Есть некоторое количество задающих и получающих методов, которые позволяют Вам определить часть элемента. По большей части эти методы работают с первой колонкой строки. Для того, чтобы получить доступ к другой колонке Вы должны получить весь элемент при помощи GetItem() и затем уже использовать получающие и задающие методы класса элемента. Вы можете задать изображение для элемента при помощи SetItemImage(item, image, selImage), где item - это индекс элемента в list'e, image и selImage - индексы в image list, которые соответствуют обычному изображению и выбранному изображению. Вы можете получить или задать текст элемента при помощи GetItemText(item) и SetItemText(item, text).</div>
<div>
Вы можете получить или задать статус индивидуального элемента при помощи GetItemState(item, stateMask) и SetItemState(item, state, stateMask). В этом случае state и state Mask - значения из таблицы 13.3. Параметр state (и возвращаемое значение от соответствующего метода) - это актуальное состояние элемента, stateMask - маска всех возможных состояний.</div>
<table border="1" cellpadding="2" cellspacing="2" style="text-align: left; width: 100%;">
<tbody>
<tr>
<th style="vertical-align: top;">Состояние</th>
<th style="vertical-align: top;">Описание</th>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_STATE_CUT</td>
<td style="vertical-align: top;">Элемент вырезан. Применимо
только под MS Windows</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_STATE_DONTCARE</td>
<td style="vertical-align: top;">Состояние не имеет значения.
Применимо только под MS Windows</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_STATE_DROPHILITED</td>
<td style="vertical-align: top;">Элемент подсвечен потому как был
перетащен. Применимо только под MS Windows</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_STATE_FOCUSED</td>
<td style="vertical-align: top;">Элемент получил фокус</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_STATE_SELECTED</td>
<td style="vertical-align: top;">Элемент выделен</td>
</tr>
</tbody>
</table>
<div>
Вы можете получить специфическую колонку при помощи метода GetColumn(col), который возвращает экземпляр wx.ListItem для колонки с индексом col - то есть элемент заголовка колонки. Вы можете задать колонку которая уже существует при помощи метода SetColumn(col, item). Можно программно получить ширину колонки при помощи метода GetColumnWidth(col), который возвращает ширину колонки в пикселях - обычно это полезно только для режима "отчёт". Вы можете задать ширину колонки при помощи SetColumnWidth(col, width). Ширина является либо числом, либо одним из специальных значений wx.LIST_AUTOSIZE, который задаёт ширину согласно самому длинному элементу, или wx.LIST_AUTOSIZE_USEHEADER, который задаёт ширину в соответствии с шириной заголовка столбца. Под ОС, кроме Widnows, wx.LIST_AUTOSIZE_USEHEADER может просто задать ширину столбца в 80 пикселей.</div>
<div>
Если Вы сомневаетесь в индексах, которые Вы уже добавили, Вы можете запросить список уже добавленных индексов. Метод GetColumnCount() возвращает число колонок, определённых в list, а метод GetItemCount() возвращает число строк. Если ваш list находится в режиме "список", тогда метод GetCountPerPage() возвратит число элементов в каждом столбце.</div>
<div>
Для того, чтобы удалить элемент из list'a используйте DeleteItem(item), который принимает индекс элемента в list'e. Если Вы хотите удалить все элементы разом, воспользуйтесь методом DeleteAllItems() или ClearAll(). Вы можете удалить колонку методом DelectColumn(col), который принимает индекс удаляемой колонки.</div>
<h2>
13.3 Ответ на действия пользователя</h2>
<div>
Обычно задача элемента list - сделать что-то, когда пользователь выбирает элемент в list'e. В следующем разделе мы покажем на какие события list'a можно реагировать и приведём пример использования событий этого элемента.</div>
<h3>
13.3.1 Как я могу реагировать на выбор пользователя?</h3>
<div>
Как и другие элементы управления, list генерирует события в ответ на действия пользователя. Вы можете установить обработчик события при помощи метода Bind(), как это показывалось в <a href="http://wiki.python.su/%D0%9A%D0%BD%D0%B8%D0%B3%D0%B8/WxPythonInAction/%D0%A0%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%20%D0%B2%20%D1%81%D1%80%D0%B5%D0%B4%D0%B5%20%D1%83%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D1%8F%D0%B5%D0%BC%D0%BE%D0%B9%20%D1%81%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D1%8F%D0%BC%D0%B8" target="_blank">главе 3</a>. Все обработчики событий являются экземплярами класса wx.ListEvent, подкласса wx.CommandEvent. У wx.ListEvent есть несколько установочных методов, специфичных для класса. Некоторые из них специфичны для некоторых типов событий, как описано в других разделах. Общие свойства для всех типов событий описаны в таблице 13.4</div>
<table border="1" cellpadding="2" cellspacing="2" style="text-align: left; width: 100%;">
<tbody>
<tr>
<th style="vertical-align: top;">Метод</th>
<th style="vertical-align: top;">Описание</th>
</tr>
<tr>
<td style="vertical-align: top;">GetData()</td>
<td style="vertical-align: top;">Элемент данных, ассоциированный
с элементом list'a события</td>
</tr>
<tr>
<td style="vertical-align: top;">GetKeyCode()</td>
<td style="vertical-align: top;">В событии нажатия кнопки - код
нажатой кнопки</td>
</tr>
<tr>
<td style="vertical-align: top;">GetIndex()</td>
<td style="vertical-align: top;">Индекс элемента,
задействованного в событии</td>
</tr>
<tr>
<td style="vertical-align: top;">GetItem()</td>
<td style="vertical-align: top;">wx.ListItem, задействованный в
событии</td>
</tr>
<tr>
<td style="vertical-align: top;">GetImage()</td>
<td style="vertical-align: top;">Изображение в ячейке,
задействованной в событии</td>
</tr>
<tr>
<td style="vertical-align: top;">GetMask()</td>
<td style="vertical-align: top;">Битовая маска ячейки,
задействованной в событии</td>
</tr>
<tr>
<td style="vertical-align: top;">GetPoint()</td>
<td style="vertical-align: top;">Положение мыши на момент
возникновения события</td>
</tr>
<tr>
<td style="vertical-align: top;">GetText()</td>
<td style="vertical-align: top;">Текст в ячейке, задействованной
в событии</td>
</tr>
</tbody>
</table>
<div>
Есть несколько типов событий wx.ListEvent, каждый из которых может быть передан своему обработчику. Некоторые из них мы обсудим позже. В таблице 13.5 перечислены все типы событий, которые работают с выбранным элементом list'a.</div>
<table border="1" cellpadding="2" cellspacing="2" style="text-align: left; width: 100%;">
<tbody>
<tr>
<th style="vertical-align: top;">Тип События</th>
<th style="vertical-align: top;">Описание</th>
</tr>
<tr>
<td style="vertical-align: top;">EVT_LIST_BEGIN_DRAG</td>
<td style="vertical-align: top;">Вызывается, когда пользователь
начинает операцию перетаскивания при помощи левой клавиши мыши</td>
</tr>
<tr>
<td style="vertical-align: top;">EVT_LIST_BEGIN_RDRAG</td>
<td style="vertical-align: top;">Вызывается, когда пользователь
начинает операцию перетаскивания при помощи правой клавиши мыши</td>
</tr>
<tr>
<td style="vertical-align: top;">EVT_LIST_DELETE_ALL_ITEMS</td>
<td style="vertical-align: top;">Вызывается методом DeleteAll()
list'a</td>
</tr>
<tr>
<td style="vertical-align: top;">EVT_LIST_DELETE_ITEM</td>
<td style="vertical-align: top;">Вызывается методом Delete()
list'a</td>
</tr>
<tr>
<td style="vertical-align: top;">EVT_LIST_INSERT_ITEM</td>
<td style="vertical-align: top;">Вызывается при вставке элемента
в list</td>
</tr>
<tr>
<td style="vertical-align: top;">EVT_LIST_ITEM_ACTIVATED</td>
<td style="vertical-align: top;">Вызывается при активации
выбранного элемента двойным кликом или нажатием enter</td>
</tr>
<tr>
<td style="vertical-align: top;">EVT_LIST_ITEM_DESELECTED</td>
<td style="vertical-align: top;">Вызывается когда элемент теряет
выделение</td>
</tr>
<tr>
<td style="vertical-align: top;">EVT_LIST_ITEM_FOCUSED</td>
<td style="vertical-align: top;">Вызывается при изменении фокуса
элемента</td>
</tr>
<tr>
<td style="vertical-align: top;">EVT_LIST_MIDDLE_CLICK</td>
<td style="vertical-align: top;">Вызывается при нажатии средней
кнопки мыши на list'e</td>
</tr>
<tr>
<td style="vertical-align: top;">EVT_LIST_RIGHT_CLICK</td>
<td style="vertical-align: top;">Вызывается при нажатии правой
кнопки мыши на list'e</td>
</tr>
<tr>
<td style="vertical-align: top;">EVT_LIST_SELECTED</td>
<td style="vertical-align: top;">Вызывается при нажатии левой
кнопки мыши на list'e и выделении элемента</td>
</tr>
<tr>
<td style="vertical-align: top;">EVT_LIST_ITEM_KEY_DOWN</td>
<td style="vertical-align: top;">Вызывается при нажатии клавиши,
если list имеет при этом фокус</td>
</tr>
</tbody>
</table>
<div>
В листинге 13.3 мы покажем пример использования большинства этих типов.</div>
<h3>
13.3.2 Как я могу реагировать на выбор пользователем заголовка колонки?</h3>
<div>
В дополнение к событиям, которые возникают, когда пользователь действует в "теле" листа, есть события, возникающие при взаимодействиях пользователя с заголовками колонок. Объект wx.ListEvent, создаваемый колонкой имеет соответствующий метод GetColumn(), который возвращает индекс колонки, вызвавшей событие. Если это событие перетаскивания границы колонки, то возвращается индекс колонки, находящейся слева от перетаскиваемой границы. Если событие вызывается кликом вне колонки, то метод вернёт -1. Таблица 13.6 содержит типы событий для колонок.</div>
<table border="1" cellpadding="2" cellspacing="2" style="text-align: left; width: 100%;">
<tbody>
<tr>
<th style="vertical-align: top;">Тип события</th>
<th style="vertical-align: top;">Описание</th>
</tr>
<tr>
<td style="vertical-align: top;">EVT_LIST_COL_BEGIN_DRAG</td>
<td style="vertical-align: top;">Вызывается, когда пользователь
начинает перетаскивать границу колонки</td>
</tr>
<tr>
<td style="vertical-align: top;">EVT_LIST_COL_CLICK</td>
<td style="vertical-align: top;">Вызывается кликом в заголовке
столбца</td>
</tr>
<tr>
<td style="vertical-align: top;">EVT_LIST_COL_RIGHT_CLICK</td>
<td style="vertical-align: top;">Вызывается правым кликом в
заголовке столбца</td>
</tr>
<tr>
<td style="vertical-align: top;">EVT_LIST_COL_END_DRAG</td>
<td style="vertical-align: top;">Вызывается, когда пользователь
заканчивает перетаскивать границу колонки</td>
</tr>
</tbody>
</table>
<div>
Листинг 13.3 покажет обработку некоторых этих событий (кроме того, тут будут использованы некоторые методы, ещё нами не описанные). Обратите внимание на события, вызываемые при помощи меню.<br />
<div style="text-align: center;">
Листинг 13.3 Пример событий и свойств list'a</div>
<br />
<br />
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;">import wx</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;">import sys, glob, random</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;">import data</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;">class DemoFrame(wx.Frame):</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"> def __init__(self):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">wx.Frame.__init__(self, None, -1,</span><span style="font-family: 'Courier New', Courier, monospace;">"Other wx.ListCtrl Stuff",</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">size=(700,500))</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list = None</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.editable = False</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.MakeMenu()</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.MakeListCtrl()</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> # Создаём list</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;">def MakeListCtrl(self, otherflags=0):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">if self.list:</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.Destroy()</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">if self.editable:</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">otherflags |= wx.LC_EDIT_LABELS</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Загружаем изображения в image list</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">il = wx.ImageList(16,16, True)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">for name in glob.glob("smicon??.png"):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">bmp = wx.Bitmap(name, wx.BITMAP_TYPE_PNG)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">il_max = il.Add(bmp)</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list = wx.ListCtrl(self, -1,</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">style=wx.LC_REPORT|otherflags)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.AssignImageList(il, wx.IMAGE_LIST_SMALL)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Добавляем колонки</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">for col, text in enumerate(data.columns):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.InsertColumn(col, text)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Добавляем строки</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">for row, item in </span><span style="font-family: 'Courier New', Courier, monospace;">enumerate(data.rows):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">index = self.list.InsertStringItem(sys.maxint, item[0])</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">for col, text in enumerate(item[1:]):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.SetStringItem(index, col+1, text)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Соединяем со случайным изображением</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">img = random.randint(0, il_max)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.SetItemImage(index, img, img)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Задаём элемент данных</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.SetItemData(index, row)</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Устанавливаем ширину колонок</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.SetColumnWidth(0,</span><span style="font-family: 'Courier New', Courier, monospace;">120)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.SetColumnWidth(1,</span><span style="font-family: 'Courier New', Courier, monospace;">wx.LIST_AUTOSIZE)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.SetColumnWidth(2,</span><span style="font-family: 'Courier New', Courier, monospace;">wx.LIST_AUTOSIZE)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.SetColumnWidth(3,</span><span style="font-family: 'Courier New', Courier, monospace;">wx.LIST_AUTOSIZE_USEHEADER)</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Задаём обработчик событий пользователя</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;">self.Bind(wx.EVT_LIST_ITEM_SELECTED,</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;">self.OnItemSelected,</span><span style="font-family: Courier New, Courier, monospace;">self.list)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.Bind(wx.EVT_LIST_ITEM_DESELECTED,</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.OnItemDeselected,</span><span style="font-family: 'Courier New', Courier, monospace;">self.list)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated,</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.SendSizeEvent()</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Создаём меню</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">def MakeMenu(self):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">mbar = wx.MenuBar()</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">menu = wx.Menu()</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">item = menu.Append(-1, "E&xit\tAlt-X")</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.Bind(wx.EVT_MENU, self.OnExit, item)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">mbar.Append(menu, "&File")</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">menu = wx.Menu()</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">item = menu.Append(-1,</span><span style="font-family: 'Courier New', Courier, monospace;"> "Sort ascending")</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.Bind(wx.EVT_MENU,</span><span style="font-family: 'Courier New', Courier, monospace;"> self.OnSortAscending, item)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">item = menu.Append(-1,</span><span style="font-family: 'Courier New', Courier, monospace;"> "Sort descending")</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.Bind(wx.EVT_MENU,</span><span style="font-family: 'Courier New', Courier, monospace;"> self.OnSortDescending, item)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">item = menu.Append(-1,</span><span style="font-family: 'Courier New', Courier, monospace;"> "Sort by submitter")</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.Bind(wx.EVT_MENU,</span><span style="font-family: 'Courier New', Courier, monospace;"> self.OnSortBySubmitter, item)</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">menu.AppendSeparator()</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">item = menu.Append(-1,</span><span style="font-family: 'Courier New', Courier, monospace;"> "Show selected")</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.Bind(wx.EVT_MENU,</span><span style="font-family: 'Courier New', Courier, monospace;"> self.OnShowSelected, item)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">item = menu.Append(-1,</span><span style="font-family: 'Courier New', Courier, monospace;"> "Select all")</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.Bind(wx.EVT_MENU,</span><span style="font-family: 'Courier New', Courier, monospace;"> self.OnSelectAll, item)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">item = menu.Append(-1,</span><span style="font-family: 'Courier New', Courier, monospace;"> "Select none")</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.Bind(wx.EVT_MENU,</span><span style="font-family: 'Courier New', Courier, monospace;"> self.OnSelectNone, item)</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">menu.AppendSeparator()</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">item = menu.Append(-1,</span><span style="font-family: 'Courier New', Courier, monospace;"> "Set item text colour")</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.Bind(wx.EVT_MENU,</span><span style="font-family: 'Courier New', Courier, monospace;"> self.OnSetTextColour, item)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">item = menu.Append(-1,</span><span style="font-family: 'Courier New', Courier, monospace;"> "Set item background colour")</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.Bind(wx.EVT_MENU,</span><span style="font-family: 'Courier New', Courier, monospace;"> self.OnSetBGColour, item)</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">menu.AppendSeparator()</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">item = menu.Append(-1, "Enable item editing",</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">kind=wx.ITEM_CHECK)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.Bind(wx.EVT_MENU, self.OnEnableEditing, item)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">item = menu.Append(-1, "Edit current item")</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.Bind(wx.EVT_MENU, self.OnEditItem, item)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">mbar.Append(menu, "&Demo")</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.SetMenuBar(mbar)</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;">def OnExit(self, evt):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.Close()</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Обработчик выбора элемента</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;">def OnItemSelected(self, evt):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">item = evt.GetItem()</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">print "Item selected:", item.GetText()</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Обработчик снятия выбора элемента</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;">def OnItemDeselected(self, evt):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">item = evt.GetItem()</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">print "Item deselected:", item.GetText()</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Обработчик активирования элемента</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;">def OnItemActivated(self, evt):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">item = evt.GetItem()</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">print "Item activated:", item.GetText()</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Перестраиваем list, задав стиль сортировки</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;">def OnSortAscending(self, evt):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.MakeListCtrl(wx.LC_SORT_ASCENDING)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;">def OnSortDescending(self, evt):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.MakeListCtrl(wx.LC_SORT_DESCENDING)</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> # Сортируем при помощи вложенной функции</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;">def OnSortBySubmitter(self, evt):</span><span style="font-family: Courier New, Courier, monospace;"> </span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">def compare_func(row1, row2):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"># сравниваем значения 4 столбца данных</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">val1 = data.rows[row1][3]</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">val2 = data.rows[row2][3]</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">if val1 < val2: return -1</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">if val1 > val2: return 1</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">return 0</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.SortItems(compare_func)</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Показываем выбранный элемента</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;">def OnShowSelected(self, evt):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">print "These items are selected:"</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">index = self.list.GetFirstSelected()</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">if index == -1:</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">print "\tNone"</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">return</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">while index != -1:</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">item = self.list.GetItem(index)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">print "\t%s" % item.GetText()</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">index = self.list.GetNextSelected(index)</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Выбираем все элементы</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;">def OnSelectAll(self, evt):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">for index in range(self.list.GetItemCount()):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.Select(index, True)</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Отменяем выбор элемента</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;">def OnSelectNone(self, evt):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">index = self.list.GetFirstSelected()</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">while index != -1:</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.Select(index, False)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">index = self.list.GetNextSelected(index)</span></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;">def OnSetTextColour(self, evt):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">dlg = wx.ColourDialog(self)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Изменяем цвет текста</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">if dlg.ShowModal() == wx.ID_OK:</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">colour = dlg.GetColourData().GetColour()</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">index = self.list.GetFirstSelected()</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">while index != -1:</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.SetItemTextColour(index, colour)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">index = self.list.GetNextSelected(index)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">dlg.Destroy()</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Изменяем цвет фона</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;">def OnSetBGColour(self, evt):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">dlg = wx.ColourDialog(self)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">if dlg.ShowModal() == wx.ID_OK:</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">colour = dlg.GetColourData().GetColour()</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">index = self.list.GetFirstSelected()</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">while index != -1:</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.SetItemBackgroundColour(index, colour)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">index = self.list.GetNextSelected(index)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">dlg.Destroy()</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Включаем редактирование</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;">def OnEnableEditing(self, evt):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.editable = evt.IsChecked()</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.MakeListCtrl()</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Редактируем выделенный элемент</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;">def OnEditItem(self, evt):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">index = self.list.GetFirstSelected()</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">if index != -1:</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.EditLabel(index)</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;">class DemoApp(wx.App):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;">def OnInit(self):</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">frame = DemoFrame()</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.SetTopWindow(frame)</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">print "Program output appears here..."</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">frame.Show()</span></div>
<div style="text-align: left;">
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">return True</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;">app = DemoApp(redirect=True)</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;">app.MainLoop()</span></div>
<div style="text-align: left;">
<br /></div>
<br />
<br /></div>
<div>
После того, как Вы запустите этот код, Вы увидите демонстрацию возможностей элемента list, включая те, что мы ещё не обсуждали.</div>
<h2>
13.4 Редактирование и сортировка list'a</h2>
<div>
В этом разделе мы обсудим редактирование, сортировку и поиск элементов в list'e.</div>
<h4>
13.4.1 Как я могу редактировать надпись?</h4>
<div>
Редактирование элементов в list'e не составляет проблемы, за исключением режима "отчёт", где пользователь может редактировать только первую колонку каждого столбца. Для остальных режимов никакой проблемы нет - можно спокойно редактировать надпись каждого элемента.</div>
<div>
Для того, чтобы сделать list редактируемым, добавьте флаг wx.LC_EDIT_LABELS в конструктор экземпляра.</div>
<div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;">list = wx.ListCtrl(self, -1, style = wx.LC_REPORT | wx.LC_EDIT_LABELS)</span></div>
</div>
<div>
Если флаг редактирования установлен, то пользователь может начать редактирование нажав на уже выделенный элемент (это не должен быть двойной клик). Редактирование похоже на переименование в Windwos Explorer. Пользователю даётся небольшое поле для редактирования надписи там, где она до этого находилась. Нажатие Enter завершает редактирование и текст становится новой надписью. Клик мышкой где-либо вне пределов окна редактирования тоже завершает редактирование. Одновременно не может быть больше одной сессии редактирования. Нажатие Escape тоже завершает редактирование, но все изменения отменяются.</div>
<div>
Следующие два события возникают во время сессии редактирования:</div>
<div>
<ul>
<li>EVT_LIST_BEGIN_LABEL_EDIT</li>
<li>EVT_LIST_END_LABEL_EDIT</li>
</ul>
<div>
Помните, что если Вы хотите нормально передать событие дальше после вашего собственного обработчика, Вам надо включить в обработчик вызов метода Skip(). Событие типа EVT_LIST_BEGIN_LABEL_EDIT возникает в начале сессии редактирования, а EVT_LIST_END_LABEL_EDIT в конце сессии (не важно, как именно она завершается). Вы можете заветировать событие начала редактирования, в таком случае сессия редактирования даже не начнётся. Ветирование события конца редактирования поможет защитить текст list'a от изменения.</div>
</div>
<div>
Класс wx.ListEvent имеет несколько свойств, интересных только при обработке события EVT_LIST_END_LABEL_EDIT. Метод GetLabel() возвращает новый текст элемента листа, после того, как его редактирование было завершено и подтверждено. Если редактирование было завершено нажатием escape, то метод возвращает пустую строку. Таким образом, Вы не можете использовать GetLabel(), чтобы отличить отмену редактирования от сознательного изменения текста элемента на пустую строку. Если это нужно узнать, то метод IsEditCancelled() возвращает True, если редактирование было отменено, и False в противном случае.<br />
Если Вы хотите чтобы другие пользовательские события начинали сессию редактирования элемента, используйте метод EditLabel(item), где item - индекс элемента листа, который нужно отредактировать. Этот метод вызывает событие EVT_LIST_BEGIN_LABEL_EDIT и сессия редактирования продолжается, как если бы она была начата непосредственно пользователем.<br />
Если Вы хотите напрямую манипулировать элементом текста, который используется для редактирования, то Вы можете получить его при помощи метода list'a GetEditControl(). Этот метод возвращает элемент text, который используется для текущего редактирования. Если сейчас ничего не редактируется, то метод вернёт None. На данный момент метод работает только под Windows.<br />
<h4>
13.4.2 Как я могу отсортировать мой list?</h4>
</div>
<div>
Есть три способа отсортировать list в wxPython, которые мы обсудим в этом разделе, расположив по возрастанию сложности.</div>
<h4>
Сортировка list'a при создании</h4>
<div>
Самый простой способ отсортировать list - сообщить о необходимости сортировки конструктору при создании. Это можно сделать при помощи флагов стиля wx.LC_SORT_ASCENDING или wx.LC_SORT_DESCENDING. Этот флаг сортирует list при первоначальном отображении и, на MS Windows, ghb каждом добавлении элемента. Сортировка основана на тексте для каждого элемента и является простым сравнением строк. Если list отображается в режиме "отчёт", сортировка происходит на основании колонки 0 (самой левой) каждой строки.</div>
<h4>
Сортировка на основании данных, отличных от отображаемого текста</h4>
<div>
Случается, что Вы хотите отсортировать свой list не на основании отображаемого элементами текста, а на основании чего-то другого. Это можно сделать в wxPython, но это потребует от Вас некоторых усилий. Во-первых, Вам нужно задать данные для каждого элемента list'a при помощи метода SetItemData(item, data). item - индекс элемента в не отсортированном list'e, а data - данные, которые Вы хотите ассоциировать с этим элементом. data должно быть либо числом, либо long (в соответствии с C++ типами данных), что ограничивает полезность этого механизма. Для того, чтобы получить значение данных для строки, используйте метод GetItemData(item).</div>
<div>
После того, как всем элементам присвоены данные, Вы можете использовать метод SortItems(func), чтобы отсортировать элемента. Аргументом является вызываемый объект, принимающий два целых числа. Функция вызывается с данными двух элементов, которые надо сравнить - ссылки на сами элементы не передаются. Функция должна вернуть положительное число, если первый элемент больше второго (т.е. должен быть раньше в отсортированном list'e), отрицательное, если первый элемент меньше второго (т.е. должен быть позже второго) и ноль, если оба элемента равны. Хотя самый простой способ сделать это - просто сравнить два числа, это не единственное, что Вы можете сделать. Например, данные элемента могут служить ключом к внешнему словарю или списку, который содержит уже более сложные данные, которые и надо сравнить для вычисления порядка сортировки.</div>
<h4>
Сортировка колонок с <a href="http://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%81%D1%8C_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)" target="_blank">примесью</a></h4>
<div>
Самый частый случай сортировки list'a - позволить пользователю отсортировать list в режиме "отчёт" по любому столбцу, кликнув на него. Вы можете сделать это при помощи механизма SortItems(), но в таком случае будет сложновато отследить колонки. К счастью примесь wxPython, называемая ColumnSorterMixin, управляет информацией за Вас; живёт от в wx.lib.mixins.listctrl. На рисунке 13.5 показана сортировка столбцов при помощи примеси.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEissHus2qIuZZ3vhjEbbwb3F1-mTyKQI14Nxm_fwTVNL1ImwGL7Bys-J6GQSb7aFitvY6BS5TXtywioZfQCsAu8bCUJ87L4rUsYMKawXsndaXiMRRlvmjQ6BQTbvXT-4wtRBEgEXa7wesk/s1600/13-5.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEissHus2qIuZZ3vhjEbbwb3F1-mTyKQI14Nxm_fwTVNL1ImwGL7Bys-J6GQSb7aFitvY6BS5TXtywioZfQCsAu8bCUJ87L4rUsYMKawXsndaXiMRRlvmjQ6BQTbvXT-4wtRBEgEXa7wesk/s1600/13-5.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Рисунок 13.5 Сортировка при помощи примеси - обратите внимание на стрелочку в заголовке колонки, обозначающую направление сортировки</td></tr>
</tbody></table>
<br /></div>
<div>
Примесь объявляется так же как и любое множественное наследование:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">import wx.lib.mixins.listctrl as listmix</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">class ListCtrlPanel(wx.Panel, listmix.ColumnSorterMixin):</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> def __init__ (self, parent, log):</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS)</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> self.list = TestListCtrl(self, tID)</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> self.itemDataMap = musicdata</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> listmix.ColumnSorterMixin.__init__(self, 3)</span></div>
<div>
<br /></div>
<div>
Обратите внимание, что примесь не расширяет сам list, хотя она может использоваться и для этого, но скорее всего Вы создадите с ней свою панель. Панель получает код для управления сортировкой и связывает с ним событие клика мышью на заголовке колонки. Листинг 13.4 отображает пример такой сортировки.<br />
<div style="text-align: center;">
Листинг 13.4 list в режиме "отчёт" с сортировкой при помощи примеси</div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: left;">
</div>
<span style="font-family: Courier New, Courier, monospace;">import </span><span style="font-family: 'Courier New', Courier, monospace;">wx</span><br />
<span style="font-family: Courier New, Courier, monospace;">import</span><span style="font-family: 'Courier New', Courier, monospace;"> wx.lib.mixins.listctrl</span><br />
<span style="font-family: Courier New, Courier, monospace;">import</span><span style="font-family: 'Courier New', Courier, monospace;"> sys, glob, random</span><br />
<span style="font-family: Courier New, Courier, monospace;">import</span><span style="font-family: 'Courier New', Courier, monospace;"> data</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"># Наследуем из примеси</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">class DemoFrame(wx.Frame, wx.lib.mixins.listctrl.ColumnSorterMixin):</span><br />
<span style="font-family: Courier New, Courier, monospace;"> def __init__(self):</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">wx.Frame.__init__(self, None, -1,</span><span style="font-family: 'Courier New', Courier, monospace;">"wx.ListCtrl with</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">ColumnSorterMixin", </span><span style="font-family: 'Courier New', Courier, monospace;">size=(600,400))</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"><br /></span>
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;">il = wx.ImageList(16,16, True)</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;">for name in glob.glob("smicon??.png"):</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">bmp = wx.Bitmap(name, wx.BITMAP_TYPE_PNG)</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">il_max = il.Add(bmp)</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"># Добавляем стрелочки в image list</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;">self.up = il.AddWithColourMask(</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">wx.Bitmap("sm_up.bmp", wx.BITMAP_TYPE_BMP), "blue")</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;">self.dn = il.AddWithColourMask(</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">wx.Bitmap("sm_down.bmp", wx.BITMAP_TYPE_BMP), "blue")</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list = wx.ListCtrl(self, -1, style=wx.LC_REPORT)</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.AssignImageList(il, wx.IMAGE_LIST_SMALL) </span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">for col, text in enumerate(data.columns):</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.InsertColumn(col, text)</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Создаём карту данных</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.itemDataMap = {}</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">for item in data.rows:</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">index = self.list.InsertStringItem(sys.maxint, item[0])</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">for col, text in enumerate(item[1:]):</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.SetStringItem(index, col+1, text)</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Ассоциируем данные с картой</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.SetItemData(index, index)</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.itemDataMap[index] = item</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">img = random.randint(0, il_max)</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.SetItemImage(index, img, img)</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.SetColumnWidth(0,</span><span style="font-family: 'Courier New', Courier, monospace;">120)</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.SetColumnWidth(1,</span><span style="font-family: 'Courier New', Courier, monospace;">wx.LIST_AUTOSIZE)</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.SetColumnWidth(2,</span><span style="font-family: 'Courier New', Courier, monospace;">wx.LIST_AUTOSIZE)</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">self.list.SetColumnWidth(3,</span><span style="font-family: 'Courier New', Courier, monospace;">wx.LIST_AUTOSIZE_USEHEADER)</span><br />
<br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> # Инициализируем сортировки колонки</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">wx.lib.mixins.listctrl.ColumnSorterMixin.__init__(self,</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">len(data.columns))</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">def GetListCtrl(self):</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">return self.list</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;">def GetSortImages(self):</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">return (self.dn, self.up)</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">app = wx.PySimpleApp()</span><br />
<span style="font-family: Courier New, Courier, monospace;">frame = DemoFrame()</span><br />
<span style="font-family: Courier New, Courier, monospace;">frame.Show()</span><br />
<span style="font-family: Courier New, Courier, monospace;">app.MainLoop()</span></div>
<div>
<br /></div>
<div>
Для того, чтобы примесь заработала, Вы должны сделать следующее в вашем классе панели:</div>
<div>
<ol>
<li>Класс, который расширяется ColumnSorterMixin, должен иметь метод GetListCtrl(), который возвращает list, который и нужно отсортировать. Этот метод используется примесью чтобы получить ссылку на list.</li>
<li>В методе __init__() расширяемого класса Вы должны создать list, на который будет ссылаться GetListCtrl() <i>до</i> того, как Вы вызовите метод __init__() ColumnSorterMixin. Метод __init__() примеси принимает один аргумент - количество колонок в list'e.</li>
<li>Вы должны использовать SetListData() для того, чтобы присвоить уникальные данные для каждой строки list'a. Это может быть (и скорее всего будет) индекс, или более сложная структура.</li>
<li>Расширяемый класс должен иметь атрибут itemDataMap. Этот атрибут должен быть словарём. Ключами этого словаря являются данные, установленные SetListData(). Значениями словаря должны быть кортежи значений, которые Вы хотите использовать для каждой колонки. (Скорее всего это будет просто текст каждой колонки). Другими словами, itemDataMap представляет данные list'a в форме, удобной для сортировки.</li>
</ol>
<div>
Обычно при применении ColumnSorterMixin Вы либо создаёте itemDataMap при добавлении элементов в ваш list, либо Вы сперва создаёте itemDataMap, а затем используете его для построения самого list'a.</div>
</div>
<div>
Хотя этот метод может быть сложен в использовании, ColumnSorterMixin - хороший выбор для большинства случаев сортировки.</div>
<h3>
13.4.3 Как я могу узнать больше о list'e?</h3>
<div>
Иногда Вам требуется определить какой элемент выбран в list'e из какого-то другого места вашей программы, или Вам требуется изменить элемент, выбранный на данный момент в ответ на действия пользователя, или на что-то, произошедшее в вашей программе.</div>
<div>
Есть несколько методов для поиска индекса элемента в list'e, предоставляющих и другую информацию об элементе, как это описано в таблице 13.7</div>
<table border="1" cellpadding="2" cellspacing="2" style="text-align: left; width: 100%;">
<tbody>
<tr>
<th style="vertical-align: top;">Метод</th>
<th style="vertical-align: top;">Описание</th>
</tr>
<tr>
<td style="vertical-align: top;">FindItem(start, str,
partial=False)</td>
<td style="vertical-align: top;">Находит первый элемент list'a,
чья метка соответствует str. Если start = -1, nj поиск начинается с
начала, иначе - с индекса start. Если partial = True, тогда достаточно,
чтобы начало метки элемента совпадало с указанной строкой, а не вся
метка.</td>
</tr>
<tr>
<td style="vertical-align: top;">FindItemAtPos(start, point,
direction)</td>
<td style="vertical-align: top;">Находит первый элемент рядом с
point, экземляром wx.Point, указывающим положение относительно верхнего
левого угла list'a. Параметр direction указывает wxPython в каком
направлении двигаться от point в поисках элемента. Возможные значения -
wx.LIST_FIND_LEFT, wx.LIST_FIND_RIGHT, wx.LIST_FIND_UP.</td>
</tr>
<tr>
<td style="vertical-align: top;">FindItemData(start, data)</td>
<td style="vertical-align: top;">Ищет элемент с указанными
данными data (данные задаются при помощи SetItemData()). Параметр start
идентичен аналогу из метода FindItem.</td>
</tr>
<tr>
<td style="vertical-align: top;">HitTest(point)</td>
<td style="vertical-align: top;">Возвращает кортеж в форме
(index, flags). index - индекс элемента в этой точке или -1, если
такого элемента нет. Параметр flags содержит информацию о точке и
элементе. Это битовая маска, чьи значения приведены в таблице 13.8</td>
</tr>
</tbody>
</table>
<div>
Таблица 13.8 содержит возможные компоненты возвращаемого значения flags HitTest(). Если это применимо, то может быть возвращено более одного флага.</div>
<table border="1" cellpadding="2" cellspacing="2" style="text-align: left; width: 100%;">
<tbody>
<tr>
<th style="vertical-align: top;">Флаг</th>
<th style="vertical-align: top;">Описание</th>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_HITTEST_ABOVE</td>
<td style="vertical-align: top;">Точка находится выше клиентской
зоны list'a</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_HITTEST_BELOW</td>
<td style="vertical-align: top;">Точка находится ниже клиентской
зоны list'a</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_HITTEST_NOWHERE</td>
<td style="vertical-align: top;">Точка находится в клиентской
зоне list'a, но не является частью какого-либо элемента. Обычно причина
в том, что точка находится после всех элементов</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_HITTEST_ONITEM</td>
<td style="vertical-align: top;">Точка находится где-то в
границах элемента с индексом index</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_HITTEST_ONITEMICON</td>
<td style="vertical-align: top;">Точка находится на иконке
элемента с индексом index</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_HITTEST_ONITEMLABEL</td>
<td style="vertical-align: top;">Точка находится на метке
элемента с индексом index</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_HITTEST_ONITEMRIGHT</td>
<td style="vertical-align: top;">Точка находится в пустой области
справа от элемента с индексом index</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_HITTEST_ONITEMSTATEICON</td>
<td style="vertical-align: top;">Точка находится на иконке
состояния элемента. Это подразумевает, что list находится в режиме
"дерева" (??? tree mode ???) и есть определённое пользователем
состояние.</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_HITTEST_TOLEFT</td>
<td style="vertical-align: top;">Точка находится левее клиентской
зоны list'a</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_HITTEST_TORIGHT</td>
<td style="vertical-align: top;">Точка находится правее
клиентской зоны list'a</td>
</tr>
</tbody>
</table>
<div>
Чтобы двигаться в другом направлении у нас есть несколько методов, которые предоставляют информацию об элементе по имеющемуся индексу. Методы GetItem() и GetItemText() были рассмотрены раньше. Остальные методы перечислены в таблице 13.9</div>
<table border="1" cellpadding="2" cellspacing="2" style="text-align: left; width: 100%;">
<tbody>
<tr>
<th style="vertical-align: top;">Метод</th>
<th style="vertical-align: top;">Описание</th>
</tr>
<tr>
<td style="vertical-align: top;">GetItemPosition(item)</td>
<td style="vertical-align: top;">Возвращает позицию элемента в
качестве wx.Point. Интересно только в режимах "иконка" или "маленькая
иконка". Возвращается точка верхнего левого угла элемента.</td>
</tr>
<tr>
<td style="vertical-align: top;">GetItemRect(item,
code=wx.LIST_RECT_BOUNDS)</td>
<td style="vertical-align: top;">Возвращает wx.Rect, очерчивающий
прямоугольник вокруг элемента с индексом item. Параметр code
опциональный. Значение по умолчанию - wx.LIST_RECT_BOUDS, в результате
чего возвращается прямоугольник, очерчивающий границы элемента. Другим
значением может быть wx.LIST_RECT_ICON, в результате чего вернётся
прямоугольник, очерчивающий только иконку, или wx.LIST_RECT_LABEL, где
прямоугольник будет очерчивать только метку.</td>
</tr>
<tr>
<td style="vertical-align: top;">GetNextItem(item,
geometry=wx.LIST_ALL, state=wx.LIST_STATE_DONTCARE)</td>
<td style="vertical-align: top;">Возвращает следующий элемент в
list'e после указанного индекса item, на основе параметров geometry и
state. Значения этих параметров перечислены в следующих таблицах.</td>
</tr>
<tr>
<td style="vertical-align: top;">SetItemPosition(item, pos)</td>
<td style="vertical-align: top;">Перемещает элемент с индексом
item в позицию wx.Point из параметра pos. Имеет смысл только для
режимов "иконка" и "маленькая иконка"</td>
</tr>
</tbody>
</table>
<div>
Таблица 13.10 содержит значения параметра geometry метода GetNextItem(). Параметр geometry используется только под MS Windows.</div>
<table border="1" cellpadding="2" cellspacing="2" style="text-align: left; width: 100%;">
<tbody>
<tr>
<th style="vertical-align: top;">Значение</th>
<th style="vertical-align: top;">Описание</th>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_NEXT_ABOVE</td>
<td style="vertical-align: top;">Найти элемент с указанным
статусом, который отображается выше, чем стартовый элемент.</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_NEXT_ALL</td>
<td style="vertical-align: top;">Найти элемент с указанным
статусом, следующий за стартовым индексом по порядку.</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_NEXT_BELOW</td>
<td style="vertical-align: top;">Найти элемент с указанным
статусом, который отображается ниже, чем стартовый элемент.</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_NEXT_LEFT</td>
<td style="vertical-align: top;">Найти элемент с указанным
статусом, который отображается левее, чем стартовый элемент.</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_NEXT_RIGHT</td>
<td style="vertical-align: top;">Найти элемент с указанным
статусом, который отображается правее, чем стартовый элемент.</td>
</tr>
</tbody>
</table>
<div>
Таблица 13.11 содержит возможные значения параметра state метода GetNextItem()</div>
<table border="1" cellpadding="2" cellspacing="2" style="text-align: left; width: 100%;">
<tbody>
<tr>
<th style="vertical-align: top;">Значение</th>
<th style="vertical-align: top;">Описание</th>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_STATE_CUT</td>
<td style="vertical-align: top;">Искать только среди тех
элементов, которые "вырезаны"</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_STATE_DONTCARE</td>
<td style="vertical-align: top;">Искать среди всех элементов, вне
зависимости от их состояния</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_STATE_DROPHILITED</td>
<td style="vertical-align: top;">Искать только среди тех
элементов, которые являются целью для "перетаскивания"</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_STATE_FOCUSED</td>
<td style="vertical-align: top;">Искать только среди элементов, у
которых есть фокус</td>
</tr>
<tr>
<td style="vertical-align: top;">wx.LIST_STATE_SELECED</td>
<td style="vertical-align: top;">Искать только среди выбранных
элементов</td>
</tr>
</tbody>
</table>
<div>
Таблица 13.12 содержит методы, используемые для изменения цвета и шрифта текста, отображаемого на элементе</div>
<table border="1" cellpadding="2" cellspacing="2" style="text-align: left; width: 100%;">
<tbody>
<tr>
<th style="vertical-align: top;">Методы</th>
<th style="vertical-align: top;">Описание</th>
</tr>
<tr>
<td style="vertical-align: top;">GetBackgroundColour()<br />
SetBackgroundColour(col)</td>
<td style="vertical-align: top;">Работает с фоновым цветом всего
list'a. Параметр col - wx.Colour или строка с названием цвета</td>
</tr>
<tr>
<td style="vertical-align: top;">GetItemBackgroundColour(item)<br />
SetItemBackgroundColour(item,col)</td>
<td style="vertical-align: top;">Работает с фоновым цветом
элемента с индексом item. Эти методы можно использовать только в режиме
"отчёт"</td>
</tr>
<tr>
<td style="vertical-align: top;">GetItemTextColour(item)<br />
SetItemColour(item,col)</td>
<td style="vertical-align: top;">Работает с цветом текста
элемента с индексом item. Эти методы можно использовать только в режиме
"отчёт"</td>
</tr>
<tr>
<td style="vertical-align: top;">GetTextColour()<br />
SetTextColour(col)</td>
<td style="vertical-align: top;">Работает с цветом текста всего
list'a.</td>
</tr>
</tbody>
</table>
<div>
Таблица 13.13 содержит оставшиеся методы, не попавшие ни в одну из предыдущих групп, но тоже очень полезные</div>
<table border="1" cellpadding="2" cellspacing="2" style="text-align: left; width: 100%;">
<tbody>
<tr>
<th style="vertical-align: top;">Методы</th>
<th style="vertical-align: top;">Описание</th>
</tr>
<tr>
<td style="vertical-align: top;">GetItemSpacing()</td>
<td style="vertical-align: top;">Возвращает wx.Size элемента с
пространством между элементами в пикселях</td>
</tr>
<tr>
<td style="vertical-align: top;">GetSelectedItemCount()</td>
<td style="vertical-align: top;">Возвращает число элементов в
list'e, которые на данный момент выбраны</td>
</tr>
<tr>
<td style="vertical-align: top;">GetTopItem()</td>
<td style="vertical-align: top;">Возвращает индекс элемента в
верху видимой части. Полезно только для режимов "список" и "отчёт"</td>
</tr>
<tr>
<td style="vertical-align: top;">GetViewRect()</td>
<td style="vertical-align: top;">Возвращает wx.Rect,
соответствующий минимальному прямоугольнику, который нужен для того,
чтобы вместить все элементы без прокручивания. Полезно только для
режимов "иконка" и "маленькая иконка"</td>
</tr>
<tr>
<td style="vertical-align: top;">ScrollList(dx,dy)</td>
<td style="vertical-align: top;">Прокручивает list. Параметр dy -
изменение вертикальной координаты в пикселях. dx - горизонтальной. Для
режимов "иконка", "маленькая иконка" и "отчёт" размер даётся в пикселях.
Для "списка" - в колонках отображаемых элементов.</td>
</tr>
</tbody>
</table>
<div>
Эти таблицы раскрывают большую часть функциональности list'a. Однако, все list'ы, которые мы видели до сих пор, имеют одно ограничение - данные всех элементов должны находиться в памяти. В следующем разделе мы обсудим способ, который позволяет обойтись только теми данными, которые нужны для отображения элемента.</div>
<h2>
13.5 Создание виртуального list'a</h2>
<div>
Давайте предположим, что ваше wxPython приложение должно отобразить список всех ваших клиентов. Сперва Вы использовали обычный list и всё было хорошо. Время идёт, и ваше использование wxPython делает Вас всё больше и больше успешным. Ваш список клиентов становится всё больше и больше. Очень много клиентов - и у вашего приложения начинаются проблемы. Скорее всего оно будет тратить много времени на запуск. Возможно оно начинает потреблять всё больше и больше памяти. Что Вы можете сделать? Вы можете создать виртуальный list.</div>
<div>
Описанная проблема - результат того, каким образом управляется list. Обычно данные копируются в list оттуда, где они генерируются. Это потенциальная трата ресурсов и, хотя для небольших list'ов разница может быть незаметна, для больших листов это может сэкономить большое количество памяти и существенно сократить время загрузки.<br />
Для того, чтобы сократить затраты памяти и ускорить загрузку list'a, wxPython позволяет объявить <i>виртуальный</i> list, что подразумевает, что информация для каждого элемента создаётся при необходимости отобразить этот элемент. Соответственно нам не нужно хранить каждый элемент в памяти и мы не объявляем весь list при запуске. C другой стороны, поиск элементов в таком list'e может быть медленнее, чем в обычном. На рисунке 13.6 Вы можете видеть пример такого list'a. Код этого примера приведён в листинге 13.5.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrDuyiUfM2i7INmynKnROMn1I05kui29H8p4i163aoaD8agMaQNcxN1T_5fsZLhiMZXvBjdtAqmT7IIOqqKUHWa1-e7UlFkof1vrs9dH6k2oWhZi9ZOurg835vg0UOdCWOqWrExm70IMY/s1600/13-6.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrDuyiUfM2i7INmynKnROMn1I05kui29H8p4i163aoaD8agMaQNcxN1T_5fsZLhiMZXvBjdtAqmT7IIOqqKUHWa1-e7UlFkof1vrs9dH6k2oWhZi9ZOurg835vg0UOdCWOqWrExm70IMY/s1600/13-6.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Рисунок 13.6 Виртуальный list</td></tr>
</tbody></table>
<div style="text-align: center;">
Листинг 13.5 Виртуальный list</div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: left;">
</div>
<span style="font-family: Courier New, Courier, monospace;">import wx</span><br />
<span style="font-family: Courier New, Courier, monospace;">import sys, glob, random</span><br />
<span style="font-family: Courier New, Courier, monospace;">import data</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"># Источник данных</span><br />
<span style="font-family: Courier New, Courier, monospace;">class DataSource:</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">def GetColumnHeaders(self):</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">return data.columns</span><br />
<span style="font-family: Courier New, Courier, monospace;">defGetCount(self):</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">return len(data.rows)</span><br />
<span style="font-family: Courier New, Courier, monospace;">def GetItem(self, index):</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">return data.rows[index]</span><br />
<span style="font-family: Courier New, Courier, monospace;">def UpdateCache(self, start, end):</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">pass</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace;"># Объявляем виртуальный list</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">class VirtualListCtrl(wx.ListCtrl):</span><br />
<span style="font-family: Courier New, Courier, monospace;">def __init__(self, parent, dataSource):</span><br />
# Создаём list c флагом виртуальности<br />
<span style="font-family: 'Courier New', Courier, monospace;">wx.ListCtrl.__init__(self, parent,</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">style=wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_VIRTUAL)</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">self.dataSource = dataSource</span><br />
<span style="font-family: Courier New, Courier, monospace;">self.Bind(wx.EVT_LIST_CACHE_HINT, self.DoCacheItems)</span><br />
# Задаём размер list'a<br />
<span style="font-family: 'Courier New', Courier, monospace;">self.SetItemCount(dataSource.GetCount())</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">columns = dataSource.GetColumnHeaders()</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">for col, text in enumerate(columns):</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">self.InsertColumn(col, text)</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">def DoCacheItems(self, evt):</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">self.dataSource.UpdateCache(</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">evt.GetCacheFrom(), evt.GetCacheTo())</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
# Получаем текст по запросу<br />
<span style="font-family: Courier New, Courier, monospace;">def OnGetItemText(self, item, col):</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">data = self.dataSource.GetItem(item)</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">return data[col]</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">def OnGetItemAttr(self, item): return None</span><br />
<span style="font-family: Courier New, Courier, monospace;">def OnGetItemImage(self, item): return -1</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">class DemoFrame(wx.Frame):</span><br />
<span style="font-family: Courier New, Courier, monospace;">def __init__(self):</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">wx.Frame.__init__(self, None, -1,</span><span style="font-family: 'Courier New', Courier, monospace;">"Virtual wx.ListCtrl",</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">size=(600,400))</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">self.list = VirtualListCtrl(self, DataSource())</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">app = wx.PySimpleApp()</span><br />
<span style="font-family: Courier New, Courier, monospace;">frame = DemoFrame()</span><br />
<span style="font-family: Courier New, Courier, monospace;">frame.Show()</span><br />
<span style="font-family: Courier New, Courier, monospace;">app.MainLoop()</span><br />
<br />
<br />
Класс источника данных - простой пример, который хранит наши элементы. Настоящий класс источника данных может получать данные из БД или делать ещё что-то, но главное он должен предоставлять тот же интерфейс, что и наш простой пример.<br />
Для того чтобы создать виртуальный list, сперва мы передаём флаг wx.LC_VIRTUAL при создании обычного list'a. Обычно Вы будете создавать list в качестве подкласса wx.ListCtrl, а не просто используя конструктор. Причина в том, что Вам потребуется переопределить некоторые методы wx.ListCtrl для заполнения виртуального list'a. Это будет выглядеть как-то так:<br />
<br />
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;">class MyVirtualList (wx.ListCtrl):</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"> def __init__(self, parent):</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"> wx.ListCtrl.__init__(self, parent, -1, style=wx.LC_REPORT | wx.LC_VIRTUAL)</span></div>
<br />
Виртуальный list должен также иногда вызывать метод SetItemCount() в процессе своей инициализации. Таким образом он узнаёт сколько данные содержится в источнике данных, устанавливает соответствующий лимит и настраивает полосы прокрутки. Вы можете снова вызвать SetItemCount() если количество элементов в источнике данных изменяется. Любой метод On, который Вы переопределяете должен быть способным обработать любое значение между 0 и SetItemCount()-1.<br />
Ваш виртуальный list может переопределить три метода родительского класса для того, чтобы определить что будет отображаться. Самый важный метод - OnGetItemText(item, col). item и col - строка и столбец ячейки, которая будет отображена, возвращаться должна строка, которая будет отображаться в этой ячейке. Например, этот метод просто отображает координаты ячейки:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">def OnGetItemText(self, item, col):</span><br />
<span style="font-family: Courier New, Courier, monospace;"> return "Item %d, column %d" % (item, col)</span><br />
<br />
Если Вы хотите отобразить изображение, Вы должны переопределить метод OnGetItemImage(item), который должен вернуть индекс изображения в связанном image list. Если Вы не переопределяете этот метод, базовый класс вернёт -1, что означает, что никакого изображения не будет показано. Если Вы хотите изменить какой-то из атрибутов отображения строки, тогда Вы должны переопределить метод OnGetItemAttr(item), который так же принимает индекс строки и возвращает экземпляр класса wx.ListItemAttr. У этого класса есть несколько устанавливающих и получающих методов, которые могут быть использованы для настройки цвета, выравнивания или других свойств строки.<br />
Если данные, на которых основывается ваш виртуальный list, меняются и Вы хотите обновить их отображение, Вы можете использовать метод RefreshItem(item), который принудительно перерисовывает указанную строку. Метод RefreshItems(itemFrom, itemTo) перерисовывает элементы между двумя индексами.<br />
Чтобы помочь оптимизировать получение данных в вашем источнике данных, виртуальный list может посылает EVT_LIST_CACHE_HINT когда он хочет отобразить новую страницу данных. Это даёт вашему источнику данных возможность получить несколько записей из вашей БД (или откуда-бы то ни было) и сохранить их. Последующий вызов OnGetItemText() для этих элементов будет работать быстрее, чем если бы ему надо было получать данные для каждого элемента по отдельности.<br />
<h2>
13.6 Итоги</h2>
<br />
<ul>
<li>list в wxPython - это виджет для отображения списка информации. Он сложнее и более функционален, чем простой list box. list является экземпляром класса wx.ListCtrl. Он может быть отображён в режиме "иконка" и "маленькая иконка", в котором каждый элемент представлен в виде иконки; "список", где элементы расположены в столбцах и "отчёт", который представляет элементы с несколькими колонками, заголовками колонок, по одному элементу на строку.</li>
<li>Изображения для list'a управляются элементом image list - массивом изображений с доступом по индексу. list может работать с разными image list'ами для разных режимов, позволяя легко переключаться между режимом "иконка" и "маленькая иконка".</li>
<li>Для добавления текста в list Вы используете метод InsertStringItem(index, label), а для изображения - InsertImageItem(index, imageIndex). Чтобы добавить и то и другое сразу Вам нужен InsertImageStringItem(index, label, imageIndex). Чтобы добавить колонку в режиме "отчёт" нужен метод InsertColumn(col, heading, format=wx.LIST_FORMAT_LEFT, width=-1). После того, как колонка добавлена, Вы можете добавить текст в новую колонку при помощи метода SetStringItem(index, col, label, imageId=-1).</li>
<li>list генерирует различные события, которые могут быть привязаны к действиям программы. События являются экземплярами класса wx.ListEvent. Стандартные типы событий: EVT_LIST_INSERT_ITEM, EVT_LIST_ITEM_ACTIVATED, EVT_LIST_ITEM_SELECTED.</li>
<li>Если list объявлен с флагом wx.LC_EDIT_LABELS, то пользователь может редактировать текст элементов при его выборе. Редактирование подтверждается нажатием enter или кликом вне элемента, для отказа от редактирования надо нажать escape.</li>
<li>Вы можете отсортировать list, объявив его с флагом wx.LC_SORT_ASCENDING или wx.LC_SORT_DESCENDING. В этом случае элементы будут отсортированы в соответствии со значениями строк. В режиме "отчёт" для этого используются строки из колонки 0. Кроме того, Вы можете использовать метод SortItem(func), чтобы создать свою собственную функцию сортировки. Кроме того, если list находится в режиме "отчёт", Вы можете использовать примесь wx.lib.mixins.listctrl.ColumnSorterMixin, чтобы дать пользователю возможность сортировки по выбранной колонке.</li>
<li>List, объявленный с флагом wx.LC_VIRTUAL, является виртуальным list'ом, что означает, что данные для отображения в нём получаются динамически по мере необходимости. Для такого list'a Вы должны переопределить метод OnGetItemText(item, col), чтобы он возвращал текст, который должен отображаться в указанной строке и колонке. Кроме того, Вы можете переопределить методы OnGetItemImage(item) и OnGetItemAttr(item), чтобы они возвращали изображение или атрибуты отображения для каждой строки. Если данные для отображения изменяются, то обновить отдельную строку можно при помощи метода RefreshItem(item), а несколько строк - RefreshItems(itemFrom, itemTo).</li>
</ul>
<div>
Иногда ваши данные слишком сложны для хранения в простом list'e. Вам нужно что-то более двухмерное. Это называется grid и мы обсудим его в следующей главе.</div>
</div>
</div>
Ishayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com2tag:blogger.com,1999:blog-2142461056765545912.post-66768773797053731512013-01-08T10:19:00.003+04:002013-01-08T10:19:51.008+04:00Взломан wiki.python.org (Перевод)<div style="text-align: justify;">
28 декабря неизвестный, используя неизвестный ранее эксплойт, взломал <a href="http://wiki.python.org/">http://wiki.python.org</a>. Атакующий получил шелл-доступ пользователя moin, другие сервисы не были затронуты.</div>
<br />
<div style="text-align: justify;">
Через некоторое время атакующий удалил все файлы пользователя moin, включая данные вики Python и Jython. Кроме того, атакующий имел полный доступ ко всем данным пользователя <a href="http://moinmo.in/" target="_blank">MoinMoin</a> на всех вики. В свете этого Python Software Foundation советует всем пользователям вики сменить свои пароли, в том числе пароли и на других сайтах, если они совпадают с паролем на вики. Мы приносим извинения за произошедшее, будем сообщать все новости по поводу появления новой и улучшенной <a href="http://wiki.python.org/">wiki.python.org</a>.</div>
<div style="text-align: justify;">
Все вопросы направляйте на <a href="mailto:jnoller@python.org">jnoller@python.org</a>. Спасибо за понимание.</div>
<div style="text-align: justify;">
<br /></div>
<div class="post-body entry-content" style="background-color: white; font-size: 13px; line-height: 1.3em; margin: 0px 0px 0.75em;">
<span style="color: #222222; font-family: Verdana, sans-serif;"><a href="http://pyfound.blogspot.ru/2013/01/wikipythonorg-compromised.html?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed:+PythonSoftwareFoundationNews+(Python+Software+Foundation+News)" target="_blank">Источник</a></span></div>
Ishayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com0tag:blogger.com,1999:blog-2142461056765545912.post-51272821320096722682013-01-07T09:31:00.000+04:002013-01-07T09:31:45.365+04:00Django 1.5 и Python 3 (Перевод)<span style="background-color: #f6f6ef; color: black;"></span><br />
<div style="font-family: Verdana; font-size: 12px; margin-top: 8px; text-align: justify;">
<span style="background-color: #f6f6ef; color: black;">Django 1.5 уже "полностью" поддерживает Python 3, как минимум с технической точки зрения. Поддержка реализована, проверена и работает. Я планирую поместить свой сайт на Django 1.5 / Python 3.3 уже в этом году. Так что в этом смысле всё "готово".</span></div>
<div style="font-family: Verdana; font-size: 12px; margin-top: 8px; text-align: justify;">
<span style="background-color: #f6f6ef; color: black;">Однако, это не значит, что я рекомендую делать это другим.</span></div>
<div style="margin-top: 8px; text-align: justify;">
<span style="background-color: #f6f6ef; color: black;"><span style="font-family: Verdana;"><span style="font-size: 12px;">У мы даём серьёзные обещания обратной совместимости и мы ещё не на 100% хорошо соответствуем Python 3 API. Есть маленькая (не нулевая) вероятность, что надо будет что-то изменить между 1.5 и 1.6; и мы бы хотели сохранить возможность обратной несовместимости (для Python 3).</span></span></span></div>
<div style="margin-top: 8px; text-align: justify;">
<span style="background-color: #f6f6ef; color: black;"><span style="font-family: Verdana;"><span style="font-size: 12px;">Кроме того, есть маленькая (но, опять же, не нулевая) вероятность что есть 1-3 серьёзрых бага в поддержке Python 3 и мы не хотим, чтобы люди с этим столкнулись.</span></span></span></div>
<div style="margin-top: 8px; text-align: justify;">
<span style="background-color: #f6f6ef; color: black;"><span style="font-family: Verdana;"><span style="font-size: 12px;">Наконец, значительная часть "хорошести" Django - сторонние приложения, многие из которых не поддерживают ещё Python 3. И это серьёзная проблема для Django / Py3, так как многие сайты используют большое количество сторонних приложений. Так что перед переходом на Python 3 Вы должны решить для себя вопрос: "Готов ли я отказаться от этого приложения или готов портировать его на Python 3 и внести патч?"</span></span></span></div>
<div style="margin-top: 8px; text-align: justify;">
<span style="background-color: #f6f6ef; color: black;"><span style="font-family: Verdana;"><span style="font-size: 12px;">В случае моего сайта я к этому готов. Я достаточно хорошо знаю Django, чтобы не бояться потенциальных багов и обратной несовместимости и я могу заняться патчами для Python 3.</span></span></span></div>
<div style="margin-top: 8px; text-align: justify;">
<span style="background-color: #f6f6ef; color: black;"><span style="font-family: Verdana;"><span style="font-size: 12px;">Но к большинству пользователей это не относится, так что я надеюсь, что большая часть пользователей Django дождётся 1.6 перед тем, как начать использовать Python 3.</span></span></span></div>
<div style="margin-top: 8px; text-align: justify;">
<span style="background-color: #f6f6ef; color: black;"><span style="font-family: Verdana;"><span style="font-size: 12px;">У нас пока нет твёрдых сроков. Я думаю, что 1.6 можно ждать где-то через 6-9 месяцев, но это зависит от слишком многих факторов. Реально срок может быть и год и 3-4 месяца. Увидим</span></span><span style="font-family: Verdana; font-size: 12px;"> :)</span></span></div>
<div style="background-color: #f6f6ef; font-family: Verdana; font-size: 12px; margin-top: 8px;">
<a href="https://news.ycombinator.com/item?id=5009484" target="_blank">Источник</a></div>
Ishayahu Lastovhttp://www.blogger.com/profile/03850137965550355992noreply@blogger.com0