MySQL ShellをPythonモードで使ってみた　その1

# MySQL ShellをPythonモードで使ってみた

Oracle主催の[MySQL Technology Cafe #7](https://oracle-code-tokyo-dev.connpass.com/event/158989/)でMySQL Shellのハンズオンがセミナーが開催されたのでMySQL Shellを使ってみた

# MySQL 8.0.19をインストール
2020年1月13日に公開されたMySQL 8.0.19を利用する

MySQL 8.0.19 Community Server 及び MySQL Shellを書きからダウンロードしてインストール
https://dev.mysql.com/downloads/

<img width="780" alt="Screen Shot 2020-01-17 at 18.32.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213053/3d745507-c279-d36d-4ce5-84a2181e8bd0.png">
OS X の System Preferenceを一度閉じて、再度開かないとVersion表示等が更新されないので注意

> MySQL Shellについてはダウンロードしたpkgがサインされていないので、System PreferenceのSecurity & Privacyで実行を許可する必要が有る

## MySQL Shellはプラグインで拡張できる
MySQL Shellはプラグインで拡張できるという事でプラグインをgit hubからpullして実際に呼び出すハンズオンが行われた

プラグイン拡張を作製する場合には
Frédéric Descamps氏のGitHubを参考にすると良い
https://github.com/lefred/mysqlshell-plugins

プラグインのファイルのデフォルトの格納先
`~/.mysqlsh/plugins`

格納先を変更したい場合は、環境変数`MYSQLSH_USER_CONFIG_HOME`に指定する

プラグインのディレクトリには必ず初期化スクリプトが必要なので、
`init.js`, `init.py`等の初期化スクリプトをプラグインのファイルの格納先に置く必要が有るとの事

## Pythonでプラグインを作製する場合の注意

- PEP8に準拠すること

プラグインのディレクトリ下にサブディレクトリを配置できるので、プラグインの機能毎にサブディレクトリにプラグインをまとめると良い

MySQL Shellのマニュアルは下記のリンクから参照できる
https://dev.mysql.com/doc/mysql-shell/8.0/en/

# Python in MySQL Shell

ここからは、ハンズオンの内容を整理して、疑問点を確認するためのメモ

先ずはプラグインのファイルの格納先の作製

```console
$ mkdir -p ~/.mysqlsh/plugins
```

次にMySQL Shellの様子を確認
python のモードで起動する

```console
$ mysqlsh --py
MySQL Shell 8.0.19

Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates.
Other names may be trademarks of their respective owners.

Type '\help' or '\?' for help; '\quit' to exit.
```

環境中のPythonのバージョンと定義済みオブジェクトの確認
> 以下 `MySQL  Py > `部分がプロンプト


```console
 MySQL  Py > import sys 
 MySQL  Py > sys.version
3.7.4 (default, Nov 26 2019, 05:13:11) 
[Clang 11.0.0 (clang-1100.0.33.8)]
 MySQL  Py > [ item for item in dir() if not item.startswith('__')]
[
    "db", 
    "dba", 
    "mysql", 
    "mysqlx", 
    "raw_input", 
    "session", 
    "shell", 
    "sys", 
    "util"
]
```

パス周りの確認してMySQL Shellを一旦終了

```console
 MySQL  Py > [item for item in sys.path]
[
    "/usr/local/mysql-shell-8.0.19-macos10.15-x86-64bit/share/mysqlsh/oci_sdk/PyNaCl-1.3.0-py3.7-macosx-10.14-x86_64.egg", 
    "/usr/local/mysql-shell-8.0.19-macos10.15-x86-64bit/share/mysqlsh/oci_sdk/six-1.13.0-py3.7.egg", 
    "/usr/local/mysql-shell-8.0.19-macos10.15-x86-64bit/share/mysqlsh/oci_sdk/cffi-1.13.2-py3.7-macosx-10.14-x86_64.egg", 
    "/usr/local/mysql-shell-8.0.19-macos10.15-x86-64bit/share/mysqlsh/oci_sdk/pyasn1-0.4.8-py3.7.egg", 
    "/usr/local/mysql-shell-8.0.19-macos10.15-x86-64bit/share/mysqlsh/oci_sdk/cryptography-2.8-py3.7-macosx-10.14-x86_64.egg", 
    "/usr/local/mysql-shell-8.0.19-macos10.15-x86-64bit/share/mysqlsh/oci_sdk/python_dateutil-2.8.1-py3.7.egg", 
    "/usr/local/mysql-shell-8.0.19-macos10.15-x86-64bit/share/mysqlsh/oci_sdk/pyOpenSSL-19.1.0-py3.7.egg", 
    "/usr/local/mysql-shell-8.0.19-macos10.15-x86-64bit/share/mysqlsh/oci_sdk/bcrypt-3.1.7-py3.7-macosx-10.14-x86_64.egg", 
    "/usr/local/mysql-shell-8.0.19-macos10.15-x86-64bit/share/mysqlsh/oci_sdk/certifi-2019.11.28-py3.7.egg", 
    "/usr/local/mysql-shell-8.0.19-macos10.15-x86-64bit/share/mysqlsh/oci_sdk/paramiko-2.4.2-py3.7.egg", 
    "/usr/local/mysql-shell-8.0.19-macos10.15-x86-64bit/share/mysqlsh/oci_sdk/pytz-2019.3-py3.7.egg", 
    "/usr/local/mysql-shell-8.0.19-macos10.15-x86-64bit/share/mysqlsh/oci_sdk/configparser-3.5.0-py3.7.egg", 
    "/usr/local/mysql-shell-8.0.19-macos10.15-x86-64bit/share/mysqlsh/oci_sdk", 
    "/usr/local/mysql-shell-8.0.19-macos10.15-x86-64bit/lib/mysqlsh/lib/python37.zip", 
    "/usr/local/mysql-shell-8.0.19-macos10.15-x86-64bit/lib/mysqlsh/lib/python3.7", 
    "/usr/local/mysql-shell-8.0.19-macos10.15-x86-64bit/lib/mysqlsh/lib/python3.7/lib-dynload", 
    "/usr/local/mysql-shell-8.0.19-macos10.15-x86-64bit/lib/mysqlsh/lib/python3.7/site-packages"
]
 MySQL  Py > exit()
```

ちょっと様子がわかった

## init.py で何が起きるのか

### init.pyが無い場合

これを確認するために、空の`~/.mysqlsh/plugins/ext`ディレクトリを作製してMySQL Shellを起動してみる

```console
$ mkdir -p ~/.mysqlsh/plugins 
$ mkdir -p ~/.mysqlsh/plugins/ext
$ mysqlsh --py
MySQL Shell 8.0.19

Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates.
Other names may be trademarks of their respective owners.

Type '\help' or '\?' for help; '\quit' to exit.
 MySQL  Py > exit()
```

特に何も起こらない

### サブディレクトリ中にinit.pyがある場合

`~/.mysqlsh/plugins/ext/init.py`を作製してMySQL Shellを起動する

```console
$ echo "print('I\'m ~/.mysqlsh/plugins/ext/init.py')" > ~/.mysqlsh/plugins/ext/init.py
$ mysqlsh --py
 MySQL Shell 8.0.19

Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates.
Other names may be trademarks of their respective owners.

Type '\help' or '\?' for help; '\quit' to exit.
I'm ~/.mysqlsh/plugins/ext/init.py
 MySQL  Py > exit()
```

MySQL Shellの起動時に`~/.mysqlsh/plugins/ext/init.py`が実行された

### サブディレクトリ中にinit.pyがあり、さらにそのサブディレクトリ中にinit.pyがある場合

`~/.mysqlsh/plugins/ext/test`ディレクトリを作成して、`init.py`を配置してMySQL Shellを起動する

```console
$ mkdir -p ~/.mysqlsh/plugins/ext/test
$ echo "print('I\'m ~/.mysqlsh/plugins/ext/test/init.py')" > ~/.mysqlsh/plugins/ext/test/init.py
$ mysqlsh --py 
MySQL Shell 8.0.19

Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates.
Other names may be trademarks of their respective owners.

Type '\help' or '\?' for help; '\quit' to exit.
I'm ~/.mysqlsh/plugins/ext/init.py
 MySQL  Py > exit()
```

この場合は`~/.mysqlsh/plugins/ext/test/init.py`は実行されない

### サブディレクトリ中にinit.pyが無く、さらにそのサブディレクトリ中にinit.pyがある場合

`~/.mysqlsh/plugins/ext/init.py`を削除してMySQL Shellを起動する

```console
$ rm ~/.mysqlsh/plugins/ext/init.py
$ mysqlsh --py --log-level=debug
MySQL Shell 8.0.19

Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates.
Other names may be trademarks of their respective owners.

Type '\help' or '\?' for help; '\quit' to exit.
I'm ~/.mysqlsh/plugins/ext/test/init.py
 MySQL  Py > exit()
```

`~/.mysqlsh/plugins/ext/test/init.py`が実行されている事が確認できる

マニュアルの6.3.2 Creating Plugin Groupsの記述

> If a subdirectory of the plugins folder does not contain an initialization script (an init.js or init.py file), MySQL Shell treats it as a plugin group and searches its subfolders for the initialization scripts for the plugins. The containing folder can contain other files with code that is shared by the plugins in the plugin group. 

プラグインのディレクトリーの中にinit.pyやinit.jsが無い場合にはplugin groupとして扱われ、サブディレクトリ中のinit.py等の初期化スクリプトを検索する

という事は、上位のディレクトリに`init.py`があると、サブディレクトリ中の`init.py`は実行されないという事

### プラグインディレクトリ直下にinit.pyがある場合

それなら、`~/.mysqlsh/plugins/`下に直接`init.py`を配置すると何が起きるか

```console
$ echo "print('I\'m ~/.mysqlsh/plugins/init.py')" > ~/.mysqlsh/plugins/init.py
$ mysqlsh --py 
MySQL Shell 8.0.19

Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates.
Other names may be trademarks of their respective owners.

Type '\help' or '\?' for help; '\quit' to exit.
I'm ~/.mysqlsh/plugins/ext/test/init.py
 MySQL  Py > exit()
```

何も変化は無い
つまり`~/.mysqlsh/plugins/`に`init.py`を配置しても実行されず、サブディレクトリ中の`init.py`が検索されて実行される

## init.py の置き場所に注意

上記から`init.py`の置き場所には注意が必要だとわかる

- `~/.mysqlsh/plugins` に置いた `init.py`は実行されずサブディレクトリを検索する
- `~/.mysqlsh/plugins`のサブディレクトリに`init.py`を置くと実行される
- `~/.mysqlsh/plugins`のサブディレクトリに`init.py`がなければ、さらにそのサブディレクトリ中の`init.py`を検索して実行する
    - `init.py`が見つかればそのディレクトリのサブディレクトリにある`init.py`は無視される

今回はここまで:smile: