Beispiel #1
0
def autoimport(noclobber=True,
               skip=None,
               calling_mod_name=None,
               calling_mod_path=None,
               level=2):
    """This function imports some pytest-helper and pytest attributes into the
    calling module's global namespace.  This avoids having to explicitly do
    common imports.  Even if `autoimport` is called from inside a test function
    it will still place its imports in the module's global namespace.  A
    `PytestHelperException` will be raised if any of those globals already
    exist, unless `noclobber` is set false.

    The `imports` option is a list of (name,value) pairs to import
    automatically.  Since using it each time would be as much trouble as doing
    the imports, explicitly, it is mainly meant to be set in configuration
    files.  In a config file the values are evaluated in the global namespace
    of `pytest_helper`.  The `skip` option is a list of names to skip in
    importing, if just one or two are causing problems locally to a file.

    The default variables that are imported from the `pytest_helper` module are
    `locals_to_globals`, `clear_locals_from_globals`, and `unindent`.  The
    module `pytest` is imported as `pytest`.  The functions from pytest that
    are imported by default are `raises`, `fail`, `fixture`, and `skip`,
    `xfail`, and `approx`."""

    mod_info = get_calling_module_info(module_name=calling_mod_name,
                                       module_path=calling_mod_path,
                                       level=level)
    calling_mod_name, calling_mod, calling_mod_path, calling_mod_dir, in_pkg = mod_info

    # Override arguments with any values set in the config file.
    noclobber = get_config_value("autoimport_noclobber", noclobber,
                                 calling_mod, calling_mod_dir)
    skip = get_config_value("autoimport_skip", skip, calling_mod,
                            calling_mod_dir)

    def insert_in_dict(d, name, value, noclobber):
        """Insert (name, value) in dict d checking for noclobber."""
        if noclobber and name in d:
            raise PytestHelperException(
                "The pytest_helper function autoimport"
                "\nattempted an overwrite with noclobber set.  The attribute"
                " is: " + name)
        try:
            d[name] = value
        except KeyError:
            raise

    g = get_calling_fun_globals_dict(level=level)

    for name, value in autoimport_DEFAULTS:
        if skip and name in skip: continue
        insert_in_dict(g, name, value, noclobber)
def autoimport(noclobber=True, skip=None,
              calling_mod_name=None, calling_mod_path=None, level=2):
    """This function imports some pytest-helper and pytest attributes into the
    calling module's global namespace.  This avoids having to explicitly do
    common imports.  A `PytestHelperException` will be raised if any of those
    globals already exist, unless `noclobber` is set false.

    The `imports` option is a list of (name,value) pairs to import
    automatically.  Since using it each time would be as much trouble as doing
    the imports, explicitly, it is mainly meant to be set in configuration
    files.  In a config file the values are evaluated in the global namespace
    of `pytest_helper`.  The `skip` option is a list of names to skip in
    importing, if just one or two are causing problems locally to a file.
    
    The default variables that are imported from the `pytest_helper` module are
    `locals_to_globals`, and `clear_locals_from_globals`.  The module `py.test`
    is imported as the single name `pytest`.  The functions from pytest that
    are imported by default are `raises`, `fail`, `fixture`, and `skip`, and
    `xfail`."""

    mod_info = get_calling_module_info(module_name=calling_mod_name,
                                       module_path=calling_mod_path, level=level)
    calling_mod_name, calling_mod, calling_mod_path, calling_mod_dir = mod_info

    # Override arguments with any values set in the config file.
    noclobber = get_config_value("autoimport_noclobber", noclobber,
                                             calling_mod, calling_mod_dir)
    skip = get_config_value("autoimport_skip", skip,
                                             calling_mod, calling_mod_dir)

    def insert_in_dict(d, name, value, noclobber):
        """Insert (name, value) in dict d checking for noclobber."""
        if noclobber and name in d:
            raise PytestHelperException("The pytest_helper function autoimport"
                    "\nattempted an overwrite with noclobber set.  The attribute"
                    " is: " + name)
        try:
           d[name] = value
        except KeyError:
            raise

    g = get_calling_fun_globals_dict(level=level)

    for name, value in autoimport_DEFAULTS:
        if skip and name in skip: continue
        insert_in_dict(g, name, value, noclobber)

    return
def init(set_package=False, conf=True, calling_mod_name=None,
                                        calling_mod_path=None, level=2):
    """A function to initialize the `pytest_helper` module just after importing
    it.  This function is currently only necessary in rare cases where Python's
    current working directory (CWD) is changed between the time when the
    executing module is first loaded and when `script_run` or `sys_path` is
    called from that module.  In those cases the module's pathname relative to
    the previous CWD will be incorrectly expanded relative to the new CWD.
    Calling this function causes the earlier expanded pathname to be cached.
    This function should be called before any function call or import which
    changes the CWD and which doesn't change it back afterward.  Importing
    `pytest_helper` just after the system imports and then immediately calling
    this function should work.
    
    The `init` function takes an optional keyword argument `set_package`.  If
    it is true then whenever the calling module is a script the package
    attribute of module `__main__` will be automatically set.  This allows for
    using explicit relative imports from scripts, but it must be called before
    the explicit relative imports are attempted.  If the calling module was run
    as a script then the function call `pytest_helper.init(set_package=True)`
    will import the `set_package_attribute` package and initialize it.
    Otherwise, it will do the same as the ordinary call.
        
    If the parameter `conf` is set false then no configuration files will be
    searched for or used.  Otherwise, the configuration file will be searched
    for by any function which has an option settable in a config file
    (including the `init` function itself).
    """
    # The get_calling_module_info function caches the module info, including the
    # calling_mod_path, as a side effect.
    mod_info = get_calling_module_info(module_name=calling_mod_name,
                                       module_path=calling_mod_path, level=level)
    calling_mod_name, calling_mod, calling_mod_path, calling_mod_dir = mod_info

    # Disable the configuration file if requested.
    if not conf or not ALLOW_USER_CONFIG_FILES:
        get_config(calling_mod, calling_mod_dir, disable=True)

    # Override init arguments with any values set in the config file.
    set_package = get_config_value("init_set_package", set_package,
                                             calling_mod, calling_mod_dir)

    # Handle the set_package option.
    if set_package:
        if calling_mod_name == "__main__":
            import set_package_attribute
            set_package_attribute.init()

    return
def script_run(testfile_paths=None, self_test=False, pytest_args=None, pyargs=False,
               modify_syspath=False, calling_mod_name=None, calling_mod_path=None,
               exit=True, always_run=False, level=2):
    """Run pytest on the specified test files when the calling module is run as
    a script.  Using this function requires at least pytest 2.0.
    
    The argument `testfile_paths` should be either the pathname of a file or
    directory to run pytest on, or else a list of such file and directory
    paths.  Any relative paths will be interpreted relative to the directory of
    the module which calls this function.

    The calculation of relative paths can fail in cases where Python's CWD is
    changed between the time when the calling module is loaded and a
    pytest-helper function is called.  (Most programs do not change the CWD
    like that, or if they do they return it to its previous value.)  In those
    cases the `pytest_helper.init()` function can be called just after
    importing `pytest_helper` (or absolute pathnames can be used).
   
    The recommended use of `script_run` is to place it inside a guard
    conditional which runs only for scripts, and to call it before doing any
    other non-system imports.  The early call avoids possible problems with
    relative imports when running it from inside modules that are part of
    packages.  The use of the guard conditional is optional, but is more
    explicit and slightly more efficient.

    If `self_test` is `True` then pytest will be run on the file of the calling
    script itself, i.e., tests are assumed to be in the same file as the code
    to test.

    The `pytest_args` allows command-line arguments to be passed to pytest when
    it is run.  It can be set to a string of all the options or else a list of
    strings (with one item in the list for each flag and for each flag
    argument).  Options containing non-separator spaces, such as whitespace in
    quoted filenames, are currently not allowed in the string form.  In that
    case the list form should be used.

    The pytest command-line argument `--pyargs` allows a mix of filenames and
    Python package names to be passed to pytest as test files.  Note that
    pytest *always* imports modules as part of a package if there is an
    `__init__.py` file in the directory; the `--pyargs` just allows
    Python-style module names.  When `pyargs` is set true pytest will be run
    with the `--pyargs` option set, and any items in `testfile_paths` which
    contain no path-separator character (slash) will be left unprocessed rather
    than being converted into absolute pathnames.  The pytest option `--pyargs`
    will not work correctly unless this flag is set.  The default is
    `pyargs=False`, i.e., by default all paths are converted to absolute
    pathnames.  It usually will not matter, but in this mode you can specify a
    directory name relative to the current directory and not have it treated as
    a Python module name by using `./dirname` rather than simply `filename`.

    If `modify_syspath` is set true (the default is false) then the first item
    in the `sys.path` list is deleted just after `script_run` is called.  When
    a module is run as a script Python always adds the directory of the script
    as the first item in `sys.path`.  This can sometimes cause hard-to-trace
    import errors when directories inside paths are inserted in `sys.path`.
    This flag should seldom be needed because pytest seems to already take care
    of this.

    The `calling_mod_name` argument is a fallback in case the calling
    function's module is not correctly located by introspection.  It is usually
    not required (though it is slightly more efficient).  Use it as:
    `module_name=__name__`.  Similarly for `calling_mod_path`, but that should
    be passed the pathname of the calling module's file.
    
    If `exit` is set false `sys.exit(0)` will not be called after the tests
    finish.  The default is to exit after the tests finish (otherwise when
    tests run from the top of a module are finished the rest of the file will
    still be executed).  Setting `exit` false can be used to make several
    separate `script_run` calls in sequence.
    
    If `always_run` is true then tests will be run regardless of whether or not
    the function was called from a script.
    
    The parameter `level` is the level up the calling stack to look for the
    calling module and should not usually need to be set."""

    mod_info = get_calling_module_info(module_name=calling_mod_name,
                                       module_path=calling_mod_path, level=level)
    calling_mod_name, calling_mod, calling_mod_path, calling_mod_dir = mod_info

    if calling_mod_name != "__main__":
        if not always_run: return

    # Convert string pytest_args arguments to a list.
    def convert_arg_string_to_list(arg_list_or_string):
        if not arg_list_or_string:
            pytest_arglist = []
        elif isinstance(arg_list_or_string, str):
            pytest_arglist = ["-" + s for s in arg_list_or_string.split("-") if s]
            pytest_arglist = [s for x in pytest_arglist for s in x.split()]
        else:
            pytest_arglist = arg_list_or_string
        return pytest_arglist

    # Override arguments with any values set in the config file.
    pytest_arglist = convert_arg_string_to_list(pytest_args)

    pytest_arglist = convert_arg_string_to_list(  # These override passed-in args.
                             get_config_value("script_run_pytest_args", pytest_arglist,
                                             calling_mod, calling_mod_dir))
    pytest_arglist += convert_arg_string_to_list( # These are added to passed-in args.
                             get_config_value("script_run_extra_pytest_args", [],
                                             calling_mod, calling_mod_dir))

    if modify_syspath:
        del sys.path[0]

    if isinstance(testfile_paths, str):
        testfile_paths = [testfile_paths]
    elif testfile_paths is None:
        testfile_paths = []

    if self_test:
        testfile_paths.append(calling_mod_path)

    testfile_paths = [os.path.expanduser(p) for p in testfile_paths]

    # If pyargs is set, don't expand any arguments which do not have a slash in
    # them.  In that case it was not a relative pathname anyway (except to
    # current dir, which necessitates the use of "./filename" rather than
    # "filename").  Will be treated as a package if pyargs=True.
    if pyargs:
        testfile_paths = [expand_relative(p, calling_mod_dir)
                          if os.path.sep in p else p for p in testfile_paths]
    else:
        testfile_paths = [expand_relative(p, calling_mod_dir) for p in testfile_paths]

    # Add "--pyargs" to arguments if not there and no flag not to.
    if pyargs and "--pyargs" not in pytest_arglist:
        pytest_arglist.append("--pyargs")

    # Generate calling string and call pytest on the file.
    for t in testfile_paths:
        # Call pytest main; this requires pytest 2.0 or greater.
        py.test.main(pytest_arglist + [t])

    if exit:
        sys.exit(0)
    return
Beispiel #5
0
def script_run(testfile_paths=None,
               self_test=False,
               pytest_args=None,
               pyargs=False,
               modify_syspath=None,
               calling_mod_name=None,
               calling_mod_path=None,
               single_call=True,
               exit=True,
               always_run=False,
               skip=False,
               pskip=False,
               level=2):
    """Run pytest on the specified test files when the calling module is run as
    a script.  Using this function requires at least pytest 2.0.  If the module
    from which this script is called is not `__main__` then this script
    immediately returns and does nothing (unless `always_run` is set true).

    The argument `testfile_paths` should be either the pathname of a file or
    directory to run pytest on, or else a list of such file and directory
    paths.  Any relative paths will be interpreted relative to the directory of
    the module which calls this function.

    The calculation of relative paths can fail in cases where Python's CWD is
    changed between the time when the calling module is loaded and a
    pytest-helper function is called.  (Most programs do not change the CWD
    like that, or if they do they return it to its previous value.)  In those
    cases the `pytest_helper.init()` function can be called just after
    importing `pytest_helper` (or absolute pathnames can be used).

    The recommended use of `script_run` is to place it inside a guard
    conditional which runs only for scripts, and to call it before doing any
    other non-system imports.  The early call avoids possible problems with
    relative imports when running it from inside modules that are part of
    packages.  The use of the guard conditional is optional, but is more
    explicit and slightly more efficient.

    If `self_test` is `True` then pytest will be run on the file of the calling
    script itself, i.e., tests are assumed to be in the same file as the code
    to test.

    The `pytest_args` allows command-line arguments to be passed to pytest when
    it is run.  It can be set to a string of all the options or else a list of
    strings (with one item in the list for each flag and for each flag
    argument).  Options containing non-separator spaces, such as whitespace in
    quoted filenames, are currently not allowed in the string form.  In that
    case the list form should be used.

    The pytest command-line argument `--pyargs` allows a mix of filenames and
    Python package names to be passed to pytest as test files.  Note that
    pytest *always* imports modules as part of a package if there is an
    `__init__.py` file in the directory; the `--pyargs` just allows
    Python-style module names.  When `pyargs` is set true pytest will be run
    with the `--pyargs` option set, and any items in `testfile_paths` which
    contain no path-separator character (slash) will be left unprocessed rather
    than being converted into absolute pathnames.  The pytest option `--pyargs`
    will not work correctly unless this flag is set.  The default is
    `pyargs=False`, i.e., by default all paths are converted to absolute
    pathnames.  It usually will not matter, but in this mode you can specify a
    directory name relative to the current directory and not have it treated as
    a Python module name by using `./dirname` rather than simply `filename`.

    If `modify_syspath` is explicitly set `True` then the first item in the
    `sys.path` list is deleted, but only if it has not been deleted before (by
    this package or by the `set_package_attribute` package).  If
    `modify_syspath` is set false then the system path is not modified.  The
    default is `None`, which modifies the system path if the calling module is
    part of a package and otherwise does not.  The reason for this option is
    that when a module is run as a script Python always adds the directory of
    the script as the first item in `sys.path`.  This can sometimes cause
    hard-to-trace import errors when directories inside paths are inserted in
    `sys.path`.  Deleting that added directory first prevents those errors.  If
    `script_run` does not call exit at the end (because `exit==False`) then,
    before returning, any modified system path is restored to a saved copy of
    its full, original condition.

    The `calling_mod_name` argument is a fallback in case the calling
    function's module is not correctly located by introspection.  It is usually
    not required (though it is slightly more efficient).  Use it as:
    `module_name=__name__`.  Similarly for `calling_mod_path`, but that should
    be passed the pathname of the calling module's file.

    By default the script-run program passes all the user-specified testfile
    paths to a single run of pytest.  If `single_call` is set false then
    instead the paths are looped over, one by one, with a separate call to
    pytest on each one.

    If `exit` is set false `sys.exit(0)` will not be called after the tests
    finish.  The default is to exit after the tests finish (otherwise when
    tests run from the top of a module are finished the rest of the file will
    still be executed).  Setting `exit` false can be used to make several
    separate `script_run` calls in sequence.

    If `always_run` is true then tests will be run regardless of whether or not
    the function was called from a script.

    If `skip` is set to true from the default false then the function returns
    immediately without doing anything.  This is just a keyword argument switch
    that can be used to temporarily turn off test-running without large changes
    to the code.  The module runs normally without pytest being invoked.  The
    `pskip` option is the same, except that it also sets the package attribute
    via `set_package_attribute`.  This option is useful if the script is being
    run inside a package, since it allows relative imports to be used in the
    script.  (In this case the `modify_syspath` argument is passed to the `init`
    function of `set_package_attribute`).

    The parameter `level` is the level up the calling stack to look for the
    calling module and should not usually need to be set."""
    if skip:
        return
    if pskip:
        set_package_attribute.init(modify_syspath)
        return

    mod_info = get_calling_module_info(module_name=calling_mod_name,
                                       module_path=calling_mod_path,
                                       level=level)
    calling_mod_name, calling_mod, calling_mod_path, calling_mod_dir, in_pkg = mod_info

    if calling_mod_name != "__main__" and not always_run:
        return

    def convert_arg_string_to_list(arg_list_or_string):
        """Convert string pytest_args arguments to a list, keeping lists unchanged."""
        if not arg_list_or_string:
            pytest_arglist = []
        elif isinstance(arg_list_or_string, str):
            pytest_arglist = arg_list_or_string.split()
        else:
            pytest_arglist = arg_list_or_string
        return pytest_arglist

    # Override arguments with any values set in the config file.
    pytest_arglist = convert_arg_string_to_list(pytest_args)

    pytest_arglist = convert_arg_string_to_list(  # These override passed-in args.
        get_config_value("script_run_pytest_args", pytest_arglist, calling_mod,
                         calling_mod_dir))
    pytest_arglist += convert_arg_string_to_list(  # These are added to passed-in args.
        get_config_value("script_run_extra_pytest_args", [], calling_mod,
                         calling_mod_dir))

    if modify_syspath or (modify_syspath is None and in_pkg):
        set_package_attribute._delete_sys_path_0()

    if isinstance(testfile_paths, str):
        testfile_paths = [testfile_paths]
    elif testfile_paths is None:
        testfile_paths = []

    if self_test:
        testfile_paths.append(calling_mod_path)

    testfile_paths = [os.path.expanduser(p) for p in testfile_paths]

    # If pyargs is set, don't expand any arguments which do not have a slash in
    # them.  In that case it was not a relative pathname anyway (except to
    # current dir, which necessitates the use of "./filename" rather than
    # "filename").  Will be treated as a package if pyargs=True.
    if pyargs:
        testfile_paths = [
            expand_relative(p, calling_mod_dir) if os.path.sep in p else p
            for p in testfile_paths
        ]
    else:
        testfile_paths = [
            expand_relative(p, calling_mod_dir) for p in testfile_paths
        ]

    # Add "--pyargs" to arguments if not there and no flag not to.
    if pyargs and "--pyargs" not in pytest_arglist:
        pytest_arglist.append("--pyargs")

    # Generate calling string and call pytest on the file.
    if single_call:
        pytest.main(pytest_arglist + testfile_paths)
    else:
        for testfile in testfile_paths:
            # Call pytest main; this requires pytest 2.0 or greater.
            pytest.main(pytest_arglist + [testfile])

    if exit:
        sys.exit(0)