2016年に作ったOSSのツール・ライブラリまとめ

2016年に作成した以下のOSSについて、それぞれ概要と例示

- CLIツール x 2
- Pythonライブラリ x 10


# CLIツール
## [sqlitebiter](https://github.com/thombashi/sqlitebiter)
`CSV`/`Excel`/`HTML`/`JSON`/`LTSV`/`Markdown`/`TSV`/`Google Sheets`  を`SQLite`データベースファイルに変換するツール。
指定したURLから変換することもできる。

```bash:from-file
$ ls
sample_data.csv  sample_data.xlsx  sample_data_multi.json  sample_data_single.json
$ sqlitebiter file * -o sample.sqlite
[INFO] convert 'sample_data.csv' to 'sample_data' table
[INFO] convert 'sample_data.xlsx' to 'samplesheet1' table
[INFO] convert 'sample_data.xlsx' to 'samplesheet3' table
[INFO] convert 'sample_data_multi.json' to 'sample_data_multi_table_b' table
[INFO] convert 'sample_data_multi.json' to 'sample_data_multi_table_a' table
[INFO] convert 'sample_data_single.json' to 'sample_data_single_json3' table
$ ls sample.sqlite
sample.sqlite
```

```bash:from-URL
$ sqlitebiter -v url "https://en.wikipedia.org/wiki/Comparison_of_firewalls"
[INFO] convert 'https://en.wikipedia.org/wiki/Comparison_of_firewalls' to 'Comparison_of_firewalls_Wikipedia_html1 (Firewall TEXT, License TEXT, CostUsageLimits TEXT, OS TEXT)' table
[INFO] convert 'https://en.wikipedia.org/wiki/Comparison_of_firewalls' to 'Comparison_of_firewalls_Wikipedia_html2 (Firewall TEXT, License TEXT, Cost TEXT, OS TEXT)' table
[INFO] convert 'https://en.wikipedia.org/wiki/Comparison_of_firewalls' to 'Comparison_of_firewalls_Wikipedia_html3 (CanTarget TEXT, Changingdefaultpolicytoacceptrejectbyissuingasinglerule TEXT, IPdestinationaddresses TEXT, IPsourceaddresses TEXT, TCPUDPdestinationports TEXT, TCPUDPsourceports TEXT, EthernetMACdestinationaddress TEXT, EthernetMACsourceaddress TEXT, Inboundfirewallingress TEXT, Outboundfirewallegress TEXT)' table
[INFO] convert 'https://en.wikipedia.org/wiki/Comparison_of_firewalls' to 'Comparison_of_firewalls_Wikipedia_html4 (Can TEXT, [workatOSILayer4statefulfirewall] TEXT, [workatOSILayer7applicationinspection] TEXT, ChangeTTLTransparenttotraceroute TEXT, ConfigureREJECTwithanswer TEXT, DMZdemilitarizedzoneallowsforsingleseveralhostsnottobefirewalled TEXT, Filteraccordingtotimeofday TEXT, RedirectTCPUDPportsportforwarding TEXT, RedirectIPaddressesforwarding TEXT, FilteraccordingtoUserAuthorization TEXT, TrafficratelimitQoS TEXT, Tarpit TEXT, Log TEXT)' table
[INFO] convert 'https://en.wikipedia.org/wiki/Comparison_of_firewalls' to 'Comparison_of_firewalls_Wikipedia_html5 (Features TEXT, ConfigurationGUItextorbothmodes TEXT, [RemoteAccessWebHTTPTelnetSSHRDPSerialCOMRS232] TEXT, Changeruleswithoutrequiringrestart TEXT, Abilitytocentrallymanageallfirewallstogether TEXT)' table
[INFO] convert 'https://en.wikipedia.org/wiki/Comparison_of_firewalls' to 'Comparison_of_firewalls_Wikipedia_html6 (Features TEXT, Modularitysupportsthirdpartymodulestoextendfunctionality TEXT, [IPS : Intrusion prevention system] TEXT, OpenSourceLicense TEXT, [supports IPv6 ?] TEXT, ClassHomeProfessional TEXT, OperatingSystemsonwhichitruns TEXT)' table
[INFO] convert 'https://en.wikipedia.org/wiki/Comparison_of_firewalls' to 'Comparison_of_firewalls_Wikipedia_html7 (Can TEXT, [NAT44staticdynamicwoportsPAT] TEXT, [NAT64NPTv6] TEXT, IDSIntrusionDetectionSystem TEXT, VPNVirtualPrivateNetwork TEXT, AVAntiVirus TEXT, Sniffer TEXT, Profileselection TEXT)' table
```

- Repository: https://github.com/thombashi/sqlitebiter


## [tcconfig](https://github.com/thombashi/tcconfig)
ネットワーク帯域制御コマンドである`tc`のラッパーツール。`tc`の設定用書式をすぐ忘れてしまうため作ったもの。
以下3種のコマンドが含まれる。

- `tcset`: `tc`フィルタ設定
- `tcdel`: `tc`フィルタ削除
- `tcshow`: 現在の`tc`設定の表示

`tcset`は流入出両方のパケットにフィルタを設定できる。

```bash:tcconfig-example
# tcset --device eth0 --delay 10 --delay-distro 2  --loss 0.01 --rate 0.25M --network 192.168.0.10 --port 8080
# tcset --device eth0 --delay 1 --loss 0.02 --rate 500K --direction incoming
# tcshow --device eth0
{
    "eth0": {
        "outgoing": {
            "network=192.168.0.10/32, port=8080": {
                "delay": "10.0",
                "loss": "0.01",
                "rate": "250K",
                "delay-distro": "2.0"
            },
            "network=0.0.0.0/0": {}
        },
        "incoming": {
            "network=0.0.0.0/0": {
                "delay": "1.0",
                "loss": "0.02",
                "rate": "500K"
            }
        }
    }
}
```

- Repository: https://github.com/thombashi/tcconfig


# Pythonライブラリ
## [pytablewriter](https://github.com/thombashi/pytablewriter)
表を書くためのライブラリ。マルチバイト文字対応。

サポートフォーマット:`CSV`/`HTML`/`JavaScript`/`JSON`/`LTSV`/`Markdown`/`MediaWiki`/`Excel`/`Pandas`/`Python`/`reStructuredText`/`TOML`/`TSV`.

```python:-example
import io
import pytablewriter

writer = pytablewriter.MarkdownTableWriter()
writer.table_name = u"生成に関するパターン".encode("utf_8")
writer.header_list = [u"パターン名".encode("utf_8"), "概要", "GoF", "Code Complete[1]"]
writer.value_matrix = [
    ["Abstract Factory", u"関連する一連のインスタンスを状況に応じて、適切に生成する方法を提供する。".encode("utf_8"), "Yes", "Yes"],
    ["Builder", "複合化されたインスタンスの生成過程を隠蔽する。", "Yes", "No"],
    ["Factory Method", "実際に生成されるインスタンスに依存しない、インスタンスの生成方法を提供する。", "Yes", "Yes"],
    ["Prototype", "同様のインスタンスを生成するために、原型のインスタンスを複製する。", "Yes", "No"],
    ["Singleton", "あるクラスについて、インスタンスが単一であることを保証する。", "Yes", "Yes"],
]

with io.open("multibyte_table_output.txt", "w", encoding="utf-8") as f:
    writer.stream = f
    writer.write_table()
```

```:multibyte_table_output.txt
# 生成に関するパターン
   パターン名   |                                    概要                                    |GoF|Code Complete[1]
----------------|----------------------------------------------------------------------------|---|----------------
Abstract Factory|関連する一連のインスタンスを状況に応じて、適切に生成する方法を提供する。    |Yes|Yes             
Builder         |複合化されたインスタンスの生成過程を隠蔽する。                              |Yes|No              
Factory Method  |実際に生成されるインスタンスに依存しない、インスタンスの生成方法を提供する。|Yes|Yes             
Prototype       |同様のインスタンスを生成するために、原型のインスタンスを複製する。          |Yes|No              
Singleton       |あるクラスについて、インスタンスが単一であることを保証する。                |Yes|Yes             
```

描画すると↓のように:

   パターン名   |                                    概要                                    |GoF|Code Complete[1]
----------------|----------------------------------------------------------------------------|---|----------------
Abstract Factory|関連する一連のインスタンスを状況に応じて、適切に生成する方法を提供する。    |Yes|Yes             
Builder         |複合化されたインスタンスの生成過程を隠蔽する。                              |Yes|No              
Factory Method  |実際に生成されるインスタンスに依存しない、インスタンスの生成方法を提供する。|Yes|Yes             
Prototype       |同様のインスタンスを生成するために、原型のインスタンスを複製する。          |Yes|No              
Singleton       |あるクラスについて、インスタンスが単一であることを保証する。                |Yes|Yes          

- Repository: https://github.com/thombashi/pytablewriter



## [SimpleSQLite](https://github.com/thombashi/SimpleSQLite)
Python built-inの`sqlite3`モジュールのラッパーライブラリ。
SQLiteデータベースの作成を簡易化するためのもの。
詳しくは→[SQLiteのテーブル作成/データ挿入を簡易化するPythonライブラリSimpleSQLiteを作った](http://qiita.com/vmmhypervisor/items/99c7cdae78af338bd232)

- Repository: https://github.com/thombashi/SimpleSQLite


## [DateTimeRange](https://github.com/thombashi/DateTimeRange)
時間の範囲を扱うためのライブラリ。夏時間対応有り。
詳しくは→[時間範囲を扱うPythonライブラリDateTimeRangeを作った](http://qiita.com/vmmhypervisor/items/8af938391ecce5713ced)

- Repository: https://github.com/thombashi/DateTimeRange


## [DataProperty](https://github.com/thombashi/DataProperty)
型情報、文字列としての長さ等の属性情報を抽出するためのライブラリ。
データ単体か、データ配列を対象とできる。
データ行列から各列の情報を抽出することもできる。

```pycon:データ単体から属性情報を抽出する例
>>> from dataproperty import DataProperty
>>> DataProperty(-1.1)
data=-1.1, typename=FLOAT, align=right, str_len=4, ascii_char_width=4, integer_digits=1, decimal_places=1, additional_format_len=1
```

```python:データ行列から各列の属性情報を抽出する例
import sys
import datetime
from dataproperty import DataPropertyExtractor, Typecode

def display_col_dp(dp_list, attr_name):
    """show a value assocciated with an attribute for each
    DataProperty instance in the dp_list"""

    print()
    print("---------- {:s} ----------".format(attr_name))
    print([getattr(dp, attr_name) for dp in dp_list])

def main():
    # sample data definitions
    dt = datetime.datetime(2017, 1, 1, 0, 0, 0)
    inf = float("inf")
    nan = float("nan")
    data_matrix = [
        [1, 1.1,  "aa",   1,   1,     True,   inf,   nan,   dt],
        [2, 2.2,  "bbb",  2.2, 2.2,   False,  "inf", "nan", dt],
        [3, 3.33, "cccc", -3,  "ccc", "true", inf,
            "NAN", "2017-01-01T01:23:45+0900"],
    ]

    # extract property for each column from a matrix
    dp_extractor = DataPropertyExtractor()
    dp_extractor.header_list = [
        "int", "float", "str", "num", "mix", "bool", "inf", "nan", "time"]
    dp_extractor.data_matrix = data_matrix
    col_dp_list = dp_extractor.to_col_dataproperty_list()

    print("---------- typename ----------")
    print([Typecode.get_typename(dp.typecode) for dp in col_dp_list])

    display_col_dp(col_dp_list, "align")
    display_col_dp(col_dp_list, "ascii_char_width")
    display_col_dp(col_dp_list, "decimal_places")

if __name__ == "__main__":
    sys.exit(main())
```

```bash:output
---------- typename ----------
['INTEGER', 'FLOAT', 'STRING', 'FLOAT', 'STRING', 'BOOL', 'INFINITY', 'NAN', 'STRING']

---------- align ----------
[right, right, left, right, left, left, left, left, left]

---------- ascii_char_width ----------
[3, 5, 4, 4, 3, 5, 8, 3, 24]

---------- decimal_places ----------
[0, 2, nan, 1, 1, nan, nan, nan, nan]
```

- Repository: https://github.com/thombashi/DataProperty



## [pingparsing](https://github.com/thombashi/pingparsing)
`ping`コマンド実行結果をパースするためのライブラリ。
`ping`実行もできる。

```bash:input
>ping google.com -n 10 > ping_win.txt

>type ping_win.txt

Pinging google.com [216.58.196.238] with 32 bytes of data:
Reply from 216.58.196.238: bytes=32 time=87ms TTL=51
Reply from 216.58.196.238: bytes=32 time=97ms TTL=51
Reply from 216.58.196.238: bytes=32 time=56ms TTL=51
Reply from 216.58.196.238: bytes=32 time=95ms TTL=51
Reply from 216.58.196.238: bytes=32 time=194ms TTL=51
Reply from 216.58.196.238: bytes=32 time=98ms TTL=51
Reply from 216.58.196.238: bytes=32 time=93ms TTL=51
Reply from 216.58.196.238: bytes=32 time=96ms TTL=51
Reply from 216.58.196.238: bytes=32 time=96ms TTL=51
Reply from 216.58.196.238: bytes=32 time=165ms TTL=51

Ping statistics for 216.58.196.238:
    Packets: Sent = 10, Received = 10, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 56ms, Maximum = 194ms, Average = 107ms
```

↑のような`ping`の実行結果をパースする。
ライブラリを使った [サンプル](https://github.com/thombashi/pingparsing/blob/master/examples/parse_sample.py) の実行結果が↓

```bash:output
parse_sample.py -f ping_win.txt
# properties ---
packet_transmit: 10
packet_receive: 10
packet_loss: 0.0
rtt_min: 56.0
rtt_avg: 107.0
rtt_max: 194.0
rtt_mdev: None

# asdict ---
{
    "packet_loss": 0.0,
    "packet_transmit": 10,
    "rtt_min": 56.0,
    "rtt_avg": 107.0,
    "packet_receive": 10,
    "rtt_max": 194.0,
    "rtt_mdev": null
}
```

- Repository: https://github.com/thombashi/pingparsing


## [pathvalidate](https://github.com/thombashi/pathvalidate)
ファイル名等の文字列のvalidate、無効な文字の置換をするライブラリ。

```python:Windows/Linux両方でファイル名として有効な文字列に置換する例
import pathvalidate

filename = "_a*b:c<d>e%f/(g)h+i_0.txt"
print(pathvalidate.sanitize_filename(filename))
```

```output
_abcde%f(g)h+i_0.txt
```

- Repository: https://github.com/thombashi/pathvalidate


## [mbstrdecoder](https://github.com/thombashi/mbstrdecoder)
文字列をUnicodeにするライブラリ。
これによってUnicodeで悩まされることが減った。

```python
from mbstrdecoder import MultiByteStrDecoder

encoded_multibyte_text = u"マルチバイト文字".encode("utf-8")

# エンコードされた文字列、Unicode文字列どちらでも利用可。
decoder = MultiByteStrDecoder(encoded_multibyte_text)

print(encoded_multibyte_text)
print(decoder.unicode_str)
print(decoder.codec)
```

```bash:output
b'\xe3\x83\x9e\xe3\x83\xab\xe3\x83\x81\xe3\x83\x90\xe3\x82\xa4\xe3\x83\x88\xe6\x96\x87\xe5\xad\x97'
マルチバイト文字
utf_8
```

- Repository: https://github.com/thombashi/mbstrdecoder


## [pytablereader](https://github.com/thombashi/pytablereader)
`CSV`/`Excel`/`HTML`/`JSON`/`LTSV`/`Markdown`/`TSV`のテキスト/ファイルからテーブルデータを抽出するためのライブラリ。

- Repository: https://github.com/thombashi/pytablereader


## [sqliteschema](https://github.com/thombashi/sqliteschema)
SQLiteのデータベースファイルのスキーマを取得するライブラリ。

```python:sqliteschema-example
import sys
import simplesqlite
import sqliteschema

def make_database():
    db_path = "example.sqlite"
    con = simplesqlite.SimpleSQLite(db_path, "w")

    con.create_table_from_data_matrix(
        table_name="sampletable0",
        attr_name_list=["attr_a", "attr_b"],
        data_matrix=[[1, 2], [3, 4]])

    con.create_table_from_data_matrix(
        table_name="sampletable1",
        attr_name_list=["foo", "bar", "hoge"],
        data_matrix=[
            [1, 2.2, "aa"],
            [3, 4.4, "bb"],
        ],
        index_attr_list=("foo", "hoge"))

    con.create_table(
        "constraints",
        [
            "primarykey_id INTEGER PRIMARY KEY",
            "notnull_value REAL NOT NULL",
            "unique_value INTEGER UNIQUE",
        ]
    )

    return db_path

def main():
    db_path = make_database()
    extractor = sqliteschema.SqliteSchemaExtractor(db_path)
    print(extractor.dumps())

    return 0

if __name__ == "__main__":
    sys.exit(main())
```

```bash:output
.. table:: sampletable0

    +--------------+---------+-----------+--------+------+-----+
    |Attribute name|Data type|Primary key|Not NULL|Unique|Index|
    +==============+=========+===========+========+======+=====+
    |attr_a        |INTEGER  |           |        |      |     |
    +--------------+---------+-----------+--------+------+-----+
    |attr_b        |INTEGER  |           |        |      |     |
    +--------------+---------+-----------+--------+------+-----+

.. table:: sampletable1

    +--------------+---------+-----------+--------+------+-----+
    |Attribute name|Data type|Primary key|Not NULL|Unique|Index|
    +==============+=========+===========+========+======+=====+
    |foo           |INTEGER  |           |        |      |X    |
    +--------------+---------+-----------+--------+------+-----+
    |bar           |REAL     |           |        |      |     |
    +--------------+---------+-----------+--------+------+-----+
    |hoge          |TEXT     |           |        |      |X    |
    +--------------+---------+-----------+--------+------+-----+

.. table:: constraints

    +--------------+---------+-----------+--------+------+-----+
    |Attribute name|Data type|Primary key|Not NULL|Unique|Index|
    +==============+=========+===========+========+======+=====+
    |primarykey_id |INTEGER  |X          |        |      |     |
    +--------------+---------+-----------+--------+------+-----+
    |notnull_value |REAL     |           |X       |      |     |
    +--------------+---------+-----------+--------+------+-----+
    |unique_value  |INTEGER  |           |        |X     |     |
    +--------------+---------+-----------+--------+------+-----+
```

- Repository: https://github.com/thombashi/sqliteschema


## [subprocrunner](https://github.com/thombashi/subprocrunner)
`subprocess`モジュールのラッパーライブラリ。

```python:subprocrunner-example
from subprocrunner import SubprocessRunner

runner = SubprocessRunner("echo test")
print("return code: {:d}".format(runner.run()))
print("stdout: {}".format(runner.stdout))
```

```bash:output
return code: 0
stdout: test
```

- Repository: https://github.com/thombashi/subprocrunner