Created
May 28, 2017 12:21
-
-
Save tera3939/cf4d04292c59c2dab2df5b5e156cd940 to your computer and use it in GitHub Desktop.
Pythonのimport文をホックするやつ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
from . import music_importer | |
sys.meta_path.append(music_importer.MusicImporter) | |
# このモジュールでimport sysされているため、必ずsys.modulesにsysはある | |
sys.modules['sys'] = sys |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
import time | |
import wave | |
from types import ModuleType | |
from typing import Dict, List, Optional | |
from pathlib import Path | |
from importlib.abc import MetaPathFinder, Loader | |
from importlib.machinery import ModuleSpec | |
import pyaudio | |
ModulePaths = List[str] | |
class AudioModule(ModuleType): | |
def __init__(self, spec: ModuleSpec, path: str): | |
self.__name__ = spec.name | |
self.__loader__ = spec.loader | |
if spec.submodule_search_locations is not None: | |
self.__path__ = spec.submodule_search_locations | |
if spec.parent is not None: | |
self.__package__ = spec.parent | |
self._p = pyaudio.PyAudio() | |
self._wf = wave.open(path, 'rb') | |
self._stream = self._p.open( | |
format=self._p.get_format_from_width(self._wf.getsampwidth()), | |
channels=self._wf.getnchannels(), | |
rate=self._wf.getframerate(), | |
output=True, | |
stream_callback=self._callback | |
) | |
def _callback(self, in_data: "型がわからねえ", frame_count: int, | |
time_info: Dict[str, float], status: int): | |
data = self._wf.readframes(frame_count) | |
return (data, pyaudio.paContinue) | |
def start(self): | |
self._stream.start_stream() | |
while self._stream.is_active(): | |
time.sleep(0.1) | |
def close(self): | |
self._stream.stop_stream() | |
self._wf.close() | |
self._stream.close() | |
self._p.terminate() | |
class MusicImporter(Loader, MetaPathFinder): | |
_root = Path("C:/Users/tera/Music") | |
@classmethod | |
def create_module(self, spec: ModuleSpec) -> Optional[ModuleType]: | |
"""ロード中にモジュールオブジェクトを作成して返す関数 | |
get_code()にspec.nameを渡して実行、返り値をモジュールに組み込み返す | |
ここではModuleTypeに必要な属性を詰め込むことでモジュールを作成する. | |
引数: | |
spec: Finder.find_spec()が返すmodule spec | |
""" | |
abs_path = str(self._root / (spec.name + ".wav")) | |
audio = AudioModule(spec, abs_path) | |
return audio | |
@classmethod | |
def exec_module(self, module: ModuleType): | |
"""モジュールの名前空間で実行 == exec(code, module.__dict__) | |
ここでは動画を再生する | |
""" | |
print(module.__dict__) | |
module.start() | |
module.close() | |
@staticmethod | |
def module_repr(module: ModuleType) -> str: | |
return '<module {!r} (video)>'.format(module.__name__) | |
@classmethod | |
def load_module(self, fullname: str): | |
pass | |
@classmethod | |
def find_spec(cls, fullname: str, path: ModulePaths=None, | |
target: ModuleSpec=None) -> Optional[ModuleSpec]: | |
""" BuiltinImporterではis_builtinでfullnameがbuiltinか判定し、 | |
そうである場合にその名前を持ちoriginがbuiltinであるmodule specを返している。 | |
ここでは/path/to/videoにfullname+拡張子の名前を持つファイルが無ければNoneを、 | |
あればその名前とLoaderとしてVideoMetaPathLoaderを持つmodule specを返す。 | |
引数: | |
fullname: インポートされるモジュールの完全修飾名。 | |
path: インポートされるモジュールの__path__属性の値。 | |
最上位のモジュールの場合はNoneとなる。 | |
target: 後でロードされるターゲットとなる既存のモジュール。 | |
importlib.reload()等によってリロードされるときセットされる。 | |
""" | |
filename = fullname + ".wav" | |
if (cls._root / filename).is_file(): | |
m = ModuleSpec(fullname, cls) | |
return m | |
else: | |
# dirの場合はエラー(気が向いたら対応) | |
raise ImportError | |
@classmethod | |
def find_module(cls, fullname: str, | |
path: ModulePaths=None) -> Optional[Loader]: | |
""" BuiltinImporterではclsのfind_spec()を呼んで返り値のloader属性を返している。 | |
""" | |
spec = cls.find_spec(fullname, path) | |
return spec.loader if spec is not None else None | |
if __name__ == '__main__': | |
import sys | |
sys.meta_path.append(MusicImporter) | |
import music_name |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment