# Path: ubelt/util_import.py
# class PythonPathContext(object):
#     """
#     Context for temporarily adding a dir to the PYTHONPATH.
# 
#     Used in testing, and used as a helper in certain ubelt functions.
# 
#     Warning:
#         Even though this context manager takes precautions, this modifies the
#         python path, and things can go wrong when that happens.  This is
#         generally safe as long as nothing else you do inside of this context
#         modifies the path. If the path is modified in this context, we will try
#         to detect it and warn.
# 
#     Args:
#         dpath (str): directory to insert into the PYTHONPATH
#         index (int): position to add to. Typically either -1 or 0.
# 
#     Example:
#         >>> with PythonPathContext('foo', -1):
#         >>>     assert sys.path[-1] == 'foo'
#         >>> assert sys.path[-1] != 'foo'
#         >>> with PythonPathContext('bar', 0):
#         >>>     assert sys.path[0] == 'bar'
#         >>> assert sys.path[0] != 'bar'
# 
#     Example:
#         >>> # xdoctest: +REQUIRES(module:pytest)
#         >>> # Mangle the path inside the context
#         >>> self = PythonPathContext('foo', 0)
#         >>> self.__enter__()
#         >>> sys.path.insert(0, 'mangled')
#         >>> import pytest
#         >>> with pytest.warns(UserWarning):
#         >>>     self.__exit__(None, None, None)
# 
#     Example:
#         >>> # xdoctest: +REQUIRES(module:pytest)
#         >>> self = PythonPathContext('foo', 0)
#         >>> self.__enter__()
#         >>> sys.path.remove('foo')
#         >>> import pytest
#         >>> with pytest.raises(RuntimeError):
#         >>>     self.__exit__(None, None, None)
#     """
#     def __init__(self, dpath, index=0):
#         self.dpath = dpath
#         self.index = index
# 
#     def __enter__(self):
#         if self.index < 0:
#             self.index = len(sys.path) + self.index + 1
#         sys.path.insert(self.index, self.dpath)
# 
#     def __exit__(self, type, value, trace):
#         need_recover = False
#         if len(sys.path) <= self.index:  # nocover
#             msg_parts = [
#                 'sys.path changed while in PythonPathContext.',
#                 'len(sys.path) = {!r} but index is {!r}'.format(
#                     len(sys.path), self.index),
#             ]
#             need_recover = True
# 
#         if sys.path[self.index] != self.dpath:  # nocover
#             # The path is not where we put it, the path must have been mangled
#             msg_parts = [
#                 'sys.path changed while in PythonPathContext',
#                 'Expected dpath={!r} at index={!r} in sys.path, but got '
#                 'dpath={!r}'.format(
#                     self.dpath, self.index, sys.path[self.index]
#                 )
#             ]
#             need_recover = True
# 
#         if need_recover:
#             # Try and find where the temporary path went
#             try:
#                 real_index = sys.path.index(self.dpath)
#             except ValueError:
#                 msg_parts.append('Expected dpath was not in sys.path')
#                 raise RuntimeError('\n'.join(msg_parts))
#             else:
#                 # We were able to recover, but warn the user. This method of
#                 # recovery is a heuristic and does not work in some cases.
#                 msg_parts.append((
#                     'Expected dpath was at index {}. '
#                     'This could indicate conflicting module namespaces.'
#                 ).format(real_index))
#                 warnings.warn('\n'.join(msg_parts))
#                 sys.path.pop(real_index)
#         else:
#             sys.path.pop(self.index)


import itertools as it
import ubelt as ub
import sys
import pytest
    import ast
            import sys
        import os
    import xdoctest
from os.path import join
from ubelt.util_import import PythonPathContext
    from xdoctest import static_analysis as static
        assert '_tmproot373.sub1.sub2' in sys.modules
        assert '_tmproot373' in sys.modules


def test_import_modname_builtin():
    module = ub.import_module_from_name('ast')
    assert module is ast


def _static_modname_to_modpath(modname, **kwargs):
    # Calls ub.modname_to_modpath with checks
    had = modname in sys.modules
    try:
        modpath = ub.modname_to_modpath(modname, **kwargs)
    except ValueError:
        modpath = None
    if not had:
        assert modname not in sys.modules, (
            '{} should not be imported'.format(modname))
    return modpath


def test_modname_to_modpath_single():
    with ub.TempDir() as temp:
        dpath = temp.dpath

        # Single module
        single = ub.touch(join(dpath, '_tmpsingle.py'))
        single_main = ub.touch(join(dpath, '__main__.py'))


# Path: ubelt/util_import.py
# class PythonPathContext(object):
#     """
#     Context for temporarily adding a dir to the PYTHONPATH.
# 
#     Used in testing, and used as a helper in certain ubelt functions.
# 
#     Warning:
#         Even though this context manager takes precautions, this modifies the
#         python path, and things can go wrong when that happens.  This is
#         generally safe as long as nothing else you do inside of this context
#         modifies the path. If the path is modified in this context, we will try
#         to detect it and warn.
# 
#     Args:
#         dpath (str): directory to insert into the PYTHONPATH
#         index (int): position to add to. Typically either -1 or 0.
# 
#     Example:
#         >>> with PythonPathContext('foo', -1):
#         >>>     assert sys.path[-1] == 'foo'
#         >>> assert sys.path[-1] != 'foo'
#         >>> with PythonPathContext('bar', 0):
#         >>>     assert sys.path[0] == 'bar'
#         >>> assert sys.path[0] != 'bar'
# 
#     Example:
#         >>> # xdoctest: +REQUIRES(module:pytest)
#         >>> # Mangle the path inside the context
#         >>> self = PythonPathContext('foo', 0)
#         >>> self.__enter__()
#         >>> sys.path.insert(0, 'mangled')
#         >>> import pytest
#         >>> with pytest.warns(UserWarning):
#         >>>     self.__exit__(None, None, None)
# 
#     Example:
#         >>> # xdoctest: +REQUIRES(module:pytest)
#         >>> self = PythonPathContext('foo', 0)
#         >>> self.__enter__()
#         >>> sys.path.remove('foo')
#         >>> import pytest
#         >>> with pytest.raises(RuntimeError):
#         >>>     self.__exit__(None, None, None)
#     """
#     def __init__(self, dpath, index=0):
#         self.dpath = dpath
#         self.index = index
# 
#     def __enter__(self):
#         if self.index < 0:
#             self.index = len(sys.path) + self.index + 1
#         sys.path.insert(self.index, self.dpath)
# 
#     def __exit__(self, type, value, trace):
#         need_recover = False
#         if len(sys.path) <= self.index:  # nocover
#             msg_parts = [
#                 'sys.path changed while in PythonPathContext.',
#                 'len(sys.path) = {!r} but index is {!r}'.format(
#                     len(sys.path), self.index),
#             ]
#             need_recover = True
# 
#         if sys.path[self.index] != self.dpath:  # nocover
#             # The path is not where we put it, the path must have been mangled
#             msg_parts = [
#                 'sys.path changed while in PythonPathContext',
#                 'Expected dpath={!r} at index={!r} in sys.path, but got '
#                 'dpath={!r}'.format(
#                     self.dpath, self.index, sys.path[self.index]
#                 )
#             ]
#             need_recover = True
# 
#         if need_recover:
#             # Try and find where the temporary path went
#             try:
#                 real_index = sys.path.index(self.dpath)
#             except ValueError:
#                 msg_parts.append('Expected dpath was not in sys.path')
#                 raise RuntimeError('\n'.join(msg_parts))
#             else:
#                 # We were able to recover, but warn the user. This method of
#                 # recovery is a heuristic and does not work in some cases.
#                 msg_parts.append((
#                     'Expected dpath was at index {}. '
#                     'This could indicate conflicting module namespaces.'
#                 ).format(real_index))
#                 warnings.warn('\n'.join(msg_parts))
#                 sys.path.pop(real_index)
#         else:
#             sys.path.pop(self.index)


# Path: tests/test_import.py
import itertools as it
import ubelt as ub
import sys
import pytest
    import ast
            import sys
        import os
    import xdoctest
from os.path import join
from ubelt.util_import import PythonPathContext
    from xdoctest import static_analysis as static

        assert '_tmproot373.sub1.sub2' in sys.modules
        assert '_tmproot373' in sys.modules


def test_import_modname_builtin():
    module = ub.import_module_from_name('ast')
    assert module is ast


def _static_modname_to_modpath(modname, **kwargs):
    # Calls ub.modname_to_modpath with checks
    had = modname in sys.modules
    try:
        modpath = ub.modname_to_modpath(modname, **kwargs)
    except ValueError:
        modpath = None
    if not had:
        assert modname not in sys.modules, (
            '{} should not be imported'.format(modname))
    return modpath


def test_modname_to_modpath_single():
    with ub.TempDir() as temp:
        dpath = temp.dpath

        # Single module
        single = ub.touch(join(dpath, '_tmpsingle.py'))
        single_main = ub.touch(join(dpath, '__main__.py'))


        with PythonPathContext(dpath):