pytest_helper_main module¶
Description¶
This module contains helper functions for using the pytest unit testing framework.
Functions to help with running tests¶
-
pytest_helper.pytest_helper_main.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)[source]¶ 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 (unlessalways_runis set true).The argument
testfile_pathsshould 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 importingpytest_helper(or absolute pathnames can be used).The recommended use of
script_runis 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_testisTruethen 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_argsallows 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
--pyargsallows 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__.pyfile in the directory; the--pyargsjust allows Python-style module names. Whenpyargsis set true pytest will be run with the--pyargsoption set, and any items intestfile_pathswhich contain no path-separator character (slash) will be left unprocessed rather than being converted into absolute pathnames. The pytest option--pyargswill not work correctly unless this flag is set. The default ispyargs=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./dirnamerather than simplyfilename.If
modify_syspathis explicitly setTruethen the first item in thesys.pathlist is deleted, but only if it has not been deleted before (by this package or by theset_package_attributepackage). Ifmodify_syspathis set false then the system path is not modified. The default isNone, 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 insys.path. This can sometimes cause hard-to-trace import errors when directories inside paths are inserted insys.path. Deleting that added directory first prevents those errors. Ifscript_rundoes not call exit at the end (becauseexit==False) then, before returning, any modified system path is restored to a saved copy of its full, original condition.The
calling_mod_nameargument 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 forcalling_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_callis set false then instead the paths are looped over, one by one, with a separate call to pytest on each one.If
exitis set falsesys.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). Settingexitfalse can be used to make several separatescript_runcalls in sequence.If
always_runis true then tests will be run regardless of whether or not the function was called from a script.If
skipis 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. Thepskipoption is the same, except that it also sets the package attribute viaset_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 themodify_syspathargument is passed to theinitfunction ofset_package_attribute).The parameter
levelis the level up the calling stack to look for the calling module and should not usually need to be set.
-
pytest_helper.pytest_helper_main.sys_path(dirs_to_add=None, add_parent=False, add_grandparent=False, add_gn_parent=False, add_self=False, insert_position=1, calling_mod_name=None, calling_mod_path=None, level=2)[source]¶ Add the canonical absolute pathname of each directory in the list
dirs_to_addtosys.path(but only if it isn’t there already). A single string representing a path can also be passed todirs_to_add. Relative pathnames are always interpreted relative to the directory of the calling module (i.e., the directory of the module that calls this function). The notes about relative paths for thescript_runfunction also apply here.The keyword arguments
add_parentandadd_grandparentare shortcuts that can be used instead of putting the equivalent relative path on the listdirs_to_add. If the keyword argumentadd_gn_parentis set to a non-negative integernthen the (grand)nparent is added to the path, where (grand)1parent is the grandparent. Ifadd_selfis true then the directory of the calling module is added to the systemsys.pathlist.The keyword argument
insert_positiondetermines where insys.paththe the pathnames are placed (usinginsert). The default is 1. If inserting at 0 watch for conflicts with themodify_syspathoptions toscript_runandinit.The parameters
calling_mod_nameandcalling_mod_dircan be set as a fallback in case the introspection for finding the calling module’s information fails for some reason. The parameterlevelis the level up the calling stack to look for the calling module and should not usually need to be set.
-
pytest_helper.pytest_helper_main.restore_previous_sys_path()[source]¶ This function undoes the effect of the last call to
sys_path, returningsys.pathto its previous, saved value. This can be useful at times.
-
pytest_helper.pytest_helper_main.init(modify_syspath=None, conf=True, calling_mod_name=None, calling_mod_path=None, level=2)[source]¶ A function to initialize the
pytest_helpermodule just after importing it. This function is useful, for example, in rare cases where Python’s current working directory (CWD) is changed between the time when the executing module is first loaded and whenscript_runorsys_pathis 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. Importingpytest_helperjust after the system imports and then immediately calling this function should work.The
modify_syspathoption affects whether or not thesys.path[0]element is removed. The defaultNoneis to remove it for scripts run from inside packages since that can mess up the imports of modules running as packages.If the parameter
confis 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 theinitfunction itself). The configuration information for modules is cached, and so is only looked up once.
Functions to help in writing tests¶
-
pytest_helper.pytest_helper_main.autoimport(noclobber=True, skip=None, calling_mod_name=None, calling_mod_path=None, level=2)[source]¶ 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
autoimportis called from inside a test function it will still place its imports in the module’s global namespace. APytestHelperExceptionwill be raised if any of those globals already exist, unlessnoclobberis set false.The
importsoption 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 ofpytest_helper. Theskipoption 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_helpermodule arelocals_to_globals,clear_locals_from_globals, andunindent. The modulepytestis imported aspytest. The functions from pytest that are imported by default areraises,fail,fixture, andskip,xfail, andapprox.
-
pytest_helper.pytest_helper_main.locals_to_globals(fun_locals=None, fun_globals=None, clear=False, noclobber=True, ignore_params=True, level=2)[source]¶ Copy all local variables in the calling test function’s local scope to the global scope of the module from which that function was called. The test function’s parameters are ignored (i.e., they are local variables but they are not made global). Setting
ignore_paramsfalse copies them, too.This routine should generally be called near the end of a test function or fixture. It allows for variables to be shared with other test functions, as globals.
Calls to
locals_to_globalsdo not allow existing global variables to be overwritten unless they were either 1) set by a previous run of this function, or 2)noclobberis set false. Otherwise aLocalsToGlobalsErrorwill be raised. This avoids accidentally overwriting important global attributes (especially when tests are in the same module being tested).This routine’s effect is similar to the effect of explicitly declaring each of a function’s local variables to be
global, or doingglobals().update(locals()), except that 1) it ignores local variables which are function parameters, 2) it adds more error checks, and 3) it can clear any previously-set values.Note that the globals set with
locals_to_globalscan be accessed and used in any other test function in the module, but they are still read-only (as usual with globals). An attribute must be explicitly declaredglobalin order to modify the global value. (It is then no longer local to the function, solocals_to_globalswill not affect it, butclearwill still remember it and clear it if called.)If
clearis true (the default is false) then any variable that was set on the last run of this function will be automatically cleared before any new ones are set. This is good to call in the first-run fixture or setup function, since it helps avoid “false positives” where a later test succeeds only because of a global left over from a previous test. Note globals on the saved list of globals are cleared even if their values were later modified.The argument
fun_localscan be used as a fallback to pass thelocals()dict from the function in case the introspection technique does not work for some reason. Thefun_globalsargument can similarly be passed globals() as a fallback. So you could call:locals_to_globals(locals(), globals())
to bypass the introspection used to locate the two dicts.
The
levelargument is the level up the calling stack to look for the calling function. In order to call an intermediate function which then calls this function, for example,levelwould need to be increased by one.
-
pytest_helper.pytest_helper_main.clear_locals_from_globals(level=2)[source]¶ Clear all the global variables that were added by locals_to_globals. This is called automatically by
locals_to_globalsunless that function is run withclearset false. This only affects the module from which the function is called.
-
pytest_helper.pytest_helper_main.unindent(unindent_level, string)[source]¶ Strip indentation from a docstring. This function is useful in tests where you have assertions that something equals a multi-line string. It allows the strings to be represented as multi-line docstrings but indented in a way that matches the surrounding code.
Calling this function on a string 1) splits it into lines (keeping empty lines, too), 2) discards the first and last line, and 3) removes
unindent_levelcharacters from the beginning of each line. Then 4) the modified lines are joined with newline and returned. Raises an exception on an attempt to strip non-whitespace or if there are fewer than two lines.