Package: illogical
(py)illogicalA micro conditional engine used to parse the logical and comparison expressions, evaluate an expression in data context, and provide access to a text form of the given expression.Revision: Mar 10, 2023.Other implementations:TS/JSGOAboutThis project has been developed to provide Python implementation ofspaceavocado/illogical.Getting StartedYou can install the(py)illogicalfromPyPI:python-mpipinstallillogicalThe reader is supported on Python 3.7 and above.Table of Content(py)illogicalAboutGetting StartedBasic UsageEvaluateStatementParseEvaluableSimplifySerializeWorking with ExpressionsEvaluation Data ContextAccessing Array Element:Accessing Array Element via Reference:Nested ReferencingComposite Reference KeyData Type CastingOperand TypesValueReferenceCollectionComparison ExpressionsEqualNot EqualGreater ThanGreater Than or EqualLess ThanLess Than or EqualInNot InPrefixSuffixOverlapNonePresentLogical ExpressionsAndOrNorXorNotEngine OptionsReference Serialize OptionsFromToCollection Serialize OptionsEscape CharacterSimplify OptionsIgnored PathsIgnored Paths RegExOperator MappingContributingLicenseBasic Usagefromillogical.illogicalimportIllogical# Create a new instance of the engineillogical=Illogical()# Evaluate an expressionillogical.evaluate(["==",1,1],{})For advanced usage, pleaseEngine Options.EvaluateEvaluate comparison or logical expression:illogical.evaluate(Comparison ExpressionorLogical Expression,Evaluation Data Context)=>boolExamplecontext={"name":"peter",}# Comparison expressionillogical.evaluate(["==",5,5],context)illogical.evaluate(["==","circle","circle"],context)illogical.evaluate(["==",True,True],context)illogical.evaluate(["==","$name","peter"],context)illogical.evaluate(["NIL","$RefA"],context)# Logical expressionillogical.evaluate(["AND",["==",5,5],["==",10,10]],context)illogical.evaluate(["AND",["==","circle","circle"],["==",10,10]],context)illogical.evaluate(["OR",["==","$name","peter"],["==",5,10]],context)StatementGet expression string representation:illogical.statement(Comparison ExpressionorLogical Expression)=>strExample# Comparison expressionillogical.statement(["==",5,5])# (5 == 5)illogical.statement(["==","circle","circle"])# ("circle" == "circle")illogical.statement(["==",True,True])# (True == True)illogical.statement(["==","$name","peter"])# ({name} == "peter")illogical.statement(["NIL","$RefA"])# ({RefA} <is nil>)# Logical expressionillogical.statement(["AND",["==",5,5],["==",10,10]])# ((5 == 5) AND (10 == 10))illogical.statement(["AND",["==","circle","circle"],["==",10,10]])# (("circle" == "circle") AND (10 == 10))illogical.statement(["OR",["==","$name","peter"],["==",5,10]])# (({name} == "peter") OR (5 == 10))ParseParse the expression into aEvaluableobject, i.e. it returns the parsed self-evaluable condition expression.illogical.parse(Comparison ExpressionorLogical Expression)=>EvaluableEvaluableevaluable.evaluate(context)please seeEvaluation Data Context.evaluable.simplify(context)please seeSimplify.evaluable.serialize()please seeSerialize.str(evaluable) | evaluable.__str__()please seeStatement.Exampleevaluable=illogical.parse(["==","$name","peter"])evaluable.evaluate({"name":"peter"})# Trueprint(evaluable)# ({name} == "peter")SimplifySimplifies an expression with a given context. This is useful when you already have some of
the properties of context and wants to try to evaluate the expression.Exampleevaluable=illogical.parse(["AND",["==","$a",10],["==","$b",20]])evaluable.simplify({"a":10})# ({b} == 20)evaluable.simplify({"a":20})# FalseValues not found in the context will cause the parent operand not to be evaluated and returned
as part of the simplified expression.In some situations we might want to evaluate the expression even if referred value is not
present. You can provide a list of keys that will be strictly evaluated even if they are not
present in the context.Examplefromillogical.illogicalimportIllogicalfromillogical.parser.parseimportOptionsignored_paths=["ignored"],ignored_path_rx=[r"^ignored"],illogical=Illogical(Options(ignored_paths=ignored_paths,ignored_path_rx=ignored_path_rx))evaluable=illogical.parse(["AND",["==","$a",10],["==","$ignored",20]])evaluable.simplify({"a":10})# False# $ignored" will be evaluated to None.Alternatively we might want to do the opposite and strictly evaluate the expression for all referred
values not present in the context except for a specified list of optional keys.Examplefromillogical.illogicalimportIllogicalfromillogical.parser.parseimportOptionsignored_paths=["b"]illogical=Illogical(Options(ignored_paths=ignored_paths))evaluable=illogical.parse(["OR",["==","$a",10],["==","$b",20},["==","$c",20]])evaluable.simplify({"c":10})# ({a} == 10)# except for "$b" everything not in context will be evaluated to None.SerializeSerializes an expression into the raw expression form, reverse the parse operation.Exampleevaluable=illogical.parse(["AND",["==","$a",10],["==",10,20]])evaluable.serialize()# ["AND", ["==", "$a", 10], ["==", 10, 20]]Working with ExpressionsEvaluation Data ContextThe evaluation data context is used to provide the expression with variable references, i.e. this allows for the dynamic expressions. The data context is object with properties used as the references keys, and its values as reference values.Valid reference values: dist, str, int, float, list; set; tuple of (bool, string, int, float).To reference the nested reference, please use "." delimiter, e.g.:$address.cityAccessing Array Element:$options[1]Accessing Array Element via Reference:$options[{index}]Theindexreference is resolved within the data context as an array index.Nested Referencing$address.{segment}Thesegmentreference is resolved within the data context as a property key.Composite Reference Key$shape{shapeType}TheshapeTypereference is resolved within the data context, and inserted into the outer reference key.E.g.shapeTypeis resolved as "B" and would compose the$shapeBouter reference.This resolution could be n-nested.Data Type Casting$payment.amount.(Type)Cast the given data context into the desired data type before being used as an operand in the evaluation.Note: If the conversion is invalid, then a warning message is being logged.Supported data type conversions:.(String): cast a given reference to String..(Number): cast a given reference to Number..(Integer): cast a given reference to Integer..(Float): cast a given reference to Float..(Boolean): cast a given reference to Boolean.Example# Data contextcontext={"name":"peter","country":"canada","age":21,"options":[1,2,3],"address":{city:"Toronto",country:"Canada",},"index":2,"segment":"city","shapeA":"box","shapeB":"circle","shapeType":"B",}# Evaluate an expression in the given data contextillogical.evaluate([">","$age",20],context)# Trueillogical.evaluate(["==","$address.city","Toronto"],context)# True# Accessing Array Elementillogical.evaluate(["==","$options[1]",2],context)# True# Accessing Array Element via Referenceillogical.evaluate(["==","$options[{index}]",3],context)# True# Nested Referencingillogical.evaluate(["==","$address.{segment}","Toronto"],context)# True# Composite Reference Keyillogical.evaluate(["==","$shape{shapeType}","circle"],context)# True# Data Type Castingillogical.evaluate(["==","$age.(String)","21"],context)# TrueOperand TypesTheComparison Expressionexpect operands to be one of the below:ValueSimple value types: string, int, float, bool, None.Exampleval1=5var2="cirle"var3=Trueillogical.parse(["AND",["==",val1,var2],["==",var3,var3]])ReferenceThe reference operand value is resolved from theEvaluation Data Context, where the the operands name is used as key in the context.The reference operand must be prefixed with$symbol, e.g.:$name. This might be customized viaReference Predicate Parser Option.ExampleExpressionData Context["==", "$age", 21]{age: 21}["==", "circle", "$shape"]{shape: "circle"}["==", "$visible", True]{visible: True}CollectionThe operand could be an array mixed fromValueandReference.ExampleExpressionData Context["IN", [1, 2], 1]{}["IN", "circle", ["$shapeA", "$shapeB"]{shapeA: "circle", shapeB: "box"}["IN", ["$number", 5], 5]{number: 3}Comparison ExpressionsEqualExpression format:["==",Left Operand,Right Operand].Valid operand types: string, int, float, bool, None.["==",5,5]illogical.evaluate(["==",5,5],context)# TrueNot EqualExpression format:["!=",Left Operand,Right Operand].Valid operand types: string, int, float, bool, None.["!=","circle","square"]illogical.evaluate(["!=","circle","square"],context)# TrueGreater ThanExpression format:[">",Left Operand,Right Operand].Valid operand types: int, float.[">",10,5]illogical.evaluate([">",10,5],context)# TrueGreater Than or EqualExpression format:[">=",Left Operand,Right Operand].Valid operand types: int, float.[">=",5,5]illogical.evaluate([">=",5,5],context)# TrueLess ThanExpression format:["<",Left Operand,Right Operand].Valid operand types: int, float.["<",5,10]illogical.evaluate(["<",5,10],context)# TrueLess Than or EqualExpression format:["<=",Left Operand,Right Operand].Valid operand types: int, float.["<=",5,5]illogical.evaluate(["<=",5,5],context)# TrueInExpression format:["IN",Left Operand,Right Operand].Valid operand types: string, int, float, bool, None and list; set; tuple of (string, int, float, bool, None).["IN",5,[1,2,3,4,5]]["IN",["circle","square","triangle"],"square"]illogical.evaluate(["IN",5,[1,2,3,4,5]],context)# Trueillogical.evaluate(["IN",["circle","square","triangle"],"square"],context)# TrueNot InExpression format:["NOT IN",Left Operand,Right Operand].Valid operand types: string, int, float, bool, None and list; set; tuple of (string, int, float, bool, None).["IN",10,[1,2,3,4,5]]["IN",["circle","square","triangle"],"oval"]illogical.evaluate(["NOT IN",10,[1,2,3,4,5]],context)# Trueillogical.evaluate(["NOT IN",["circle","square","triangle"],"oval"],context)# TruePrefixExpression format:["PREFIX",Left Operand,Right Operand].Valid operand types: string.Left operand is the PREFIX term.Right operand is the tested word.["PREFIX","hemi","hemisphere"]illogical.evaluate(["PREFIX","hemi","hemisphere"],context)# Trueillogical.evaluate(["PREFIX","hemi","sphere"],context)# FalseSuffixExpression format:["SUFFIX",Left Operand,Right Operand].Valid operand types: string.Left operand is the tested word.Right operand is the SUFFIX term.["SUFFIX","establishment","ment"]illogical.evaluate(["SUFFIX","establishment","ment"],context)# Trueillogical.evaluate(["SUFFIX","establish","ment"],context)# FalseOverlapExpression format:["OVERLAP",Left Operand,Right Operand].Valid operand types: list; set; tuple of (string, int, float, bool, None).["OVERLAP",[1,2],[1,2,3,4,5]]["OVERLAP",["circle","square","triangle"],["square"]]illogical.evaluate(["OVERLAP",[1,2,6],[1,2,3,4,5]],context)# Trueillogical.evaluate(["OVERLAP",["circle","square","triangle"],["square","oval"]],context)# TrueNoneExpression format:["NONE",Reference Operand].["NONE","$RefA"]illogical.evaluate(["NONE","RefA"],{})# Trueillogical.evaluate(["NONE","RefA"],{"RefA":10})# FalsePresentEvaluates as FALSE when the operand is UNDEFINED or NULL.Expression format:["PRESENT",Reference Operand].["PRESENT","$RefA"]illogical.evaluate(["PRESENT","RefA"],{})# Falseillogical.evaluate(["PRESENT","RefA"],{"RefA":10})# Trueillogical.evaluate(["PRESENT","RefA"],{"RefA":False})# Trueillogical.evaluate(["PRESENT","RefA"],{"RefA":"val"})# TrueLogical ExpressionsAndThe logical AND operator returns the bool value TRUE if both operands are TRUE and returns FALSE otherwise.Expression format:["AND", Left Operand 1, Right Operand 2, ... , Right Operand N].Valid operand types:Comparison ExpressionorNested Logical Expression.["AND",["==",5,5],["==",10,10]]illogical.evaluate(["AND",["==",5,5],["==",10,10]],context)# TrueOrThe logical OR operator returns the bool value TRUE if either or both operands is TRUE and returns FALSE otherwise.Expression format:["OR", Left Operand 1, Right Operand 2, ... , Right Operand N].Valid operand types:Comparison ExpressionorNested Logical Expression.["OR",["==",5,5],["==",10,5]]illogical.evaluate(["OR",["==",5,5],["==",10,5]],context)# TrueNorThe logical NOR operator returns the bool value TRUE if both operands are FALSE and returns FALSE otherwise.Expression format:["NOR", Left Operand 1, Right Operand 2, ... , Right Operand N]Valid operand types:Comparison ExpressionorNested Logical Expression.["NOR",["==",5,1],["==",10,5]]illogical.evaluate(["NOR",["==",5,1],["==",10,5]],context)# TrueXorThe logical NOR operator returns the bool value TRUE if both operands are FALSE and returns FALSE otherwise.Expression format:["XOR", Left Operand 1, Right Operand 2, ... , Right Operand N]Valid operand types:Comparison ExpressionorNested Logical Expression.["XOR",["==",5,5],["==",10,5]]illogical.evaluate(["XOR",["==",5,5],["==",10,5]],context)# True["XOR",["==",5,5],["==",10,10]]illogical.evaluate(["XOR",["==",5,5],["==",10,10]],context)# FalseNotThe logical NOT operator returns the bool value TRUE if the operand is FALSE, TRUE otherwise.Expression format:["NOT", Operand]Valid operand types:Comparison ExpressionorNested Logical Expression.["NOT",["==",5,5]]illogical.evaluate(["NOT",["==",5,5]],context)# TrueEngine OptionsReference Serialize OptionsUsagefromillogical.illogicalimportIllogicalfromillogical.parser.parseimportOptionsillogical=Illogical(Options(reference_from=reference_from,reference_to=reference_to))FromA function used to determine if the operand is a reference type, otherwise evaluated as a static value.Callable[[str],str]Return value:True= reference typeFalse= value typeDefault reference predicate:The$symbol at the begging of the operand is used to predicate the reference type., E.g.$State,$Country.ToA function used to transform the operand into the reference annotation stripped form. I.e. remove any annotation used to detect the reference type. E.g. "$Reference" => "Reference".Callable[[str],str]Default reference transform:It removes the$symbol at the begging of the operand name.Collection Serialize OptionsUsagefromillogical.illogicalimportIllogicalfromillogical.parser.parseimportOptionsescape_character="\\"illogical=Illogical(Options(escape_character=escape_character))Escape CharacterCharter used to escape fist value within a collection, if the value contains operator value.Example["==", 1, 1]# interpreted as EQ expression["\==", 1, 1]# interpreted as a collectionDefault escape character:\Simplify OptionsOptions applied while an expression is being simplified.Usagefromillogical.illogicalimportIllogicalfromillogical.parser.parseimportOptionsignored_paths=["ignored"]ignored_path_rx=[r"^prefix"]illogical=Illogical(Options(ignored_paths=ignored_paths,ignored_path_rx=ignored_path_rx))Ignored PathsReference paths which should be ignored while simplification is applied. Must be an exact match.Ignored Paths RegExReference paths which should be ignored while simplification is applied. Matching regular expression patterns.Operator MappingMapping of the operators. The key is unique operator key, and the value is the key used to represent the given operator in the raw expression.Usagefromillogical.illogicalimportIllogicalfromillogical.parser.parseimportOptions,DEFAULT_OPERATOR_MAPPING,EQoperator_mapping=DEFAULT_OPERATOR_MAPPING.copy()operator_mapping[EQ]="IS"illogical=Illogical(Options(operator_mapping=operator_mapping))Default operator mapping:DEFAULT_OPERATOR_MAPPING={# LogicalAND:"AND",OR:"OR",NOR:"NOR",XOR:"XOR",NOT:"NOT",# ComparisonEQ:"==",NE:"!=",GT:">",GE:">=",LT:"<",LE:"<=",NONE:"NONE",PRESENT:"PRESENT",IN:"IN",NIN:"NOT IN",OVERLAP:"OVERLAP",PREFIX:"PREFIX",SUFFIX:"SUFFIX",}ContributingSeecontributing.md.LicenseIllogical is released under the MIT license. Seelicense.md.