dwas¶
Everything explicitly exposed here is part of the dwas public API.
In addition to what is here, dwas also exposed the following public modules:
This module contains common predefined steps to help reduce duplication. |
Warning
While dwas is not at version 1.0.0, it does not guarantee API stability.
Inventory¶
Classes¶
Holds the global configuration for |
|
Holds the information about a step in the pipeline. |
|
Defines the runner for a step, and provides utilities for the step to run. |
|
Defines a step creating artifacts that can be consumed by dependent steps. |
|
Defines a step that needs to do custom cleanup. |
|
Defines a step that will act in the context of its dependent steps. |
|
Defines a step that needs some setup that can be cached. |
Functions¶
Generate a |
|
Register the decorated step, and handle installing its dependencies. |
|
Parametrize the decorated step with the provided values. |
|
Register the provided step, and handle installing its dependencies. |
|
Register the provided step. |
|
Register a step group. |
|
Set default values for parameters on the given step. |
|
Register the decorated step and make it available to the pipeline. |
Exceptions¶
Base exception used for exceptions thrown by DWAS. |
|
Exception raised when |
|
Exception raised when the number of parameters does not match the number of ids. |
|
Exception raised when values were passed multiple times for the same parameter. |
Classes¶
- class dwas.Config(cache_path: str, log_path: str | None, *, verbosity: int, colors: bool | None, n_jobs: int, skip_missing_interpreters: bool, skip_setup: bool, skip_run: bool, fail_fast: bool)[source]¶
Bases:
objectHolds the global configuration for
dwas.This contains a lot of the configuration that can be set from the command line and can be access in each step to configure their behavior.
- cache_path: Path¶
The path to the root of the cache directory used by dwas.
Note that in most cases, you can use the step-specific cache at
StepRunner.cache_pathand expose data viaStepWithArtifacts.gather_artifacts().
- colors: bool¶
Whether to use colored output or not for the output.
Determining whether color output is available is not trivial and many programs do it differently.
Here is how dwas does it:
The cli supports –color|–no-color to force the value
Then, it will look for
PY_COLORSand enable colors if this is"1", and disable if it is"0". Any other option will abort the program.Then, it will look if
NO_COLORSis set. If so, it will disable colors.Then, it will look if
FORCE_COLORis set. If so, it will enable colors.Then, it will detect if this is running in various CIs (currently github actions is supported.) and enable colors if they support it.
Finally, it will look if this is attached to a tty and enable colors if so.
- environ: dict[str, str]¶
The environment to use when running commands.
This environment is on purpose minimal, and will only let pass values like
proxies:
http_proxy,https_proxy,no_proxyca certificates variables:
URL_CA_BUNDLE,REQUEST_CA_BUNDLE,SSL_CERT_FILElanguage:
LANG,LANGUAGEpip:
PIP_INDEX_URL,PIP_EXTRA_INDEX_URLpython:
PYTHONHASHSEEDsystem:
PATH,LD_LIBRARY_PATH,TMPDIRuv:
UV_DEFAULT_INDEX,UV_INDEX
If will also forcefully set
PY_COLORSandNO_COLORbased on the configuration. SeeConfig.colors.If
PYTHONHASHSEEDis not passed when calling dwas, this will set it to a random value and log it to allow repeating the current run.
- n_jobs: int¶
The number of jobs to run in parallel.
0 will use the number of cpus on the machine as given by
multiprocessing.cpu_count().
- skip_run: bool¶
Whether to skip the run part of each step.
This is the reverse of
skip_setup, and only runs the setup part.
- class dwas.Step(*args, **kwargs)[source]¶
Bases:
ProtocolHolds the information about a step in the pipeline.
A step is essentially a function that can be called and that has a
__name__attribute.Steps can then be parametrized by the help of
dwas.parametrize(), and registered usingregister_step(). at which point they are usable by dwas.- Examples:
A step can either be a simple function:
@step() def my_step(step: StepRunner) -> None: step.run(["echo", "hello!"])
Or a class:
# NOTE: you don't need to explicitely inherit from `Step` class MyStep: def __call__(self, step: StepRunner) -> None: step.run(["echo", "hello!"]) register_step(MyStep(), name="my_step")
Note
Use whichever method you prefer. Both are supported. Classes tend to be easier for reusability, but functions work well if you just use them in your project.
We will strive to provide both types in examples.
- __call__(*args: Any, **kwargs: Any) None[source]¶
The method to run when the step is invoked.
- Parameters:
It can take any amount of parameters, that can be passed by keyword, so positional only arguments are not supported.
Parameters will then be passed using parametrization, with a few specific parameters being reserved by the system. Namely:
step, which is used to pass theStepRunner.user_args, which is used to pass arguments that the user would have passed on the cli. This can be useful, to allow users to interact with some cli tool your step might be calling.
For passing other arguments, see
dwas.parametrize()anddwas.set_defaults().
- class dwas.StepRunner[source]¶
Bases:
objectDefines the runner for a step, and provides utilities for the step to run.
This is passed as an argument to every step that executes as
step.It provides various utilities to allow the step to run in an isolated, standardized environment.
- property cache_path: Path¶
The path to the cache for the current step.
This can be used to store temporary files or any other artifacts.
This will be cleaned up and emptied before the step runs.
- property config: Config¶
The global configuration for the current run.
At this point, you should not be modifying it. However, you can use it to act differently on what you are doing. For example, you might want to use the
Config.verbosityto configure the output of some commands you run.
- get_artifacts(key: str) list[Any][source]¶
Get the artifacts exported by previous steps for the given key.
See
StepWithArtifacts.gather_artifacts()for how to expose artifacts from a step.Note
This only returns artifacts exported by the direct dependencies of the current step, and does not go recursively. Unless this depends on a step group, in which case it returns the artifacts of all dependencies in the group.
- Parameters:
key – The name of the key for which to get the artifacts
- Returns:
A list of artifacts, one per step providing artifacts for the given key.
- install(*packages: str, sync: bool = False, no_deps: bool = False, force_reinstall: bool = False) None[source]¶
Install the provided packages in the current environment.
This is a wrapper around the canonical way of installing packages in the provided environment (e.g. pip), so that users don’t need to handle the details when changing the type of virtual environment (e.g. if you wanted to move to conda.).
- Examples:
Here’s a few ways of installing packages depending on what you want.
## # Without syncing files ## # Install a single package step.install(["mypy"]) # Install dependencies from a requirements.txt file step.install(["--requirements=requirements.txt"]) # Install only the package's dependencies but not the package step.install(["--requirements=pyproject.toml"]) # Install the current package (See dwas.predefined.Package for a better way) step.install(["."]) # Install a dependency group step.install(["--group=dev"]) ## # Syncing files from a lockfile ## # Install only the package's dependencies but not the package step.install([], sync=True) # Install a group of the package step.install(["--only-group=dev"], sync=True) # Install the dependencies and a group step.install(["--group=dev"])
- Parameters:
packages – which packages to install
sync – Use uv sync instead of pip install to install the dependencies. This ensures is resolves dependencies according to the lock file, and not installing the latest versions. Note that semantics change a bit, so it is not fully interchangeable with sync=False.
no_deps – ignore the package’s dependencies when installing
force_reinstall – force the re-installation of the package and its dependencies even if already installed
- Raises:
KeyboardInterrupt – If the user has tried aborting the program and is waiting for it to finish.
- property python: str¶
The name of the current python interpreter.
Note
This is not the absolute path to it, just its name.
- run(command: list[str], *, cwd: str | bytes | os.PathLike[str] | os.PathLike[bytes] | None = None, env: dict[str, str] | None = None, external_command: bool = False, silent_on_success: bool = False) subprocess.CompletedProcess[None][source]¶
Run the provided command in the current environment.
This method makes it’s best to ensure the process’ environment is as isolated as possible. It should be used whenever possible, instead of calling
subprocessdirectly.It will enforce that the first argument of the command is part of the python virtual environment that is specially created for the current step (in the case when there is isolation).
It will also ensure that the environment in which it is run is clean, and will only get environment entries from
Config.environ. To add more values, use env.- Parameters:
command – The command to run, as a list of arguments.
cwd – The working directory in which to run the command.
env – Additional environment variables to pass to the process. Those will be merged on top of the
Config.environvalues and can override them, but not remove them.external_command – Set to true if you want to run a command that lives outside the current virtual environment. Otherwise, this will fail the command.
silent_on_success – Whether to silence the command’s output if it succeeds, or show it every time.
- Returns:
a
subprocess.CompletedProcesswith stderr and stdout set toNone.- Raises:
KeyboardInterrupt – If the user has tried aborting the program and is waiting for it to finish.
- set_env(variable: str, value: str) None[source]¶
Set a specific environment variable for this runner.
This can be useful for example to set environment variables inside another step when setting up a dependent.
- Parameters:
variable – The name of the environment variable to set.
value – The value to set the variable to.
- class dwas.StepWithArtifacts(*args, **kwargs)[source]¶
-
Defines a step creating artifacts that can be consumed by dependent steps.
Sometimes, you want to share artifacts between jobs. For example, you might have some
pytestruns that generate coverage reports, and then you want to aggregate them together.This allows a programmatic interface between steps to access artifacts. See
StepRunner.get_artifacts()for how to retrieve those artifacts from another step.- Examples:
If you wanted to have multiple pytest steps, and one that aggregates the coverage, you could do:
Tip
This is what the provided
dwas.predefined.pytest()step does.@step() @parametrize(python=["3.9", "3.10"]) def pytest(step: StepRunner) -> None: step.run( ["pytest"], env={ "COVERAGE_FILE": str( step.cache_path.joinpath(step.python, "coverage") ), }, ) def gather_artifacts(step: "StepRunner") -> Dict[str, List[Any]]: return step.cache_path.joinpath(step.python, "coverage") pytest.gather_artifacts = gather_artifacts
class Pytest: def _get_coverage_file(self, step: StepRunner) -> str: return str(step.cache_path / "reports" / "coverage") def gather_artifacts(self, step: StepRunner) -> Dict[str, List[Any]]: return {"coverage_files": [self._get_coverage_file(step)]} def __call__(self, step: StepRunner) -> None: step.run( ["pytest", *args], env={"COVERAGE_FILE": self._get_coverage_file(step)}, ) register_step(parametrize("python", ["3.9", "3.10"])(Pytest()))
And you could then combine and display the coverage like:
@managed_step(dependencies=["coverage"], requires=["pytest"]) def coverage(self, step: StepRunner) -> None: env = {"COVERAGE_FILE": str(step.cache_path / "coverage")} coverage_files = step.get_artifacts("coverage_files") if not coverage_files: raise Exception("No coverage files provided. Can't proceed") step.run(["coverage", "combine", "--keep", *coverage_files], env=env) step.run(["coverage", "html"], env=env)
Tip
The
dwas.predefined.coverage()step does roughly this.
- gather_artifacts(step: StepRunner) dict[str, list[Any]][source]¶
Gather all artifacts exposed by this step.
- Parameters:
step – The step handler that was used when running the step.
- Returns:
A dictionary of artifact key to a list of arbitrary data. This must return a list, as they are merged with other steps’ artifacts into a single list per artifact key.
- class dwas.StepWithCleanup(*args, **kwargs)[source]¶
-
Defines a step that needs to do custom cleanup.
Sometimes, a step might write outside of the dwas-managed cache, in which case it might be desirable for it to be able to clean that directory.
This allows a step to hook on the
dwas --cleaninvocation to cleanup such files.- Examples:
If you wanted to generated documentation, and wanted to have it easily accessible, you could do:
Tip
This is a simplified example of what
dwas.predefined.sphinx()does@managed_step(dependencies=["sphinx"], output="./build/docs") def sphinx(step: StepRunner, output: str) -> None: step.run(["sphinx-build", "-b=html", "docs/", output]) def clean(output: str) -> None: with suppress(FileNotFoundError): shutil.rmtree(output) sphinx.clean = clean
class Sphinx(Step): def __init__(self) -> None: self.__name__ = "sphinx" def __call__(self, step: StepRunner, output: str) -> None: step.run(["sphinx-build", "-b=html", "docs/", output]) def clean(output: str) -> None: with suppress(FileNotFoundError): shutil.rmtree(output)
- class dwas.StepWithDependentSetup(*args, **kwargs)[source]¶
-
Defines a step that will act in the context of its dependent steps.
In addition to having a
__call__()method, aStepcan act in the context of a dependent step, before this one runs.This allows another step to, for example, install the project it just built into another virtual environment.
Note
This method is called after
setup()Warning
This method is always called when running, and cannot be skipped like
setup()by passing--no-setup.- Examples:
You might want to have a step that builds a wheel of your current package and run your tests against it. This could be done like:
Note
A more complete packaging example is provided as
dwas.predefined.package()@managed_step(dependencies=["build"]) def package(step: StepRunner) -> None: step.run([step.python, "-m", "build", f"--outdir={step.cache_path}"]) def install(self, original_step: StepRunner, current_step: StepRunner) -> None: wheels = list(original_step.cache_path.glob("*.whl")) # Assuming this is a universal wheel assert len(wheels) == 1 current_step.install(str(wheels[0])) package.setup_dependent = install # This can now be used as a dependency @step(requires=["package"]) def my_step(step: StepRunner) -> None: step.run(["myproject", "--help"])
class Package: def __call__(step: StepRunner) -> None: step.run([step.python, "-m", "build", f"--outdir={step.cache_path}"]) def setup_dependent( self, original_step: StepRunner, current_step: StepRunner, ) -> None: wheels = list(original_step.cache_path.glob("*.whl")) # Assuming this is a universal wheel assert len(wheels) == 1 current_step.install(str(wheels[0])) register_managed_step(Package(), name="package", dependencies=["build"]) # This can now be used as a dependency @step(requires=["package"]) def my_step(step: StepRunner) -> None: step.run(["myproject", "--help"])
- setup_dependent(original_step: StepRunner, current_step: StepRunner) None[source]¶
Run some logic into a dependent step.
- Parameters:
original_step – The original step handler that was used when the step defining this method was called.
current_step – The current step handler, that contains the context of the step that is going to be executed.
- class dwas.StepWithSetup(*args, **kwargs)[source]¶
-
Defines a step that needs some setup that can be cached.
In addition to having a
__call__method, aStep, can implement asetup()function, that gets called before the method.This can be useful to separate the actual running of the step, from the necessary preparations.
Warning
the
setupis meant to contain work that does not necessarily needs to happen at every run of your step, and can be cached in between.Tip
When running
dwasrepeatedly, you can pass a--no-setupflag to avoid running those steps again and thus speedup your run.- Examples:
A setup method can be added on a step declaration:
Note
A more complete pytest example is provided as
dwas.predefined.pytest().@step() def pytest(step: StepRunner) -> None: step.run(["pytest"]) def install_dependencies(step: StepRunner) -> None: step.install("pytest") pytest.setup = install_dependencies
class Pytest: def setup(self, step: StepRunner) -> None: step.install("pytest") def __call__(self, step: StepRunner) -> None: step.run(["pytest"]) register_step(Pytest(), name="pytest")
Tip
This is what
register_managed_step()does to install your python dependencies.
- setup: Callable[[...], None]¶
The setup method that will be invoked before running the step.
This step should run work that is necessary for the test to be able to run but that does not require running every time, as it can be skipped when running dwas with –no-setup.
- Parameters:
Parameters are passed to this function the same way they are passed to
__call__()
Functions¶
- dwas.build_parameters(**kwargs: Any) Callable[[T], T][source]¶
Generate a
parametrize()call based on the provided parameters.This is a shortcut to build a single
parametrize()call, for all non-Nonevalues that are passed in.It will only pass the arguments as a single entry, so this will only ever generate a single entry.
This is basically a shortcut for:
for key, value in parameters.items(): if value is not None: func = parametrize(key, [value])(func)
- Parameters:
kwargs – Any key/value pair to pass as a parametrize argument
- Returns:
A function to apply the parameters on the given step.
- dwas.managed_step(dependencies: Sequence[str] | None, *, dependencies_sync: bool | None = None, name: str | None = None, description: str | None = None, python: str | None = None, requires: list[str] | None = None, run_by_default: bool | None = None, passenv: list[str] | None = None, setenv: dict[str, str] | None = None) Callable[[Step], Step][source]¶
Register the decorated step, and handle installing its dependencies.
This is a convenience wrapper calling
register_managed_step()on the decorated object.- Parameters:
dependencies – A list of dependencies to install as a setup phase. If
None, will expect adependenciesparameter to be passed viaparametrize().dependencies_sync – Use uv sync when dealing with dependencies instead of pip install. See
StepRunner.install()for examples and details.name – The name used to refer to this step
description – An optional description of what the current step does
python – The python version to use in this step
requires – The list of steps that this step depends on
run_by_default – Whether this step should run by default or not
passenv – A list of environment variables to pass through to the step.
setenv – A list of environment variables to set in the context of the step.
- dwas.parametrize(arg_names: str, args_values: Sequence[Any], ids: Sequence[str | None] | None = None) Callable[[T], T][source]¶
- dwas.parametrize(arg_names: Sequence[str], args_values: Sequence[Sequence[Any]], ids: Sequence[str | None] | None = None) Callable[[T], T]
Parametrize the decorated step with the provided values.
Parametrization allows running a specific step with multiple configurations. For example, you might want to run a
pyteststep against both python3.10 and python3.11. With parametrization you do not need to repeat the step.It is possible to make multiple calls to parametrize on the same step, as long as the parameter names do not conflict. In which case, the product of both parametrization steps will be generated.
Note
Parameters, once set for a specific argument cannot be overridden. If you want to provide default values, see
set_defaults().- Parameters:
arg_names – The name of the argument to parametrize. Or a list of names if multiple values need to be passed.
args_values – A list of values to be used for the given argument. When parametrizing multiple arguments at once, this becomes a list of list of argument values.
ids –
A list of ids for each entry in arg_values.
If not provided, it will be either:
””, if only one value was passed for the parametrization
built based on the string representation of the values, in order.
- Returns:
A decorator that can be applied to a step to apply the parametrization.
- Raises:
MismatchedNumberOfParametersException – if the number of ids and the number of arg_values do not match.
ParameterConflictException – if values have already been provided for a specific argument (e.g. by another parametrize call)
- Examples:
You might want to parametrize a single argument. In which case you can do:
# The step needs to be applied after parametrization @step() # This step needs to run for both python 3.10 and python3.11 @parametrize("python", ["3.10", "3.11"]) def print_python_version(step: StepRunner) -> None: step.execute([self.python, "--version"])
Or you might want to parametrize multiple arguments at once. In that case you can do:
# The step needs to be applied after parametrization. # Note that we don't supply the usual 'dependencies' argument here, it # will be handled by parametrization. @managed_step() # This needs to run with: # - python 3.10 against django 3.0 and 4.0 # - python3.11 against django 4.0 @parametrize( ["python", "dependencies"], [ ["3.10", ["django==3.0"]], ["3.10", ["django==4.0"]], ["3.11", ["django==4.0"]], ], ) def test(step: StepRunner) -> None: step.run([self.python, "manage.py", "test"])
And finally, you can also combine multiple parametrize calls:
# The step needs to be applied after parametrization again. # Note that we don't supply the usual 'dependencies' argument here, it # will be handled by parametrization. @managed_step() # This needs to run with: # - python3.10 and 3.11 # - both against django 3.0 and 4.0 @parametrize("python", ["3.10", "3.11"]) @parametrize("dependencies", [["django==3.0"], ["django==4.0"]]) def test(step: StepRunner) -> None: step.run([self.python, "manage.py", "test"])
- dwas.register_managed_step(func: Step, dependencies: Sequence[str] | None = None, *, dependencies_sync: bool | None = None, name: str | None = None, description: str | None = None, python: str | None = None, requires: list[str] | None = None, run_by_default: bool | None = None, passenv: list[str] | None = None, setenv: dict[str, str] | None = None) Step[source]¶
Register the provided step, and handle installing its dependencies.
A managed step is a step that depends on python packages being present in the environment, and this is taking care of installing the dependencies for it as a setup phase.
See also
register_step()has a more thorough explanation of other parameters.- Parameters:
func – The function or class instance to register as a step
dependencies – A list of dependencies to install as a setup phase. If
None, will expect adependenciesparameter to be passed viaparametrize().dependencies_sync – Use uv sync when dealing with dependencies instead of pip install. See
StepRunner.install()for examples and details.name – The name to give to the step. Defaults to
func.__name__description – An optional description of what the current step does
python – The python version to use for this step
requires – The list of steps this step depends on
run_by_default – Whether to run by default or not
passenv – A list of environment variables to pass through to the step.
setenv – A list of environment variables to set in the context of the step.
- Returns:
The step that was passed as argument.
- Raises:
BaseDwasException – If the
funcpassed already has asetupattribute defined.
- dwas.register_step(func: Step, *, name: str | None = None, description: str | None = None, python: str | None = None, requires: list[str] | None = None, run_by_default: bool | None = None, passenv: list[str] | None = None, setenv: dict[str, str] | None = None) Step[source]¶
Register the provided step.
- Parameters:
func – The function or class instance to register as a step
name –
The name used to refer to this step.
If this is not provided, the
funcparameter must have a__name__attribute, which will then be used.Note
All normal function objects in python will automatically have a
__name__defined as their name.You could thus just do:
def my_step(step: StepRunner): ... register_step(my_step)
and it will be available as
my_step.description –
An optional description of what the current step does
In order to help developers on your project, adding descriptions to various steps can make it easier to understand what they should use.
For example:
register_step(your_step, description="This step does something") # The description here will be: # "This step does something"
The description will be added to all steps generated here unless you also parametrize them with a description. In which case, only the top level group created will use the description passed.
The other steps will use the parametrized description.
In the case of multiple steps, the description will also be formatted with the various arguments passed.
For example:
register_step( parametrize("python", ["3.9", "3.10"])(test), description="Run tests for python {python}", ) # Will give the following descriptions: # - test: "Run tests for python {python}" # - test[3.9]: "Run tests for python 3.9" # - test[3.10]: "Run tests for python3.10"
Or if you want to give a separate description for each:
register_step( parametrize( ("builder", "description"), [ ("html", "Build html documentation"), ("linkcheck", "Check documentation links are valid"), ] )(sphinx_step), name="docs", description="Build and check documentation" ) # Will give the following descriptions: # - docs: Build and check documentation # - docs[html]: Build html documentation # - docs[linkcheck]: Check documentation links are valid
python –
The python version to use in this step.
It can be either:
None, in which case it will use the same version that is used to rundwas.a version (e.g.
"3.10"), in which case cpython is assumeda string (e.g.
"pypy3.9", or"python3.10"), in which case it will be used as is.
requires –
The list of steps that this step depends on.
Note
All dependencies will run whenever this step is requested unless
--onlyor--exceptare used.run_by_default – Whether this step should run by default or not.
Noneis considered asTruehere.passenv – A list of environment variables to pass through to the step.
setenv – A list of environment variables to set in the context of the step.
- Returns:
The step that was passed as argument.
- Raises:
BaseDwasException – If no
nameis passed and thefuncparameter does not have a__name__attribute.
- dwas.register_step_group(name: str, requires: list[str], description: str | None = None, *, run_by_default: bool | None = None) None[source]¶
Register a step group.
A step group is a step that has no action and only depends on other steps.
It allows calling multiple steps in a row or together more easily, and, when used together with
parametrize(), allows calling all the steps generated as a single step.It will pass every artifacts and information from required steps to the caller when asked.
- Parameters:
name – The name to give to the group of step
requires – The list of steps that are part of the group
description – An optional description of what the current step does
run_by_default – Whether to run this step by default or not
- dwas.set_defaults(values: dict[str, Any]) Callable[[T], T][source]¶
Set default values for parameters on the given step.
Those values can be overridden by using
parametrize().Only a single call to
set_defaults()can be made for a given object, trying to set it multiple times will raise aDefaultsAlreadySetException.See also
parametrize()for an explanation of how parameters work.- Parameters:
values – A dictionary of default values to set on the step
- Returns:
A decorator that can be applied to a step to apply the parametrization.
- Raises:
DefaultsAlreadySetException – If
set_defaults()was already called on the given object.
- dwas.step(*, name: str | None = None, description: str | None = None, python: str | None = None, requires: list[str] | None = None, run_by_default: bool | None = None, passenv: list[str] | None = None, setenv: dict[str, str] | None = None) Callable[[Step], Step][source]¶
Register the decorated step and make it available to the pipeline.
This is a convenience wrapper calling
register_step()on the decorated object.- Parameters:
name – The name used to refer to this step
description – An optional description of what the current step does
python – The python version to use in this step
requires – The list of steps that this step depends on
run_by_default – Whether this step should run by default or not
passenv – A list of environment variables to pass through to the step.
setenv – A list of environment variables to set in the context of the step.
Exceptions¶
- exception dwas.BaseDwasException(message: str, exit_code: int = 2)[source]¶
Bases:
ExceptionBase exception used for exceptions thrown by DWAS.
- Parameters:
message – A user-facing message explaining what happened.
exit_code –
the exit code to use for the dwas process if the exception is not caught.
1 means a pipeline run failed
2 means a user or configuration error
- exception dwas.DefaultsAlreadySetException(func: Callable[[...], None])[source]¶
Bases:
BaseDwasExceptionException raised when
set_defaults()has already been called on an object.
- exception dwas.MismatchedNumberOfParametersException(n_args_values: int, n_args_ids: int)[source]¶
Bases:
BaseDwasExceptionException raised when the number of parameters does not match the number of ids.