diff --git a/lib/galaxy/tool_util/verify/assertion_models.py b/lib/galaxy/tool_util/verify/assertion_models.py
index eb4429170655..142c476ffdb6 100644
--- a/lib/galaxy/tool_util/verify/assertion_models.py
+++ b/lib/galaxy/tool_util/verify/assertion_models.py
@@ -81,12 +81,8 @@ def check_non_negative_if_int(v: typing.Any):
has_line_negate_description = """A boolean that can be set to true to negate the outcome of the assertion."""
-class has_line_model(AssertionModel):
- r"""Asserts the specified output contains the line specified by the
- argument line. The exact number of occurrences can be optionally
- specified by the argument n"""
-
- that: Literal["has_line"] = "has_line"
+class base_has_line_model(AssertionModel):
+ """base model for has_line describing attributes."""
line: str = Field(
...,
@@ -133,6 +129,20 @@ class has_line_model(AssertionModel):
)
+class has_line_model(base_has_line_model):
+ r"""Asserts the specified output contains the line specified by the
+ argument line. The exact number of occurrences can be optionally
+ specified by the argument n"""
+
+ that: Literal["has_line"] = "has_line"
+
+
+class has_line_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ has_line: base_has_line_model
+
+
has_line_matching_expression_description = """The regular expressions to attempt match in the output."""
has_line_matching_n_description = """Desired number, can be suffixed by ``(k|M|G|T|P|E)i?``"""
@@ -148,12 +158,8 @@ class has_line_model(AssertionModel):
has_line_matching_negate_description = """A boolean that can be set to true to negate the outcome of the assertion."""
-class has_line_matching_model(AssertionModel):
- r"""Asserts the specified output contains a line matching the
- regular expression specified by the argument expression. If n is given
- the assertion checks for exactly n occurences."""
-
- that: Literal["has_line_matching"] = "has_line_matching"
+class base_has_line_matching_model(AssertionModel):
+ """base model for has_line_matching describing attributes."""
expression: str = Field(
...,
@@ -200,6 +206,20 @@ class has_line_matching_model(AssertionModel):
)
+class has_line_matching_model(base_has_line_matching_model):
+ r"""Asserts the specified output contains a line matching the
+ regular expression specified by the argument expression. If n is given
+ the assertion checks for exactly n occurences."""
+
+ that: Literal["has_line_matching"] = "has_line_matching"
+
+
+class has_line_matching_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ has_line_matching: base_has_line_matching_model
+
+
has_n_lines_n_description = """Desired number, can be suffixed by ``(k|M|G|T|P|E)i?``"""
has_n_lines_delta_description = (
@@ -213,12 +233,8 @@ class has_line_matching_model(AssertionModel):
has_n_lines_negate_description = """A boolean that can be set to true to negate the outcome of the assertion."""
-class has_n_lines_model(AssertionModel):
- r"""Asserts the specified output contains ``n`` lines allowing
- for a difference in the number of lines (delta)
- or relative differebce in the number of lines"""
-
- that: Literal["has_n_lines"] = "has_n_lines"
+class base_has_n_lines_model(AssertionModel):
+ """base model for has_n_lines describing attributes."""
n: Annotated[
typing.Optional[typing.Union[str, int]],
@@ -260,6 +276,20 @@ class has_n_lines_model(AssertionModel):
)
+class has_n_lines_model(base_has_n_lines_model):
+ r"""Asserts the specified output contains ``n`` lines allowing
+ for a difference in the number of lines (delta)
+ or relative differebce in the number of lines"""
+
+ that: Literal["has_n_lines"] = "has_n_lines"
+
+
+class has_n_lines_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ has_n_lines: base_has_n_lines_model
+
+
has_text_text_description = """The text to search for in the output."""
has_text_n_description = """Desired number, can be suffixed by ``(k|M|G|T|P|E)i?``"""
@@ -275,12 +305,8 @@ class has_n_lines_model(AssertionModel):
has_text_negate_description = """A boolean that can be set to true to negate the outcome of the assertion."""
-class has_text_model(AssertionModel):
- r"""Asserts specified output contains the substring specified by
- the argument text. The exact number of occurrences can be
- optionally specified by the argument n"""
-
- that: Literal["has_text"] = "has_text"
+class base_has_text_model(AssertionModel):
+ """base model for has_text describing attributes."""
text: str = Field(
...,
@@ -327,6 +353,20 @@ class has_text_model(AssertionModel):
)
+class has_text_model(base_has_text_model):
+ r"""Asserts specified output contains the substring specified by
+ the argument text. The exact number of occurrences can be
+ optionally specified by the argument n"""
+
+ that: Literal["has_text"] = "has_text"
+
+
+class has_text_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ has_text: base_has_text_model
+
+
has_text_matching_expression_description = """The regular expressions to attempt match in the output."""
has_text_matching_n_description = """Desired number, can be suffixed by ``(k|M|G|T|P|E)i?``"""
@@ -342,13 +382,8 @@ class has_text_model(AssertionModel):
has_text_matching_negate_description = """A boolean that can be set to true to negate the outcome of the assertion."""
-class has_text_matching_model(AssertionModel):
- r"""Asserts the specified output contains text matching the
- regular expression specified by the argument expression.
- If n is given the assertion checks for exacly n (nonoverlapping)
- occurences."""
-
- that: Literal["has_text_matching"] = "has_text_matching"
+class base_has_text_matching_model(AssertionModel):
+ """base model for has_text_matching describing attributes."""
expression: str = Field(
...,
@@ -395,14 +430,26 @@ class has_text_matching_model(AssertionModel):
)
-not_has_text_text_description = """The text to search for in the output."""
+class has_text_matching_model(base_has_text_matching_model):
+ r"""Asserts the specified output contains text matching the
+ regular expression specified by the argument expression.
+ If n is given the assertion checks for exacly n (nonoverlapping)
+ occurences."""
+
+ that: Literal["has_text_matching"] = "has_text_matching"
-class not_has_text_model(AssertionModel):
- r"""Asserts specified output does not contain the substring
- specified by the argument text"""
+class has_text_matching_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ has_text_matching: base_has_text_matching_model
+
+
+not_has_text_text_description = """The text to search for in the output."""
- that: Literal["not_has_text"] = "not_has_text"
+
+class base_not_has_text_model(AssertionModel):
+ """base model for not_has_text describing attributes."""
text: str = Field(
...,
@@ -410,6 +457,19 @@ class not_has_text_model(AssertionModel):
)
+class not_has_text_model(base_not_has_text_model):
+ r"""Asserts specified output does not contain the substring
+ specified by the argument text"""
+
+ that: Literal["not_has_text"] = "not_has_text"
+
+
+class not_has_text_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ not_has_text: base_not_has_text_model
+
+
has_n_columns_n_description = """Desired number, can be suffixed by ``(k|M|G|T|P|E)i?``"""
has_n_columns_delta_description = (
@@ -429,19 +489,8 @@ class not_has_text_model(AssertionModel):
has_n_columns_negate_description = """A boolean that can be set to true to negate the outcome of the assertion."""
-class has_n_columns_model(AssertionModel):
- r"""Asserts tabular output contains the specified
- number (``n``) of columns.
-
- For instance, ````. The assertion tests only the first line.
- Number of columns can optionally also be specified with ``delta``. Alternatively the
- range of expected occurences can be specified by ``min`` and/or ``max``.
-
- Optionally a column separator (``sep``, default is `` ``) `and comment character(s)
- can be specified (``comment``, default is empty string). The first non-comment
- line is used for determining the number of columns."""
-
- that: Literal["has_n_columns"] = "has_n_columns"
+class base_has_n_columns_model(AssertionModel):
+ """base model for has_n_columns describing attributes."""
n: Annotated[
typing.Optional[typing.Union[str, int]],
@@ -493,30 +542,38 @@ class has_n_columns_model(AssertionModel):
)
-attribute_is_path_description = """The Python xpath-like expression to find the target element."""
+class has_n_columns_model(base_has_n_columns_model):
+ r"""Asserts tabular output contains the specified
+ number (``n``) of columns.
-attribute_is_attribute_description = """The XML attribute name to test against from the target XML element."""
+ For instance, ````. The assertion tests only the first line.
+ Number of columns can optionally also be specified with ``delta``. Alternatively the
+ range of expected occurences can be specified by ``min`` and/or ``max``.
-attribute_is_text_description = """The expected attribute value to test against on the target XML element"""
+ Optionally a column separator (``sep``, default is `` ``) `and comment character(s)
+ can be specified (``comment``, default is empty string). The first non-comment
+ line is used for determining the number of columns."""
-attribute_is_negate_description = """A boolean that can be set to true to negate the outcome of the assertion."""
+ that: Literal["has_n_columns"] = "has_n_columns"
-class attribute_is_model(AssertionModel):
- r"""Asserts the XML ``attribute`` for the element (or tag) with the specified
- XPath-like ``path`` is the specified ``text``.
+class has_n_columns_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
- For example:
+ has_n_columns: base_has_n_columns_model
- ```xml
-
- ```
- The assertion implicitly also asserts that an element matching ``path`` exists.
- With ``negate`` the result of the assertion (on the equality) can be inverted (the
- implicit assertion on the existence of the path is not affected)."""
+attribute_is_path_description = """The Python xpath-like expression to find the target element."""
+
+attribute_is_attribute_description = """The XML attribute name to test against from the target XML element."""
+
+attribute_is_text_description = """The expected attribute value to test against on the target XML element"""
+
+attribute_is_negate_description = """A boolean that can be set to true to negate the outcome of the assertion."""
- that: Literal["attribute_is"] = "attribute_is"
+
+class base_attribute_is_model(AssertionModel):
+ """base model for attribute_is describing attributes."""
path: str = Field(
...,
@@ -539,6 +596,29 @@ class attribute_is_model(AssertionModel):
)
+class attribute_is_model(base_attribute_is_model):
+ r"""Asserts the XML ``attribute`` for the element (or tag) with the specified
+ XPath-like ``path`` is the specified ``text``.
+
+ For example:
+
+ ```xml
+
+ ```
+
+ The assertion implicitly also asserts that an element matching ``path`` exists.
+ With ``negate`` the result of the assertion (on the equality) can be inverted (the
+ implicit assertion on the existence of the path is not affected)."""
+
+ that: Literal["attribute_is"] = "attribute_is"
+
+
+class attribute_is_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ attribute_is: base_attribute_is_model
+
+
attribute_matches_path_description = """The Python xpath-like expression to find the target element."""
attribute_matches_attribute_description = """The XML attribute name to test against from the target XML element."""
@@ -550,21 +630,8 @@ class attribute_is_model(AssertionModel):
attribute_matches_negate_description = """A boolean that can be set to true to negate the outcome of the assertion."""
-class attribute_matches_model(AssertionModel):
- r"""Asserts the XML ``attribute`` for the element (or tag) with the specified
- XPath-like ``path`` matches the regular expression specified by ``expression``.
-
- For example:
-
- ```xml
-
- ```
-
- The assertion implicitly also asserts that an element matching ``path`` exists.
- With ``negate`` the result of the assertion (on the matching) can be inverted (the
- implicit assertion on the existence of the path is not affected)."""
-
- that: Literal["attribute_matches"] = "attribute_matches"
+class base_attribute_matches_model(AssertionModel):
+ """base model for attribute_matches describing attributes."""
path: str = Field(
...,
@@ -587,12 +654,59 @@ class attribute_matches_model(AssertionModel):
)
+class attribute_matches_model(base_attribute_matches_model):
+ r"""Asserts the XML ``attribute`` for the element (or tag) with the specified
+ XPath-like ``path`` matches the regular expression specified by ``expression``.
+
+ For example:
+
+ ```xml
+
+ ```
+
+ The assertion implicitly also asserts that an element matching ``path`` exists.
+ With ``negate`` the result of the assertion (on the matching) can be inverted (the
+ implicit assertion on the existence of the path is not affected)."""
+
+ that: Literal["attribute_matches"] = "attribute_matches"
+
+
+class attribute_matches_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ attribute_matches: base_attribute_matches_model
+
+
element_text_path_description = """The Python xpath-like expression to find the target element."""
element_text_negate_description = """A boolean that can be set to true to negate the outcome of the assertion."""
-class element_text_model(AssertionModel):
+class base_element_text_model(AssertionModel):
+ """base model for element_text describing attributes."""
+
+ path: str = Field(
+ ...,
+ description=element_text_path_description,
+ )
+
+ negate: typing.Union[bool, str] = Field(
+ False,
+ description=element_text_negate_description,
+ )
+
+ children: typing.Optional["assertion_list"] = None
+ asserts: typing.Optional["assertion_list"] = None
+
+ @model_validator(mode="before")
+ @classmethod
+ def validate_children(self, data: typing.Any):
+ if isinstance(data, dict) and "children" not in data and "asserts" not in data:
+ raise ValueError("At least one of 'children' or 'asserts' must be specified for this assertion type.")
+ return data
+
+
+class element_text_model(base_element_text_model):
r"""This tag allows the developer to recurisively specify additional assertions as
child elements about just the text contained in the element specified by the
XPath-like ``path``, e.g.
@@ -610,17 +724,11 @@ class element_text_model(AssertionModel):
that: Literal["element_text"] = "element_text"
- path: str = Field(
- ...,
- description=element_text_path_description,
- )
- negate: typing.Union[bool, str] = Field(
- False,
- description=element_text_negate_description,
- )
+class element_text_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
- children: "assertion_list"
+ element_text: base_element_text_model
element_text_is_path_description = """The Python xpath-like expression to find the target element."""
@@ -632,7 +740,26 @@ class element_text_model(AssertionModel):
element_text_is_negate_description = """A boolean that can be set to true to negate the outcome of the assertion."""
-class element_text_is_model(AssertionModel):
+class base_element_text_is_model(AssertionModel):
+ """base model for element_text_is describing attributes."""
+
+ path: str = Field(
+ ...,
+ description=element_text_is_path_description,
+ )
+
+ text: str = Field(
+ ...,
+ description=element_text_is_text_description,
+ )
+
+ negate: typing.Union[bool, str] = Field(
+ False,
+ description=element_text_is_negate_description,
+ )
+
+
+class element_text_is_model(base_element_text_is_model):
r"""Asserts the text of the XML element with the specified XPath-like ``path`` is
the specified ``text``.
@@ -648,20 +775,11 @@ class element_text_is_model(AssertionModel):
that: Literal["element_text_is"] = "element_text_is"
- path: str = Field(
- ...,
- description=element_text_is_path_description,
- )
- text: str = Field(
- ...,
- description=element_text_is_text_description,
- )
+class element_text_is_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
- negate: typing.Union[bool, str] = Field(
- False,
- description=element_text_is_negate_description,
- )
+ element_text_is: base_element_text_is_model
element_text_matches_path_description = """The Python xpath-like expression to find the target element."""
@@ -673,21 +791,8 @@ class element_text_is_model(AssertionModel):
)
-class element_text_matches_model(AssertionModel):
- r"""Asserts the text of the XML element with the specified XPath-like ``path``
- matches the regular expression defined by ``expression``.
-
- For example:
-
- ```xml
-
- ```
-
- The assertion implicitly also asserts that an element matching ``path`` exists.
- With ``negate`` the result of the assertion (on the matching) can be inverted (the
- implicit assertion on the existence of the path is not affected)."""
-
- that: Literal["element_text_matches"] = "element_text_matches"
+class base_element_text_matches_model(AssertionModel):
+ """base model for element_text_matches describing attributes."""
path: str = Field(
...,
@@ -705,24 +810,38 @@ class element_text_matches_model(AssertionModel):
)
-has_element_with_path_path_description = """The Python xpath-like expression to find the target element."""
+class element_text_matches_model(base_element_text_matches_model):
+ r"""Asserts the text of the XML element with the specified XPath-like ``path``
+ matches the regular expression defined by ``expression``.
-has_element_with_path_negate_description = (
- """A boolean that can be set to true to negate the outcome of the assertion."""
-)
-
-
-class has_element_with_path_model(AssertionModel):
- r"""Asserts the XML output contains at least one element (or tag) with the specified
- XPath-like ``path``, e.g.
+ For example:
```xml
-
+
```
- With ``negate`` the result of the assertion can be inverted."""
+ The assertion implicitly also asserts that an element matching ``path`` exists.
+ With ``negate`` the result of the assertion (on the matching) can be inverted (the
+ implicit assertion on the existence of the path is not affected)."""
- that: Literal["has_element_with_path"] = "has_element_with_path"
+ that: Literal["element_text_matches"] = "element_text_matches"
+
+
+class element_text_matches_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ element_text_matches: base_element_text_matches_model
+
+
+has_element_with_path_path_description = """The Python xpath-like expression to find the target element."""
+
+has_element_with_path_negate_description = (
+ """A boolean that can be set to true to negate the outcome of the assertion."""
+)
+
+
+class base_has_element_with_path_model(AssertionModel):
+ """base model for has_element_with_path describing attributes."""
path: str = Field(
...,
@@ -735,6 +854,25 @@ class has_element_with_path_model(AssertionModel):
)
+class has_element_with_path_model(base_has_element_with_path_model):
+ r"""Asserts the XML output contains at least one element (or tag) with the specified
+ XPath-like ``path``, e.g.
+
+ ```xml
+
+ ```
+
+ With ``negate`` the result of the assertion can be inverted."""
+
+ that: Literal["has_element_with_path"] = "has_element_with_path"
+
+
+class has_element_with_path_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ has_element_with_path: base_has_element_with_path_model
+
+
has_n_elements_with_path_path_description = """The Python xpath-like expression to find the target element."""
has_n_elements_with_path_n_description = """Desired number, can be suffixed by ``(k|M|G|T|P|E)i?``"""
@@ -756,21 +894,8 @@ class has_element_with_path_model(AssertionModel):
)
-class has_n_elements_with_path_model(AssertionModel):
- r"""Asserts the XML output contains the specified number (``n``, optionally with ``delta``) of elements (or
- tags) with the specified XPath-like ``path``.
-
- For example:
-
- ```xml
-
- ```
-
- Alternatively to ``n`` and ``delta`` also the ``min`` and ``max`` attributes
- can be used to specify the range of the expected number of occurences.
- With ``negate`` the result of the assertion can be inverted."""
-
- that: Literal["has_n_elements_with_path"] = "has_n_elements_with_path"
+class base_has_n_elements_with_path_model(AssertionModel):
+ """base model for has_n_elements_with_path describing attributes."""
path: str = Field(
...,
@@ -817,12 +942,45 @@ class has_n_elements_with_path_model(AssertionModel):
)
-class is_valid_xml_model(AssertionModel):
+class has_n_elements_with_path_model(base_has_n_elements_with_path_model):
+ r"""Asserts the XML output contains the specified number (``n``, optionally with ``delta``) of elements (or
+ tags) with the specified XPath-like ``path``.
+
+ For example:
+
+ ```xml
+
+ ```
+
+ Alternatively to ``n`` and ``delta`` also the ``min`` and ``max`` attributes
+ can be used to specify the range of the expected number of occurences.
+ With ``negate`` the result of the assertion can be inverted."""
+
+ that: Literal["has_n_elements_with_path"] = "has_n_elements_with_path"
+
+
+class has_n_elements_with_path_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ has_n_elements_with_path: base_has_n_elements_with_path_model
+
+
+class base_is_valid_xml_model(AssertionModel):
+ """base model for is_valid_xml describing attributes."""
+
+
+class is_valid_xml_model(base_is_valid_xml_model):
r"""Asserts the output is a valid XML file (e.g. ````)."""
that: Literal["is_valid_xml"] = "is_valid_xml"
+class is_valid_xml_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ is_valid_xml: base_is_valid_xml_model
+
+
xml_element_path_description = """The Python xpath-like expression to find the target element."""
xml_element_attribute_description = """The XML attribute name to test against from the target XML element."""
@@ -844,40 +1002,8 @@ class is_valid_xml_model(AssertionModel):
xml_element_negate_description = """A boolean that can be set to true to negate the outcome of the assertion."""
-class xml_element_model(AssertionModel):
- r"""Assert if the XML file contains element(s) or tag(s) with the specified
- [XPath-like ``path``](https://lxml.de/xpathxslt.html). If ``n`` and ``delta``
- or ``min`` and ``max`` are given also the number of occurences is checked.
-
- ```xml
-
-
-
-
-
- ```
-
- With ``negate="true"`` the outcome of the assertions wrt the precence and number
- of ``path`` can be negated. If there are any sub assertions then check them against
-
- - the content of the attribute ``attribute``
- - the element's text if no attribute is given
-
- ```xml
-
-
-
-
-
- ```
-
- Sub-assertions are not subject to the ``negate`` attribute of ``xml_element``.
- If ``all`` is ``true`` then the sub assertions are checked for all occurences.
-
- Note that all other XML assertions can be expressed by this assertion (Galaxy
- also implements the other assertions by calling this one)."""
-
- that: Literal["xml_element"] = "xml_element"
+class base_xml_element_model(AssertionModel):
+ """base model for xml_element describing attributes."""
path: str = Field(
...,
@@ -934,21 +1060,58 @@ class xml_element_model(AssertionModel):
)
children: typing.Optional["assertion_list"] = None
+ asserts: typing.Optional["assertion_list"] = None
-has_json_property_with_text_property_description = """The property name to search the JSON document for."""
+class xml_element_model(base_xml_element_model):
+ r"""Assert if the XML file contains element(s) or tag(s) with the specified
+ [XPath-like ``path``](https://lxml.de/xpathxslt.html). If ``n`` and ``delta``
+ or ``min`` and ``max`` are given also the number of occurences is checked.
-has_json_property_with_text_text_description = """The expected text value of the target JSON attribute."""
+ ```xml
+
+
+
+
+
+ ```
+ With ``negate="true"`` the outcome of the assertions wrt the precence and number
+ of ``path`` can be negated. If there are any sub assertions then check them against
-class has_json_property_with_text_model(AssertionModel):
- r"""Asserts the JSON document contains a property or key with the specified text (i.e. string) value.
+ - the content of the attribute ``attribute``
+ - the element's text if no attribute is given
```xml
-
- ```"""
+
+
+
+
+
+ ```
+
+ Sub-assertions are not subject to the ``negate`` attribute of ``xml_element``.
+ If ``all`` is ``true`` then the sub assertions are checked for all occurences.
+
+ Note that all other XML assertions can be expressed by this assertion (Galaxy
+ also implements the other assertions by calling this one)."""
+
+ that: Literal["xml_element"] = "xml_element"
+
+
+class xml_element_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ xml_element: base_xml_element_model
- that: Literal["has_json_property_with_text"] = "has_json_property_with_text"
+
+has_json_property_with_text_property_description = """The property name to search the JSON document for."""
+
+has_json_property_with_text_text_description = """The expected text value of the target JSON attribute."""
+
+
+class base_has_json_property_with_text_model(AssertionModel):
+ """base model for has_json_property_with_text describing attributes."""
property: str = Field(
...,
@@ -961,6 +1124,22 @@ class has_json_property_with_text_model(AssertionModel):
)
+class has_json_property_with_text_model(base_has_json_property_with_text_model):
+ r"""Asserts the JSON document contains a property or key with the specified text (i.e. string) value.
+
+ ```xml
+
+ ```"""
+
+ that: Literal["has_json_property_with_text"] = "has_json_property_with_text"
+
+
+class has_json_property_with_text_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ has_json_property_with_text: base_has_json_property_with_text_model
+
+
has_json_property_with_value_property_description = """The property name to search the JSON document for."""
has_json_property_with_value_value_description = (
@@ -968,14 +1147,8 @@ class has_json_property_with_text_model(AssertionModel):
)
-class has_json_property_with_value_model(AssertionModel):
- r"""Asserts the JSON document contains a property or key with the specified JSON value.
-
- ```xml
-
- ```"""
-
- that: Literal["has_json_property_with_value"] = "has_json_property_with_value"
+class base_has_json_property_with_value_model(AssertionModel):
+ """base model for has_json_property_with_value describing attributes."""
property: str = Field(
...,
@@ -988,19 +1161,29 @@ class has_json_property_with_value_model(AssertionModel):
)
-has_h5_attribute_key_description = """HDF5 attribute to check value of."""
+class has_json_property_with_value_model(base_has_json_property_with_value_model):
+ r"""Asserts the JSON document contains a property or key with the specified JSON value.
-has_h5_attribute_value_description = """Expected value of HDF5 attribute to check."""
+ ```xml
+
+ ```"""
+ that: Literal["has_json_property_with_value"] = "has_json_property_with_value"
-class has_h5_attribute_model(AssertionModel):
- r"""Asserts HDF5 output contains the specified ``value`` for an attribute (``key``), e.g.
- ```xml
-
- ```"""
+class has_json_property_with_value_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ has_json_property_with_value: base_has_json_property_with_value_model
- that: Literal["has_h5_attribute"] = "has_h5_attribute"
+
+has_h5_attribute_key_description = """HDF5 attribute to check value of."""
+
+has_h5_attribute_value_description = """Expected value of HDF5 attribute to check."""
+
+
+class base_has_h5_attribute_model(AssertionModel):
+ """base model for has_h5_attribute describing attributes."""
key: str = Field(
...,
@@ -1013,13 +1196,27 @@ class has_h5_attribute_model(AssertionModel):
)
-has_h5_keys_keys_description = """HDF5 attributes to check value of as a comma-separated string."""
+class has_h5_attribute_model(base_has_h5_attribute_model):
+ r"""Asserts HDF5 output contains the specified ``value`` for an attribute (``key``), e.g.
+
+ ```xml
+
+ ```"""
+
+ that: Literal["has_h5_attribute"] = "has_h5_attribute"
-class has_h5_keys_model(AssertionModel):
- r"""Asserts the specified HDF5 output has the given keys."""
+class has_h5_attribute_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ has_h5_attribute: base_has_h5_attribute_model
- that: Literal["has_h5_keys"] = "has_h5_keys"
+
+has_h5_keys_keys_description = """HDF5 attributes to check value of as a comma-separated string."""
+
+
+class base_has_h5_keys_model(AssertionModel):
+ """base model for has_h5_keys describing attributes."""
keys: str = Field(
...,
@@ -1027,6 +1224,18 @@ class has_h5_keys_model(AssertionModel):
)
+class has_h5_keys_model(base_has_h5_keys_model):
+ r"""Asserts the specified HDF5 output has the given keys."""
+
+ that: Literal["has_h5_keys"] = "has_h5_keys"
+
+
+class has_h5_keys_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ has_h5_keys: base_has_h5_keys_model
+
+
has_archive_member_path_description = """The regular expression specifying the archive member."""
has_archive_member_all_description = (
@@ -1046,53 +1255,8 @@ class has_h5_keys_model(AssertionModel):
has_archive_member_negate_description = """A boolean that can be set to true to negate the outcome of the assertion."""
-class has_archive_member_model(AssertionModel):
- r"""This tag allows to check if ``path`` is contained in a compressed file.
-
- The path is a regular expression that is matched against the full paths of the objects in
- the compressed file (remember that "matching" means it is checked if a prefix of
- the full path of an archive member is described by the regular expression).
- Valid archive formats include ``.zip``, ``.tar``, and ``.tar.gz``. Note that
- depending on the archive creation method:
-
- - full paths of the members may be prefixed with ``./``
- - directories may be treated as empty files
-
- ```xml
-
- ```
-
- With ``n`` and ``delta`` (or ``min`` and ``max``) assertions on the number of
- archive members matching ``path`` can be expressed. The following could be used,
- e.g., to assert an archive containing n±1 elements out of which at least
- 4 need to have a ``txt`` extension.
-
- ```xml
-
-
- ```
-
- In addition the tag can contain additional assertions as child elements about
- the first member in the archive matching the regular expression ``path``. For
- instance
-
- ```xml
-
-
-
- ```
-
- If the ``all`` attribute is set to ``true`` then all archive members are subject
- to the assertions. Note that, archive members matching the ``path`` are sorted
- alphabetically.
-
- The ``negate`` attribute of the ``has_archive_member`` assertion only affects
- the asserts on the presence and number of matching archive members, but not any
- sub-assertions (which can offer the ``negate`` attribute on their own). The
- check if the file is an archive at all, which is also done by the function, is
- not affected."""
-
- that: Literal["has_archive_member"] = "has_archive_member"
+class base_has_archive_member_model(AssertionModel):
+ """base model for has_archive_member describing attributes."""
path: str = Field(
...,
@@ -1144,6 +1308,62 @@ class has_archive_member_model(AssertionModel):
)
children: typing.Optional["assertion_list"] = None
+ asserts: typing.Optional["assertion_list"] = None
+
+
+class has_archive_member_model(base_has_archive_member_model):
+ r"""This tag allows to check if ``path`` is contained in a compressed file.
+
+ The path is a regular expression that is matched against the full paths of the objects in
+ the compressed file (remember that "matching" means it is checked if a prefix of
+ the full path of an archive member is described by the regular expression).
+ Valid archive formats include ``.zip``, ``.tar``, and ``.tar.gz``. Note that
+ depending on the archive creation method:
+
+ - full paths of the members may be prefixed with ``./``
+ - directories may be treated as empty files
+
+ ```xml
+
+ ```
+
+ With ``n`` and ``delta`` (or ``min`` and ``max``) assertions on the number of
+ archive members matching ``path`` can be expressed. The following could be used,
+ e.g., to assert an archive containing n±1 elements out of which at least
+ 4 need to have a ``txt`` extension.
+
+ ```xml
+
+
+ ```
+
+ In addition the tag can contain additional assertions as child elements about
+ the first member in the archive matching the regular expression ``path``. For
+ instance
+
+ ```xml
+
+
+
+ ```
+
+ If the ``all`` attribute is set to ``true`` then all archive members are subject
+ to the assertions. Note that, archive members matching the ``path`` are sorted
+ alphabetically.
+
+ The ``negate`` attribute of the ``has_archive_member`` assertion only affects
+ the asserts on the presence and number of matching archive members, but not any
+ sub-assertions (which can offer the ``negate`` attribute on their own). The
+ check if the file is an archive at all, which is also done by the function, is
+ not affected."""
+
+ that: Literal["has_archive_member"] = "has_archive_member"
+
+
+class has_archive_member_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ has_archive_member: base_has_archive_member_model
has_size_value_description = """Deprecated alias for `size`"""
@@ -1161,13 +1381,17 @@ class has_archive_member_model(AssertionModel):
has_size_negate_description = """A boolean that can be set to true to negate the outcome of the assertion."""
-class has_size_model(AssertionModel):
- r"""Asserts the specified output has a size of the specified value
-
- Attributes size and value or synonyms though value is considered deprecated.
- The size optionally allows for absolute (``delta``) difference."""
+class base_has_size_model(AssertionModel):
+ """base model for has_size describing attributes."""
- that: Literal["has_size"] = "has_size"
+ value: Annotated[
+ typing.Optional[typing.Union[str, int]],
+ BeforeValidator(check_bytes),
+ BeforeValidator(check_non_negative_if_int),
+ ] = Field(
+ None,
+ description=has_size_value_description,
+ )
size: Annotated[
typing.Optional[typing.Union[str, int]],
@@ -1209,6 +1433,21 @@ class has_size_model(AssertionModel):
)
+class has_size_model(base_has_size_model):
+ r"""Asserts the specified output has a size of the specified value
+
+ Attributes size and value or synonyms though value is considered deprecated.
+ The size optionally allows for absolute (``delta``) difference."""
+
+ that: Literal["has_size"] = "has_size"
+
+
+class has_size_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ has_size: base_has_size_model
+
+
has_image_center_of_mass_center_of_mass_description = """The required center of mass of the image intensities (horizontal and vertical coordinate, separated by a comma)."""
has_image_center_of_mass_channel_description = """Restricts the assertion to a specific channel of the image (where ``0`` corresponds to the first image channel)."""
@@ -1218,14 +1457,8 @@ class has_size_model(AssertionModel):
)
-class has_image_center_of_mass_model(AssertionModel):
- r"""Asserts the specified output is an image and has the specified center of mass.
-
- Asserts the output is an image and has a specific center of mass,
- or has an Euclidean distance of ``eps`` or less to that point (e.g.,
- ````)."""
-
- that: Literal["has_image_center_of_mass"] = "has_image_center_of_mass"
+class base_has_image_center_of_mass_model(AssertionModel):
+ """base model for has_image_center_of_mass describing attributes."""
center_of_mass: Annotated[str, BeforeValidator(check_center_of_mass)] = Field(
...,
@@ -1243,6 +1476,22 @@ class has_image_center_of_mass_model(AssertionModel):
)
+class has_image_center_of_mass_model(base_has_image_center_of_mass_model):
+ r"""Asserts the specified output is an image and has the specified center of mass.
+
+ Asserts the output is an image and has a specific center of mass,
+ or has an Euclidean distance of ``eps`` or less to that point (e.g.,
+ ````)."""
+
+ that: Literal["has_image_center_of_mass"] = "has_image_center_of_mass"
+
+
+class has_image_center_of_mass_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ has_image_center_of_mass: base_has_image_center_of_mass_model
+
+
has_image_channels_channels_description = """Expected number of channels of the image."""
has_image_channels_delta_description = """Maximum allowed difference of the number of channels (default is 0). The observed number of channels has to be in the range ``value +- delta``."""
@@ -1254,14 +1503,8 @@ class has_image_center_of_mass_model(AssertionModel):
has_image_channels_negate_description = """A boolean that can be set to true to negate the outcome of the assertion."""
-class has_image_channels_model(AssertionModel):
- r"""Asserts the output is an image and has a specific number of channels.
-
- The number of channels is plus/minus ``delta`` (e.g., ````).
-
- Alternatively the range of the expected number of channels can be specified by ``min`` and/or ``max``."""
-
- that: Literal["has_image_channels"] = "has_image_channels"
+class base_has_image_channels_model(AssertionModel):
+ """base model for has_image_channels describing attributes."""
channels: Annotated[typing.Optional[StrictInt], BeforeValidator(check_non_negative_if_set)] = Field(
None,
@@ -1289,6 +1532,22 @@ class has_image_channels_model(AssertionModel):
)
+class has_image_channels_model(base_has_image_channels_model):
+ r"""Asserts the output is an image and has a specific number of channels.
+
+ The number of channels is plus/minus ``delta`` (e.g., ````).
+
+ Alternatively the range of the expected number of channels can be specified by ``min`` and/or ``max``."""
+
+ that: Literal["has_image_channels"] = "has_image_channels"
+
+
+class has_image_channels_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ has_image_channels: base_has_image_channels_model
+
+
has_image_height_height_description = """Expected height of the image (in pixels)."""
has_image_height_delta_description = """Maximum allowed difference of the image height (in pixels, default is 0). The observed height has to be in the range ``value +- delta``."""
@@ -1300,13 +1559,8 @@ class has_image_channels_model(AssertionModel):
has_image_height_negate_description = """A boolean that can be set to true to negate the outcome of the assertion."""
-class has_image_height_model(AssertionModel):
- r"""Asserts the output is an image and has a specific height (in pixels).
-
- The height is plus/minus ``delta`` (e.g., ````).
- Alternatively the range of the expected height can be specified by ``min`` and/or ``max``."""
-
- that: Literal["has_image_height"] = "has_image_height"
+class base_has_image_height_model(AssertionModel):
+ """base model for has_image_height describing attributes."""
height: Annotated[typing.Optional[StrictInt], BeforeValidator(check_non_negative_if_set)] = Field(
None,
@@ -1334,6 +1588,21 @@ class has_image_height_model(AssertionModel):
)
+class has_image_height_model(base_has_image_height_model):
+ r"""Asserts the output is an image and has a specific height (in pixels).
+
+ The height is plus/minus ``delta`` (e.g., ````).
+ Alternatively the range of the expected height can be specified by ``min`` and/or ``max``."""
+
+ that: Literal["has_image_height"] = "has_image_height"
+
+
+class has_image_height_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ has_image_height: base_has_image_height_model
+
+
has_image_mean_intensity_channel_description = """Restricts the assertion to a specific channel of the image (where ``0`` corresponds to the first image channel)."""
has_image_mean_intensity_mean_intensity_description = """The required mean value of the image intensities."""
@@ -1345,13 +1614,8 @@ class has_image_height_model(AssertionModel):
has_image_mean_intensity_max_description = """An upper bound of the required mean value of the image intensities."""
-class has_image_mean_intensity_model(AssertionModel):
- r"""Asserts the output is an image and has a specific mean intensity value.
-
- The mean intensity value is plus/minus ``eps`` (e.g., ````).
- Alternatively the range of the expected mean intensity value can be specified by ``min`` and/or ``max``."""
-
- that: Literal["has_image_mean_intensity"] = "has_image_mean_intensity"
+class base_has_image_mean_intensity_model(AssertionModel):
+ """base model for has_image_mean_intensity describing attributes."""
channel: typing.Optional[StrictInt] = Field(
None,
@@ -1379,6 +1643,21 @@ class has_image_mean_intensity_model(AssertionModel):
)
+class has_image_mean_intensity_model(base_has_image_mean_intensity_model):
+ r"""Asserts the output is an image and has a specific mean intensity value.
+
+ The mean intensity value is plus/minus ``eps`` (e.g., ````).
+ Alternatively the range of the expected mean intensity value can be specified by ``min`` and/or ``max``."""
+
+ that: Literal["has_image_mean_intensity"] = "has_image_mean_intensity"
+
+
+class has_image_mean_intensity_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ has_image_mean_intensity: base_has_image_mean_intensity_model
+
+
has_image_mean_object_size_channel_description = """Restricts the assertion to a specific channel of the image (where ``0`` corresponds to the first image channel)."""
has_image_mean_object_size_labels_description = """List of labels, separated by a comma. Labels *not* on this list will be excluded from consideration. Cannot be used in combination with ``exclude_labels``."""
@@ -1398,14 +1677,8 @@ class has_image_mean_intensity_model(AssertionModel):
)
-class has_image_mean_object_size_model(AssertionModel):
- r"""Asserts the output is an image with labeled objects which have the specified mean size (number of pixels),
-
- The mean size is plus/minus ``eps`` (e.g., ````).
-
- The labels must be unique."""
-
- that: Literal["has_image_mean_object_size"] = "has_image_mean_object_size"
+class base_has_image_mean_object_size_model(AssertionModel):
+ """base model for has_image_mean_object_size describing attributes."""
channel: typing.Optional[StrictInt] = Field(
None,
@@ -1449,6 +1722,22 @@ class has_image_mean_object_size_model(AssertionModel):
)
+class has_image_mean_object_size_model(base_has_image_mean_object_size_model):
+ r"""Asserts the output is an image with labeled objects which have the specified mean size (number of pixels),
+
+ The mean size is plus/minus ``eps`` (e.g., ````).
+
+ The labels must be unique."""
+
+ that: Literal["has_image_mean_object_size"] = "has_image_mean_object_size"
+
+
+class has_image_mean_object_size_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ has_image_mean_object_size: base_has_image_mean_object_size_model
+
+
has_image_n_labels_channel_description = """Restricts the assertion to a specific channel of the image (where ``0`` corresponds to the first image channel)."""
has_image_n_labels_labels_description = """List of labels, separated by a comma. Labels *not* on this list will be excluded from consideration. Cannot be used in combination with ``exclude_labels``."""
@@ -1466,15 +1755,8 @@ class has_image_mean_object_size_model(AssertionModel):
has_image_n_labels_negate_description = """A boolean that can be set to true to negate the outcome of the assertion."""
-class has_image_n_labels_model(AssertionModel):
- r"""Asserts the output is an image and has the specified labels.
-
- Labels can be a number of labels or unique values (e.g.,
- ````).
-
- The primary usage of this assertion is to verify the number of objects in images with uniquely labeled objects."""
-
- that: Literal["has_image_n_labels"] = "has_image_n_labels"
+class base_has_image_n_labels_model(AssertionModel):
+ """base model for has_image_n_labels describing attributes."""
channel: typing.Optional[StrictInt] = Field(
None,
@@ -1517,6 +1799,23 @@ class has_image_n_labels_model(AssertionModel):
)
+class has_image_n_labels_model(base_has_image_n_labels_model):
+ r"""Asserts the output is an image and has the specified labels.
+
+ Labels can be a number of labels or unique values (e.g.,
+ ````).
+
+ The primary usage of this assertion is to verify the number of objects in images with uniquely labeled objects."""
+
+ that: Literal["has_image_n_labels"] = "has_image_n_labels"
+
+
+class has_image_n_labels_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ has_image_n_labels: base_has_image_n_labels_model
+
+
has_image_width_width_description = """Expected width of the image (in pixels)."""
has_image_width_delta_description = """Maximum allowed difference of the image width (in pixels, default is 0). The observed width has to be in the range ``value +- delta``."""
@@ -1528,13 +1827,8 @@ class has_image_n_labels_model(AssertionModel):
has_image_width_negate_description = """A boolean that can be set to true to negate the outcome of the assertion."""
-class has_image_width_model(AssertionModel):
- r"""Asserts the output is an image and has a specific width (in pixels).
-
- The width is plus/minus ``delta`` (e.g., ````).
- Alternatively the range of the expected width can be specified by ``min`` and/or ``max``."""
-
- that: Literal["has_image_width"] = "has_image_width"
+class base_has_image_width_model(AssertionModel):
+ """base model for has_image_width describing attributes."""
width: Annotated[typing.Optional[StrictInt], BeforeValidator(check_non_negative_if_set)] = Field(
None,
@@ -1562,7 +1856,22 @@ class has_image_width_model(AssertionModel):
)
-any_assertion_model = Annotated[
+class has_image_width_model(base_has_image_width_model):
+ r"""Asserts the output is an image and has a specific width (in pixels).
+
+ The width is plus/minus ``delta`` (e.g., ````).
+ Alternatively the range of the expected width can be specified by ``min`` and/or ``max``."""
+
+ that: Literal["has_image_width"] = "has_image_width"
+
+
+class has_image_width_model_nested(AssertionModel):
+ r"""Nested version of this assertion model."""
+
+ has_image_width: base_has_image_width_model
+
+
+any_assertion_model_flat = Annotated[
typing.Union[
has_line_model,
has_line_matching_model,
@@ -1597,4 +1906,100 @@ class has_image_width_model(AssertionModel):
Field(discriminator="that"),
]
-assertion_list = RootModel[typing.List[any_assertion_model]]
+any_assertion_model_nested = typing.Union[
+ has_line_model_nested,
+ has_line_matching_model_nested,
+ has_n_lines_model_nested,
+ has_text_model_nested,
+ has_text_matching_model_nested,
+ not_has_text_model_nested,
+ has_n_columns_model_nested,
+ attribute_is_model_nested,
+ attribute_matches_model_nested,
+ element_text_model_nested,
+ element_text_is_model_nested,
+ element_text_matches_model_nested,
+ has_element_with_path_model_nested,
+ has_n_elements_with_path_model_nested,
+ is_valid_xml_model_nested,
+ xml_element_model_nested,
+ has_json_property_with_text_model_nested,
+ has_json_property_with_value_model_nested,
+ has_h5_attribute_model_nested,
+ has_h5_keys_model_nested,
+ has_archive_member_model_nested,
+ has_size_model_nested,
+ has_image_center_of_mass_model_nested,
+ has_image_channels_model_nested,
+ has_image_height_model_nested,
+ has_image_mean_intensity_model_nested,
+ has_image_mean_object_size_model_nested,
+ has_image_n_labels_model_nested,
+ has_image_width_model_nested,
+]
+
+assertion_list = RootModel[typing.List[typing.Union[any_assertion_model_flat, any_assertion_model_nested]]]
+
+
+class assertion_dict(AssertionModel):
+
+ has_line: typing.Optional[base_has_line_model] = None
+
+ has_line_matching: typing.Optional[base_has_line_matching_model] = None
+
+ has_n_lines: typing.Optional[base_has_n_lines_model] = None
+
+ has_text: typing.Optional[base_has_text_model] = None
+
+ has_text_matching: typing.Optional[base_has_text_matching_model] = None
+
+ not_has_text: typing.Optional[base_not_has_text_model] = None
+
+ has_n_columns: typing.Optional[base_has_n_columns_model] = None
+
+ attribute_is: typing.Optional[base_attribute_is_model] = None
+
+ attribute_matches: typing.Optional[base_attribute_matches_model] = None
+
+ element_text: typing.Optional[base_element_text_model] = None
+
+ element_text_is: typing.Optional[base_element_text_is_model] = None
+
+ element_text_matches: typing.Optional[base_element_text_matches_model] = None
+
+ has_element_with_path: typing.Optional[base_has_element_with_path_model] = None
+
+ has_n_elements_with_path: typing.Optional[base_has_n_elements_with_path_model] = None
+
+ is_valid_xml: typing.Optional[base_is_valid_xml_model] = None
+
+ xml_element: typing.Optional[base_xml_element_model] = None
+
+ has_json_property_with_text: typing.Optional[base_has_json_property_with_text_model] = None
+
+ has_json_property_with_value: typing.Optional[base_has_json_property_with_value_model] = None
+
+ has_h5_attribute: typing.Optional[base_has_h5_attribute_model] = None
+
+ has_h5_keys: typing.Optional[base_has_h5_keys_model] = None
+
+ has_archive_member: typing.Optional[base_has_archive_member_model] = None
+
+ has_size: typing.Optional[base_has_size_model] = None
+
+ has_image_center_of_mass: typing.Optional[base_has_image_center_of_mass_model] = None
+
+ has_image_channels: typing.Optional[base_has_image_channels_model] = None
+
+ has_image_height: typing.Optional[base_has_image_height_model] = None
+
+ has_image_mean_intensity: typing.Optional[base_has_image_mean_intensity_model] = None
+
+ has_image_mean_object_size: typing.Optional[base_has_image_mean_object_size_model] = None
+
+ has_image_n_labels: typing.Optional[base_has_image_n_labels_model] = None
+
+ has_image_width: typing.Optional[base_has_image_width_model] = None
+
+
+assertions = typing.Union[assertion_list, assertion_dict]