Example #1
0
def import_requirement(requirement: Requirement) -> ModuleType:
    '''
    Import and return the top-level module object satisfying the passed
    :mod:`setuptools`-specific requirement.

    Parameters
    ----------
    requirement : Requirement
        Object describing this module or package's required name and version.

    Returns
    ----------
    ModuleType
        Top-level package object implementing this requirement.

    Raises
    ----------
    ImportError
        If this package is unimportable.
    '''

    # Avoid circular import dependencies.
    from betse.util.py.module import pymodname
    from betse.util.py.module.pymodname import (
        DISTUTILS_PROJECT_NAME_TO_MODULE_NAME)

    # Fully-qualified name of this requirement's package.
    package_name = DISTUTILS_PROJECT_NAME_TO_MODULE_NAME[
        requirement.project_name]

    # Log this importation, which can often have unexpected side effects.
    logs.log_debug('Importing third-party package "%s"...', package_name)

    # Import and return this package.
    return pymodname.import_module(package_name)
Example #2
0
    def _run_pyinstaller_imported(self) -> None:
        '''
        Run the currently configured PyInstaller command within the current
        Python process -- rather than as an external command in a different
        Python process.

        This function imports and executes PyInstaller's CLI implementation in
        the current Python process, circumventing the inevitable complications
        that arise when running PyInstaller as an external command.
        '''

        # Defer heavyweight imports.
        from betse.util.py.module import pymodname

        # PyInstaller's top-level "__main__" module, providing programmatic
        # access to its CLI implementation.
        pyinstaller_main = pymodname.import_module(
            module_name='PyInstaller.__main__',
            exception_message=('PyInstaller not installed under the '
                               'active Python interpreter.'))

        # Run PyInstaller and propagate its exit status as ours to the caller.
        print('Running PyInstaller with arguments: {}'.format(
            self._pyinstaller_args))
        sys.exit(pyinstaller_main.run(pyi_args=self._pyinstaller_args))
Example #3
0
    def test_package(self) -> ModuleType:
        '''
        **Root test package** (i.e., topmost package for this application's
        ancillary test suite, typically of the same name as this application
        suffixed by ``_test``) for this application.

        Caveats
        ----------
        **This package is typically not installed with this application,** as
        tests are useless (or at least incidental) for most end user purposes.
        Instead, this package is only distributed with tarballs archiving the
        contents of this application's repository at stable releases time. This
        package is *not* guaranteed to exist and, in fact, typically does not.

        Raises
        ----------
        ImportError
            If this package either does not exist *or* does exist but is
            unimportable (e.g., due to package-scoped side effects at
            importation time).
        '''

        # Avoid circular import dependencies.
        from betse.util.py.module import pymodname

        # Introspection for the glorious victory.
        return pymodname.import_module(module_name=self.test_package_name)
Example #4
0
    def _init_pytest(self) -> None:
        '''
        Dynamically import the top-level :mod:`pytest` package into this
        object's :attr:`_pytest` instance variable.

        Specifically, this method imports the top-level :mod:`_pytest.main`
        module, providing programmatic access to the CLI implementation of
        :mod:`pytest`. While :mod:`pytest` is also runnable as an external
        command, doing so invites non-trivial complications. Unlike most Python
        applications (e.g., PyInstaller), :mod:`pytest` is *not* dynamically
        importable via the following import machinery:

            # Don't do this.
            >>> pytest_main = pymodname.import_module(
            ...    'pytest.main', exception_message=(
            ...    'py.test not installed under the current Python interpreter.'))

        Attempting to do so reliably raises exceptions resembling:

            AttributeError: 'module' object has no attribute '__path__'

        The reason why appears to be package ``__path__`` manipulations
        dynamically performed by the private :mod:`_pytest` package. Sadly,
        attempting to import :func:`_pytest.main` fails with an even more
        inscrutable exception. The solution, of course, is to brute-force it
        by only dynamically importing the root :mod:`pytest` package.
        '''

        # Defer heavyweight imports.
        from betse.util.py.module import pymodname

        # Import the public "pytest" package *BEFORE* the private "_pytest"
        # package. While importation order is typically ignorable, imports can
        # technically have side effects. Tragicomically, this is the case here.
        # Importing the public "pytest" package establishes runtime
        # configuration required by submodules of the private "_pytest"
        # package. The former *MUST* always be imported before the latter.
        # Failing to do so raises obtuse exceptions at runtime... which is bad.
        self._pytest_public = pymodname.import_module(
            'pytest',
            exception_message=(
                'py.test not installed under the active Python interpreter.'))
        self._pytest_private = pymodname.import_module(
            '_pytest',
            exception_message=(
                'py.test not installed under the active Python interpreter.'))
Example #5
0
def get_c_extension() -> ModuleType:
    '''
    Arbitrary Numpy-specific submodule guaranteed to be implemented as a C
    extension.

    Application startup typically tests platform-specific libraries linked
    against this C extension to attempt to dynamically detect whether this
    version of Numpy is multithreaded or not.

    :func:`get_c_extension_name_qualified`
        Further details.
    '''

    # One-liners for the greater glory of BETSE.
    return pymodname.import_module(get_c_extension_name_qualified())
Example #6
0
def resolve_module(module: ModuleOrStrTypes) -> ModuleType:
    '''
    Dynamically import and return the module with the passed name if the passed
    parameter is a string *or* return the passed module as is otherwise.

    Motivation
    ----------
    This utility function is principally intended to simplify the
    implementation of public functions defined by this submodule and the
    :mod:`betse.util.py.module.pypackage` submodule.

    Parameters
    ----------
    module : ModuleOrStrTypes
        Either:

        * The fully-qualified name of this module, in which case this function
          dynamically imports this module.
        * A previously imported module object.

    Returns
    ----------
    ModuleType
        Module object resolved from the passed parameter.
    '''

    # Avoid circular import dependencies.
    from betse.util.py.module import pymodname

    # Return either...
    return (
        # A module object dynamically imported as this module name...
        pymodname.import_module(module)
        # If a module name rather than object was passed; else...
        if types.is_str(module) else
        # This module object.
        module)
Example #7
0
def get_object_type_package_root(obj: object) -> ModuleType:
    '''
    **Root package** (i.e., topmost package whose package name contains no
    ``.`` delimiters) transitively defining the class of the passed object.

    Parameters
    ----------
    obj : object
        Object to retrieve the root package name of.

    Returns
    ----------
    ModuleType
        Root package transitively defining this object's class.
    '''

    # Avoid circular import dependencies.
    from betse.util.py.module import pymodname

    # Fully-qualified name of the root package of this object's class.
    class_package_root_name = get_object_type_package_root_name(obj)

    # Return the previously imported instance of this root package.
    return pymodname.import_module(module_name=class_package_root_name)