Skip to content

Ensure __version__ is retrieved while all dependencies are available #253

@flying-sheep

Description

@flying-sheep

load_module is deprecated. And exec_module has a distinct advantage:

Since we try to get __version__ from a module that possibly doesn’t have its dependencies installed, we could partially execute the module by ignoring exceptions (ImportErrors would be sufficient). If the module manages to already set its __version__ before an ImportError is raised, flit install will still work.

This allows to only add those dependencies to build-requires which are needed to get the __version__, and let flit do the rest.

import importlib.util

def get_docstring_and_version_via_import(target):
    """
    Return a tuple like (docstring, version) for the given module,
    extracted by importing the module and pulling __doc__ & __version__
    from it.
    """
    log.debug("Loading module %s", target.file)
    spec = importlib.util.spec_from_file_location(target.name, str(target.file))
    m = importlib.util.module_from_spec(spec)
    with _module_load_ctx():
        spec.loader.exec_module(m)
    docstring = m.__dict__.get('__doc__', None)
    version = m.__dict__.get('__version__', None)
    return docstring, version

@contextmanager
def _module_load_ctx():
    """Preserve some global state that modules might change at import time.
    - Handlers on the root logger.
    - Ignores ImportErrors
    """
    logging_handlers = logging.root.handlers[:]
    try:
        yield
    except ImportError:
        pass
    finally:
        logging.root.handlers = logging_handlers

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions