pysetup3のご紹介
python2ではsetuptoolsやdistutilsがありますが、python3では "packaging"という新しいパッケージ用ライブラリが搭載されます。
pysetup3はこのpackagingを使うためのコマンドです。これは、setuptoolsやdistutilsを使うためのコマンドがpipやeasy_installである、という関係と同じです。
まとめるとこういう関係になります。(正確にはちょっとずれていますがまあこんなものかと)
ライブラリ | ツール | |
---|---|---|
python3.2まで | distutils/setuptools/distribute | easy_install/pip/buildout |
python3.3〜 | packaging | pysetup3 |
なお、packagingはpython2.4〜3.2ではdistutils2という名前でバックポートされ、サードパーティパッケージとして配布されます。
pysetup3のドキュメントはこちらです。
http://docs.python.org/dev/install/pysetup.html
使い方
pysetup3はpython3.3から標準搭載されます。python 3.3はまだリリースされていないので、使うには http://hg.python.org/cpython/ から開発版を取得してくる必要があります。あるいは、python2〜3.2で使うにはhttps://bitbucket.org/tarek/distutils2/wiki/Home からソースをとってくる必要があります。なお、distutils2の場合、listコマンドが使えないなどの制限がありますのでご注意ください。
さて、pysetup3の使い方です。まずはhelpを見ます。
% pysetup3 --help Usage: pysetup [options] action [action_options] Actions: run: Run one or several commands metadata: Display the metadata of a project install: Install a project remove: Remove a project search: Search for a project in the indexes list: List installed projects graph: Display a graph create: Create a project generate-setup: Generate a backward-compatible setup.py
ちなみに、distutils2ではこうなります。
Actions: run: Run one or several commands metadata: Display the metadata of a project install: Install a project remove: Remove a project search: Search for a project graph: Display a graph create: Create a Project
listがないのはどういうことだって言う感じですが…
検索 (search)
ということで、まずはbuchoパッケージを検索してみます。
% pysetup3 search bucho not implemented %
...
えーっと。実装されてないって…
気を取り直して次行きましょう。
インストール (install)
落としてきたtar.gzを使って install してみます。
% pysetup3 install bucho-0.1.1.tar.gz Installing from archive: '/home/prosou/shirou/bucho-0.1.1.tar.gz' Traceback (most recent call last): File "setup.py", line 2, in <module> import setuptools ImportError: No module named 'setuptools' failed to install
あー、buchoはsetuptoolsに依存しているのですね。pysetup3 install distribute をしたらこのエラーは出なくなりましたが、代わりに
option --single-version-externally-managed not recognized
と言われてしまいました。よく分かりません…
pysetup3の作者、tarekのパッケージなら平気だと思います。
% pysetup3.3 install flake8-1.0.tar.gz ..... % pysetup3.3 list 'flake8' 1.0 (from '/home/rudi/local/lib/python3.3/site-packages/flake8-1.0-py3.3.dist-info') Found 1 projects installed.
うまくインストールできたようです。
なお、インストールは
- pypi
- 検索はできなくてもインストールはできます。 pysetup3 install flake8としてください
- tar.gzへのURL (http://host/packages/project-1.0.tar.gz)
- setup.pyかsetup.cfgが含まれたディレクトリ
からもインストールできます。また、
% pysetup3 install project==1.0
というようにすることで、インストールするバージョンを決めることもできます。
インストール済みのパッケージリスト (list)
listで今インストールされているパッケージのリストが出ます。
% pysetup3.3 list 'flake8' 1.0 (from '/home/rudi/local/lib/python3.3/site-packages/flake8-1.0-py3.3.dist-info') Found 1 projects installed.
情報の表示 (metadata)
パッケージの情報を得るにはmetadataを使います。
% pysetup3.3 metadata flake8 Metadata-Version: 1.1 Name: flake8 Version: 1.0 Platform: UNKNOWN Supported-Platform: Summary: code checking using pep8 and pyflakes Description: ====== (以下省略)
また、-fをつけることにより、表示される情報を制限することも出来ます。
% pysetup3 metadata -f name -f version flake8 Name: flake8 Version: 1.0
インストールされているものにしか使えないようです。
グラフの表示 (graph)
% pysetup3.3 graph flake8 'flake8' 1.0
依存するパッケージのグラフを表示してくれるそうです。
アンインストール (remove)
% pysetup3.3 remove flake8 'flake8' cannot be removed. Error: [Errno 18] Cross-device link
what? …ちょっと今回は追いませんが、これがきちんと出来るのがいいところなのに…
プロジェクトを作成する (create)
createコマンドを打つと、setup.cfgを対話型で作ってくれます。途中でyを答えると今のディレクトリをチェックして全部含めてくれますので便利です。
ちなみに、pysetupはsetup.pyではなく、setup.cfgを使うようになることに注意してください。 (このあたりはpycon 2011 JPのtarekの講演を参考にしてください。)
% pysetup3.3 create Project name [setup]: test Current version number [1.0.0]: Project description summary: > Thi is test Author name: shirou Author email address: rudy@example.com Project home page: test Do you want me to automatically build the file list with everything I can find in the current directory? If you say no, you will have to define them manually. (y/n): y Do you want to set Trove classifiers? (y/n): y Please select the project status: 0 - Planning 1 - Pre-Alpha 2 - Alpha 3 - Beta 4 - Production/Stable 5 - Mature 6 - Inactive Status: 1 What license do you use?: BSD Matching licenses: 1) License :: OSI Approved :: BSD License Type the number of the license you wish to use or ? to try again:: 1 What license do you use?: Do you want to set other trove identifiers? (y/n) [n]: n Wrote "setup.cfg".
また、setup.pyがあると
% pysetup3 create A legacy setup.py has been found. Would you like to convert it to a setup.cfg? (y/n) [y]: y
と聞いてくれます。でもsphinxを試したら ImportError: No module named 'sphinx' と言われてしまいました。
互換性のためにsetup.pyを作る (genearte-setup)
% generate-setup The setup.py was generated
とすると、setup.pyが出来上がります。でも、現段階では別にディレクトリの内容を読んでくれるわけではなく、単にsetup.pyのひな形ができるだけです。
コマンド (run)
pysetup3には今まで述べてきたコマンドの他にも setup.py 相当コマンドがあります。 setup.pyが使われなくなる代わりに、今までsetup.pyで行ってきたことがここに入っているという感じですね。
% pysetup3 run --list-commands List of available commands: bdist: create a built (binary) distribution bdist_dumb: create a "dumb" built distribution bdist_wininst: create an executable installer for Windows build: build everything needed to install build_clib: build C/C++ libraries used by extension modules build_ext: build C/C++ extension modules (compile/link to build directory) build_py: build pure Python modules (copy to build directory) build_scripts: build scripts (copy and fix up shebang line) check: check PEP compliance of metadata clean: clean up temporary files from 'build' command install_data: install platform-independent data files install_dist: install everything from build directory install_distinfo: create a .dist-info directory for the distribution install_headers: install C/C++ header files install_lib: install all modules (extensions and pure Python) install_scripts: install scripts (Python or otherwise) register: register a release with PyPI sdist: create a source distribution (tarball, zip file, etc.) test: run the project's test suite upload: upload distribution to PyPI upload_docs: upload HTML documentation to PyPI
まとめ
というわけで、python3.3から使えるようになるpysetupコマンドについて述べてきました。正直まだ使えないなというレベルではありますが、3.3リリースが予定されているのは来年8月ですし、これからどんどん良くなっていくと思います。
明日は初心者向けのエントリを書いてくださる @takanory さんにお願いします。
Blockdiag Advent Calander 1日目 href機能
blockdiagアドベントカレンダー、初日です。
今回はblockdiag 1.1.1から入ったhref機能についてご紹介します。
href機能とは、ノードの属性にhrefを指定することで、SVG形式で出力する時そのノードをクリックをしたらhref属性で指定したURLに飛ぶ、という機能です。
例えば、
diag { A [label="blockdiag", href="http://blockdiag.com"] B [label="python", href="http://python.org"] A -> B }
としておき、SVG形式で生成します。SVGファイルをブラウザで開いてそれぞれのノードをクリックすると、指定したURLに飛びます。
ただし、残念ながらxlink:hrefに対応していないSVGエディタでは飛びませんし、PNG形式では無意味です。
sphinxとの連携
現在sphinxcontribにもこの機能を使うように変更を行っている最中です。反映されると、以下のように書けるようになります。
.. blockdiag:: diagram { A [label="blockdiag", href="http://blockdiag.com"] B [label="python", href=":ref:python"] A -> B }
ノードBのhrefに注目してください。:ref:pythonと指定してあります。sphinxでは
.. _python:
を章や節の前に(一行開けて)書くとそこに対して :ref:python でリンクを貼れます。これと同じ事がsphinxのblockdiag内でもできます。
また、sphinxと連携した場合、PNG形式の場合でもクリッカブルマップを自動的に設定してクリックできるようになります。
使い道
自動生成を行うと、大きな図が出来てしまうことがあります。そういう場合は分割させたいのですが、関連が分からなくなってしまいます。この様な時にhref機能があると便利です。
今後
今後グループにもこの機能を追加するかもしれません。blockdiagにはグループを別のファイルに分割する機能(-sオプション)がありますので、リンクを自動的にしてくれるならば、大きな図でも見やすくできるかもしれないと考えています。
mercurialのファイルを(なぜか)タイムスタンプで履歴管理
履歴管理はファイル名に日付を付けるのが基本ですよね。
ということで、mercurialのチェンジセットに含まれているファイルを、日付を付けたファイル名で展開するスクリプトを作りました。レポジトリのディレクトリに移動し、このスクリプトを実行してください。
…ええ、ええ、言いたいことはよーく分かっています。でもですね、なにも言わないでください…
#!/usr/bin/env python # -*- coding: utf-8 -*- # # This script extracts changed files in changesets with timestamp suffix. # # Yes, I know timestamp based history management is not the mercurial way. # but, but, sigh... # # license: new BSD # from mercurial import ui from mercurial import hg import datetime import os MAXAGE = 10 # 展開するチェンジセットの数 FORMAT = "%Y%m%d-%H%M%S" u = ui.ui() repo = hg.repository(u, '.') tip = repo.changectx("tip") tip_rev = tip.rev() for i in range(tip_rev, tip_rev - MAXAGE, -1): ctx = repo.changectx(i) unix_timestamp = ctx.date()[0] tz = ctx.date()[1] # currently not used d = datetime.datetime.fromtimestamp(unix_timestamp) for filename in ctx.files(): fctx = ctx[filename] fname = os.path.join(repo.root, "{0}-{1}".format(filename, d.strftime(FORMAT)) ) try: f = open(fname, "w") f.write(fctx.data()) finally: if f: f.close()
denyhostsの設定を見直した
生活のかなりの部分を依存しているサーバをさくらのVPSサーバに移行したんだけど、sshアタックがすごい。同じホストから1秒間に3回ぐらいくる。
もちろんdenyhostsを入れてるんだけど、それでもすごい数のアタックが来ていることがログから分かってて、なんでかな、と思って設定ファイルをみてたらその理由が分かりました。
# DAEMON_SLEEP: when DenyHosts is run in daemon mode (--daemon flag) # this is the amount of time DenyHosts will sleep between polling # the SECURE_LOG. See the comments in the PURGE_DENY section (above) # for details on specifying this value or for complete details # refer to: http://denyhosts.sourceforge.net/faq.html#timespec # DAEMON_SLEEP = 30s
という設定があり、初期設定は30秒になっている。これはなにかと言うと、daemonモードでチェックする間隔を設定するもの。つまり、daemonモードではこの間隔でしかチェックしないので、今のように1秒間に3回くらってもすぐには対応できない、というわけ。
もちろん、辞書攻撃じゃ30秒では破れないだろうからセキュリティ的には問題ない(と思う)だろうけど、ログがたくさんになるのはちょっとね。
というわけで、ちょっと間隔を狭めてみた。これでどうなるかな。
fabricでトンネルする
最近fabricを使っていろいろ作業しています。
で、踏み台サーバごしにアクセスする必要があるマシンがあるのですが、fabricの中でトンネルを作って作業したいなと思いました、ちょっと調べてみると https://gist.github.com/856179 にcodeがありましたので、それを利用させてもらいました。ありがとうございます。
具体的には以下のような感じにしました。
#!/usr/bin/env python # -*- coding: utf-8 -*- from fabric.api import run, env # 事前にtunnel.pyを https://gist.github.com/856179 から入手 from tunnel import make_tunnel def staging(): env.hosts = ['example1'] def get_hostname(): with make_tunnel('your_tunnel_host_name') as t: run('hostname')
なお、env.host_stringを使っている場合は、tunnelの中でenv.host_stringを127.0.0.1に書き換えてしまいますので、withの前で別のところにとっておきましょう。
Beautiful SoupでHTMLやXMLをparseしよう
Beautiful SoupはHTMLやXMLをparseしてくれるパーサーライブラリです。でも、Beautiful Soupは単なるパーサーじゃなくてちょっと賢い奴なんです。
今回、このBeautiful Soupのドキュメントを翻訳しました。
http://www.tdoc.info/beautifulsoup/
下に軽く紹介していますが、詳しくはこのドキュメントをご覧ください。
Beautiful Soupをざっくり紹介
Beautiful Soupがどういうやつかって?例えばこんなHTMLがあったとしましょう。
<HTML> <body> 改行<br> したいよね <br/> <! --あれ、空白が入ってるちょっと変なコメント--> <p> bodyが閉じてないよ? </html>
結構変なHTMLですよね。でも、巷にはこういうのも結構あるんです。で、これをtest1.htmlだとします。これをこんな感じのスクリプトでパースしてみると、
soup = BeautifulSoup(open("test1.html")) print soup.prettify()
こうなります。
<html> <body> 改行 <br /> したいよね <br /> <!--あれ、空白が入ってるちょっと変なコメント--> <p> bodyが閉じてないよ? </p> </body> </html>
他にも、
<html> <form> <table> <td><input name="input1">一行目二列目 <tr><td>二行目 </form>あれ、テーブル閉じてないよ? <td>こっちは? </html>
を
<html> <form> <table> <td> <input name="input1" /> 一行目二列目 </td> <tr> <td> 二行目 </td> </tr> </table> </form> あれ、テーブル閉じてないよ? <td> こっちは? </td> </html>
という感じにしてくれます。
インストール
ふつーpipですよねー。
% pip install beautifulsoup
使い方
まずはimportします。
from BeautifulSoup import BeautifulSoup # HTMLの場合こっち from BeautifulSoup import BeautifulStoneSoup # XMLの場合こっち import BeautifulSoup # 全部の場合これ
その後、BeautifulSoupコンストラクタを作って、あとはこれを使います。
soup = BeautifulSoup(html_string)
タグを検索
例えば、こういうHTMLドキュメントがあったとします。
<html> <h1>H1です</h1> 段落 <p> ですよ<br/> </p> <table> <tr id="tr-1">閉じてないけどtr-1です<td>td-1-1</td><td>td-1-2 <tr id="tr-2">tr-2です<td class="td">td-2-1</td><td>td-3 </html>
タグはタグの名前で検索できますし、nextSiblingとかを使って順々にたどることも出来ます。もちろんforで回すことも出来ます。
parentで上に、contentsで下に、nextSiblingとprevSiblingで同じ階層にたどる、という感じでしょうか。
soup = BeautifulSoup(doc) print(soup.h1) # h1を表示 print("-------------------------------") print(soup.table.td) # <table><td>の最初を表示 print("-------------------------------") print(soup.table.tr) # <table><tr>の最初表示 print("-------------------------------") tr1 = soup.table.tr print(tr1.nextSibling) # tr-1のnextSibling print("-------------------------------") print(tr1.nextSibling["id"]) # tr-2のid属性 print("-------------------------------") print(tr1.nextSibling.contents[1]["class"]) # tr-2の子のtdのclass属性 print("-------------------------------")
とすると、こう出ます。
<h1>H1です</h1> ------------------------------- <td>td-1-1</td> ------------------------------- <tr id="tr-1">閉じてないけどtr-1です<td>td-1-1</td><td>td-1-2 </td></tr> ------------------------------- <tr id="tr-2">tr-2です<td class="td">td-2-1</td><td>td-3 </td></tr> ------------------------------- tr-2 ------------------------------- td
検索
パースしたツリーを検索できます。
print(soup.findAll('td')) # tdを全部見つけてきます。 print("-------------------------------") import re print(soup.findAll(re.compile('^t'))) # tで始まるタグを全部持ってきます print("-------------------------------")
[<td>td-1-1</td>, <td>td-1-2 </td>, <td class="td">td-2-1</td>, <td>td-3 </td>] ------------------------------- [<table> <tr id="tr-1">閉じてないけどtr-1です<td>td-1-1</td><td>td-1-2 </td></tr><tr id="tr-2">tr-2です<td class="td">td-2-1</td><td>td-3 </td></tr></table>, <tr id="tr-1">閉じてないけどtr-1です<td>td-1-1</td><td>td-1-2 </td></tr>, <td>td-1-1</td>, <td>td-1-2 </td>, <tr id="tr-2">tr-2です<td class="td">td-2-1</td><td>td-3 </td></tr>, <td class="td">td-2-1</td>, <td>td-3 </td>] -------------------------------
文字列への挿入/削除
文字列の途中に挿入するには、overlayを使う。
SELECT overlay('Txxxxas' placing 'hom' from 2 for 0) => Thomxxxxas
文字列の途中を削除するにも overlayを使う
SELECT overlay('1234' placing '' from 2 for 1) => 134