今さらPython3 (54) - YAMLなど

第8章をゆっくりと読み進めてます。

入門 Python 3

入門 Python 3

YAML

初めて聞く名前じゃないんだけど、何に使ったか覚えてない。というぐらいの認識。そんな名前のファイル名がないか、自分のMacの中を検索掛けたら、Wordpressからはてなブログに引っ越したときのファイルに使われていた模様。ちなみに、このブログで一番アクセスが多いのは、このときのネタだったりする。

deutschina.hatenablog.com

それはさておき、YAMLとはなんぞや。

YAML - Wikipedia

うんちくはともかく、動かしてみる。

name:
	first: James
	last: McIntyre
dates:
	birth: 1828-05-25
	death: 1906-03-31
details:
	bearded: true
	themes: [cheese, Canada]
books:
	url: http://www.gutenberg.org/files/36068/36068-h/36068-h.htm
poem:
	- title: 'Motto'
	text: |
			Politeness, perseverance and pluck,
			To their possessor will bring good luck.
	- title: 'Canadian Charms'
	text: |
			Here industry is not in vain,
			For we have bounteous crops of grain,
			And you behold on every field
			Of grass and roots abundant yield,
			But after all the greatest charm
			Is the snug home upon the farm,
			And stone walls now keep cattle warm.

このファイルをまず作って、mcintyre.yamlという名前で保存。PyYAMLは見たことないのでインストールしてみる。

>>> quit()
$ pip3 install pyyaml
Collecting pyyaml
  Downloading PyYAML-3.11.tar.gz (248kB)
    100% |████████████████████████████████| 249kB 1.5MB/s 
Installing collected packages: pyyaml
  Running setup.py install for pyyaml
Successfully installed pyyaml-3.11
$ python3
Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 23 2015, 02:52:03) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 

ここでPythonに戻り、

>>> import yaml
>>> with open('mcintyre.yaml', 'rt') as fin:
...     text = fin.read()
... 
>>> data = yaml.load(text)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/yaml/__init__.py", line 72, in load
    return loader.get_single_data()
  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/yaml/constructor.py", line 35, in get_single_data
...
yaml.scanner.ScannerError: while scanning for the next token
found character '\t' that cannot start any token
  in "<unicode string>", line 2, column 1:
    	first: James
    ^

シャイセ!と唯一知っているドイツ語の単語が口から出てきました。何のことはない、ファイル作るときにタブを打ったら、そんなの読めないよと怒られた模様。タブをスペースに置き換えたり、インデントのエラーなどを乗り越えて何とかここまで。

>>> with open('mcintyre.yaml', 'rt') as fin:
...     text = fin.read()
... 
>>> data = yaml.load(text)
>>> 
>>> data['details']
{'bearded': True, 'themes': ['cheese', 'Canada']}
>>> data
{'poems': [{'text': 'Politeness, perseverance and pluck,\nTo their possessor will bring good luck.\n', 'title': 'Motto'}, {'text': 'Here industry is not in vain,\nFor we have bounteous crops of grain,\nAnd you behold on every field\nOf grass and roots abundant yield,\nBut after all the greatest charm\nIs the snug home upon the farm,\nAnd stone walls now keep cattle warm.\n', 'title': 'Canadian Charms'}], 'books': {'url': 'http://www.gutenberg.org/files/36068/36068-h/36068-h.htm'}, 'dates': {'death': datetime.date(1906, 3, 31), 'birth': datetime.date(1828, 5, 25)}, 'name': {'last': 'McIntyre', 'first': 'James'}, 'details': {'bearded': True, 'themes': ['cheese', 'Canada']}}
>>>
>>> len(data['poems'])
2
>>> data['poems'][1]['title']
'Canadian Charms'
>>>  

入れ子の辞書状態で保存されるあたりは、JSONと大差ない感じ。PyYAMLに限らず出所の分からないファイルの扱いには十分に注意しないと行けないというのが次の話だね。

Ned Batchelder: War is peace

セキュリティの話

PythonXMLに関したページを開くと、ページの上の方に脆弱性の警告みたいのが書いてあるんだけど、それだけ過去に大きなインパクトを与えてきたんだろうと理解。

tiran / defusedxml — Bitbucket

ということで、defusedxmlをゲットしておきましょう。

$ pip3 search defusedxml
defusedxml     - XML bomb protection for Python stdlib modules
safedexml      - a defusedxml version of dead-simple Object-XML mapper for Python
$ pip3 install defusedxml
Collecting defusedxml
  Downloading defusedxml-0.4.1.tar.gz (48kB)
    100% |████████████████████████████████| 49kB 5.2MB/s 
Installing collected packages: defusedxml
  Running setup.py install for defusedxml
Successfully installed defusedxml-0.4.1

pipがあると本当に助かる。

>>> #danger
...
>>> from xml.etree.ElementTree import parse
>>> et = parse(xmlfile)
>>> #protected
...
>>> from defusedxml.ElementTree import parse
>>> et = parse(xmlfile)

xmlfileというのを定義していないから、実際には動かないけど、覚えておきましょう。

(つづく)