"importlib" --- "import" の実装
*******************************

Added in version 3.1.

**ソースコード:** Lib/importlib/__init__.py

======================================================================


はじめに
========

The purpose of the "importlib" package is three-fold.

1つ目は Python ソースコード中にある "import" 文の(そして、拡張として、
"__import__()" 関数の)実装を提供することです。このパッケージは
"import" 文の、どの Python インタープリターでも動作する実装を提供しま
す。また、 Python 以外の言語で実装されたどの実装よりも把握しやすい実装
を提供します。

2つ目の目的は、このパッケージが公開している "import" を実装するための
要素を利用して、(*インポーター* として知られる) インポートプロセスで動
作するカスタムのオブジェクトを実装しやすくすることです。

Three, the package contains modules exposing additional functionality
for managing aspects of Python packages:

* "importlib.metadata" presents access to metadata from third-party
  distributions.

* "importlib.resources" provides routines for accessing non-code
  "resources" from Python packages.

参考:

  import 文
     "import" 文の言語リファレンス。

  Packages specification
     パッケージの元の仕様。幾つかの動作はこの仕様が書かれた頃から変更
     されています (例: "sys.modules" で "None" に基づくリダイレクト)。

  "__import__()" 関数
     "import" 文はこの関数のシンタックスシュガーです。

  sys.path モジュール検索パスの初期化
     The initialization of "sys.path".

  **PEP 235**
     大文字小文字を区別しないプラットフォームでのインポート

  **PEP 263**
     Python のソースコードのエンコーディング

  **PEP 302**
     新しいインポートフック

  **PEP 328**
     複数行のインポートと、絶対/相対インポート

  **PEP 366**
     main モジュールの明示的な相対インポート

  **PEP 420**
     暗黙的な名前空間パッケージ

  **PEP 451**
     インポートシステムのための ModuleSpec 型

  **PEP 488**
     PYO ファイルの撤廃

  **PEP 489**
     複数フェーズでの拡張モジュールの初期化

  **PEP 552**
     決定論的 pyc

  **PEP 3120**
     デフォルトのソースエンコーディングとして UTF-8 を使用

  **PEP 3147**
     PYC リポジトリディレクトリ


関数
====

importlib.__import__(name, globals=None, locals=None, fromlist=(), level=0)

   組み込みの "__import__()" 関数の実装です。

   注釈:

     プログラムからモジュールをインポートする場合はこの関数の代わりに
     "import_module()" を使ってください。

importlib.import_module(name, package=None)

   モジュールをインポートします。*name* 引数は、インポートするモジュー
   ルを絶対または相対表現 (例えば "pkg.mod" または "..mod") で指定しま
   す。name が相対表現で与えられたら、*package* 引数を、パッケージ名を
   解決するためのアンカーとなるパッケージの名前に設定する必要がありま
   す (例えば "import_module('..mod', 'pkg.subpkg')" は "pkg.mod" をイ
   ンポートします)。

   "import_module()" 関数は "importlib.__import__()" を単純化するラッ
   パーとして働きます。つまり、この関数のすべての意味は
   "importlib.__import__()" から受け継いでいます。これらの2つの関数の
   最も重要な違いは、 "import_module()" が指定されたパッケージやモジュ
   ール (例えば "pkg.mod") を返すのに対し、 "__import__()" はトップレ
   ベルのパッケージやモジュール (例えば "pkg") を返すことです。

   もしモジュールを動的にインポートしていて、インタープリタの実行開始
   後にモジュールが作成された (例えば、 Python ソースファイルを作成し
   た) 場合、インポートシステムが新しいモジュールを見つけられるように
   、 "invalidate_caches()" を呼ぶ必要があるでしょう。

   バージョン 3.3 で変更: 親パッケージは自動的にインポートされます。

importlib.invalidate_caches()

   "sys.meta_path" に保存されたファインダーの内部キャッシュを無効にし
   ます。ファインダーが "invalidate_caches()" を実装していれば、無効化
   を行うためにそれが呼び出されます。すべてのファインダーが新しいモジ
   ュールの存在に気づくことを保証しているプログラムの実行中に、モジュ
   ールが作成またはインストールされたなら、この関数が呼び出されるべき
   です。

   Added in version 3.3.

   バージョン 3.10 で変更: Namespace packages created/installed in a
   different "sys.path" location after the same namespace was already
   imported are noticed.

importlib.reload(module)

   以前にインポートされた *module* をリロードします。引数はモジュール
   オブジェクトでなければならず、したがってそれ以前に必ずインポートに
   成功していなければなりません。この関数は、モジュールのソースファイ
   ルを外部エディタで編集していて Python インタープリタから離れること
   なく新しいバージョンを試したい際に便利です。戻り値はモジュールオブ
   ジェクトです。 (もし再インポートが異なるオブジェクトを
   "sys.modules" に配置したら、元の *module* とは異なるかもしれません
   。)

   "reload()" が実行された場合:

   * Python モジュールのコードは再コンパイルされ、モジュールレベルのコ
     ードが再度実行されます。モジュールの辞書中にある何らかの名前に結
     び付けられたオブジェクトは、そのモジュールを最初にロードしたとき
     の *ローダー* を再利用して新たに定義されます。拡張モジュールの
     "init" 関数が二度呼び出されることはありません。

   * Python における他のオブジェクトと同様、以前のオブジェクトのメモリ
     領域は、参照カウントがゼロにならないかぎり再利用されません。

   * モジュール名前空間内の名前は新しいオブジェクト (または更新された
     オブジェクト) を指すよう更新されます。

   * 以前のオブジェクトが (外部の他のモジュールなどからの) 参照を受け
     ている場合、それらを新たなオブジェクトに再束縛し直すことはないの
     で、必要なら自分で名前空間を更新しなければなりません。

   いくつか補足説明があります:

   モジュールが再ロードされた際、その辞書 (モジュールのグローバル変数
   を含みます) はそのまま残ります。名前の再定義を行うと、以前の定義を
   上書きするので、一般的には問題はありません。新たなバージョンのモジ
   ュールが古いバージョンで定義された名前を定義していない場合、古い定
   義がそのまま残ります。辞書がグローバルテーブルやオブジェクトのキャ
   ッシュを維持していれば、この機能をモジュールを有効性を引き出すため
   に使うことができます --- つまり、 "try" 文を使えば、必要に応じてテ
   ーブルがあるかどうかをテストし、その初期化を飛ばすことができます:

      try:
          cache
      except NameError:
          cache = {}

   組み込みモジュールや動的にロードされるモジュールを再ロードすること
   は、一般的にそれほど便利ではありません。 "sys", "__main__",
   "builtins" やその他重要なモジュールの再ロードはお勧め出来ません。多
   くの場合、拡張モジュールは 1 度以上初期化されるようには設計されてお
   らず、再ロードされた場合には何らかの理由で失敗するかもしれません。

   一方のモジュールが "from" ... "import" ... を使って、オブジェクトを
   他方のモジュールからインポートしているなら、他方のモジュールを
   "reload()" で呼び出しても、そのモジュールからインポートされたオブジ
   ェクトを再定義することはできません --- この問題を回避する一つの方法
   は、 "from" 文を再度実行することで、もう一つの方法は "from" 文の代
   わりに "import" と限定的な名前 (*module.name*) を使うことです。

   あるモジュールがクラスのインスタンスを生成している場合、そのクラス
   を定義しているモジュールの再ロードはそれらインスタンスのメソッド定
   義に影響しません --- それらは古いクラス定義を使い続けます。これは派
   生クラスの場合でも同じです。

   Added in version 3.4.

   バージョン 3.7 で変更: リロードされたモジュールの "ModuleSpec" が欠
   けていたときは "ModuleNotFoundError" が送出されます。

   警告:

     This function is not thread-safe. Calling it from multiple
     threads can result in unexpected behavior. It's recommended to
     use the "threading.Lock" or other synchronization primitives for
     thread-safe module reloading.


"importlib.abc" -- Abstract base classes related to import
==========================================================

**ソースコード:** Lib/importlib/abc.py

======================================================================

The "importlib.abc" module contains all of the core abstract base
classes used by "import". Some subclasses of the core abstract base
classes are also provided to help in implementing the core ABCs.

抽象基底クラス階層:

   object
    +-- MetaPathFinder
    +-- PathEntryFinder
    +-- Loader
         +-- ResourceLoader --------+
         +-- InspectLoader          |
              +-- ExecutionLoader --+
                                    +-- FileLoader
                                    +-- SourceLoader

class importlib.abc.MetaPathFinder

   *meta path finder* を表す抽象基底クラスです。

   Added in version 3.3.

   バージョン 3.10 で変更: No longer a subclass of "Finder".

   find_spec(fullname, path, target=None)

      An abstract method for finding a *spec* for the specified
      module.  If this is a top-level import, *path* will be "None".
      Otherwise, this is a search for a subpackage or module and
      *path* will be the value of "__path__" from the parent package.
      If a spec cannot be found, "None" is returned. When passed in,
      "target" is a module object that the finder may use to make a
      more educated guess about what spec to return.
      "importlib.util.spec_from_loader()" may be useful for
      implementing concrete "MetaPathFinders".

      Added in version 3.4.

   invalidate_caches()

      このファインダーで使われている内部キャッシュがあれば無効にするオ
      プションのメソッドです。 "sys.meta_path" 上のすべてのファインダ
      ーのキャッシュを無効化する際、 "importlib.invalidate_caches()"
      によって使われます。

      バージョン 3.4 で変更: Returns "None" when called instead of
      "NotImplemented".

class importlib.abc.PathEntryFinder

   *path entry finder* を表す抽象基底クラスです。 "MetaPathFinder" と
   似ているところがありますが、 "PathEntryFinder" は
   "importlib.machinery.PathFinder" が提供するパスに基づく import サブ
   システムの中でのみ使うことが意図されています。

   Added in version 3.3.

   バージョン 3.10 で変更: No longer a subclass of "Finder".

   find_spec(fullname, target=None)

      指定されたモジュールに対応する *スペック* を検索する抽象メソッド
      。ファインダーは、割り当てられている *パス・エントリー* 内のモジ
      ュールだけを検索します。スペックが見つからなければ "None" が返さ
      れます。 "target" は、渡されてきたならモジュールオブジェクトです
      。これはファインダーがどのようなスペックを返せばよいか推測するた
      めに使用します。具体的な "PathEntryFinders" を実装するためには
      "importlib.util.spec_from_loader()" が便利かもしれません。

      Added in version 3.4.

   invalidate_caches()

      このファインダーで使われている内部キャッシュがあれば無効にするオ
      プションのメソッドです。キャッシュされたすべてのファインダーの無
      効化する際、
      "importlib.machinery.PathFinder.invalidate_caches()" によって使
      われます。

class importlib.abc.Loader

   *loader* の抽象基底クラスです。ローダーの厳密な定義は **PEP 302**
   を参照してください。

   リソースの読み出しをサポートさせたいローダーには、
   "importlib.resources.abc.ResourceReader" で指定されている
   "get_resource_reader()" メソッドを実装してください。

   バージョン 3.7 で変更: オプションの "get_resource_reader()" メソッ
   ドが導入されました。

   create_module(spec)

      モジュールをインポートする際に使用されるモジュールオブジェクトを
      返すメソッド。このメソッドは "None" を戻すことができ、その場合は
      デフォルトのモジュール作成のセマンティクスが適用されることを示し
      ます。

      Added in version 3.4.

      バージョン 3.6 で変更: "exec_module()" が定義されている場合は、
      このメソッドはオプションではなくなりました。

   exec_module(module)

      モジュールがインポートまたはリロードされる際に、そのモジュールを
      モジュール自身の名前空間の中で実行する抽象的なメソッド。
      "exec_module()" が呼ばれる時点で、モジュールはすでに初期設定され
      ている必要があります。 このメソッドが存在するときは、
      "create_module()" の定義が必須です。

      Added in version 3.4.

      バージョン 3.6 で変更: "create_module()" の定義が必須となりまし
      た。

   load_module(fullname)

      A legacy method for loading a module.  If the module cannot be
      loaded, "ImportError" is raised, otherwise the loaded module is
      returned.

      If the requested module already exists in "sys.modules", that
      module should be used and reloaded. Otherwise the loader should
      create a new module and insert it into "sys.modules" before any
      loading begins, to prevent recursion from the import.  If the
      loader inserted a module and the load fails, it must be removed
      by the loader from "sys.modules"; modules already in
      "sys.modules" before the loader began execution should be left
      alone.

      The loader should set several attributes on the module (note
      that some of these attributes can change when a module is
      reloaded):

      * "module.__name__"

      * "module.__file__"

      * "module.__cached__" *(deprecated)*

      * "module.__path__"

      * "module.__package__" *(deprecated)*

      * "module.__loader__" *(deprecated)*

      When "exec_module()" is available then backwards-compatible
      functionality is provided.

      バージョン 3.4 で変更: Raise "ImportError" when called instead
      of "NotImplementedError".  Functionality provided when
      "exec_module()" is available.

      バージョン 3.4 で非推奨、バージョン 3.15 で削除予定: The
      recommended API for loading a module is "exec_module()" (and
      "create_module()").  Loaders should implement it instead of
      "load_module()".  The import machinery takes care of all the
      other responsibilities of "load_module()" when "exec_module()"
      is implemented.

class importlib.abc.ResourceLoader

   *TraversableResources に取って代わられました*

      *loader* の抽象基底クラスで、ストレージバックエンドから任意のリ
      ソースをロードするオプションの **PEP 302** プロトコルを実装しま
      す。

      バージョン 3.7 で非推奨: This ABC is deprecated in favour of
      supporting resource loading through
      "importlib.resources.abc.TraversableResources". This class
      exists for backwards compatibility only with other ABCs in this
      module.

      abstractmethod get_data(path)

            An abstract method to return the bytes for the data
            located at *path*. Loaders that have a file-like storage
            back-end that allows storing arbitrary data can implement
            this abstract method to give direct access to the data
            stored. "OSError" is to be raised if the *path* cannot be
            found. The *path* is expected to be constructed using a
            module's "__file__" attribute or an item from a package's
            "__path__".

            バージョン 3.4 で変更: "NotImplementedError" の代わりに
            "OSError" を送出します。

class importlib.abc.InspectLoader

   *loader* の抽象基底クラスで、ローダーがモジュールを検査するためのオ
   プションの **PEP 302** プロトコルを実装します。

   get_code(fullname)

      モジュールの "code" オブジェクトを返すか、 (例えば組み込みモジュ
      ールの場合に) モジュールがコードオブジェクトを持たなければ
      "None" を返します。要求されたモジュールをローダーが見つけられな
      かった場合は "ImportError" を送出します。

      注釈:

        このメソッドにはデフォルト実装がありますが、とはいえパフォーマ
        ンスのために、可能ならばオーバライドしたほうが良いです。

      バージョン 3.4 で変更: このメソッドはもはや抽象メソッドではなく
      、具象実装が提供されます。

   abstractmethod get_source(fullname)

         モジュールのソースを返す抽象メソッドです。これは認識されたす
         べての行セパレータを "'\n'" 文字に変換し、 *universal
         newlines* を使ったテキスト文字列として返されます。利用できる
         ソースがなければ (例えば組み込みモジュール)、 "None" を返しま
         す。指定されたモジュールが見つからなければ、 "ImportError" を
         送出します。

         バージョン 3.4 で変更: "NotImplementedError" の代わりに
         "ImportError" を送出します。

   is_package(fullname)

      モジュールがパッケージであれば True を返し、そうでなければ False
      を返すオプションのメソッドです。 *ローダー* がモジュールを見つけ
      られなかったなら "ImportError" が送出されます。

      バージョン 3.4 で変更: "NotImplementedError" の代わりに
      "ImportError" を送出します。

   static source_to_code(data, path='<string>')

      Python のソースからコードオブジェクトを作ります。

      *data* 引数は "compile()" 関数がサポートするもの (すなわち文字列
      かバイト) なら何でも構いません。*path* 引数はソースコードの元々
      の場所への "パス" でなければなりませんが、抽象概念 (例えば zip
      ファイル内の場所) でも構いません。

      結果のコードオブジェクトを使って、 "exec(code, module.__dict__)"
      を呼ぶことでモジュール内でコードを実行できます。

      Added in version 3.4.

      バージョン 3.5 で変更: スタティックメソッドになりました。

   exec_module(module)

      "Loader.exec_module()" の実装です。

      Added in version 3.4.

   load_module(fullname)

      Implementation of "Loader.load_module()".

      バージョン 3.4 で非推奨、バージョン 3.15 で削除予定: use
      "exec_module()" instead.

class importlib.abc.ExecutionLoader

   "InspectLoader" から継承された抽象基底クラスで、実装されていれば、
   モジュールをスクリプトとして実行する助けになります。この抽象基底ク
   ラスはオプションの **PEP 302** プロトコルを表します。

   abstractmethod get_filename(fullname)

         An abstract method that is to return the value of "__file__"
         for the specified module. If no path is available,
         "ImportError" is raised.

         ソースコードが利用できるなら、そのモジュールのロードにバイト
         コードが使われたかにかかわらず、このメソッドはそのソースファ
         イルへのパスを返す必要があります。

         バージョン 3.4 で変更: "NotImplementedError" の代わりに
         "ImportError" を送出します。

class importlib.abc.FileLoader(fullname, path)

   "ResourceLoader" と "ExecutionLoader" から継承された抽象基底クラス
   で、 "ResourceLoader.get_data()" および
   "ExecutionLoader.get_filename()" の具象実装を提供します。

   *fullname* 引数は、ローダーが解決しようとするモジュールの、完全に解
   決された名前です。*path* 引数は、モジュールのファイルへのパスです。

   Added in version 3.3.

   name

      ローダーが扱えるモジュールの名前です。

   path

      モジュールのファイルへのパスです。

   load_module(fullname)

      Calls super's "load_module()".

      バージョン 3.4 で非推奨、バージョン 3.15 で削除予定: Use
      "Loader.exec_module()" instead.

   abstractmethod get_filename(fullname)

      "path" を返します。

   abstractmethod get_data(path)

      *path* をバイナリファイルとして読み込み、そのバイト列を返します
      。

class importlib.abc.SourceLoader

   ソース (オプションでバイトコード) ファイルのロードを実装する抽象基
   底クラスです。このクラスは、 "ResourceLoader" と "ExecutionLoader"
   の両方を継承し、以下の実装が必要です:

   * "ResourceLoader.get_data()"

   * "ExecutionLoader.get_filename()"
        ソースファイルへのパスのみを返す必要があります。ソースなしのロ
        ードはサポートされていません。

   このクラスでこれらの抽象メソッドを定義することで、バイトコードファ
   イルを追加でサポートします。これらのメソッドを定義しなければ (また
   はそのモジュールが "NotImplementedError" を送出すれば)、このローダ
   ーはソースコードに対してのみ働きます。これらのメソッドを実装するこ
   とで、ローダーはソースとバイトコードファイル *の組み合わせ* に対し
   て働きます。バイトコードのみを与えた *ソースのない* ロードは認めら
   れません。バイトコードファイルは、 Python コンパイラによる解析の工
   程をなくして速度を上げる最適化です。ですから、バイトコード特有の
   API は公開されていません。

   path_stats(path)

      指定されたパスについてのメタデータを含む "dict" を返す、オプショ
      ンの抽象メソッドです。サポートされる辞書のキーは:

      * "'mtime'" (必須): ソースコードの更新時刻を表す整数または浮動小
        数点数です。

      * "'size'" (任意): バイト数で表したソースコードのサイズです。

      未来の拡張のため、辞書内の他のキーは無視されます。パスが扱えなけ
      れば、 "OSError" が送出されます。

      Added in version 3.3.

      バージョン 3.4 で変更: "NotImplementedError" の代わりに
      "OSError" を送出します。

   path_mtime(path)

      指定されたパスの更新時刻を返す、オプションの抽象メソッドです。

      バージョン 3.3 で非推奨: このメソッドは廃止され、 "path_stats()"
      が推奨されます。このモジュールを実装する必要はありませんが、互換
      性のため現在も利用できます。パスが扱えなければ、 "OSError" が送
      出されます。

      バージョン 3.4 で変更: "NotImplementedError" の代わりに
      "OSError" を送出します。

   set_data(path, data)

      ファイルパスに指定されたバイト列を書き込むオプションの抽象メソッ
      ドです。存在しない中間ディレクトリがあれば、自動で作成されます。

      When writing to the path fails because the path is read-only
      ("errno.EACCES"/"PermissionError"), do not propagate the
      exception.

      バージョン 3.4 で変更: 呼ばれたときに "NotImplementedError" を送
      出することは最早ありません。

   get_code(fullname)

      "InspectLoader.get_code()" の具象実装です。

   exec_module(module)

      "Loader.exec_module()" の具象実装です。

      Added in version 3.4.

   load_module(fullname)

      Concrete implementation of "Loader.load_module()".

      バージョン 3.4 で非推奨、バージョン 3.15 で削除予定: Use
      "exec_module()" instead.

   get_source(fullname)

      "InspectLoader.get_source()" の具象実装です。

   is_package(fullname)

      "InspectLoader.is_package()" の具象実装です。モジュールは、次の
      *両方* を満たすならパッケージであると決定されます。モジュールの
      ("ExecutionLoader.get_filename()" で与えられる) ファイルパスが、
      ファイル拡張子を除くと "__init__" という名のファイルであること。
      モジュール名自体が "__init__" で終わらないこと。


"importlib.machinery" -- Importers and path hooks
=================================================

**ソースコード:** Lib/importlib/machinery.py

======================================================================

このモジュールには、 "import" がモジュールを検索してロードするのに役立
つ様々なオブジェクトがあります。

importlib.machinery.SOURCE_SUFFIXES

   認識されているソースモジュールのファイル接尾辞を表す文字列のリスト
   です。

   Added in version 3.3.

importlib.machinery.DEBUG_BYTECODE_SUFFIXES

   最適化されていないバイトコードモジュールのファイル接尾辞を表す文字
   列のリストです。

   Added in version 3.3.

   バージョン 3.5 で非推奨: Use "BYTECODE_SUFFIXES" instead.

importlib.machinery.OPTIMIZED_BYTECODE_SUFFIXES

   最適化されたバイトコードモジュールのファイル接尾辞を表す文字列のリ
   ストです。

   Added in version 3.3.

   バージョン 3.5 で非推奨: Use "BYTECODE_SUFFIXES" instead.

importlib.machinery.BYTECODE_SUFFIXES

   認識されているバイトコードモジュールのファイル接尾辞を表す文字列の
   リストです (先頭のドットを含みます)。

   Added in version 3.3.

   バージョン 3.5 で変更: この値は "__debug__" に依存しなくなりました
   。

importlib.machinery.EXTENSION_SUFFIXES

   認識されている最適化された拡張モジュールのファイル接尾辞を表す文字
   列のリストです。

   Added in version 3.3.

importlib.machinery.all_suffixes()

   標準のインポート機構によって認識されているすべてのファイル接尾辞を
   表す文字列の組み合わせられたリストを返します。これが役立つのは、あ
   るファイルシステムパスがモジュールを参照する可能性があるかだけを知
   りたくて、そのモジュールの種類を詳しく知る必要はないコード (例えば
   "inspect.getmodulename()") です。

   Added in version 3.3.

class importlib.machinery.BuiltinImporter

   組み込みモジュールの *importer* です。すべての既知のモジュールは
   "sys.builtin_module_names" に列挙されています。このクラスは
   "importlib.abc.MetaPathFinder" および "importlib.abc.InspectLoader"
   抽象基底クラスを実装します。

   インスタンス化の必要性を軽減するため、このクラスにはクラスメソッド
   だけが定義されています。

   バージョン 3.5 で変更: **PEP 489** の一環として、ビルトインインポー
   ターは "Loader.create_module()" と "Loader.exec_module()" を実装し
   ています。

class importlib.machinery.FrozenImporter

   フリーズされたモジュールの *インポーター* です。このクラスは
   "importlib.abc.MetaPathFinder" および "importlib.abc.InspectLoader"
   抽象基底クラスを実装します。

   インスタンス化の必要性を軽減するため、このクラスにはクラスメソッド
   だけが定義されています。

   バージョン 3.4 で変更: Gained "create_module()" and "exec_module()"
   methods.

class importlib.machinery.WindowsRegistryFinder

   Windows レジストリで宣言されたモジュールの *finder* です。このクラ
   スは "importlib.abc.MetaPathFinder" 抽象基底クラスを実装します。

   インスタンス化の必要性を軽減するため、このクラスにはクラスメソッド
   だけが定義されています。

   Added in version 3.3.

   バージョン 3.6 で非推奨: 代わりに "site" の設定を使ってください。
   Python の将来のバージョンでは、デフォルトでこのファインダーが使えな
   くなるかもしれません。

class importlib.machinery.PathFinder

   "sys.path" およびパッケージの "__path__" 属性の *Finder* です。この
   クラスは "importlib.abc.MetaPathFinder" 抽象基底クラスを実装します
   。

   インスタンス化の必要性を軽減するため、このクラスにはクラスメソッド
   だけが定義されています。

   classmethod find_spec(fullname, path=None, target=None)

      "sys.path" または定義されていれば *path* から、 *fullname* で指
      定されたモジュールの *スペック* の検索を試みるクラスメソッドです
      。検索されるそれぞれのパスエントリに対して
      "sys.path_importer_cache" が検査されます。偽でないオブジェクトが
      見つかれば、それが目的のモジュールを検索するための *パスエントリ
      ・ファインダー* として使われます。 "sys.path_importer_cache" に
      目的のエントリが見つからなければ、パスエントリに対するファインダ
      ーが "sys.path_hooks" から検索され、見つかれば、それが
      "sys.path_importer_cache" に保管されるとともに、モジュールについ
      て問い合わせられます。それでもファインダーが見つからなければ
      "None" が保管され、また返されます。

      Added in version 3.4.

      バージョン 3.5 で変更: もしカレントワーキングディレクトリ -- 空
      の文字列によって表されている -- がすでに有効でなければ、 "None"
      が返されますが値は "sys.path_importer_cache" にキャッシュされま
      せん。

   classmethod invalidate_caches()

      Calls "importlib.abc.PathEntryFinder.invalidate_caches()" on all
      finders stored in "sys.path_importer_cache" that define the
      method. Otherwise entries in "sys.path_importer_cache" set to
      "None" are deleted.

      バージョン 3.7 で変更: Entries of "None" in
      "sys.path_importer_cache" are deleted.

   バージョン 3.4 で変更: "''" (すなわち空の文字列) に対してはカレント
   ワーキングディレクトリとともに "sys.path_hooks" のオブジェクトを呼
   び出します。

class importlib.machinery.FileFinder(path, *loader_details)

   ファイルシステムからの結果をキャッシュする
   "importlib.abc.PathEntryFinder" の具象実装です。

   *path* 引数は検索を担当するファインダーのディレクトリです。

   *loader_details* 引数は、可変個の 2 要素タプルで、それぞれがローダ
   ーとローダーが認識するファイル接尾辞のシーケンスとを含みます。ロー
   ダーは、呼び出し可能でモジュール名と見つかったファイルのパスとの 2
   引数を受け付けることを期待されます。

   ファインダーはモジュール検索のたびに stat を呼び出し、必要に応じて
   ディレクトリの内容をキャッシュすることで、コードキャッシュが古くな
   っていないことを確かめます。キャッシュの古さはオペレーティングシス
   テムのファイルシステムのステート情報の粒度に依存しますから、モジュ
   ールを検索し、新しいファイルを作成し、その後に新しいファイルが表す
   モジュールを検索する、という競合状態の可能性があります。この操作が
   stat の呼び出しの粒度に収まるほど速く起こると、モジュールの検索が失
   敗します。これを防ぐためには、モジュールを動的に作成する際に、必ず
   "importlib.invalidate_caches()" を呼び出してください。

   Added in version 3.3.

   path

      ファインダーが検索されるパスです。

   find_spec(fullname, target=None)

      "path" 内で *fullname* を扱うスペックの探索を試みます。

      Added in version 3.4.

   invalidate_caches()

      内部キャッシュを完全に消去します。

   classmethod path_hook(*loader_details)

      A class method which returns a closure for use on
      "sys.path_hooks". An instance of "FileFinder" is returned by the
      closure using the path argument given to the closure directly
      and *loader_details* indirectly.

      クロージャへの引数が存在するディレクトリでなければ、
      "ImportError" が送出されます。

class importlib.machinery.SourceFileLoader(fullname, path)

   "importlib.abc.FileLoader" を継承し、その他いくつかのメソッドの具象
   実装を提供する、 "importlib.abc.SourceLoader" の具象実装です。

   Added in version 3.3.

   name

      このローダーが扱うモジュールの名前です。

   path

      ソースファイルへのパスです。

   is_package(fullname)

      "path" がパッケージを表すとき "True" を返します。

   path_stats(path)

      "importlib.abc.SourceLoader.path_stats()" の具象実装です。

   set_data(path, data)

      "importlib.abc.SourceLoader.set_data()" の具象実装です。

   load_module(name=None)

      Concrete implementation of "importlib.abc.Loader.load_module()"
      where specifying the name of the module to load is optional.

      バージョン 3.6 で非推奨、バージョン 3.15 で削除予定: Use
      "importlib.abc.Loader.exec_module()" instead.

class importlib.machinery.SourcelessFileLoader(fullname, path)

   バイトコードファイル (すなわちソースコードファイルが存在しない) を
   インポートできる "importlib.abc.FileLoader" の具象実装です。

   注意として、バイトコードを直接使う (つまりソースコードファイルがな
   い) と、そのモジュールはすべての Python 実装では使用できないし、新
   しいバージョンの Python ではバイトコードフォーマットが変更されてい
   たら使用できません。

   Added in version 3.3.

   name

      ローダーが扱うモジュールの名前です。

   path

      バイトコードファイルへのパスです。

   is_package(fullname)

      そのモジュールがパッケージであるかを "path" に基づいて決定します
      。

   get_code(fullname)

      "path" から作成された "name" のコードオブジェクトを返します。

   get_source(fullname)

      このローダーが使われたとき、バイトコードファイルのソースがなけれ
      ば "None" を返します。

   load_module(name=None)

   Concrete implementation of "importlib.abc.Loader.load_module()"
   where specifying the name of the module to load is optional.

   バージョン 3.6 で非推奨、バージョン 3.15 で削除予定: Use
   "importlib.abc.Loader.exec_module()" instead.

class importlib.machinery.ExtensionFileLoader(fullname, path)

   拡張モジュールのための "importlib.abc.ExecutionLoader" の具象実装で
   す。

   *fullname* 引数はローダーがサポートするモジュールの名前を指定します
   。*path* 引数は拡張モジュールのファイルへのパスです。

   Note that, by default, importing an extension module will fail in
   subinterpreters if it doesn't implement multi-phase init (see **PEP
   489**), even if it would otherwise import successfully.

   Added in version 3.3.

   バージョン 3.12 で変更: Multi-phase init is now required for use in
   subinterpreters.

   name

      ローダーがサポートするモジュールの名前です。

   path

      拡張モジュールへのパスです。

   create_module(spec)

      与えられたスペックから **PEP 489** に従ってモジュールオブジェク
      トを作成します。

      Added in version 3.5.

   exec_module(module)

      与えられたモジュールオブジェクトを **PEP 489** に従って初期化し
      ます。

      Added in version 3.5.

   is_package(fullname)

      Returns "True" if the file path points to a package's "__init__"
      module based on "EXTENSION_SUFFIXES".

   get_code(fullname)

      拡張モジュールにコードオブジェクトがなければ "None" を返します。

   get_source(fullname)

      拡張モジュールにソースコードがなければ "None" を返します。

   get_filename(fullname)

      "path" を返します。

      Added in version 3.4.

class importlib.machinery.NamespaceLoader(name, path, path_finder)

   A concrete implementation of "importlib.abc.InspectLoader" for
   namespace packages.  This is an alias for a private class and is
   only made public for introspecting the "__loader__" attribute on
   namespace packages:

      >>> from importlib.machinery import NamespaceLoader
      >>> import my_namespace
      >>> isinstance(my_namespace.__loader__, NamespaceLoader)
      True
      >>> import importlib.abc
      >>> isinstance(my_namespace.__loader__, importlib.abc.Loader)
      True

   Added in version 3.11.

class importlib.machinery.ModuleSpec(name, loader, *, origin=None, loader_state=None, is_package=None)

   A specification for a module's import-system-related state.  This
   is typically exposed as the module's "__spec__" attribute.  Many of
   these attributes are also available directly on a module: for
   example, "module.__spec__.origin == module.__file__".  Note,
   however, that while the *values* are usually equivalent, they can
   differ since there is no synchronization between the two objects.
   For example, it is possible to update the module's "__file__" at
   runtime and this will not be automatically reflected in the
   module's "__spec__.origin", and vice versa.

   Added in version 3.4.

   name

      The module's fully qualified name (see "module.__name__"). The
      *finder* should always set this attribute to a non-empty string.

   loader

      The *loader* used to load the module (see "module.__loader__").
      The *finder* should always set this attribute.

   origin

      The location the *loader* should use to load the module (see
      "module.__file__"). For example, for modules loaded from a ".py"
      file this is the filename. The *finder* should always set this
      attribute to a meaningful value for the *loader* to use.  In the
      uncommon case that there is not one (like for namespace
      packages), it should be set to "None".

   submodule_search_locations

      A (possibly empty) *sequence* of strings enumerating the
      locations in which a package's submodules will be found (see
      "module.__path__"). Most of the time there will only be a single
      directory in this list.

      The *finder* should set this attribute to a sequence, even an
      empty one, to indicate to the import system that the module is a
      package.  It should be set to "None" for non-package modules.
      It is set automatically later to a special object for namespace
      packages.

   loader_state

      The *finder* may set this attribute to an object containing
      additional, module-specific data to use when loading the module.
      Otherwise it should be set to "None".

   cached

      The filename of a compiled version of the module's code (see
      "module.__cached__"). The *finder* should always set this
      attribute but it may be "None" for modules that do not need
      compiled code stored.

   parent

      (Read-only) The fully qualified name of the package the module
      is in (or the empty string for a top-level module). See
      "module.__package__". If the module is a package then this is
      the same as "name".

   has_location

      "True" if the spec's "origin" refers to a loadable location,
      "False" otherwise.  This value impacts how "origin" is
      interpreted and how the module's "__file__" is populated.

class importlib.machinery.AppleFrameworkLoader(name, path)

   フレームワーク形式の拡張モジュールを読み込み事ができる、特殊な
   "importlib.machinery.ExtensionFileLoader" です。

   iOS App Store との互換性のため、 iOS アプリの *すべての* バイナリモ
   ジュールは、パッケージ化されたアプリの "Frameworks" フォルダーに保
   存された、適切なメタデータ付きのフレームワークにある動的ライブラリ
   である必要があります。フレームワークごとにバイナリは一つだけで、
   Frameworks フォルダーの外に実行可能バイナリデータを設置することはで
   きません。

   To accommodate this requirement, when running on iOS, extension
   module binaries are *not* packaged as ".so" files on "sys.path",
   but as individual standalone frameworks. To discover those
   frameworks, this loader is registered against the ".fwork" file
   extension, with a ".fwork" file acting as a placeholder in the
   original location of the binary on "sys.path". The ".fwork" file
   contains the path of the actual binary in the "Frameworks" folder,
   relative to the app bundle. To allow for resolving a framework-
   packaged binary back to the original location, the framework is
   expected to contain a ".origin" file that contains the location of
   the ".fwork" file, relative to the app bundle.

   例えば、"from foo.bar import _whiz" をインポートする場合を考えてみ
   ましょう。 "_whiz" がバイナリモジュール
   "sources/foo/bar/_whiz.abi3.so" で実装されており、 "sources" のアプ
   リケーションバンドルからの相対パスが "sys.path" に登録されています
   。このモジュールは
   "Frameworks/foo.bar._whiz.framework/foo.bar._whiz" （フレームワーク
   名はモジュールの完全なインポートパスから命名されています）として、
   "Info.plist" ファイルをバイナリをフレームワークとして識別する
   ".framework" ディレクトリ内に設置して配布しなければなりません。
   "foo.bar._whiz" モジュールは、元の場所で、
   "Frameworks/foo.bar._whiz/foo.bar._whiz" のパスを含む
   "sources/foo/bar/_whiz.abi3.fwork" マーカーファイルに記述されます。
   また、フレームワークは、 ".fwork" へのパスを含む
   "Frameworks/foo.bar._whiz.framework/foo.bar._whiz.origin" も含まな
   ければなりません。

   When a module is loaded with this loader, the "__file__" for the
   module will report as the location of the ".fwork" file. This
   allows code to use the "__file__" of a  module as an anchor for
   file system traversal. However, the spec origin will reference the
   location of the *actual* binary in the ".framework" folder.

   The Xcode project building the app is responsible for converting
   any ".so" files from wherever they exist in the "PYTHONPATH" into
   frameworks in the "Frameworks" folder (including stripping
   extensions from the module file, the addition of framework
   metadata, and signing the resulting framework), and creating the
   ".fwork" and ".origin" files. This will usually be done with a
   build step in the Xcode project; see the iOS documentation for
   details on how to construct this build step.

   Added in version 3.13.

   Availability: iOS.

   name

      ローダーがサポートするモジュールの名前です。

   path

      拡張モジュールの ".fwork" ファイルへのパス。


"importlib.util" -- Utility code for importers
==============================================

**ソースコード:** Lib/importlib/util.py

======================================================================

このモジュールには、 *インポーター* の構築を助ける様々なオブジェクトが
あります。

importlib.util.MAGIC_NUMBER

   バイトコードバージョン番号を表しているバイト列。バイトコードのロー
   ド／書き込みについてヘルプが必要なら "importlib.abc.SourceLoader"
   を参照してください。

   Added in version 3.4.

importlib.util.cache_from_source(path, debug_override=None, *, optimization=None)

   ソース *path* に関連付けられたバイトコンパイルされたファイルの
   **PEP 3147**/**PEP 488** パスを返します。例えば、 *path* が
   "/foo/bar/baz.py" なら、 Python 3.2 の場合返り値は
   "/foo/bar/__pycache__/baz.cpython-32.pyc" になります。 "cpython-32"
   という文字列は、現在のマジックタグから得られます (マジックタグにつ
   いては "get_tag()" を参照; "sys.implementation.cache_tag" が未定義
   なら "NotImplementedError" が送出されます。)

   *optimization* パラメータは、バイトコードファイルの最適化レベルを指
   定するために使われます。空文字列は最適化しないことを表します。した
   がって、 *optimization* が "''" のとき "/foo/bar/baz.py" に対して
   "/foo/bar/__pycache__/baz.cpython-32.pyc" というバイトコードパスが
   返ります。 "None" にするとインタープリタの最適化レベルが使われます
   。それ以外では値の文字列表現が使われます。したがって、
   *optimization* が "2" のとき  "/foo/bar/baz.py" に対して
   "/foo/bar/__pycache__/baz.cpython-32.opt-2.pyc" というバイトコード
   パスが返ります。 *optimization* の文字列表現は英数字だけが可能で、
   そうでなければ "ValueError" が上げられます。

   The *debug_override* parameter is deprecated and can be used to
   override the system's value for "__debug__". A "True" value is the
   equivalent of setting *optimization* to the empty string. A "False"
   value is the same as setting *optimization* to "1". If both
   *debug_override* an *optimization* are not "None" then "TypeError"
   is raised.

   Added in version 3.4.

   バージョン 3.5 で変更: *optimization* パラメータが追加され、
   *debug_override* パラメータは deprecated になりました。

   バージョン 3.6 で変更: *path-like object* を受け入れるようになりま
   した。

importlib.util.source_from_cache(path)

   **PEP 3147** ファイル名への *path* が与えられると、関連するソースコ
   ードのファイルパスを返します。例えば、 *path* が
   "/foo/bar/__pycache__/baz.cpython-32.pyc" なら、返されるパスは
   "/foo/bar/baz.py" になります。 *path* は存在する必要はありませんが
   、 **PEP 3147** または **PEP 488** フォーマットに一致しない場合は
   "ValueError" が送出されます。 "sys.implementation.cache_tag" が定義
   されていない場合、 "NotImplementedError" が送出されます。

   Added in version 3.4.

   バージョン 3.6 で変更: *path-like object* を受け入れるようになりま
   した。

importlib.util.decode_source(source_bytes)

   与えられたソースコードを表すバイト列をデコードして、文字列としてそ
   れを一般的な改行形式 (universal newlines) で返します
   ("importlib.abc.InspectLoader.get_source()" で要求されるように)。

   Added in version 3.4.

importlib.util.resolve_name(name, package)

   相対的なモジュール名を解決して絶対的なものにします。

   **name** の先頭にドットがなければ、単に **name** が返されます。これ
   により、例えば "importlib.util.resolve_name('sys',
   __spec__.parent)" を使うときに **package** 変数が必要かどうかを確認
   する必要がなくなります。

   **name** が相対的なモジュール名であるにもかかわらず **package** が
   偽値 (例えば "None" や空文字列) ならば、 "ImportError" が送出されま
   す。相対的な名前がそれを含むパッケージから抜け出る (例えば "spam"
   パッケージ内から "..bacon" を要求する) 場合にも "ImportError" が送
   出されます。

   Added in version 3.3.

   バージョン 3.9 で変更: To improve consistency with import
   statements, raise "ImportError" instead of "ValueError" for invalid
   relative import attempts.

importlib.util.find_spec(name, package=None)

   Find the *spec* for a module, optionally relative to the specified
   **package** name. If the module is in "sys.modules", then
   "sys.modules[name].__spec__" is returned (unless the spec would be
   "None" or is not set, in which case "ValueError" is raised).
   Otherwise a search using "sys.meta_path" is done. "None" is
   returned if no spec is found.

   **name** がサブモジュールを示している  (ドットを含む) 場合、親モジ
   ュールは自動的にインポートされます。

   **name** と **package** は "import_module()" に対するものと同じよう
   に機能します。

   Added in version 3.4.

   バージョン 3.7 で変更: Raises "ModuleNotFoundError" instead of
   "AttributeError" if **package** is in fact not a package (i.e.
   lacks a "__path__" attribute).

importlib.util.module_from_spec(spec)

   **spec** と "spec.loader.create_module" に基づいて新しいモジュール
   を作ります。

   "spec.loader.create_module" が "None" を返さない場合は、既に存在す
   るどの属性もリセットされません。また、 **spec** にアクセスしたり属
   性をモジュールに設定したりする際に "AttributeError" 例外が起きても
   例外は送出されません。

   この関数は、新しいモジュールを作る方法として "types.ModuleType" よ
   りも推奨されます。なぜなら、できるだけ多くのインポートコントロール
   された属性をモジュールに設定するために **spec** が使用されるからで
   す。

   Added in version 3.5.

importlib.util.spec_from_loader(name, loader, *, origin=None, is_package=None)

   この関数は、スペックに不足している情報を埋めるために "ModuleSpec"
   のような利用可能な *loader* API を使います。

   Added in version 3.4.

importlib.util.spec_from_file_location(name, location, *, loader=None, submodule_search_locations=None)

   ファイルへのパスにもとづいて "ModuleSpec" インスタンスを生成するた
   めのファクトリー関数。不足している情報は、ローダー API を利用してス
   ペックから得られる情報と、モジュールがファイルベースであるという暗
   黙的な情報によって埋められます。

   Added in version 3.4.

   バージョン 3.6 で変更: *path-like object* を受け入れるようになりま
   した。

importlib.util.source_hash(source_bytes)

   Return the hash of *source_bytes* as bytes. A hash-based ".pyc"
   file embeds the "source_hash()" of the corresponding source file's
   contents in its header.

   Added in version 3.7.

importlib.util._incompatible_extension_module_restrictions(*, disable_check)

   A context manager that can temporarily skip the compatibility check
   for extension modules.  By default the check is enabled and will
   fail when a single-phase init module is imported in a
   subinterpreter. It will also fail for a multi-phase init module
   that doesn't explicitly support a per-interpreter GIL, when
   imported in an interpreter with its own GIL.

   Note that this function is meant to accommodate an unusual case;
   one which is likely to eventually go away.  There's is a pretty
   good chance this is not what you were looking for.

   You can get the same effect as this function by implementing the
   basic interface of multi-phase init (**PEP 489**) and lying about
   support for multiple interpreters (or per-interpreter GIL).

   警告:

     Using this function to disable the check can lead to unexpected
     behavior and even crashes.  It should only be used during
     extension module development.

   Added in version 3.12.

class importlib.util.LazyLoader(loader)

   モジュールが属性アクセスできるようになるまで、モジュールのローダー
   の実行を遅延するクラス。

   This class **only** works with loaders that define "exec_module()"
   as control over what module type is used for the module is
   required. For those same reasons, the loader's "create_module()"
   method must return "None" or a type for which its "__class__"
   attribute can be mutated along with not using *slots*. Finally,
   modules which substitute the object placed into "sys.modules" will
   not work as there is no way to properly replace the module
   references throughout the interpreter safely; "ValueError" is
   raised if such a substitution is detected.

   注釈:

     起動時間が重要なプロジェクトでは、もし決して使われないモジュール
     があれば、このクラスを使ってモジュールをロードするコストを最小化
     できるかもしれません。スタートアップ時間が重要でないプロジェクト
     では、遅延されたロードの際に発生して文脈の外で起こるエラーメッセ
     ージのため、このクラスの使用は **著しく** 推奨されません。

   Added in version 3.5.

   バージョン 3.6 で変更: Began calling "create_module()", removing
   the compatibility warning for "importlib.machinery.BuiltinImporter"
   and "importlib.machinery.ExtensionFileLoader".

   classmethod factory(loader)

      遅延ローダを生成する callable を返すクラスメソッド。これは、ロー
      ダーをインスタンスとしてではなくクラスとして渡すような状況におい
      て使われることを意図しています。

         suffixes = importlib.machinery.SOURCE_SUFFIXES
         loader = importlib.machinery.SourceFileLoader
         lazy_loader = importlib.util.LazyLoader.factory(loader)
         finder = importlib.machinery.FileFinder(path, (lazy_loader, suffixes))


使用例
======


プログラムからのインポート
--------------------------

プログラムからモジュールをインポートするには、
"importlib.import_module()" を使ってください。

   import importlib

   itertools = importlib.import_module('itertools')


モジュールがインポートできるか確認する
--------------------------------------

インポートを実際に行わずに、あるモジュールがインポートできるかを知る必
要がある場合は、 "importlib.util.find_spec()" を使ってください。

Note that if "name" is a submodule (contains a dot),
"importlib.util.find_spec()" will import the parent module.

   import importlib.util
   import sys

   # For illustrative purposes.
   name = 'itertools'

   if name in sys.modules:
       print(f"{name!r} already in sys.modules")
   elif (spec := importlib.util.find_spec(name)) is not None:
       # If you chose to perform the actual import ...
       module = importlib.util.module_from_spec(spec)
       sys.modules[name] = module
       spec.loader.exec_module(module)
       print(f"{name!r} has been imported")
   else:
       print(f"can't find the {name!r} module")


ソースファイルから直接インポートする
------------------------------------

This recipe should be used with caution: it is an approximation of an
import statement where the file path is specified directly, rather
than "sys.path" being searched. Alternatives should first be
considered first, such as modifying "sys.path" when a proper module is
required, or using "runpy.run_path()" when the global namespace
resulting from running a Python file is appropriate.

To import a Python source file directly from a path, use the following
recipe:

   import importlib.util
   import sys


   def import_from_path(module_name, file_path):
       spec = importlib.util.spec_from_file_location(module_name, file_path)
       module = importlib.util.module_from_spec(spec)
       sys.modules[module_name] = module
       spec.loader.exec_module(module)
       return module


   # For illustrative purposes only (use of `json` is arbitrary).
   import json
   file_path = json.__file__
   module_name = json.__name__

   # Similar outcome as `import json`.
   json = import_from_path(module_name, file_path)


Implementing lazy imports
-------------------------

The example below shows how to implement lazy imports:

   >>> import importlib.util
   >>> import sys
   >>> def lazy_import(name):
   ...     spec = importlib.util.find_spec(name)
   ...     loader = importlib.util.LazyLoader(spec.loader)
   ...     spec.loader = loader
   ...     module = importlib.util.module_from_spec(spec)
   ...     sys.modules[name] = module
   ...     loader.exec_module(module)
   ...     return module
   ...
   >>> lazy_typing = lazy_import("typing")
   >>> #lazy_typing is a real module object,
   >>> #but it is not loaded in memory yet.
   >>> lazy_typing.TYPE_CHECKING
   False


インポーターのセットアップ
--------------------------

For deep customizations of import, you typically want to implement an
*importer*. This means managing both the *finder* and *loader* side of
things. For finders there are two flavours to choose from depending on
your needs: a *meta path finder* or a *path entry finder*. The former
is what you would put on "sys.meta_path" while the latter is what you
create using a *path entry hook* on "sys.path_hooks" which works with
"sys.path" entries to potentially create a finder. This example will
show you how to register your own importers so that import will use
them (for creating an importer for yourself, read the documentation
for the appropriate classes defined within this package):

   import importlib.machinery
   import sys

   # For illustrative purposes only.
   SpamMetaPathFinder = importlib.machinery.PathFinder
   SpamPathEntryFinder = importlib.machinery.FileFinder
   loader_details = (importlib.machinery.SourceFileLoader,
                     importlib.machinery.SOURCE_SUFFIXES)

   # Setting up a meta path finder.
   # Make sure to put the finder in the proper location in the list in terms of
   # priority.
   sys.meta_path.append(SpamMetaPathFinder)

   # Setting up a path entry finder.
   # Make sure to put the path hook in the proper location in the list in terms
   # of priority.
   sys.path_hooks.append(SpamPathEntryFinder.path_hook(loader_details))


Approximating "importlib.import_module()"
-----------------------------------------

Import itself is implemented in Python code, making it possible to
expose most of the import machinery through importlib. The following
helps illustrate the various APIs that importlib exposes by providing
an approximate implementation of "importlib.import_module()":

   import importlib.util
   import sys

   def import_module(name, package=None):
       """An approximate implementation of import."""
       absolute_name = importlib.util.resolve_name(name, package)
       try:
           return sys.modules[absolute_name]
       except KeyError:
           pass

       path = None
       if '.' in absolute_name:
           parent_name, _, child_name = absolute_name.rpartition('.')
           parent_module = import_module(parent_name)
           path = parent_module.__spec__.submodule_search_locations
       for finder in sys.meta_path:
           spec = finder.find_spec(absolute_name, path)
           if spec is not None:
               break
       else:
           msg = f'No module named {absolute_name!r}'
           raise ModuleNotFoundError(msg, name=absolute_name)
       module = importlib.util.module_from_spec(spec)
       sys.modules[absolute_name] = module
       spec.loader.exec_module(module)
       if path is not None:
           setattr(parent_module, child_name, module)
       return module
