pythonのaws-sdkのboto3を使ってライブラリのコードをちゃんと読んでみる①
boto3とは?
pythonのaws-sdkです。
他の言語のaws-sdkは大体aws-sdk
みたいな名前で公開されていることが多いのですが、なぜかpythonだけboto3
っていう名前です。
個人的にはこのドキュメントすごい読みやすくて好きなライブラリです。
awsはapiの設計がちゃんとしててわかりやすいっていうイメージがあります。
あと自分が使い慣れているというものあって、このライブラリを使ってちゃんとコードを読めるようになっていこうと思います。(今までは雰囲気でやっていた。。。)(雰囲気でやっている人も多いはず。)
ドキュメントを読む
一番シンプルそうな、EC2のclientのdescribe_instances()メソッドを例にして見てみます。
まずはドキュメントを見てみます。
response = client.describe_instances( Filters=[ { 'Name': 'string', 'Values': [ 'string', ] }, ], InstanceIds=[ 'string', ], DryRun=True|False, MaxResults=123, NextToken='string' )
この下のparamsの説明でREQUIREDなparamはないので、一旦シンプルに全取得してみます。
>>> import boto3 >>> client = boto3.client("ec2") >>> response = client.describe_instances() >>> print(response)
これでEC2の情報が取得できました。(ただし、aws config
コマンドで事前にprofileなどは設定しているものとします。)
基本このように、ドキュメントがしっかりしているライブラリはそれ道理にやればうまくいきますね。
(AWSレベルになるとソースコード読む必要性に駆られることなさそう)
ソースコードを読む
まずは、この一覧の中のboto3っていうディレクトリ配下にソースコードがあるのかな?(これも雰囲気でしかわからないレベル)
正直どこにあるのかよくわからない。
じゃあ実際にpythonから使うときはどうやって読み込まれるのか。
pipでinstallしたライブラリの保存場所とは。
Python Tips:ライブラリ・モジュールの場所を調べたい - Life with Python
これで調べられると。
>>> import boto3 >>> print(boto3.__file__) /Users/my0shym/.anyenv/envs/pyenv/versions/3.6.0/lib/python3.6/site-packages/boto3/__init__.py
そういえば、anyenvとか使ってたな。なんのパッケージ管理システムを使ってたのかもはやわからなくなっていた。
$ cd /Users/my0shym/.anyenv/envs/pyenv/versions/3.6.0/lib/python3.6/site-packages/boto3/ $ ls -l total 72 -rw-r--r-- 1 my0shym staff 3338 9 12 2018 __init__.py drwxr-xr-x 7 my0shym staff 224 9 12 2018 __pycache__ -rw-r--r-- 1 my0shym staff 1490 9 12 2018 compat.py drwxr-xr-x 12 my0shym staff 384 9 12 2018 data drwxr-xr-x 16 my0shym staff 512 9 12 2018 docs drwxr-xr-x 8 my0shym staff 256 9 12 2018 dynamodb drwxr-xr-x 6 my0shym staff 192 9 12 2018 ec2 drwxr-xr-x 4 my0shym staff 128 9 12 2018 examples -rw-r--r-- 1 my0shym staff 3993 9 12 2018 exceptions.py drwxr-xr-x 11 my0shym staff 352 9 12 2018 resources drwxr-xr-x 6 my0shym staff 192 9 12 2018 s3 -rw-r--r-- 1 my0shym staff 19614 9 12 2018 session.py -rw-r--r-- 1 my0shym staff 3095 9 12 2018 utils.py
これはboto3ディレクトリの下の構造と一緒だ。これでいいのだった。
ライブラリをimportするとまずinit.pyが読み込まれる。
init.pyは110行程度のコード。
# Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"). You # may not use this file except in compliance with the License. A copy of # the License is located at # # http://aws.amazon.com/apache2.0/ # # or in the "license" file accompanying this file. This file is # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. import logging from boto3.session import Session __author__ = 'Amazon Web Services' __version__ = '1.9.2' # The default Boto3 session; autoloaded when needed. DEFAULT_SESSION = None def setup_default_session(**kwargs): """ Set up a default session, passing through any parameters to the session constructor. There is no need to call this unless you wish to pass custom parameters, because a default session will be created for you. """ global DEFAULT_SESSION DEFAULT_SESSION = Session(**kwargs) def set_stream_logger(name='boto3', level=logging.DEBUG, format_string=None): """ Add a stream handler for the given name and level to the logging module. By default, this logs all boto3 messages to ``stdout``. >>> import boto3 >>> boto3.set_stream_logger('boto3.resources', logging.INFO) For debugging purposes a good choice is to set the stream logger to ``''`` which is equivalent to saying "log everything". .. WARNING:: Be aware that when logging anything from ``'botocore'`` the full wire trace will appear in your logs. If your payloads contain sensitive data this should not be used in production. :type name: string :param name: Log name :type level: int :param level: Logging level, e.g. ``logging.INFO`` :type format_string: str :param format_string: Log message format """ if format_string is None: format_string = "%(asctime)s %(name)s [%(levelname)s] %(message)s" logger = logging.getLogger(name) logger.setLevel(level) handler = logging.StreamHandler() handler.setLevel(level) formatter = logging.Formatter(format_string) handler.setFormatter(formatter) logger.addHandler(handler) def _get_default_session(): """ Get the default session, creating one if needed. :rtype: :py:class:`~boto3.session.Session` :return: The default session """ if DEFAULT_SESSION is None: setup_default_session() return DEFAULT_SESSION def client(*args, **kwargs): """ Create a low-level service client by name using the default session. See :py:meth:`boto3.session.Session.client`. """ return _get_default_session().client(*args, **kwargs) def resource(*args, **kwargs): """ Create a resource service client by name using the default session. See :py:meth:`boto3.session.Session.resource`. """ return _get_default_session().resource(*args, **kwargs) # Set up logging to ``/dev/null`` like a library is supposed to. # http://docs.python.org/3.3/howto/logging.html#configuring-logging-for-a-library class NullHandler(logging.Handler): def emit(self, record): pass logging.getLogger('boto3').addHandler(NullHandler())
client関連の部分だけ見てみます。
import logging from boto3.session import Session __author__ = 'Amazon Web Services' __version__ = '1.9.2' # The default Boto3 session; autoloaded when needed. DEFAULT_SESSION = None
これが呼び出されます。
def client(*args, **kwargs): """ Create a low-level service client by name using the default session. See :py:meth:`boto3.session.Session.client`. """ return _get_default_session().client(*args, **kwargs)
def _get_default_session(): """ Get the default session, creating one if needed. :rtype: :py:class:`~boto3.session.Session` :return: The default session """ if DEFAULT_SESSION is None: setup_default_session() return DEFAULT_SESSION
def setup_default_session(**kwargs): """ Set up a default session, passing through any parameters to the session constructor. There is no need to call this unless you wish to pass custom parameters, because a default session will be created for you. """ global DEFAULT_SESSION DEFAULT_SESSION = Session(**kwargs)
ここまでででDEFAULT_SESSIONにSessionモジュールが読み込まれて、それに対してclient(*args, **kwargs)
メソッド
def client(self, service_name, region_name=None, api_version=None, use_ssl=True, verify=None, endpoint_url=None, aws_access_key_id=None, aws_secret_access_key=None, aws_session_token=None, config=None): return self._session.create_client( service_name, region_name=region_name, api_version=api_version, use_ssl=use_ssl, verify=verify, endpoint_url=endpoint_url, aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key, aws_session_token=aws_session_token, config=config)
self._session.create_client
は以下より定義されている。
def __init__(self, aws_access_key_id=None, aws_secret_access_key=None, aws_session_token=None, region_name=None, botocore_session=None, profile_name=None): if botocore_session is not None: self._session = botocore_session else: # Create a new default session self._session = botocore.session.get_session()
つまりbotocore.session.get_session()
から。
botocore.session.get_session()
のbotocoreのソースコードはどこにあるのか?
調べようと思ったところでタイムアップになってしまった。
続きは次回、あるいは更新していこうと思います。