KAWAHARA-souta / alma-sbom

AlmaLinux OS SBOM data management utility.
GNU General Public License v3.0
0 stars 0 forks source link

file-magic(python3-file-magic)とimmudb_wapperの相性問題?? #9

Open KAWAHARA-souta opened 3 weeks ago

KAWAHARA-souta commented 3 weeks ago

Reproducer:

test_python3-file-magic.py

#!/usr/bin/env python3
# -*- mode:python; coding:utf-8; -*-

import magic
from typing import List

### error occured !!!!!
from immudb_wrapper import ImmudbWrapper

class Person:
    name: str
    def __init__(self, name):
        self,name=name

### error not occured
# def ret_one_Person(name) -> Person:
#     return Person(name)

### error not occured
# def ret_list_str(cls) -> List[str]:
#     return [
#         foo for cls in cls.foo
#     ]

### error occured !!!!!
def ret_list_Person(cls) -> List[Person]:
    return [
        Person(name) for name in cls.name
    ]

file_magic = magic.detect_from_filename(__file__)
print(f'{__file__} mime_type: {file_magic.mime_type}')

step to reproduce

 $ python3 -m venv env
 $ source env/bin/activate
(env) $ python -m pip install file-magic git+https://github.com/AlmaLinux/immudb-wrapper.git@0.1.5#egg=immudb_wrapper
(env) $ python test_python3-file-magic.py
/home/khwarizmi/work/python3-file-magic/test_python3-file-magic.py mime_type: text/x-script.python
Exception ignored in: <function MagicDetect.__del__ at 0x7f3ef4d45d30>
Traceback (most recent call last):
  File "/home/khwarizmi/work/python3-file-magic/env/lib64/python3.9/site-packages/magic.py", line 308, in __del__
  File "/home/khwarizmi/work/python3-file-magic/env/lib64/python3.9/site-packages/magic.py", line 135, in close
TypeError: 'NoneType' object is not callable

このエラーが発生する条件

  1. immudb_wrapperがインポートされていること
  2. 独自定義クラスのListを返す関数が定義されていること(この関数が呼び出されるかどうかはエラーの発生には関係ない)
KAWAHARA-souta commented 3 weeks ago

immudb-wrapper: https://github.com/AlmaLinux/immudb-wrapper file-magic(python3-file-magic): https://pypi.org/project/file-magic/ https://www.darwinsys.com/file/ (ソースコードは http://ftp.astron.com/pub/file/)

KAWAHARA-souta commented 3 weeks ago

detect_from_filenameはFileMagicを返す. FileMagicはnamedtupleで定義されている.

     62 FileMagic = namedtuple('FileMagic', ('mime_type', 'encoding', 'name'))
      :
    321 def _create_filemagic(mime_detected, type_detected):
    322     try:
    323         mime_type, mime_encoding = mime_detected.split('; ')
    324     except ValueError:
    325         raise ValueError(mime_detected)
    326
    327     return FileMagic(name=type_detected, mime_type=mime_type,
    328                      encoding=mime_encoding.replace('charset=', ''))
    329
    330
    331 def detect_from_filename(filename):
    332     '''Detect mime type, encoding and file type from a filename
    333
    334     Returns a `FileMagic` namedtuple.
    335     '''
    336     x = _detect_make()
    337     return _create_filemagic(x.mime_magic.file(filename),
    338                              x.none_magic.file(filename))
KAWAHARA-souta commented 3 weeks ago

エラーメッセージは,MagicDetectのデストラクタが呼びだされたときでほぼ間違いないと思う. detect_from_filenameの中でも呼び出されている_detect_makeはMagicDetectのインスタンスを返す. たぶんここで生成されたMagicDetectインスタンスの掃除でなにか起こっている.

ところで,312行目でthreadingを動かしているので,これたぶんマルチスレッド? pdbでステップ実行すると問題は発生しないので,マルチスレッドの時のダブルフリーの問題とか? ただ,そうだとしても,なぜimmudb_wrapperをインポートした時しかこれが発生しないのかが結構疑問

    285 class MagicDetect(object):
    286     def __init__(self):
    287         self.mime_magic = open(MAGIC_MIME)
    288         if self.mime_magic is None:
    289             raise error
    290         if self.mime_magic.load() == -1:
    291             self.mime_magic.close()
    292             self.mime_magic = None
    293             raise error
    294         self.none_magic = open(MAGIC_NONE)
    295         if self.none_magic is None:
    296             self.mime_magic.close()
    297             self.mime_magic = None
    298             raise error
    299         if self.none_magic.load() == -1:
    300             self.none_magic.close()
    301             self.none_magic = None
    302             self.mime_magic.close()
    303             self.mime_magic = None
    304             raise error
    305
    306     def __del__(self):
    307         if self.mime_magic is not None:
    308             self.mime_magic.close()
    309         if self.none_magic is not None:
    310             self.none_magic.close()
    311
    312 threadlocal = threading.local()
    313
    314 def _detect_make():
    315     v = getattr(threadlocal, "magic_instance", None)
    316     if v is None:
    317         v = MagicDetect()
    318         setattr(threadlocal, "magic_instance", v)
    319     return v
KAWAHARA-souta commented 3 weeks ago

threading.local() はスレッド固有の変数を定義する スレッド固有のMagicDetectインスタンスをthreadlocal.magic_instanceに保管しているという感じかな

    312 threadlocal = threading.local()
    313
    314 def _detect_make():
    315     v = getattr(threadlocal, "magic_instance", None)
    316     if v is None:
    317         v = MagicDetect()
    318         setattr(threadlocal, "magic_instance", v)
    319     return v