* Merged tests for variables and commands in the same file.
* Added support for array variables. * Support for exception logging.
This commit is contained in:
+76
-36
@@ -61,14 +61,14 @@ The only command available is `include wildcard`, which will include the choices
|
||||
|
||||
These are examples of formats you can use to insert a choice construct:
|
||||
|
||||
| Construct | Result |
|
||||
| --------- | ------ |
|
||||
| `{choice1\|5::choice2\|3::choice3}` | select 1 choice, two of them have weights |
|
||||
| `{3$$choice1\|5 if _is_sd1::choice2\|choice3}` | select 3 choices, one has a weight and a condition |
|
||||
| `{2-3$$2::choice1\|choice2\|choice3}` | select 2 to 3 choices, one of them has a weight |
|
||||
| `{r2-3$$choice1\|choice2\|choice3}` | select 2 to 3 choices allowing repetition |
|
||||
| `{2-3$$ / $$choice1\|choice2\|choice3}` | select 2 to 3 choices with separator " / " |
|
||||
| `{o$$if _is_sd1::choice1\|if _is_sd2::choice2}` | select 1 choice, both have conditions, if none matches it is allowed because we indicate that it is optional |
|
||||
| Construct | Result |
|
||||
| --------- | ------ |
|
||||
| `{choice1\|5::choice2\|3::choice3}` | select 1 choice, two of them have weights |
|
||||
| `{3$$choice1\|5 if _is_sd1::choice2\|choice3}` | select 3 choices, one has a weight and a condition |
|
||||
| `{2-3$$2::choice1\|choice2\|choice3}` | select 2 to 3 choices, one of them has a weight |
|
||||
| `{r2-3$$choice1\|choice2\|choice3}` | select 2 to 3 choices allowing repetition |
|
||||
| `{2-3$$ / $$choice1\|choice2\|choice3}` | select 2 to 3 choices with separator " / " |
|
||||
| `{o$$if _is_sd1::choice1\|if _is_sd2::choice2}` | select 1 choice, both have conditions, if none matches it is allowed because we indicate that it is optional |
|
||||
| `{choice1\|choice2\|%0.5::include path/wildcard}` | select 1 choice from the two specified and the ones inside the path/wildcard wildcard, which will be weighted with half their weights |
|
||||
|
||||
Notes:
|
||||
@@ -234,6 +234,30 @@ The *Dynamic Prompts* format is:
|
||||
|
||||
An echoed variable that uses the default because it doesn't have a value will be included in the output variables with the last default value used.
|
||||
|
||||
## Array variables
|
||||
|
||||
There is support for array variables. They use brackets `[]` to differenciate from regular variables. Empty brackets mean the whole array (used when initializing or when echoing the whole array) and a number means an indexed value. These variables can only be set with the *Dynamic Prompts* format.
|
||||
|
||||
Some examples of how to use them:
|
||||
|
||||
| Construct | Meaning |
|
||||
| --------- | ------- |
|
||||
| `${var[]=value}` | initialize and set the first value |
|
||||
| `${var[]+=}` | add an empty element to the array |
|
||||
| `${var[]+=value}` | add a value to the array |
|
||||
| `${var[]=*()}` | initialize an empty array |
|
||||
| `${var[]=*var2[]}` | initialize an array from another array |
|
||||
| `${var[]=*__wildcard__}` | initialize an array from a wildcard |
|
||||
| `${var[]=*('value',var2)}` | initialize an array from a list of values (strings or variables) |
|
||||
| `${var[]+=*var2[]}` | add elements from another array |
|
||||
| `${var[]+=*__wildcard__}` | add elements from a wildcard |
|
||||
| `${var[]}` | echo all elements with a default separator |
|
||||
| `${var[' / ']}` | echo all elements with a specific separator |
|
||||
| `${var[n]}` | echo an element from the array |
|
||||
| `${var[n]:default}` | echo an element with a default |
|
||||
|
||||
Initialization with the star operator `*` is always with inmediate evaluation.
|
||||
|
||||
## If command
|
||||
|
||||
This command allows you to filter content based on conditions.
|
||||
@@ -244,41 +268,57 @@ The full format is:
|
||||
|
||||
Any `elif`s (there can be multiple) and the `else` are optional.
|
||||
|
||||
The `conditionN` can be:
|
||||
The `conditionN` is a boolean expression, which can use `and`, `or`, `not` and grouping with parentheses, and where the simplest expression can be:
|
||||
|
||||
| Construct | Meaning |
|
||||
| --------- | ------- |
|
||||
| `variable` | check truthyness of the variable |
|
||||
| `variable [not] operation value` | check the variable against a value |
|
||||
| `variable [not] operation (value1,value2,...)` | check the variable against a list of values |
|
||||
| Construct | Meaning |
|
||||
| --------- | ------- |
|
||||
| `operand` | check truthyness of the operand, meaning not zero, empty string nor empty array |
|
||||
| `operand1 [not] operation operand2` | compare the operands |
|
||||
|
||||
For a simple value the allowed operations are `eq`, `ne`, `gt`, `lt`, `ge`, `le`, `contains` and the value can be a quoted string, an integer, or another variable name (e.g., `<ppp:if var1 contains var2>`). When the value is a variable name, it is resolved to the variable's current value before comparison. For a list of values the allowed operations are `contains`, `in` and the value of the variable is checked against all the elements of the list until one matches. The operation can be preceded by `not` for readability, instead of using it in the front.
|
||||
The operands can be a variable (`variable`, `array[]`, `array[index]`), a quoted string, an integer, a boolean, or a parenthesized list of any of them `('string', 1, variable, false, array[], array[2])`. The allowed operations depend on which operands are used.
|
||||
|
||||
When a variable used in an integer comparison is undefined or cannot be converted to an integer (e.g. it contains non-numeric text or is an empty string), the behavior depends on the `on_warning` setting: in `warn` mode the comparison evaluates to false, and in `stop` mode an error is raised.
|
||||
Variable values `true` and `false` are considered a boolean, and a digits value is an integer.
|
||||
|
||||
You can also build complex conditions joining them with boolean operators and/or/not and parentheses.
|
||||
The supported operations are: `eq`, `ne`, `gt`, `lt`, `ge`, `le`, `in` and `contains`.
|
||||
|
||||
The variable can be one set with the `set` or `add` commands (user variables) or you can use system variables like these (names starting with an underscore are reserved for system variables):
|
||||
| Operation | Supported operands |
|
||||
| --------- | ------------------ |
|
||||
| `eq` | single or array but both of the same kind |
|
||||
| `ne` | single or array but both of the same kind |
|
||||
| `gt` | single or array but both of the same kind |
|
||||
| `lt` | single or array but both of the same kind |
|
||||
| `ge` | single or array but both of the same kind |
|
||||
| `le` | single or array but both of the same kind |
|
||||
| `in` | single or array, if only one is an array it should be the second one |
|
||||
| `contains` | single or array, if only one is an array it should be the first one |
|
||||
|
||||
| System variable | Value |
|
||||
| --------------- | ----- |
|
||||
| `_model` | the loaded model identifier (`"sd1"`, `"sd2"`, `"sdxl"`, `"sd3"`, `"flux"`, `"auraflow"`). `_sd` also works but is deprecated. |
|
||||
| `_modelname` | the loaded model filename (without path). `_sdname` also works but is deprecated. |
|
||||
| `_modelfullname` | the loaded model filename (with path). `_sdfullname` also works but is deprecated. |
|
||||
Two arrays are compared element by element, except with `in` and `contains` which are considered like set operations.
|
||||
|
||||
When an operand is a variable name, it is resolved to the variable's current value before comparison. The operation can be preceded by `not` for readability, instead of using it in the front.
|
||||
|
||||
When a comparison tries to compare undefined variables or the values have different types (f.e. an integer and a string), the behavior depends on the `on_warning` setting: in `warn` mode the comparison evaluates to false, and in `stop` mode an error is raised.
|
||||
|
||||
The variable can be one set with the `set` command (user variables) or you can use system variables like these (names starting with an underscore are reserved for system variables):
|
||||
|
||||
| System variable | Value |
|
||||
| --------------- | ----- |
|
||||
| `_model` | the loaded model identifier (`"sd1"`, `"sd2"`, `"sdxl"`, `"sd3"`, `"flux"`, `"auraflow"`). `_sd` also works but is deprecated. |
|
||||
| `_modelname` | the loaded model filename (without path). `_sdname` also works but is deprecated. |
|
||||
| `_modelfullname` | the loaded model filename (with path). `_sdfullname` also works but is deprecated. |
|
||||
| `_modelclass` | the class used for the model. Note that this is dependent on the webui. In A1111 all SD versions use the same class. Can be used for new models that are not supported yet with the `_is_*` variables. The debug setting will show all system variables when generating in case you need to see which one to use for a certain model. |
|
||||
| `_is_sd` | true if the loaded model version is any version of SD |
|
||||
| `_is_sd1` | true if the loaded model version is SD 1.x |
|
||||
| `_is_sd2` | true if the loaded model version is SD 2.x |
|
||||
| `_is_sdxl` | true if the loaded model version is SDXL (includes Pony models) |
|
||||
| `_is_sd3` | true if the loaded model version is SD 3.x |
|
||||
| `_is_flux` | true if the loaded model is Flux |
|
||||
| `_is_auraflow` | true if the loaded model is AuraFlow |
|
||||
| `_is_ssd` | true if the loaded model version is SSD (Segmind Stable Diffusion 1B). Note that for an SSD model `_is_sdxl` will also be true. |
|
||||
| `_is_sdxl_no_ssd` | true if the loaded model version is SDXL and not an SSD model. |
|
||||
| `_is_sdxl_no_pony` | true if the loaded model version is SDXL and not a Pony model (the "pony" variant must be defined in settings). Kept to maintain compatibility with previous versions. |
|
||||
| `_is_vvvv` | true if the loaded model matches the *vvvv* model variant definition (based on its filename). Note that the corresponding variable for the model kind will also be true. |
|
||||
| `_is_pure_kkkk` | true if the loaded model is of kind *kkkk* (f.e. sdxl) and not a variant. |
|
||||
| `_is_variant_kkkk` | true if the loaded model version is any variant of model kind *kkkk* and not the pure version. Note that the corresponding variable for the model kind will also be true.|
|
||||
| `_is_sd` | true if the loaded model version is any version of SD |
|
||||
| `_is_sd1` | true if the loaded model version is SD 1.x |
|
||||
| `_is_sd2` | true if the loaded model version is SD 2.x |
|
||||
| `_is_sdxl` | true if the loaded model version is SDXL (includes Pony models) |
|
||||
| `_is_sd3` | true if the loaded model version is SD 3.x |
|
||||
| `_is_flux` | true if the loaded model is Flux |
|
||||
| `_is_auraflow` | true if the loaded model is AuraFlow |
|
||||
| `_is_ssd` | true if the loaded model version is SSD (Segmind Stable Diffusion 1B). Note that for an SSD model `_is_sdxl` will also be true. |
|
||||
| `_is_sdxl_no_ssd` | true if the loaded model version is SDXL and not an SSD model. |
|
||||
| `_is_sdxl_no_pony` | true if the loaded model version is SDXL and not a Pony model (the "pony" variant must be defined in settings). Kept to maintain compatibility with previous versions. |
|
||||
| `_is_vvvv` | true if the loaded model matches the *vvvv* model variant definition (based on its filename). Note that the corresponding variable for the model kind will also be true. |
|
||||
| `_is_pure_kkkk` | true if the loaded model is of kind *kkkk* (f.e. sdxl) and not a variant. |
|
||||
| `_is_variant_kkkk` | true if the loaded model version is any variant of model kind *kkkk* and not the pure version. Note that the corresponding variable for the model kind will also be true. |
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
+24
-16
@@ -9,7 +9,7 @@ INDEX: INT
|
||||
FILTER: INDEX | IDENTIFIER
|
||||
IDENTIFIER: CNAME
|
||||
SIMPLEVALUE: STRING | SIGNED_NUMBER | BOOLEAN
|
||||
COMPVALUE: SIMPLEVALUE | IDENTIFIER
|
||||
VARNAME: /(?!__)[a-zA-Z_][a-zA-Z0-9_]*/
|
||||
|
||||
// plain text and weights
|
||||
?plain: /((?!__|\bAND\b|\${)[^\\()\[\]:<>${]|\\.)+/s // exclude only the starting ones
|
||||
@@ -94,19 +94,22 @@ extranetworktag: "<" /(?!ppp:)\w+:/ encontent ">"
|
||||
?encontent.3: content_en
|
||||
|
||||
//#if ALLOW_COMMVARS or ALLOW_CHOICES or ALLOW_WILDCARDS
|
||||
vardescriptor_get.8: VARNAME [ /\[/ [ SIGNED_NUMBER | STRING | IDENTIFIER ] /\]/ ]
|
||||
vardescriptor_set.9: VARNAME [ /\[/ [ SIGNED_NUMBER | IDENTIFIER ] /\]/ ]
|
||||
|
||||
// conditions
|
||||
?condition: grouped_condition | ungrouped_condition
|
||||
?ungrouped_condition: operation | basic_condition
|
||||
?grouped_condition.8: "(" _WHITESPACE? condition _WHITESPACE? ")"
|
||||
?basic_condition: comparison_simple_value | comparison_list_value | truthy_operand
|
||||
?basic_condition: comparison | truthy_operand
|
||||
?operation: operation_not | operation_and | operation_or
|
||||
operation_and: condition _WHITESPACE "and" _WHITESPACE condition
|
||||
operation_or: condition _WHITESPACE "or" _WHITESPACE condition
|
||||
operation_not: "not" ( ( _WHITESPACE ungrouped_condition ) | ( _WHITESPACE? grouped_condition ) )
|
||||
truthy_operand: IDENTIFIER
|
||||
comparison_simple_value: IDENTIFIER _WHITESPACE ( /not/ _WHITESPACE )? /eq|ne|gt|lt|ge|le|contains/ _WHITESPACE COMPVALUE
|
||||
comparison_list_value: IDENTIFIER _WHITESPACE ( /not/ _WHITESPACE )? /contains|in/ _WHITESPACE listvalue
|
||||
listvalue.9: "(" _WHITESPACE? COMPVALUE ( _WHITESPACE? "," _WHITESPACE? COMPVALUE )* _WHITESPACE? ")"
|
||||
?complexvalue: vardescriptor_get | SIMPLEVALUE
|
||||
truthy_operand: vardescriptor_get
|
||||
comparison: ( complexvalue | listvalue ) _WHITESPACE ( /not/ _WHITESPACE )? /eq|ne|gt|lt|ge|le|contains|in/ _WHITESPACE ( complexvalue | listvalue )
|
||||
listvalue.9: "(" ( _WHITESPACE? complexvalue ( _WHITESPACE? "," _WHITESPACE? complexvalue )* )? _WHITESPACE? ")"
|
||||
//#endif
|
||||
|
||||
//#if ALLOW_COMMVARS
|
||||
@@ -122,14 +125,26 @@ extranetworktag: "<" /(?!ppp:)\w+:/ encontent ">"
|
||||
ifvalue.3: content
|
||||
|
||||
// command: set
|
||||
commandset: "<ppp:set" _WHITESPACE IDENTIFIER [ commandsetmodifiers ] _WHITESPACE? ">" commandsetcontent "<ppp:/set>"
|
||||
commandset: "<ppp:set" _WHITESPACE vardescriptor_set [ commandsetmodifiers ] _WHITESPACE? ">" commandsetcontent "<ppp:/set>"
|
||||
commandsetmodifiers: (_WHITESPACE /evaluate|ifundefined|add/ )+
|
||||
?commandsetcontent.3: content
|
||||
|
||||
// variable set
|
||||
//#if ALLOW_WILDCARDS
|
||||
starredvalue.9: "*" ( wildcard | vardescriptor_get | listvalue )
|
||||
//#else
|
||||
starredvalue.9: "*" ( vardescriptor_get | listvalue )
|
||||
//#endif
|
||||
variableset.2: "${" _WHITESPACE? vardescriptor_set [ variablesetmodifiers ] _WHITESPACE? "=" [ /!/ ] ( starredvalue | varvalue ) "}"
|
||||
variablesetmodifiers: /[+?!]+/
|
||||
|
||||
// command: echo
|
||||
commandecho: "<ppp:echo" _WHITESPACE IDENTIFIER _WHITESPACE? ( ">" [ commandechodefault "<ppp:/echo>" ] | "/>" )
|
||||
commandecho: "<ppp:echo" _WHITESPACE vardescriptor_get _WHITESPACE? ( ">" [ commandechodefault "<ppp:/echo>" ] | "/>" )
|
||||
?commandechodefault.3: content
|
||||
|
||||
// variable use
|
||||
variableuse.2: "${" _WHITESPACE? vardescriptor_get _WHITESPACE? [ ":" varvalue ] "}"
|
||||
|
||||
// command: ext
|
||||
commandext: "<ppp:ext" _WHITESPACE commandexttype _WHITESPACE commandextid [ _WHITESPACE? commandextparams ] [ _WHITESPACE? commandextif ] _WHITESPACE? ( ">" [ commandexttriggers "<ppp:/ext>" ] | "/>" )
|
||||
commandexttype: [/\$/] IDENTIFIER
|
||||
@@ -137,13 +152,6 @@ extranetworktag: "<" /(?!ppp:)\w+:/ encontent ">"
|
||||
?commandextparams.2: STRING | SIGNED_NUMBER
|
||||
?commandextif: "if" _WHITESPACE condition
|
||||
?commandexttriggers.3: content
|
||||
|
||||
// variable set
|
||||
variableset.2: "${" _WHITESPACE? IDENTIFIER [ variablesetmodifiers ] _WHITESPACE? "=" [ /!/ ] varvalue "}"
|
||||
variablesetmodifiers: /[+?!]+/
|
||||
|
||||
// variable use
|
||||
variableuse.2: "${" _WHITESPACE? IDENTIFIER _WHITESPACE? [ ":" varvalue ] "}"
|
||||
//#endif
|
||||
varvalue: content_var
|
||||
|
||||
@@ -187,7 +195,7 @@ varvalue: content_var
|
||||
wc_filter: /["']/ ( [ /#/ ] wc_filter_or | ( /#?\^/ wildcard_name ) ) /["']/
|
||||
wc_filter_or: wc_filter_and ( _WHITESPACE? "," _WHITESPACE? wc_filter_and )*
|
||||
wc_filter_and: wc_filter_simple ( _WHITESPACE? "+" _WHITESPACE? wc_filter_simple )*
|
||||
wildcardvar.7: "(" _WHITESPACE? IDENTIFIER _WHITESPACE? "=" varvalue ")"
|
||||
wildcardvar.7: "(" _WHITESPACE? vardescriptor_get _WHITESPACE? "=" varvalue ")"
|
||||
|
||||
//#if ALLOW_COMMVARS
|
||||
// command: setwcdeffilter
|
||||
|
||||
@@ -343,8 +343,8 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
)
|
||||
self.__init_sysvars()
|
||||
|
||||
def log(self, kind, message: str, min_level: DEBUG_LEVEL | None = None):
|
||||
log(self.logger, self.debug_level, kind, message, min_level)
|
||||
def log(self, kind, message: str, min_level: DEBUG_LEVEL | None = None, exc_info: bool = False):
|
||||
log(self.logger, self.debug_level, kind, message, min_level, exc_info=exc_info)
|
||||
|
||||
def __merge_configuration(self, user_config):
|
||||
"""
|
||||
@@ -1088,6 +1088,6 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in
|
||||
self.log(logging.ERROR, "Interrupting!")
|
||||
self.interrupt()
|
||||
return prompt, negative_prompt, all_variables
|
||||
except Exception as e: # pylint: disable=broad-exception-caught
|
||||
self.log(logging.ERROR, f"Unexpected error: {e}")
|
||||
except Exception: # pylint: disable=broad-exception-caught
|
||||
self.log(logging.ERROR, "Unexpected error", exc_info=True)
|
||||
return original_prompt, original_negative_prompt, all_variables
|
||||
|
||||
+2
-2
@@ -98,7 +98,7 @@ class PromptPostProcessorLogCustomAdapter(logging.LoggerAdapter):
|
||||
"""
|
||||
return f"[PPP] {msg}", kwargs
|
||||
|
||||
def log(logger: logging.Logger, debug_level: DEBUG_LEVEL, kind: int, message: str, min_level: DEBUG_LEVEL | None = None, formatted: bool = True):
|
||||
def log(logger: logging.Logger, debug_level: DEBUG_LEVEL, kind: int, message: str, min_level: DEBUG_LEVEL | None = None, formatted: bool = True, exc_info: bool = False):
|
||||
if logger:
|
||||
if min_level is None:
|
||||
if kind == logging.DEBUG:
|
||||
@@ -110,4 +110,4 @@ def log(logger: logging.Logger, debug_level: DEBUG_LEVEL, kind: int, message: st
|
||||
i_debug_level = list(DEBUG_LEVEL).index(debug_level)
|
||||
i_min_level = list(DEBUG_LEVEL).index(min_level)
|
||||
if i_debug_level >= i_min_level:
|
||||
logger.log(kind, format_output(message) if formatted else message)
|
||||
logger.log(kind, format_output(message) if formatted else message, exc_info=exc_info)
|
||||
|
||||
+566
-240
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,323 @@
|
||||
from dataclasses import replace
|
||||
|
||||
from ppp import PromptPostProcessor # pylint: disable=import-error
|
||||
from ppp_classes import ONWARNING_CHOICES # pylint: disable=import-error
|
||||
from .base_tests import PromptPair, TestPromptPostProcessorBase
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit("This script must not be run directly")
|
||||
|
||||
|
||||
class TestCommands(TestPromptPostProcessorBase):
|
||||
class TestVarCommands(TestPromptPostProcessorBase):
|
||||
|
||||
def setUp(self): # pylint: disable=arguments-differ
|
||||
super().setUp(enable_file_logging=False)
|
||||
|
||||
# Empty variable test
|
||||
|
||||
def test_empty_variable(self):
|
||||
self.process(
|
||||
PromptPair(
|
||||
"${v1=}<ppp:set v2><ppp:/set>${v3:}",
|
||||
"",
|
||||
),
|
||||
PromptPair("", ""),
|
||||
variables={"v1": "", "v2": "", "v3": ""},
|
||||
)
|
||||
|
||||
# Echoed variables tests
|
||||
|
||||
def test_echoed_variable(self):
|
||||
self.process(
|
||||
PromptPair(
|
||||
"${v1=test1}<ppp:set v2>test2<ppp:/set>${v3:test3}${v3:test4}",
|
||||
"",
|
||||
),
|
||||
# v3 is echoed withs two defaults, the output prompt has both but the variable value is the last default
|
||||
PromptPair("test3test4", ""),
|
||||
variables={"v1": "test1", "v2": "test2", "v3": "test4"},
|
||||
)
|
||||
|
||||
def test_unknown_echoed_variable(self):
|
||||
self.process(
|
||||
PromptPair(
|
||||
"${v1}",
|
||||
"",
|
||||
),
|
||||
# v3 is echoed withs two defaults, the output prompt has both but the variable value is the last default
|
||||
PromptPair("", ""),
|
||||
variables={"v1": ""},
|
||||
ppp=PromptPostProcessor(
|
||||
self.ppp_logger,
|
||||
self.def_env_info,
|
||||
replace(
|
||||
self.defopts,
|
||||
on_warning=ONWARNING_CHOICES.warn,
|
||||
),
|
||||
self.grammar_content,
|
||||
self.interrupt,
|
||||
self.wildcards_obj,
|
||||
self.extranetwork_maps_obj,
|
||||
),
|
||||
)
|
||||
|
||||
# Variable in extranetworks
|
||||
|
||||
def test_variable_in_extranetwork(self):
|
||||
self.process(
|
||||
PromptPair(
|
||||
"${f=filename}${w=0.5}<lora:${f}:${w}>",
|
||||
"",
|
||||
),
|
||||
PromptPair("<lora:filename:0.5>", ""),
|
||||
)
|
||||
|
||||
# Variable nesting tests
|
||||
|
||||
def test_var_nested_1(self): # variable default nested in variable set
|
||||
self.process(
|
||||
PromptPair(
|
||||
"${v1=test ${v2:OK}}${v1}",
|
||||
"",
|
||||
),
|
||||
PromptPair("test OK", ""),
|
||||
variables={"v1": "test OK", "v2": "OK"},
|
||||
)
|
||||
|
||||
def test_var_nested_2(self): # variable set nested in variable default
|
||||
self.process(
|
||||
PromptPair(
|
||||
"${v1:test ${v2=OK}${v2}}",
|
||||
"",
|
||||
),
|
||||
PromptPair("test OK", ""),
|
||||
variables={"v1": "test OK", "v2": "OK"},
|
||||
)
|
||||
|
||||
def test_var_nested_3(self): # variable default nested in variable default
|
||||
self.process(
|
||||
PromptPair(
|
||||
"${v1:test ${v2:OK}}",
|
||||
"",
|
||||
),
|
||||
PromptPair("test OK", ""),
|
||||
variables={"v1": "test OK", "v2": "OK"},
|
||||
)
|
||||
|
||||
# Array variable tests
|
||||
|
||||
def test_array_variable_1(self): # array variable set with += and test of index value and full array with and without default separator
|
||||
self.process(
|
||||
PromptPair(
|
||||
"${v1[]=val1}${v1[]+=val2}${v1[]+=val3}${v1[1]:defval},${v1[]:defval2},${v1['.']:defval3}",
|
||||
"",
|
||||
),
|
||||
PromptPair("val2,val1, val2, val3,val1.val2.val3", ""),
|
||||
variables={"v1[]": "val1, val2, val3", "v1[1]": "val2", "v1['.']": "val1.val2.val3"},
|
||||
)
|
||||
|
||||
def test_array_variable_2(self): # override of array variable value, test of default value when array variable is empty, test of default value when array variable is not set
|
||||
self.process(
|
||||
PromptPair(
|
||||
"${v1[]=val1}${v1[]=val2}${v1[]:defval},${v2[]:defval2},${v2[1]:defval3},${v3[]=}${v3[]:defval4}",
|
||||
"",
|
||||
),
|
||||
PromptPair("val2,defval2,defval3", ""),
|
||||
variables={"v1[]": "val2", "v2[]": "defval2", "v2[1]": "defval3", "v3[]": ""},
|
||||
)
|
||||
|
||||
def test_array_variable_3(self): # access array index by variable, set array variable to expanded array variable and add expanded array
|
||||
self.process(
|
||||
PromptPair(
|
||||
"${v1[]=val1}${v1[]+=val2}${v2=1}${v1[v2]:defval1}${v3[]=${v1[]}}${v3[]+=${v1[]}}, ${v3['.']}",
|
||||
"",
|
||||
),
|
||||
PromptPair("val2, val1, val2.val1, val2", ""),
|
||||
variables={"v1[]": "val1, val2", "v2": "1", "v1[v2]": "val2", "v3[]": "val1, val2, val1, val2"},
|
||||
)
|
||||
|
||||
def test_array_variable_4(self): # test list in array
|
||||
self.process(
|
||||
PromptPair(
|
||||
"${v1[]=val1}${v1[]+=val2}${v1[]+=val3}<ppp:if ('val1','val2') in v1[]>OK<ppp:else>not OK<ppp:/if>",
|
||||
"",
|
||||
),
|
||||
PromptPair("OK", ""),
|
||||
variables={"v1[]": "val1, val2, val3"},
|
||||
)
|
||||
|
||||
def test_array_variable_5(self): # test empty array
|
||||
self.process(
|
||||
PromptPair(
|
||||
"${v1[]=}<ppp:if v1[]>OK<ppp:else>not OK<ppp:/if>,<ppp:if not v1[0]>OK<ppp:else>not OK<ppp:/if>",
|
||||
"",
|
||||
),
|
||||
PromptPair("OK,OK", ""),
|
||||
variables={"v1[]": ""},
|
||||
)
|
||||
|
||||
def test_array_variable_6(self): # array variable set and addition with expanded values from array variables
|
||||
self.process(
|
||||
PromptPair(
|
||||
"${v1[]=val1}${v1[]+=val2}${v2[]=val3}${v3[]=*v1[]}${v3[]+=*v2[]}",
|
||||
"",
|
||||
),
|
||||
PromptPair("", ""),
|
||||
variables={"v1[]": "val1, val2", "v2[]": "val3", "v3[]": "val1, val2, val3"},
|
||||
)
|
||||
|
||||
def test_array_variable_7(self): # array variable set and addition with expanded values from wildcards
|
||||
self.process(
|
||||
PromptPair(
|
||||
"${v1[]=*__yaml/wildcard1__}${v1[]+=*__yaml/wildcard2__}${v1[2]:defval}",
|
||||
"",
|
||||
),
|
||||
PromptPair("choice3", ""),
|
||||
variables={"v1[]": "choice2, choice1, choice3, choice1"},
|
||||
)
|
||||
|
||||
def test_array_variable_8(self): # array variable set and addition with expanded values from lists
|
||||
self.process(
|
||||
PromptPair(
|
||||
"${v1[]=*()}${v1[]+=*('one','two')}${v2=three}${v1[]+=*(v2,'four')}${v1[2]:defval}",
|
||||
"",
|
||||
),
|
||||
PromptPair("three", ""),
|
||||
variables={"v1[]": "one, two, three, four", "v2": "three"},
|
||||
)
|
||||
|
||||
# Variable-vs-variable comparison tests
|
||||
|
||||
def test_cmd_if_var_vs_var_eq(self): # var eq var: both set to same value, if-branch taken
|
||||
self.process(
|
||||
PromptPair(
|
||||
"<ppp:set v1>hello<ppp:/set><ppp:set v2>hello<ppp:/set><ppp:if v1 eq v2>OK<ppp:else>not OK<ppp:/if>",
|
||||
"",
|
||||
),
|
||||
PromptPair("OK", ""),
|
||||
)
|
||||
|
||||
def test_cmd_if_var_vs_var_ne(self): # var ne var: different values, ne condition true
|
||||
self.process(
|
||||
PromptPair(
|
||||
"<ppp:set v1>apple<ppp:/set><ppp:set v2>orange<ppp:/set><ppp:if v1 ne v2>OK<ppp:else>not OK<ppp:/if>",
|
||||
"",
|
||||
),
|
||||
PromptPair("OK", ""),
|
||||
)
|
||||
|
||||
def test_cmd_if_var_vs_var_contains(self): # var contains var: var1 contains var2's value
|
||||
self.process(
|
||||
PromptPair(
|
||||
"<ppp:set v1>hello world<ppp:/set><ppp:set v2>hello<ppp:/set><ppp:if v1 contains v2>OK<ppp:else>not OK<ppp:/if>",
|
||||
"",
|
||||
),
|
||||
PromptPair("OK", ""),
|
||||
)
|
||||
|
||||
def test_cmd_if_var_vs_var_not_contains(self): # var not contains var: var1 does not contain var2's value
|
||||
self.process(
|
||||
PromptPair(
|
||||
"<ppp:set v1>hello world<ppp:/set><ppp:set v2>goodbye<ppp:/set><ppp:if v1 not contains v2>OK<ppp:else>not OK<ppp:/if>",
|
||||
"",
|
||||
),
|
||||
PromptPair("OK", ""),
|
||||
)
|
||||
|
||||
def test_cmd_if_var_vs_var_lt(self): # var lt var: var1 less than var2
|
||||
self.process(
|
||||
PromptPair(
|
||||
"<ppp:set lesser>1<ppp:/set><ppp:set greater>2<ppp:/set><ppp:if lesser lt greater>OK<ppp:else>not OK<ppp:/if>",
|
||||
"",
|
||||
),
|
||||
PromptPair("OK", ""),
|
||||
)
|
||||
|
||||
# NaN/undefined variable integer comparison tests
|
||||
|
||||
def test_cmd_if_undefined_var_int_compare_warn(self): # undefined var integer compare with on_warning=warn
|
||||
self.process(
|
||||
PromptPair(
|
||||
"<ppp:if undefined_var gt 0>OK<ppp:else>not OK<ppp:/if>",
|
||||
"",
|
||||
),
|
||||
PromptPair("not OK", ""),
|
||||
ppp=PromptPostProcessor(
|
||||
self.ppp_logger,
|
||||
self.def_env_info,
|
||||
replace(
|
||||
self.defopts,
|
||||
on_warning=ONWARNING_CHOICES.warn,
|
||||
),
|
||||
self.grammar_content,
|
||||
self.interrupt,
|
||||
self.wildcards_obj,
|
||||
self.extranetwork_maps_obj,
|
||||
),
|
||||
)
|
||||
|
||||
def test_cmd_if_undefined_var_int_compare_stop(self): # undefined var integer compare with on_warning=stop
|
||||
self.process(
|
||||
PromptPair(
|
||||
"<ppp:if undefined_var gt 0>OK<ppp:else>not OK<ppp:/if>",
|
||||
"",
|
||||
),
|
||||
PromptPair("", ""),
|
||||
interrupted=True,
|
||||
)
|
||||
|
||||
def test_cmd_if_nonnumeric_var_int_compare_warn(self): # non-numeric var integer compare with on_warning=warn
|
||||
self.process(
|
||||
PromptPair(
|
||||
"<ppp:set myvar>abc<ppp:/set><ppp:if myvar gt 0>OK<ppp:else>not OK<ppp:/if>",
|
||||
"",
|
||||
),
|
||||
PromptPair("not OK", ""),
|
||||
ppp=PromptPostProcessor(
|
||||
self.ppp_logger,
|
||||
self.def_env_info,
|
||||
replace(
|
||||
self.defopts,
|
||||
on_warning=ONWARNING_CHOICES.warn,
|
||||
),
|
||||
self.grammar_content,
|
||||
self.interrupt,
|
||||
self.wildcards_obj,
|
||||
self.extranetwork_maps_obj,
|
||||
),
|
||||
)
|
||||
|
||||
def test_cmd_if_nonnumeric_var_int_compare_stop(self): # non-numeric var integer compare with on_warning=stop
|
||||
self.process(
|
||||
PromptPair(
|
||||
"<ppp:set myvar>abc<ppp:/set><ppp:if myvar gt 0>OK<ppp:else>not OK<ppp:/if>",
|
||||
"",
|
||||
),
|
||||
PromptPair("", ""),
|
||||
interrupted=True,
|
||||
)
|
||||
|
||||
def test_cmd_if_empty_var_int_compare(self): # empty string var integer compare with on_warning=warn
|
||||
self.process(
|
||||
PromptPair(
|
||||
"<ppp:set myvar><ppp:/set><ppp:if myvar gt 0>OK<ppp:else>not OK<ppp:/if>",
|
||||
"",
|
||||
),
|
||||
PromptPair("not OK", ""),
|
||||
ppp=PromptPostProcessor(
|
||||
self.ppp_logger,
|
||||
self.def_env_info,
|
||||
replace(
|
||||
self.defopts,
|
||||
on_warning=ONWARNING_CHOICES.warn,
|
||||
),
|
||||
self.grammar_content,
|
||||
self.interrupt,
|
||||
self.wildcards_obj,
|
||||
self.extranetwork_maps_obj,
|
||||
),
|
||||
)
|
||||
|
||||
# Command tests
|
||||
|
||||
def test_cmd_stn_complex_features(self): # complex stn command with AND, BREAK and other features
|
||||
@@ -1,237 +0,0 @@
|
||||
from dataclasses import replace
|
||||
|
||||
from ppp import PromptPostProcessor
|
||||
from ppp_classes import ONWARNING_CHOICES # pylint: disable=import-error
|
||||
from .base_tests import PromptPair, TestPromptPostProcessorBase
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit("This script must not be run directly")
|
||||
|
||||
|
||||
class TestVariables(TestPromptPostProcessorBase):
|
||||
|
||||
def setUp(self): # pylint: disable=arguments-differ
|
||||
super().setUp(enable_file_logging=False)
|
||||
|
||||
# Empty variable test
|
||||
|
||||
def test_empty_variable(self):
|
||||
self.process(
|
||||
PromptPair(
|
||||
"${v1=}<ppp:set v2><ppp:/set>${v3:}",
|
||||
"",
|
||||
),
|
||||
PromptPair("", ""),
|
||||
variables={"v1": "", "v2": "", "v3": ""},
|
||||
)
|
||||
|
||||
# Echoed variables tests
|
||||
|
||||
def test_echoed_variable(self):
|
||||
self.process(
|
||||
PromptPair(
|
||||
"${v1=test1}<ppp:set v2>test2<ppp:/set>${v3:test3}${v3:test4}",
|
||||
"",
|
||||
),
|
||||
# v3 is echoed withs two defaults, the output prompt has both but the variable value is the last default
|
||||
PromptPair("test3test4", ""),
|
||||
variables={"v1": "test1", "v2": "test2", "v3": "test4"},
|
||||
)
|
||||
|
||||
def test_unknown_echoed_variable(self):
|
||||
self.process(
|
||||
PromptPair(
|
||||
"${v1}",
|
||||
"",
|
||||
),
|
||||
# v3 is echoed withs two defaults, the output prompt has both but the variable value is the last default
|
||||
PromptPair("", ""),
|
||||
variables={"v1": ""},
|
||||
ppp=PromptPostProcessor(
|
||||
self.ppp_logger,
|
||||
self.def_env_info,
|
||||
replace(
|
||||
self.defopts,
|
||||
on_warning=ONWARNING_CHOICES.warn,
|
||||
),
|
||||
self.grammar_content,
|
||||
self.interrupt,
|
||||
self.wildcards_obj,
|
||||
self.extranetwork_maps_obj,
|
||||
),
|
||||
)
|
||||
|
||||
# Variable in extranetworks
|
||||
|
||||
def test_variable_in_extranetwork(self):
|
||||
self.process(
|
||||
PromptPair(
|
||||
"${f=filename}${w=0.5}<lora:${f}:${w}>",
|
||||
"",
|
||||
),
|
||||
PromptPair("<lora:filename:0.5>", ""),
|
||||
)
|
||||
|
||||
# Variable nesting tests
|
||||
|
||||
def test_var_nested_1(self): # variable default nested in variable set
|
||||
self.process(
|
||||
PromptPair(
|
||||
"${v1=test ${v2:OK}}${v1}",
|
||||
"",
|
||||
),
|
||||
PromptPair("test OK", ""),
|
||||
variables={"v1": "test OK", "v2": "OK"},
|
||||
)
|
||||
|
||||
def test_var_nested_2(self): # variable set nested in variable default
|
||||
self.process(
|
||||
PromptPair(
|
||||
"${v1:test ${v2=OK}${v2}}",
|
||||
"",
|
||||
),
|
||||
PromptPair("test OK", ""),
|
||||
variables={"v1": "test OK", "v2": "OK"},
|
||||
)
|
||||
|
||||
def test_var_nested_3(self): # variable default nested in variable default
|
||||
self.process(
|
||||
PromptPair(
|
||||
"${v1:test ${v2:OK}}",
|
||||
"",
|
||||
),
|
||||
PromptPair("test OK", ""),
|
||||
variables={"v1": "test OK", "v2": "OK"},
|
||||
)
|
||||
|
||||
# Variable-vs-variable comparison tests
|
||||
|
||||
def test_cmd_if_var_vs_var_eq(self): # var eq var: both set to same value, if-branch taken
|
||||
self.process(
|
||||
PromptPair(
|
||||
"<ppp:set v1>hello<ppp:/set><ppp:set v2>hello<ppp:/set><ppp:if v1 eq v2>YES<ppp:else>NO<ppp:/if>",
|
||||
"",
|
||||
),
|
||||
PromptPair("YES", ""),
|
||||
)
|
||||
|
||||
def test_cmd_if_var_vs_var_ne(self): # var ne var: different values, ne condition true
|
||||
self.process(
|
||||
PromptPair(
|
||||
"<ppp:set v1>apple<ppp:/set><ppp:set v2>orange<ppp:/set><ppp:if v1 ne v2>YES<ppp:else>NO<ppp:/if>",
|
||||
"",
|
||||
),
|
||||
PromptPair("YES", ""),
|
||||
)
|
||||
|
||||
def test_cmd_if_var_vs_var_contains(self): # var contains var: var1 contains var2's value
|
||||
self.process(
|
||||
PromptPair(
|
||||
"<ppp:set v1>hello world<ppp:/set><ppp:set v2>hello<ppp:/set><ppp:if v1 contains v2>YES<ppp:else>NO<ppp:/if>",
|
||||
"",
|
||||
),
|
||||
PromptPair("YES", ""),
|
||||
)
|
||||
|
||||
def test_cmd_if_var_vs_var_not_contains(self): # var not contains var: var1 does not contain var2's value
|
||||
self.process(
|
||||
PromptPair(
|
||||
"<ppp:set v1>hello world<ppp:/set><ppp:set v2>goodbye<ppp:/set><ppp:if v1 not contains v2>YES<ppp:else>NO<ppp:/if>",
|
||||
"",
|
||||
),
|
||||
PromptPair("YES", ""),
|
||||
)
|
||||
|
||||
def test_cmd_if_var_vs_var_lt(self): # var lt var: var1 less than var2
|
||||
self.process(
|
||||
PromptPair(
|
||||
"<ppp:set lesser>1<ppp:/set><ppp:set greater>2<ppp:/set><ppp:if lesser lt greater>YES<ppp:else>NO<ppp:/if>",
|
||||
"",
|
||||
),
|
||||
PromptPair("YES", ""),
|
||||
)
|
||||
|
||||
# NaN/undefined variable integer comparison tests
|
||||
|
||||
def test_cmd_if_undefined_var_int_compare_warn(self): # undefined var integer compare with on_warning=warn
|
||||
self.process(
|
||||
PromptPair(
|
||||
"<ppp:if undefined_var gt 0>YES<ppp:else>NO<ppp:/if>",
|
||||
"",
|
||||
),
|
||||
PromptPair("NO", ""),
|
||||
ppp=PromptPostProcessor(
|
||||
self.ppp_logger,
|
||||
self.def_env_info,
|
||||
replace(
|
||||
self.defopts,
|
||||
on_warning=ONWARNING_CHOICES.warn,
|
||||
),
|
||||
self.grammar_content,
|
||||
self.interrupt,
|
||||
self.wildcards_obj,
|
||||
self.extranetwork_maps_obj,
|
||||
),
|
||||
)
|
||||
|
||||
def test_cmd_if_undefined_var_int_compare_stop(self): # undefined var integer compare with on_warning=stop
|
||||
self.process(
|
||||
PromptPair(
|
||||
"<ppp:if undefined_var gt 0>YES<ppp:else>NO<ppp:/if>",
|
||||
"",
|
||||
),
|
||||
PromptPair("", ""),
|
||||
interrupted=True,
|
||||
)
|
||||
|
||||
def test_cmd_if_nonnumeric_var_int_compare_warn(self): # non-numeric var integer compare with on_warning=warn
|
||||
self.process(
|
||||
PromptPair(
|
||||
"<ppp:set myvar>abc<ppp:/set><ppp:if myvar gt 0>YES<ppp:else>NO<ppp:/if>",
|
||||
"",
|
||||
),
|
||||
PromptPair("NO", ""),
|
||||
ppp=PromptPostProcessor(
|
||||
self.ppp_logger,
|
||||
self.def_env_info,
|
||||
replace(
|
||||
self.defopts,
|
||||
on_warning=ONWARNING_CHOICES.warn,
|
||||
),
|
||||
self.grammar_content,
|
||||
self.interrupt,
|
||||
self.wildcards_obj,
|
||||
self.extranetwork_maps_obj,
|
||||
),
|
||||
)
|
||||
|
||||
def test_cmd_if_nonnumeric_var_int_compare_stop(self): # non-numeric var integer compare with on_warning=stop
|
||||
self.process(
|
||||
PromptPair(
|
||||
"<ppp:set myvar>abc<ppp:/set><ppp:if myvar gt 0>YES<ppp:else>NO<ppp:/if>",
|
||||
"",
|
||||
),
|
||||
PromptPair("", ""),
|
||||
interrupted=True,
|
||||
)
|
||||
|
||||
def test_cmd_if_empty_var_int_compare(self): # empty string var integer compare with on_warning=warn
|
||||
self.process(
|
||||
PromptPair(
|
||||
"<ppp:set myvar><ppp:/set><ppp:if myvar gt 0>YES<ppp:else>NO<ppp:/if>",
|
||||
"",
|
||||
),
|
||||
PromptPair("NO", ""),
|
||||
ppp=PromptPostProcessor(
|
||||
self.ppp_logger,
|
||||
self.def_env_info,
|
||||
replace(
|
||||
self.defopts,
|
||||
on_warning=ONWARNING_CHOICES.warn,
|
||||
),
|
||||
self.grammar_content,
|
||||
self.interrupt,
|
||||
self.wildcards_obj,
|
||||
self.extranetwork_maps_obj,
|
||||
),
|
||||
)
|
||||
Reference in New Issue
Block a user