ci_exec.utils¶
Assorted utility functions.
This module aims to house any utility functions that may facilitate easier consumption
of the ci_exec
package.
cd
(dest, *[, create])Context manager / decorator that can be used to change directories.
merge_kwargs
(defaults, kwargs)Merge
defaults
intokwargs
and returnkwargs
.
set_env
(**kwargs)Context manager / decorator that can be used to set environment variables.
unset_env
(*args)Context manager / decorator that can be used to unset environment variables.
- class cd(dest, *, create=False)[source]¶
Context manager / decorator that can be used to change directories.
This context manager will change directories to
dest
, and after its scope expires (outside of thewith
statement, or after the decorated function) it will change directories back to the original current working directory.As a context manager:
from ci_exec import cd, which if __name__ == "__main__": # Get the build tools setup. cmake = which("cmake") ninja = which("ninja") # Suppose current directory here is "/source" with cd("build", create=True): # Current directory is now "/source/build" cmake("..", "-G", "Ninja", "-DCMAKE_BUILD_TYPE=Release") ninja() # Any code out-dented (not under the `with`): current directory is "/source"
As a decorator:
from ci_exec import cd, which @cd("build", create=True) def build(): # Inside the function: current directory is "/source/build" cmake = which("cmake") ninja = which("ninja") cmake("..", "-G", "Ninja", "-DCMAKE_BUILD_TYPE=Release") ninja() if __name__ == "__main__": # Suppose current directory here is "/source" build() # Function executes in "/source/build" # After the function current directory is "/source"
- Parameters
dest (pathlib.Path or str) – The destination to change directories to.
create (bool) – Whether or not the
dest
is allowed to be created. Default:False
, thedest
must exist already (willfail()
if it does not). IfTrue
,mkdir_p()
will be called withdest
.
- merge_kwargs(defaults, kwargs)[source]¶
Merge
defaults
intokwargs
and returnkwargs
.Intended usage is for setting defaults to
**kwargs
when the caller did not provide a given argument, but making sure not to overwrite the caller’s explicit argument when specified.For example:
>>> merge_kwargs({"a": 1, "b": 2}, {}) {'a': 1, 'b': 2} >>> merge_kwargs({"a": 1, "b": 2}, {"a": 3}) {'a': 3, 'b': 2}
Entries in the
defaults
parameter only get included of not present in thekwargs
argument. This is to facilitate something like this:from ci_exec import merge_kwargs # The function we want to customize the defaults for. def func(alpha=1, beta=2): return alpha + beta # Example: default to alpha=2, leave beta alone. def custom(**kwargs): return func(**merge_kwargs({"alpha": 2}, kwargs)) # custom() == 4 # custom(alpha=0) == 2 # custom(beta=0) == 2 # custom(alpha=0, beta=0) == 0
- class set_env(**kwargs)[source]¶
Context manager / decorator that can be used to set environment variables.
Usage example:
from ci_exec import set_env @set_env(CC="clang", CXX="clang++") def build_clang(): # CC="clang" and CXX="clang++" inside function. # ... or ... with set_env(CC="clang", CXX="clang++"): # CC="clang" and CXX="clang++" in `with` block
Prior environment variable state will be recorded and later restored when a decorated function /
with
block’s scope ends.An environment variable was already set. Its value is saved before overwriting, and then later restored:
# Example: CC=gcc was already set. with set_env(CC="clang"): # Inside block: CC="clang" # Out-dented: CC=gcc again.
An environment variable was not already set. Its value is unset again:
# Example: CC was _not_ set in environment. with set_env(CC="clang"): # Inside block: CC="clang" # Out-dented: CC _not_ set in environment.
Note
See note in unset_env for more information on removing environment variables.
- Parameters
**kwargs – Keyword argument parameter pack. Keys are the environment variable to set, and values are the desired value of the environment variable. All keys and all values must be strings.
- Raises
ValueError – If no arguments are provided (
len(kwargs) == 0
), or if any keys / values are not astr
.
- class unset_env(*args)[source]¶
Context manager / decorator that can be used to unset environment variables.
Usage example:
from ci_exec import unset_env @unset_env("CC", "CXX") def build(): # Neither CC nor CXX are set in the environment during this function call. # ... or ... with unset_env("CC", "CXX"): # Neither CC nor CXX are set in the environment inside this block.
Prior environment variable state will be recorded and later restored when a decorated function /
with
block’s scope ends. So if an environment variable was already set, its value is saved before deletion, and then later restored:# Example: CC=gcc was already set. with unset_env("CC"): # Inside block: CC not set in environment. # Out-dented: CC=gcc again.
Note
Removing the environment variable is done via
del os.environ[env_var]
. This may or may not affect child processes in the manner you expect, depending on whether your platform supportsos.unsetenv()
. See the end of the description ofos.environ
for more information.- Parameters
*args – Argument parameter pack. Each argument is an environment variable to unset. Each argument must be a string. If a specified argument is not currently set in the environment, it will effectively be skipped.
- Raises
ValueError – If no arguments are provided (
len(args) == 0
), or if any arguments are not astr
.
Tests¶
Tests for the ci_exec.utils
module.
- test_merge_kwargs()[source]¶
Validate
merge_kwargs()
merges as expected.