slateはPython3では使えない
slateはPython2系の頃によく使われていたPDF解析用のライブラリです。しかしPython2.6系しかサポートしていません https://github.com/timClicks/slate/blob/master/setup.py#L32 。 ソースを見るとslateのPython3対応が少しは入っていますが不十分な修正となっています。[Python3.4+のPullRequest](https://github.com/timClicks/slate/pull/32)も作成されていますが放置されているようです。さらにdistributeを中で使っているためインストールに失敗します。
Collecting slate Using cached slate-0.3.zip Collecting distribute (from slate) Using cached distribute-0.7.3.zip Complete output from command python setup.py egg_info: Traceback (most recent call last): File "<string>", line 1, in <module> File "/private/var/folders/hx/xp4thw0x7rj15r_2w57_wvfh0000gn/T/pip-build-57cpbkji/distribute/setuptools/__init__.py", line 2, in <module> from setuptools.extension import Extension, Library File "/private/var/folders/hx/xp4thw0x7rj15r_2w57_wvfh0000gn/T/pip-build-57cpbkji/distribute/setuptools/extension.py", line 5, in <module> from setuptools.dist import _get_unpatched File "/private/var/folders/hx/xp4thw0x7rj15r_2w57_wvfh0000gn/T/pip-build-57cpbkji/distribute/setuptools/dist.py", line 7, in <module> from setuptools.command.install import install File "/private/var/folders/hx/xp4thw0x7rj15r_2w57_wvfh0000gn/T/pip-build-57cpbkji/distribute/setuptools/command/__init__.py", line 8, in <module> from setuptools.command import install_scripts File "/private/var/folders/hx/xp4thw0x7rj15r_2w57_wvfh0000gn/T/pip-build-57cpbkji/distribute/setuptools/command/install_scripts.py", line 3, in <module> from pkg_resources import Distribution, PathMetadata, ensure_directory File "/private/var/folders/hx/xp4thw0x7rj15r_2w57_wvfh0000gn/T/pip-build-57cpbkji/distribute/pkg_resources.py", line 1518, in <module> register_loader_type(importlib_bootstrap.SourceFileLoader, DefaultProvider) AttributeError: module 'importlib._bootstrap' has no attribute 'SourceFileLoader' ---------------------------------------- Command "python setup.py egg_info" failed with error code 1 in /private/var/folders/hx/xp4thw0x7rj15r_2w57_wvfh0000gn/T/pip-build-57cpbkji/distribute/
pip install slate --pre
Collecting slate Using cached slate-0.3.zip Collecting distribute (from slate) Using cached distribute-0.7.3.zip Complete output from command python setup.py egg_info: Traceback (most recent call last): File "<string>", line 1, in <module> File "/private/var/folders/hx/xp4thw0x7rj15r_2w57_wvfh0000gn/T/pip-build-2x0di9p3/distribute/setuptools/__init__.py", line 2, in <module> from setuptools.extension import Extension, Library File "/private/var/folders/hx/xp4thw0x7rj15r_2w57_wvfh0000gn/T/pip-build-2x0di9p3/distribute/setuptools/extension.py", line 5, in <module> from setuptools.dist import _get_unpatched File "/private/var/folders/hx/xp4thw0x7rj15r_2w57_wvfh0000gn/T/pip-build-2x0di9p3/distribute/setuptools/dist.py", line 7, in <module> from setuptools.command.install import install File "/private/var/folders/hx/xp4thw0x7rj15r_2w57_wvfh0000gn/T/pip-build-2x0di9p3/distribute/setuptools/command/__init__.py", line 8, in <module> from setuptools.command import install_scripts File "/private/var/folders/hx/xp4thw0x7rj15r_2w57_wvfh0000gn/T/pip-build-2x0di9p3/distribute/setuptools/command/install_scripts.py", line 3, in <module> from pkg_resources import Distribution, PathMetadata, ensure_directory File "/private/var/folders/hx/xp4thw0x7rj15r_2w57_wvfh0000gn/T/pip-build-2x0di9p3/distribute/pkg_resources.py", line 1518, in <module> register_loader_type(importlib_bootstrap.SourceFileLoader, DefaultProvider) AttributeError: module 'importlib._bootstrap' has no attribute 'SourceFileLoader' ---------------------------------------- Command "python setup.py egg_info" failed with error code 1 in /private/var/folders/hx/xp4thw0x7rj15r_2w57_wvfh0000gn/T/pip-build-2x0di9p3/distribute/
今回はこのslateを復活させPDFを解析します。
まずfork
本家slateは https://github.com/timClicks/slate/ にあります。色々コードを変更しないといけないのでforkしてしまいます。本家のリポジトリの右上の`Fork`ボタンをクリックするとオーガニゼーション選択画面が出ます。自分とアカウントと所属するオーガニゼーション(権限を持っている必要があります)が選択できます。今回は自分のアカウントを選択します。
アカウントを選択するとforkが開始されます。
forkが終了すると新しくリポジトリのページが作成されます。今回はパッケージ名も変えてしまうつもりなので、プロジェクト名も変更します。`Settings` のページを開きます。
プロジェクト名を変更します。 今回は `slate3k` とします。`3k` というのは3000という意味で、Python3系がリリースされる以前に次期メジャーバージョンをリリースするにはもう1000年かかるというジョークでpy3kなどと呼ばれていました。Python3系がリリースされてからライブラリがPython3対応されるようになりましたが、保守されていないライブラリなどはPyhton3対応されませんでした。それらはforkされて `***3k` などと名付けられることがしばしばあります。ライブラリ名に `3k` と付くものはPython3対応したライブラリで元ネタが他にあることが多いです。
Python3対応する
インストールする
まずはcloseします。
Cloning into 'slate3k'... remote: Counting objects: 195, done. remote: Total 195 (delta 0), reused 0 (delta 0), pack-reused 195 Receiving objects: 100% (195/195), 66.84 KiB | 0 bytes/s, done. Resolving deltas: 100% (93/93), done. Checking connectivity... done.
py3kブランチを作成します。
Switched to a new branch 'py3k'
作成したブランチをリモートにpushします。
Total 0 (delta 0), reused 0 (delta 0) To [email protected]:TakesxiSximada/slate3k.git * [new branch] py3k -> py3k Branch py3k set up to track remote branch py3k from origin.
https://github.com/timClicks/slate/pull/32 のパッチは欲しいのでこれを取り込みます。 Pull Requestは`hub am`コマンドを使うことでパッチを当てられます。
hub am -3 https://github.com/timClicks/slate/pull/32
Applying: Fix tests on python 3.5 Applying: add a .gitignore file Applying: Convert README to reStructuredText so it looks better on github Applying: Fix unit tests Applying: Fix demo code Applying: Fix setup.py so it uses README.rst as readme file (py3.6.0) $ git push Counting objects: 24, done. Delta compression using up to 4 threads. Compressing objects: 100% (22/22), done. Writing objects: 100% (24/24), 3.36 KiB | 0 bytes/s, done. Total 24 (delta 13), reused 0 (delta 0) remote: Resolving deltas: 100% (13/13), completed with 6 local objects. To [email protected]:TakesxiSximada/slate3k.git 3198bfd..c31dbb7 py3k -> py3k
これでPull Requstを取り込めました。slateと名前が衝突するのは面倒なのでslate3kに変更します。まずはソースディレクトリをsrc/slateからsrc/slate3kに変更しました。 その他、修正箇所は以下になります。
commit d5f982e753f6fc22e3c5b08a052d226a53821529 Author: TakesxiSximada <[email protected]> Date: Mon Jan 23 21:02:06 2017 +0900 rename packaeg name to slate3k diff --git a/setup.py b/setup.py index 2a89881..0ec5617 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ else: with open('README.rst') as f: long_description = f.read() -setup(name='slate', +setup(name='slate3k', version='0.5.2', description='Extract text from PDF documents easily.', author='Tim McNamara',
commit c1259d4cbccf370492f19727d95d27022a8a46b5 Author: TakesxiSximada <[email protected]> Date: Mon Jan 23 21:06:37 2017 +0900 rename slate to slate3k diff --git a/src/slate3k/classes.py b/src/slate3k/classes.py index 27be417..af32cd0 100644 --- a/src/slate3k/classes.py +++ b/src/slate3k/classes.py @@ -23,7 +23,7 @@ try: except ImportError: from pdfminer.pdfpage import PDFPage if PYTHON_3: - import slate.utils as utils + import .utils as utils else: import utils diff --git a/src/slate3k/test_slate.py b/src/slate3k/test_slate.py index 8416da2..6622e31 100644 --- a/src/slate3k/test_slate.py +++ b/src/slate3k/test_slate.py @@ -12,7 +12,7 @@ PYTHON_3 = sys.version_info[0] == 3 import os if PYTHON_3: - from slate.classes import PDF + from .classes import PDF else: from classes import PDF @@ -44,5 +44,3 @@ def get_pdf_path(pdf_file): return os.path.join( os.path.dirname(__file__), pdf_file) - - diff --git a/src/slate3k/unittests.py b/src/slate3k/unittests.py index 29c2b6b..78dcd68 100644 --- a/src/slate3k/unittests.py +++ b/src/slate3k/unittests.py @@ -1,7 +1,7 @@ import unittest import os -from slate import PDF +from . import PDF class TestSlate(unittest.TestCase): def setUp(self):
commit 3960b3eb3f5182278995030ba4de545f41f9b4b7 Author: TakesxiSximada <[email protected]> Date: Mon Jan 23 21:15:46 2017 +0900 Can not use distribute diff --git a/setup.py b/setup.py index 0ec5617..2baa9ff 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ setup(name='slate3k', packages=find_packages('src'), package_dir={'': 'src'}, requires=[pdfminer], - install_requires=['distribute', pdfminer], + install_requires=[pdfminer], classifiers= [ 'Development Status :: 4 - Beta', 'Intended Audience :: Developers',
ではediable installします。editable installは開発用のインストール機能です。インストールしたライブラリのコードはsite-packagesディレクトリにコピーされるのですが、editable installの場合はコードはコピーされず、site-packages配下にはegg-linkが作成されます。ソースコード自体は元のコードが使われるのでライブラリとして使いながら開発できるようになります。
pip install -e .
Obtaining file:///Users/sximada/ng2/src/github.com/TakesxiSximada/slate3k Collecting pdfminer3k (from slate3k==0.5.2) Using cached pdfminer3k-1.3.1.tar.gz Requirement already satisfied: pytest>=2.0 in /Users/sximada/ng2/var/lib/miniconda3/envs/py3.6.0/lib/python3.6/site-packages (from pdfminer3k->slate3k==0.5.2) Requirement already satisfied: ply>=3.4 in /Users/sximada/ng2/var/lib/miniconda3/envs/py3.6.0/lib/python3.6/site-packages (from pdfminer3k->slate3k==0.5.2) Requirement already satisfied: py>=1.4.29 in /Users/sximada/ng2/var/lib/miniconda3/envs/py3.6.0/lib/python3.6/site-packages (from pytest>=2.0->pdfminer3k->slate3k==0.5.2) Building wheels for collected packages: pdfminer3k Running setup.py bdist_wheel for pdfminer3k ... done Stored in directory: /Users/sximada/Library/Caches/pip/wheels/cd/84/67/3eb20c984d51d38db1ca65ecba0d866407f46d8b3a9e72f7b2 Successfully built pdfminer3k Installing collected packages: pdfminer3k, slate3k Running setup.py develop for slate3k Successfully installed pdfminer3k-1.3.1 slate3k
インストールできました。
使ってみる
Pythonインタラクティブシェルを起動してslate3kをインポートします。
>>> import slate3k
>>>
良さそうです。
PDFをパース
from unittest import TestCase
class PDFPageParseTest(TestCase):
def test_parse_page(self):
# <PARSE_TEST>
import slate3k as slate
pdf = 'test.pdf'
with open(pdf, 'rb') as f:
doc = slate.PDF(f)
for page in doc[:2]:
print(page)
# </PARSE_TEST>