thirose’s blog

openstackやpythonなどなど

python3.5.0だけtracebackの返値が違っていたバグに当たった

今回はたまたま、openstackのnovaclientを使っていたらバグを発見しました。
その時のログはこちら -> This report is written about novaclient. · GitHub

バグの内容

python3.6を普段使ってるけど、もともとpython3.5.0で動いていたスクリプトで、普段と違う何かエラーが出てるなーというところから発見しました。
python3.5.0だけ、traceback.extract_stackで返ってくるlistの最後にtraceback.extrace_stackが入っていて、

filename, _lineno, _name, line = traceback.extract_stack()[-4]

の[-4] だと欲しいclass nameが取れない状態でした。 該当箇所 -> python-novaclient/api_versions.py at master · openstack/python-novaclient · GitHub

python3.5.0では、[-5] だったら問題なく動きます。
なので、

$ cat api_version.patch
--- api_version.py 2018-04-25 13:19:11.999263977 +0900
+++ api_version.py.change 2018-04-25 13:21:52.732243109 +0900
@@ -346,7 +346,11 @@
    # ("im_class" property does not exist at that moment)
    # we need to write own logic to obtain the full function name which
    # include module name, owner name(optional) and just function name.
- filename, _lineno, _name, line = traceback.extract_stack()[-4]
+ traceback_data = traceback.extract_stack()
+ for tl in traceback_list[::-1]:
+ if tl[2] == '<module>':
+ filename, _lineno, _name, line = tl
+ break
    module, _file_extension = os.path.splitext(filename)
    module = module.replace("/", ".")
    if module.endswith(func.__module__):

という修正をすれば動きます。
これはpython 3.5.0のみで起こるエラーで3.5.1が出た時に修正されてます。
ただ、novaclientのような書き方をしていると、また別の機会に同じようなエラーがでる可能性をもっています。

以下、検証に使ったもろもろをまとめています。

検証につかったスクリプト

# -*- coding: utf-8 -*-

import sys
from novaclient import client as nova_client
from keystoneclient.v3 import client
from keystoneauth1 import session
from keystoneauth1.identity import v3

def get_keystone_session():
    params = {
        'auth_url': KEYSTONE_ENDPOINT,
        'username': USERNAME,
        'password': PASSWORD,
        'user_domain_name': 'default',
        'project_name': PROJECT_NAME,
        'project_domain_name': 'default',
    }
    auth = v3.Password(**params)
    sess = session.Session(auth=auth)
    return sess

def update_quota(sess, server):
    project_id = PROJECT_ID
    nova = nova_client.Client('2.1', session=sess)
    print(nova.quotas.get(project_id))
    nova.quotas.update(project_id, instances=100)
    print(nova.quotas.get(project_id))
    return 'success'

if __name__ == '__main__':
    argvs = sys.argv
    sess = get_keystone_session()
    update_quota(sess, INSTANCE_ID)

各バーションのtraceback. extractのデバック結果

python 3.5.0だけ、classの情報が[-4]番目に入ってないことがわかります。

python2.7.14

[('nova_script.py', 60, '<module>', "print(get_instance(sess, '81be1886-cf7b-4b11-9208-e847fe5a9fe9'))"), ('nova_script.py', 39, 'get_instance', "nova = nova_client.Client('2.1', session=sess)"), ('/home/www/.pyenv/versions/2.7.14/lib/python2.7/site-packages/novaclient/client.py', 330, 'Client', 'api_version, client_class = _get_client_class_and_version(version)'), ('/home/www/.pyenv/versions/2.7.14/lib/python2.7/site-packages/novaclient/client.py', 224, '_get_client_class_and_version', '"novaclient.v%s.client.Client" % version.ver_major)'), ('/home/www/.pyenv/versions/2.7.14/lib/python2.7/site-packages/oslo_utils/importutils.py', 30, 'import_class', '__import__(mod_str)'),
('/home/www/.pyenv/versions/2.7.14/lib/python2.7/site-packages/novaclient/v2/__init__.py', 16, '<module>', 'from novaclient.v2.client import Client # noqa'),
('/home/www/.pyenv/versions/2.7.14/lib/python2.7/site-packages/novaclient/v2/client.py', 47, '<module>', 'from novaclient.v2 import volumes'),
('/home/www/.pyenv/versions/2.7.14/lib/python2.7/site-packages/novaclient/v2/volumes.py', 36, '<module>', 'class VolumeManager(base.Manager):'),
('/home/www/.pyenv/versions/2.7.14/lib/python2.7/site-packages/novaclient/v2/volumes.py', 60, 'VolumeManager', 'tag=None):'),
('/home/www/.pyenv/versions/2.7.14/lib/python2.7/site-packages/novaclient/api_versions.py', 382, 'decor', 'name = _get_function_name(func)'),
('/home/www/.pyenv/versions/2.7.14/lib/python2.7/site-packages/novaclient/api_versions.py', 350, '_get_function_name', 'print traceback.extract_stack()')]

python3.4.0

[('nova_script.py', 60, '<module>', "print(get_instance(sess, '81be1886-cf7b-4b11-9208-e847fe5a9fe9'))"), ('nova_script.py', 39, 'get_instance', "nova = nova_client.Client('2.1', session=sess)"), ('/home/www/.pyenv/versions/3.4.0/lib/python3.4/site-packages/novaclient/client.py', 330, 'Client', 'api_version, client_class = _get_client_class_and_version(version)'), ('/home/www/.pyenv/versions/3.4.0/lib/python3.4/site-packages/novaclient/client.py', 224, '_get_client_class_and_version', '"novaclient.v%s.client.Client" % version.ver_major)'), ('/home/www/.pyenv/versions/3.4.0/lib/python3.4/site-packages/oslo_utils/importutils.py', 30, 'import_class', '__import__(mod_str)'), ('<frozen importlib._bootstrap>', 2214, '_find_and_load', None), ('<frozen importlib._bootstrap>', 2189, '_find_and_load_unlocked', None), ('<frozen importlib._bootstrap>', 321, '_call_with_frames_removed', None), ('<frozen importlib._bootstrap>', 2214, '_find_and_load', None), ('<frozen importlib._bootstrap>', 2203, '_find_and_load_unlocked', None), ('<frozen importlib._bootstrap>', 1200, '_load_unlocked', None), ('<frozen importlib._bootstrap>', 1129, '_exec', None), ('<frozen importlib._bootstrap>', 1448, 'exec_module', None), ('<frozen importlib._bootstrap>', 321, '_call_with_frames_removed', None), ('/home/www/.pyenv/versions/3.4.0/lib/python3.4/site-packages/novaclient/v2/__init__.py', 16, '<module>', 'from novaclient.v2.client import Client # noqa'), ('<frozen importlib._bootstrap>', 2214, '_find_and_load', None), ('<frozen importlib._bootstrap>', 2203, '_find_and_load_unlocked', None), ('<frozen importlib._bootstrap>', 1200, '_load_unlocked', None), ('<frozen importlib._bootstrap>', 1129, '_exec', None), ('<frozen importlib._bootstrap>', 1448, 'exec_module', None), ('<frozen importlib._bootstrap>', 321, '_call_with_frames_removed', None), ('/home/www/.pyenv/versions/3.4.0/lib/python3.4/site-packages/novaclient/v2/client.py', 47, '<module>', 'from novaclient.v2 import volumes'), ('<frozen importlib._bootstrap>', 2261, '_handle_fromlist', None), ('<frozen importlib._bootstrap>', 321, '_call_with_frames_removed', None), ('<frozen importlib._bootstrap>', 2214, '_find_and_load', None), ('<frozen importlib._bootstrap>', 2203, '_find_and_load_unlocked', None), ('<frozen importlib._bootstrap>', 1200, '_load_unlocked', None), ('<frozen importlib._bootstrap>', 1129, '_exec', None), ('<frozen importlib._bootstrap>', 1448, 'exec_module', None), ('<frozen importlib._bootstrap>', 321, '_call_with_frames_removed', None),
('/home/www/.pyenv/versions/3.4.0/lib/python3.4/site-packages/novaclient/v2/volumes.py', 36, '<module>', 'class VolumeManager(base.Manager):'),
('/home/www/.pyenv/versions/3.4.0/lib/python3.4/site-packages/novaclient/v2/volumes.py', 60, 'VolumeManager', 'tag=None):'),
('/home/www/.pyenv/versions/3.4.0/lib/python3.4/site-packages/novaclient/api_versions.py', 382, 'decor', 'name = _get_function_name(func)'),
('/home/www/.pyenv/versions/3.4.0/lib/python3.4/site-packages/novaclient/api_versions.py', 350, '_get_function_name', 'print(traceback.extract_stack())')]

python3.5.0

[<FrameSummary file nova_script.py, line 60 in <module>>, <FrameSummary file nova_script.py, line 39 in get_instance>, <FrameSummary file /home/www/.pyenv/versions/3.5.0/lib/python3.5/site-packages/novaclient/client.py, line 330 in Client>, <FrameSummary file /home/www/.pyenv/versions/3.5.0/lib/python3.5/site-packages/novaclient/client.py, line 224 in _get_client_class_and_version>, <FrameSummary file /home/www/.pyenv/versions/3.5.0/lib/python3.5/site-packages/oslo_utils/importutils.py, line 30 in import_class>, <FrameSummary file <frozen importlib._bootstrap>, line 969 in _find_and_load>, <FrameSummary file <frozen importlib._bootstrap>, line 944 in _find_and_load_unlocked>, <FrameSummary file <frozen importlib._bootstrap>, line 222 in _call_with_frames_removed>, <FrameSummary file <frozen importlib._bootstrap>, line 969 in _find_and_load>, <FrameSummary file <frozen importlib._bootstrap>, line 958 in _find_and_load_unlocked>, <FrameSummary file <frozen importlib._bootstrap>, line 673 in _load_unlocked>, <FrameSummary file <frozen importlib._bootstrap_external>, line 662 in exec_module>, <FrameSummary file <frozen importlib._bootstrap>, line 222 in _call_with_frames_removed>, <FrameSummary file /home/www/.pyenv/versions/3.5.0/lib/python3.5/site-packages/novaclient/v2/__init__.py, line 16 in <module>>, <FrameSummary file <frozen importlib._bootstrap>, line 969 in _find_and_load>, <FrameSummary file <frozen importlib._bootstrap>, line 958 in _find_and_load_unlocked>, <FrameSummary file <frozen importlib._bootstrap>, line 673 in _load_unlocked>, <FrameSummary file <frozen importlib._bootstrap_external>, line 662 in exec_module>, <FrameSummary file <frozen importlib._bootstrap>, line 222 in _call_with_frames_removed>, <FrameSummary file /home/www/.pyenv/versions/3.5.0/lib/python3.5/site-packages/novaclient/v2/client.py, line 47 in <module>>, <FrameSummary file <frozen importlib._bootstrap>, line 1016 in _handle_fromlist>, <FrameSummary file <frozen importlib._bootstrap>, line 222 in _call_with_frames_removed>, <FrameSummary file <frozen importlib._bootstrap>, line 969 in _find_and_load>, <FrameSummary file <frozen importlib._bootstrap>, line 958 in _find_and_load_unlocked>, <FrameSummary file <frozen importlib._bootstrap>, line 673 in _load_unlocked>, <FrameSummary file <frozen importlib._bootstrap_external>, line 662 in exec_module>, <FrameSummary file <frozen importlib._bootstrap>, line 222 in _call_with_frames_removed>,
<FrameSummary file /home/www/.pyenv/versions/3.5.0/lib/python3.5/site-packages/novaclient/v2/volumes.py, line 36 in <module>>,
<FrameSummary file /home/www/.pyenv/versions/3.5.0/lib/python3.5/site-packages/novaclient/v2/volumes.py, line 60 in VolumeManager>,
<FrameSummary file /home/www/.pyenv/versions/3.5.0/lib/python3.5/site-packages/novaclient/api_versions.py, line 386 in decor>,
<FrameSummary file /home/www/.pyenv/versions/3.5.0/lib/python3.5/site-packages/novaclient/api_versions.py, line 349 in _get_function_name>,
<FrameSummary file /home/www/.pyenv/versions/3.5.0/lib/python3.5/traceback.py, line 201 in extract_stack>]

python3.5.1

[<FrameSummary file nova_script.py, line 60 in <module>>, <FrameSummary file nova_script.py, line 39 in get_instance>, <FrameSummary file /home/www/.pyenv/versions/3.5.1/lib/python3.5/site-packages/novaclient/client.py, line 330 in Client>, <FrameSummary file /home/www/.pyenv/versions/3.5.1/lib/python3.5/site-packages/novaclient/client.py, line 224 in _get_client_class_and_version>, <FrameSummary file /home/www/.pyenv/versions/3.5.1/lib/python3.5/site-packages/oslo_utils/importutils.py, line 30 in import_class>, <FrameSummary file <frozen importlib._bootstrap>, line 969 in _find_and_load>, <FrameSummary file <frozen importlib._bootstrap>, line 944 in _find_and_load_unlocked>, <FrameSummary file <frozen importlib._bootstrap>, line 222 in _call_with_frames_removed>, <FrameSummary file <frozen importlib._bootstrap>, line 969 in _find_and_load>, <FrameSummary file <frozen importlib._bootstrap>, line 958 in _find_and_load_unlocked>, <FrameSummary file <frozen importlib._bootstrap>, line 673 in _load_unlocked>, <FrameSummary file <frozen importlib._bootstrap_external>, line 662 in exec_module>, <FrameSummary file <frozen importlib._bootstrap>, line 222 in _call_with_frames_removed>, <FrameSummary file /home/www/.pyenv/versions/3.5.1/lib/python3.5/site-packages/novaclient/v2/__init__.py, line 16 in <module>>, <FrameSummary file <frozen importlib._bootstrap>, line 969 in _find_and_load>, <FrameSummary file <frozen importlib._bootstrap>, line 958 in _find_and_load_unlocked>, <FrameSummary file <frozen importlib._bootstrap>, line 673 in _load_unlocked>, <FrameSummary file <frozen importlib._bootstrap_external>, line 662 in exec_module>, <FrameSummary file <frozen importlib._bootstrap>, line 222 in _call_with_frames_removed>, <FrameSummary file /home/www/.pyenv/versions/3.5.1/lib/python3.5/site-packages/novaclient/v2/client.py, line 47 in <module>>, <FrameSummary file <frozen importlib._bootstrap>, line 1016 in _handle_fromlist>, <FrameSummary file <frozen importlib._bootstrap>, line 222 in _call_with_frames_removed>, <FrameSummary file <frozen importlib._bootstrap>, line 969 in _find_and_load>, <FrameSummary file <frozen importlib._bootstrap>, line 958 in _find_and_load_unlocked>, <FrameSummary file <frozen importlib._bootstrap>, line 673 in _load_unlocked>, <FrameSummary file <frozen importlib._bootstrap_external>, line 662 in exec_module>,
<FrameSummary file <frozen importlib._bootstrap>, line 222 in _call_with_frames_removed>,
<FrameSummary file /home/www/.pyenv/versions/3.5.1/lib/python3.5/site-packages/novaclient/v2/volumes.py, line 36 in <module>>,
<FrameSummary file /home/www/.pyenv/versions/3.5.1/lib/python3.5/site-packages/novaclient/v2/volumes.py, line 60 in VolumeManager>,
<FrameSummary file /home/www/.pyenv/versions/3.5.1/lib/python3.5/site-packages/novaclient/api_versions.py, line 382 in decor>,
<FrameSummary file /home/www/.pyenv/versions/3.5.1/lib/python3.5/site-packages/novaclient/api_versions.py, line 350 in _get_function_name>]

python3.5.5

[<FrameSummary file nova_script.py, line 60 in <module>>, <FrameSummary file nova_script.py, line 39 in get_instance>, <FrameSummary file /home/www/.pyenv/versions/3.5.5/lib/python3.5/site-packages/novaclient/client.py, line 330 in Client>, <FrameSummary file /home/www/.pyenv/versions/3.5.5/lib/python3.5/site-packages/novaclient/client.py, line 224 in _get_client_class_and_version>, <FrameSummary file /home/www/.pyenv/versions/3.5.5/lib/python3.5/site-packages/oslo_utils/importutils.py, line 30 in import_class>, <FrameSummary file <frozen importlib._bootstrap>, line 968 in _find_and_load>, <FrameSummary file <frozen importlib._bootstrap>, line 943 in _find_and_load_unlocked>, <FrameSummary file <frozen importlib._bootstrap>, line 222 in _call_with_frames_removed>, <FrameSummary file <frozen importlib._bootstrap>, line 968 in _find_and_load>, <FrameSummary file <frozen importlib._bootstrap>, line 957 in _find_and_load_unlocked>, <FrameSummary file <frozen importlib._bootstrap>, line 673 in _load_unlocked>, <FrameSummary file <frozen importlib._bootstrap_external>, line 697 in exec_module>, <FrameSummary file <frozen importlib._bootstrap>, line 222 in _call_with_frames_removed>, <FrameSummary file /home/www/.pyenv/versions/3.5.5/lib/python3.5/site-packages/novaclient/v2/__init__.py, line 16 in <module>>, <FrameSummary file <frozen importlib._bootstrap>, line 968 in _find_and_load>, <FrameSummary file <frozen importlib._bootstrap>, line 957 in _find_and_load_unlocked>, <FrameSummary file <frozen importlib._bootstrap>, line 673 in _load_unlocked>, <FrameSummary file <frozen importlib._bootstrap_external>, line 697 in exec_module>, <FrameSummary file <frozen importlib._bootstrap>, line 222 in _call_with_frames_removed>, <FrameSummary file /home/www/.pyenv/versions/3.5.5/lib/python3.5/site-packages/novaclient/v2/client.py, line 47 in <module>>, <FrameSummary file <frozen importlib._bootstrap>, line 1015 in _handle_fromlist>, <FrameSummary file <frozen importlib._bootstrap>, line 222 in _call_with_frames_removed>, <FrameSummary file <frozen importlib._bootstrap>, line 968 in _find_and_load>,
<FrameSummary file <frozen importlib._bootstrap>, line 957 in _find_and_load_unlocked>,
<FrameSummary file <frozen importlib._bootstrap>, line 673 in _load_unlocked>,
<FrameSummary file <frozen importlib._bootstrap_external>, line 697 in exec_module>,
<FrameSummary file <frozen importlib._bootstrap>, line 222 in _call_with_frames_removed>,
<FrameSummary file /home/www/.pyenv/versions/3.5.5/lib/python3.5/site-packages/novaclient/v2/volumes.py, line 36 in <module>>,
<FrameSummary file /home/www/.pyenv/versions/3.5.5/lib/python3.5/site-packages/novaclient/v2/volumes.py, line 60 in VolumeManager>,
<FrameSummary file /home/www/.pyenv/versions/3.5.5/lib/python3.5/site-packages/novaclient/api_versions.py, line 382 in decor>,
<FrameSummary file /home/www/.pyenv/versions/3.5.5/lib/python3.5/site-packages/novaclient/api_versions.py, line 350 in _get_function_name>]

python3.6.4

[<FrameSummary file nova_script.py, line 60 in <module>>, <FrameSummary file nova_script.py, line 39 in get_instance>, <FrameSummary file /home/www/.pyenv/versions/3.6.4/lib/python3.6/site-packages/novaclient/client.py, line 330 in Client>, <FrameSummary file /home/www/.pyenv/versions/3.6.4/lib/python3.6/site-packages/novaclient/client.py, line 224 in _get_client_class_and_version>, <FrameSummary file /home/www/.pyenv/versions/3.6.4/lib/python3.6/site-packages/oslo_utils/importutils.py, line 30 in import_class>, <FrameSummary file <frozen importlib._bootstrap>, line 971 in _find_and_load>, <FrameSummary file <frozen importlib._bootstrap>, line 941 in _find_and_load_unlocked>, <FrameSummary file <frozen importlib._bootstrap>, line 219 in _call_with_frames_removed>, <FrameSummary file <frozen importlib._bootstrap>, line 971 in _find_and_load>, <FrameSummary file <frozen importlib._bootstrap>, line 955 in _find_and_load_unlocked>, <FrameSummary file <frozen importlib._bootstrap>, line 665 in _load_unlocked>, <FrameSummary file <frozen importlib._bootstrap_external>, line 678 in exec_module>, <FrameSummary file <frozen importlib._bootstrap>, line 219 in _call_with_frames_removed>, <FrameSummary file /home/www/.pyenv/versions/3.6.4/lib/python3.6/site-packages/novaclient/v2/__init__.py, line 16 in <module>>, <FrameSummary file <frozen importlib._bootstrap>, line 971 in _find_and_load>, <FrameSummary file <frozen importlib._bootstrap>, line 955 in _find_and_load_unlocked>, <FrameSummary file <frozen importlib._bootstrap>, line 665 in _load_unlocked>, <FrameSummary file <frozen importlib._bootstrap_external>, line 678 in exec_module>, <FrameSummary file <frozen importlib._bootstrap>, line 219 in _call_with_frames_removed>, <FrameSummary file /home/www/.pyenv/versions/3.6.4/lib/python3.6/site-packages/novaclient/v2/client.py, line 46 in <module>>, <FrameSummary file <frozen importlib._bootstrap>, line 1023 in _handle_fromlist>, <FrameSummary file <frozen importlib._bootstrap>, line 219 in _call_with_frames_removed>, <FrameSummary file <frozen importlib._bootstrap>, line 971 in _find_and_load>, <FrameSummary file <frozen importlib._bootstrap>, line 955 in _find_and_load_unlocked>, <FrameSummary file <frozen importlib._bootstrap>, line 665 in _load_unlocked>, <FrameSummary file <frozen importlib._bootstrap_external>, line 678 in exec_module>,
<FrameSummary file <frozen importlib._bootstrap>, line 219 in _call_with_frames_removed>,
<FrameSummary file /home/www/.pyenv/versions/3.6.4/lib/python3.6/site-packages/novaclient/v2/volumes.py, line 36 in <module>>,
<FrameSummary file /home/www/.pyenv/versions/3.6.4/lib/python3.6/site-packages/novaclient/v2/volumes.py, line 60 in VolumeManager>,
<FrameSummary file /home/www/.pyenv/versions/3.6.4/lib/python3.6/site-packages/novaclient/api_versions.py, line 382 in decor>,
<FrameSummary file /home/www/.pyenv/versions/3.6.4/lib/python3.6/site-packages/novaclient/api_versions.py, line 350 in _get_function_name>]