# Path: src/jinja2/exceptions.py
# class TemplateNotFound(IOError, LookupError, TemplateError):
#     """Raised if a template does not exist.
# 
#     .. versionchanged:: 2.11
#         If the given name is :class:`Undefined` and no message was
#         provided, an :exc:`UndefinedError` is raised.
#     """
# 
#     # Silence the Python warning about message being deprecated since
#     # it's not valid here.
#     message: t.Optional[str] = None
# 
#     def __init__(
#         self,
#         name: t.Optional[t.Union[str, "Undefined"]],
#         message: t.Optional[str] = None,
#     ) -> None:
#         IOError.__init__(self, name)
# 
#         if message is None:
#             from .runtime import Undefined
# 
#             if isinstance(name, Undefined):
#                 name._fail_with_undefined_error()
# 
#             message = name
# 
#         self.message = message
#         self.name = name
#         self.templates = [name]
# 
#     def __str__(self) -> str:
#         return str(self.message)
# 
# Path: src/jinja2/utils.py
# def internalcode(f: F) -> F:
#     """Marks the function as internally used"""
#     internal_code.add(f.__code__)
#     return f
# 
# Path: src/jinja2/utils.py
# def open_if_exists(filename: str, mode: str = "rb") -> t.Optional[t.IO]:
#     """Returns a file descriptor for the filename if that file exists,
#     otherwise ``None``.
#     """
#     if not os.path.isfile(filename):
#         return None
# 
#     return open(filename, mode)


import importlib.util
import os
import sys
import typing as t
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
    from .environment import Environment
    from .environment import Template

    This is useful if you want to allow users to override builtin templates
    from a different location.
    """

    def __init__(self, loaders: t.Sequence[BaseLoader]) -> None:
        self.loaders = loaders

    def get_source(
        self, environment: "Environment", template: str
    ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]:
        for loader in self.loaders:
            try:
                return loader.get_source(environment, template)
            except TemplateNotFound:
                pass
        raise TemplateNotFound(template)

    @internalcode
    def load(
        self,
        environment: "Environment",
        name: str,
        globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
    ) -> "Template":
        for loader in self.loaders:
            try:
                return loader.load(environment, name, globals)
            except TemplateNotFound:
                pass

# Path: src/jinja2/exceptions.py
# class TemplateNotFound(IOError, LookupError, TemplateError):
#     """Raised if a template does not exist.
# 
#     .. versionchanged:: 2.11
#         If the given name is :class:`Undefined` and no message was
#         provided, an :exc:`UndefinedError` is raised.
#     """
# 
#     # Silence the Python warning about message being deprecated since
#     # it's not valid here.
#     message: t.Optional[str] = None
# 
#     def __init__(
#         self,
#         name: t.Optional[t.Union[str, "Undefined"]],
#         message: t.Optional[str] = None,
#     ) -> None:
#         IOError.__init__(self, name)
# 
#         if message is None:
#             from .runtime import Undefined
# 
#             if isinstance(name, Undefined):
#                 name._fail_with_undefined_error()
# 
#             message = name
# 
#         self.message = message
#         self.name = name
#         self.templates = [name]
# 
#     def __str__(self) -> str:
#         return str(self.message)
# 
# Path: src/jinja2/utils.py
# def internalcode(f: F) -> F:
#     """Marks the function as internally used"""
#     internal_code.add(f.__code__)
#     return f
# 
# Path: src/jinja2/utils.py
# def open_if_exists(filename: str, mode: str = "rb") -> t.Optional[t.IO]:
#     """Returns a file descriptor for the filename if that file exists,
#     otherwise ``None``.
#     """
#     if not os.path.isfile(filename):
#         return None
# 
#     return open(filename, mode)


# Path: src/jinja2/loaders.py
import importlib.util
import os
import sys
import typing as t
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
    from .environment import Environment
    from .environment import Template


    This is useful if you want to allow users to override builtin templates
    from a different location.
    """

    def __init__(self, loaders: t.Sequence[BaseLoader]) -> None:
        self.loaders = loaders

    def get_source(
        self, environment: "Environment", template: str
    ) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]:
        for loader in self.loaders:
            try:
                return loader.get_source(environment, template)
            except TemplateNotFound:
                pass
        raise TemplateNotFound(template)

    @internalcode
    def load(
        self,
        environment: "Environment",
        name: str,
        globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
    ) -> "Template":
        for loader in self.loaders:
            try:
                return loader.load(environment, name, globals)
            except TemplateNotFound:
                pass

        raise TemplateNotFound(name)