class_docstr: Load templates from a directory in a Python package.
  
  :param package_name: Import name of the package that contains the
      template directory.
  :param package_path: Directory within the imported package that
      contains the templates.
  :param encoding: Encoding of template files.
  
  The following example looks up templates in the ``pages`` directory
  within the ``project.ui`` package.
  
  .. code-block:: python
  
      loader = PackageLoader("project.ui", "pages")
  
  Only packages installed as directories (standard pip behavior) or
  zip/egg files (less common) are supported. The Python API for
  introspecting data in packages is too limited to support other
  installation methods the way this loader requires.
  
  There is limited support for :pep:`420` namespace packages. The
  template directory is assumed to only be in one namespace
  contributor. Zip files contributing to a namespace are not
  supported.
  
  .. versionchanged:: 3.0
      No longer uses ``setuptools`` as a dependency.
  
  .. versionchanged:: 3.0
      Limited PEP 420 namespace package support.
class_docstr_tok: ["Load","templates","from","a","directory","in","a","Python","package",".",":","param","package_name",":","Import","name","of","the","package","that","contains","the","template","directory",".",":","param","package_path",":","Directory","within","the","imported","package","that","contains","the","templates",".",":","param","encoding",":","Encoding","of","template","files",".","The","following","example","looks","up","templates","in","the","``","pages","``","directory","within","the","``","project.ui","``","package",".","..","code-block",":",":","python","loader","=","PackageLoader","(","``","project.ui","''",",","``","pages","''",")","Only","packages","installed","as","directories","(","standard","pip","behavior",")","or","zip\/egg","files","(","less","common",")","are","supported",".","The","Python","API","for","introspecting","data","in","packages","is","too","limited","to","support","other","installation","methods","the","way","this","loader","requires",".","There","is","limited","support","for",":","pep",":","`","420","`","namespace","packages",".","The","template","directory","is","assumed","to","only","be","in","one","namespace","contributor",".","Zip","files","contributing","to","a","namespace","are","not","supported",".","..","versionchanged",":",":","3.0","No","longer","uses","``","setuptools","``","as","a","dependency",".","..","versionchanged",":",":","3.0","Limited","PEP","420","namespace","package","support","."]
code: def __init__(
      self,
      package_name: str,
      package_path: "str" = "templates",
      encoding: str = "utf-8",
  ) -> None:
      package_path = os.path.normpath(package_path).rstrip(os.path.sep)
  
      # normpath preserves ".", which isn't valid in zip paths.
      if package_path == os.path.curdir:
          package_path = ""
      elif package_path[:2] == os.path.curdir + os.path.sep:
          package_path = package_path[2:]
  
      self.package_path = package_path
      self.package_name = package_name
      self.encoding = encoding
  
      # Make sure the package exists. This also makes namespace
      # packages work, otherwise get_loader returns None.
      package = import_module(package_name)
      spec = importlib.util.find_spec(package_name)
      assert (
          spec is not None
      ), "An import spec was not found for the package."
      loader = spec.loader
      assert (
          loader is not None
      ), "A loader was not found for the package."
      self._loader = loader
      self._archive = None
      self._package = package
      template_root = None
  
      if isinstance(loader, zipimport.zipimporter):
          self._archive = loader.archive
          pkgdir = next(iter(spec.submodule_search_locations))  # type: ignore
          template_root = os.path.join(pkgdir, package_path).rstrip(
              os.path.sep
          )
      elif hasattr(loader, "arcadia_source_finder"):
          template_root = os.path.dirname(package.__file__).rstrip(
              os.path.sep
          )
      else:
          roots: t.List[str] = []
  
          # One element for regular packages, multiple for namespace
          # packages, or None for single module file.
          if spec.submodule_search_locations:
              roots.extend(spec.submodule_search_locations)
          # A single module file, use the parent directory instead.
          elif spec.origin is not None:
              roots.append(os.path.dirname(spec.origin))
  
          for root in roots:
              root = os.path.join(root, package_path)
  
              if os.path.isdir(root):
                  template_root = root
                  break
  
      if template_root is None:
          raise ValueError(
              f"The {package_name!r} package was not installed in a"
              " way that PackageLoader understands."
          )
  
      self._template_root = template_root
  
imports: import importlib.util
  import os
  import posixpath
  import sys
  import pkgutil
  import typing
  import weakref
  import zipimport
  from collections import abc
  from hashlib import sha1
  from importlib import import_module
  from types import ModuleType
  from .exceptions import TemplateNotFound
  from .utils import internalcode
  from .utils import open_if_exists
  import __res
label_desc: Use image node_id 1 to create a new PackageLoader object from inherited base classes: BaseLoader with example: obj = PackageLoader(package_name, package_path, encoding)