Fix pattern equivalence doc style for consistency

pull/1/head
Chris Lenk 2020-11-20 15:59:55 -05:00
parent f9e9c50db9
commit b55c3bb1df
7 changed files with 181 additions and 97 deletions

View File

@ -30,7 +30,8 @@ def _get_pattern_canonicalizer():
""" """
Get a canonicalization transformer for STIX patterns. Get a canonicalization transformer for STIX patterns.
:return: The transformer Returns:
The transformer
""" """
# The transformers are either stateless or contain no state which changes # The transformers are either stateless or contain no state which changes
@ -64,11 +65,14 @@ def equivalent_patterns(pattern1, pattern2, stix_version=stix2.DEFAULT_VERSION):
""" """
Determine whether two STIX patterns are semantically equivalent. Determine whether two STIX patterns are semantically equivalent.
:param pattern1: The first STIX pattern Args:
:param pattern2: The second STIX pattern pattern1: The first STIX pattern
:param stix_version: The STIX version to use for pattern parsing, as a pattern2: The second STIX pattern
string ("2.0", "2.1", etc). Defaults to library-wide default version. stix_version: The STIX version to use for pattern parsing, as a string
:return: True if the patterns are semantically equivalent; False if not ("2.0", "2.1", etc). Defaults to library-wide default version.
Returns:
True if the patterns are semantically equivalent; False if not
""" """
patt_ast1 = stix2.pattern_visitor.create_pattern_object( patt_ast1 = stix2.pattern_visitor.create_pattern_object(
pattern1, version=stix_version, pattern1, version=stix_version,
@ -96,12 +100,14 @@ def find_equivalent_patterns(
on an input iterable and is implemented as a generator of matches. So you on an input iterable and is implemented as a generator of matches. So you
can "stream" patterns in and matching patterns will be streamed out. can "stream" patterns in and matching patterns will be streamed out.
:param search_pattern: A search pattern as a string Args:
:param patterns: An iterable over patterns as strings search_pattern: A search pattern as a string
:param stix_version: The STIX version to use for pattern parsing, as a patterns: An iterable over patterns as strings
string ("2.0", "2.1", etc). Defaults to library-wide default version. stix_version: The STIX version to use for pattern parsing, as a string
:return: A generator iterator producing the semantically equivalent ("2.0", "2.1", etc). Defaults to library-wide default version.
patterns
Returns:
A generator iterator producing the semantically equivalent patterns
""" """
search_pattern_ast = stix2.pattern_visitor.create_pattern_object( search_pattern_ast = stix2.pattern_visitor.create_pattern_object(
search_pattern, version=stix_version, search_pattern, version=stix_version,

View File

@ -16,9 +16,12 @@ def generic_cmp(value1, value2):
Generic comparator of values which uses the builtin '<' and '>' operators. Generic comparator of values which uses the builtin '<' and '>' operators.
Assumes the values can be compared that way. Assumes the values can be compared that way.
:param value1: The first value Args:
:param value2: The second value value1: The first value
:return: -1, 0, or 1 depending on whether value1 is less, equal, or greater value2: The second value
Returns:
-1, 0, or 1 depending on whether value1 is less, equal, or greater
than value2 than value2
""" """
@ -30,12 +33,15 @@ def iter_lex_cmp(seq1, seq2, cmp):
Generic lexicographical compare function, which works on two iterables and Generic lexicographical compare function, which works on two iterables and
a comparator function. a comparator function.
:param seq1: The first iterable Args:
:param seq2: The second iterable seq1: The first iterable
:param cmp: a two-arg callable comparator for values iterated over. It seq2: The second iterable
cmp: a two-arg callable comparator for values iterated over. It
must behave analogously to this function, returning <0, 0, or >0 to must behave analogously to this function, returning <0, 0, or >0 to
express the ordering of the two values. express the ordering of the two values.
:return: <0 if seq1 < seq2; >0 if seq1 > seq2; 0 if they're equal
Returns:
<0 if seq1 < seq2; >0 if seq1 > seq2; 0 if they're equal
""" """
it1 = iter(seq1) it1 = iter(seq1)
@ -84,11 +90,14 @@ def iter_in(value, seq, cmp):
a comparator function. This function checks whether the given value is a comparator function. This function checks whether the given value is
contained in the given iterable. contained in the given iterable.
:param value: A value Args:
:param seq: An iterable value: A value
:param cmp: A 2-arg comparator function which must return 0 if the args seq: An iterable
cmp: A 2-arg comparator function which must return 0 if the args
are equal are equal
:return: True if the value is found in the iterable, False if it is not
Returns:
True if the value is found in the iterable, False if it is not
""" """
result = False result = False
for seq_val in seq: for seq_val in seq:

View File

@ -32,9 +32,12 @@ def generic_constant_cmp(const1, const2):
Generic comparator for most _Constant instances. They must have a "value" Generic comparator for most _Constant instances. They must have a "value"
attribute whose value supports the builtin comparison operators. attribute whose value supports the builtin comparison operators.
:param const1: The first _Constant instance Args:
:param const2: The second _Constant instance const1: The first _Constant instance
:return: <0, 0, or >0 depending on whether the first arg is less, equal or const2: The second _Constant instance
Returns:
<0, 0, or >0 depending on whether the first arg is less, equal or
greater than the second greater than the second
""" """
return generic_cmp(const1.value, const2.value) return generic_cmp(const1.value, const2.value)
@ -44,9 +47,12 @@ def bool_cmp(value1, value2):
""" """
Compare two boolean constants. Compare two boolean constants.
:param value1: The first BooleanConstant instance Args:
:param value2: The second BooleanConstant instance value1: The first BooleanConstant instance
:return: <0, 0, or >0 depending on whether the first arg is less, equal or value2: The second BooleanConstant instance
Returns:
<0, 0, or >0 depending on whether the first arg is less, equal or
greater than the second greater than the second
""" """
@ -72,9 +78,12 @@ def hex_cmp(value1, value2):
Compare two STIX "hex" values. This decodes to bytes and compares that. Compare two STIX "hex" values. This decodes to bytes and compares that.
It does *not* do a string compare on the hex representations. It does *not* do a string compare on the hex representations.
:param value1: The first HexConstant Args:
:param value2: The second HexConstant value1: The first HexConstant
:return: <0, 0, or >0 depending on whether the first arg is less, equal or value2: The second HexConstant
Returns:
<0, 0, or >0 depending on whether the first arg is less, equal or
greater than the second greater than the second
""" """
bytes1 = bytes.fromhex(value1.value) bytes1 = bytes.fromhex(value1.value)
@ -88,9 +97,12 @@ def bin_cmp(value1, value2):
Compare two STIX "binary" values. This decodes to bytes and compares that. Compare two STIX "binary" values. This decodes to bytes and compares that.
It does *not* do a string compare on the base64 representations. It does *not* do a string compare on the base64 representations.
:param value1: The first BinaryConstant Args:
:param value2: The second BinaryConstant value1: The first BinaryConstant
:return: <0, 0, or >0 depending on whether the first arg is less, equal or value2: The second BinaryConstant
Returns:
<0, 0, or >0 depending on whether the first arg is less, equal or
greater than the second greater than the second
""" """
bytes1 = base64.standard_b64decode(value1.value) bytes1 = base64.standard_b64decode(value1.value)
@ -103,9 +115,12 @@ def list_cmp(value1, value2):
""" """
Compare lists order-insensitively. Compare lists order-insensitively.
:param value1: The first ListConstant Args:
:param value2: The second ListConstant value1: The first ListConstant
:return: <0, 0, or >0 depending on whether the first arg is less, equal or value2: The second ListConstant
Returns:
<0, 0, or >0 depending on whether the first arg is less, equal or
greater than the second greater than the second
""" """
@ -144,9 +159,12 @@ def object_path_component_cmp(comp1, comp2):
Ints and strings compare as usual to each other; ints compare less than Ints and strings compare as usual to each other; ints compare less than
strings. strings.
:param comp1: An object path component (string or int) Args:
:param comp2: An object path component (string or int) comp1: An object path component (string or int)
:return: <0, 0, or >0 depending on whether the first arg is less, equal or comp2: An object path component (string or int)
Returns:
<0, 0, or >0 depending on whether the first arg is less, equal or
greater than the second greater than the second
""" """
@ -172,8 +190,11 @@ def object_path_to_raw_values(path):
properties; "*" index steps become that string; and numeric index steps properties; "*" index steps become that string; and numeric index steps
become integers. become integers.
:param path: An ObjectPath instance Args:
:return: A generator iterator over the values path: An ObjectPath instance
Returns:
A generator iterator over the values
""" """
for comp in path.property_path: for comp in path.property_path:
@ -195,9 +216,12 @@ def object_path_cmp(path1, path2):
""" """
Compare two object paths. Compare two object paths.
:param path1: The first ObjectPath instance Args:
:param path2: The second ObjectPath instance path1: The first ObjectPath instance
:return: <0, 0, or >0 depending on whether the first arg is less, equal or path2: The second ObjectPath instance
Returns:
<0, 0, or >0 depending on whether the first arg is less, equal or
greater than the second greater than the second
""" """
if path1.object_type_name < path2.object_type_name: if path1.object_type_name < path2.object_type_name:
@ -224,9 +248,12 @@ def comparison_operator_cmp(op1, op2):
""" """
Compare two comparison operators. Compare two comparison operators.
:param op1: The first comparison operator (a string) Args:
:param op2: The second comparison operator (a string) op1: The first comparison operator (a string)
:return: <0, 0, or >0 depending on whether the first arg is less, equal or op2: The second comparison operator (a string)
Returns:
<0, 0, or >0 depending on whether the first arg is less, equal or
greater than the second greater than the second
""" """
op1_idx = _COMPARISON_OP_ORDER.index(op1) op1_idx = _COMPARISON_OP_ORDER.index(op1)
@ -241,9 +268,12 @@ def constant_cmp(value1, value2):
""" """
Compare two constants. Compare two constants.
:param value1: The first _Constant instance Args:
:param value2: The second _Constant instance value1: The first _Constant instance
:return: <0, 0, or >0 depending on whether the first arg is less, equal or value2: The second _Constant instance
Returns:
<0, 0, or >0 depending on whether the first arg is less, equal or
greater than the second greater than the second
""" """
@ -284,9 +314,12 @@ def simple_comparison_expression_cmp(expr1, expr2):
Compare "simple" comparison expressions: those which aren't AND/OR Compare "simple" comparison expressions: those which aren't AND/OR
combinations, just <path> <op> <value> comparisons. combinations, just <path> <op> <value> comparisons.
:param expr1: first _ComparisonExpression instance Args:
:param expr2: second _ComparisonExpression instance expr1: first _ComparisonExpression instance
:return: <0, 0, or >0 depending on whether the first arg is less, equal or expr2: second _ComparisonExpression instance
Returns:
<0, 0, or >0 depending on whether the first arg is less, equal or
greater than the second greater than the second
""" """
@ -315,9 +348,12 @@ def comparison_expression_cmp(expr1, expr2):
expressions' sub-components. To achieve an order-insensitive comparison, expressions' sub-components. To achieve an order-insensitive comparison,
the ASTs must be canonically ordered first. the ASTs must be canonically ordered first.
:param expr1: The first comparison expression Args:
:param expr2: The second comparison expression expr1: The first comparison expression
:return: <0, 0, or >0 depending on whether the first arg is less, equal or expr2: The second comparison expression
Returns:
<0, 0, or >0 depending on whether the first arg is less, equal or
greater than the second greater than the second
""" """
if isinstance(expr1, _ComparisonExpression) \ if isinstance(expr1, _ComparisonExpression) \

View File

@ -64,9 +64,12 @@ def observation_expression_cmp(expr1, expr2):
the expressions' sub-components. To achieve an order-insensitive the expressions' sub-components. To achieve an order-insensitive
comparison, the ASTs must be canonically ordered first. comparison, the ASTs must be canonically ordered first.
:param expr1: The first observation expression Args:
:param expr2: The second observation expression expr1: The first observation expression
:return: <0, 0, or >0 depending on whether the first arg is less, equal or expr2: The second observation expression
Returns:
<0, 0, or >0 depending on whether the first arg is less, equal or
greater than the second greater than the second
""" """
type1 = type(expr1) type1 = type(expr1)

View File

@ -22,13 +22,17 @@ def _dupe_ast(ast):
""" """
Create a duplicate of the given AST. Create a duplicate of the given AST.
Note: the comparison expression "leaves", i.e. simple <path> <op> <value> Note:
comparisons are currently not duplicated. I don't think it's necessary as The comparison expression "leaves", i.e. simple <path> <op> <value>
of this writing; they are never changed. But revisit this if/when comparisons are currently not duplicated. I don't think it's necessary
as of this writing; they are never changed. But revisit this if/when
necessary. necessary.
:param ast: The AST to duplicate Args:
:return: The duplicate AST ast: The AST to duplicate
Returns:
The duplicate AST
""" """
if isinstance(ast, AndBooleanExpression): if isinstance(ast, AndBooleanExpression):
result = AndBooleanExpression([ result = AndBooleanExpression([
@ -108,8 +112,11 @@ class ComparisonExpressionTransformer(Transformer):
Invoke a transformer callback method based on the given ast root node Invoke a transformer callback method based on the given ast root node
type. type.
:param ast: The AST Args:
:return: The callback's result ast: The AST
Returns:
The callback's result
""" """
if isinstance(ast, AndBooleanExpression): if isinstance(ast, AndBooleanExpression):
@ -153,8 +160,11 @@ class OrderDedupeTransformer(
""" """
Sort/dedupe children. AND and OR can be treated identically. Sort/dedupe children. AND and OR can be treated identically.
:param ast: The comparison expression AST Args:
:return: The same AST node, but with sorted children ast: The comparison expression AST
Returns:
The same AST node, but with sorted children
""" """
sorted_children = sorted( sorted_children = sorted(
ast.operands, key=functools.cmp_to_key(comparison_expression_cmp), ast.operands, key=functools.cmp_to_key(comparison_expression_cmp),
@ -201,8 +211,11 @@ class FlattenTransformer(ComparisonExpressionTransformer):
little difference is that we can absorb AND children if we're an AND little difference is that we can absorb AND children if we're an AND
ourselves; and OR for OR. ourselves; and OR for OR.
:param ast: The comparison expression AST Args:
:return: The same AST node, but with flattened children ast: The comparison expression AST
Returns:
The same AST node, but with flattened children
""" """
changed = False changed = False

View File

@ -38,8 +38,11 @@ def _dupe_ast(ast):
observation expressions are currently not duplicated. I don't think it's observation expressions are currently not duplicated. I don't think it's
necessary as of this writing. But revisit this if/when necessary. necessary as of this writing. But revisit this if/when necessary.
:param ast: The AST to duplicate Args:
:return: The duplicate AST ast: The AST to duplicate
Returns:
The duplicate AST
""" """
if isinstance(ast, AndObservationExpression): if isinstance(ast, AndObservationExpression):
result = AndObservationExpression([ result = AndObservationExpression([
@ -160,8 +163,11 @@ class ObservationExpressionTransformer(Transformer):
Invoke a transformer callback method based on the given ast root node Invoke a transformer callback method based on the given ast root node
type. type.
:param ast: The AST Args:
:return: The callback's result ast: The AST
Returns:
The callback's result
""" """
dispatch_name = self._DISPATCH_NAME_MAP.get(type(ast)) dispatch_name = self._DISPATCH_NAME_MAP.get(type(ast))
@ -292,10 +298,12 @@ class AbsorptionTransformer(
the right does not "contain" the left. You would need two A's on the the right does not "contain" the left. You would need two A's on the
right. right.
:param exprs_containee: The expressions we want to check for containment Args:
:param exprs_container: The expressions acting as the "container" exprs_containee: The expressions we want to check for containment
:return: True if the containee is contained in the container; False if exprs_container: The expressions acting as the "container"
not
Returns:
True if the containee is contained in the container; False if not
""" """
# make our own list we are free to manipulate without affecting the # make our own list we are free to manipulate without affecting the
@ -336,10 +344,12 @@ class AbsorptionTransformer(
in the container (rhs), B follows A, so it "contains" the lhs even in the container (rhs), B follows A, so it "contains" the lhs even
though there is other stuff mixed in. though there is other stuff mixed in.
:param exprs_containee: The expressions we want to check for containment Args:
:param exprs_container: The expressions acting as the "container" exprs_containee: The expressions we want to check for containment
:return: True if the containee is contained in the container; False if exprs_container: The expressions acting as the "container"
not
Returns:
True if the containee is contained in the container; False if not
""" """
ee_iter = iter(exprs_containee) ee_iter = iter(exprs_containee)

View File

@ -25,9 +25,12 @@ def _path_is(object_path, path_pattern):
index path step; _ANY_KEY matches any key path step, and _ANY matches any index path step; _ANY_KEY matches any key path step, and _ANY matches any
path step. path step.
:param object_path: An ObjectPath instance Args:
:param path_pattern: An iterable giving the pattern path steps object_path: An ObjectPath instance
:return: True if the path matches the pattern; False if not path_pattern: An iterable giving the pattern path steps
Returns:
True if the path matches the pattern; False if not
""" """
path_values = object_path_to_raw_values(object_path) path_values = object_path_to_raw_values(object_path)
@ -70,8 +73,9 @@ def _mask_bytes(ip_bytes, prefix_size):
Retain the high-order 'prefix_size' bits from ip_bytes, and zero out the Retain the high-order 'prefix_size' bits from ip_bytes, and zero out the
remaining low-order bits. This side-effects ip_bytes. remaining low-order bits. This side-effects ip_bytes.
:param ip_bytes: A mutable byte sequence (e.g. a bytearray) Args:
:param prefix_size: An integer prefix size ip_bytes: A mutable byte sequence (e.g. a bytearray)
prefix_size: An integer prefix size
""" """
addr_size_bytes = len(ip_bytes) addr_size_bytes = len(ip_bytes)
addr_size_bits = 8 * addr_size_bytes addr_size_bits = 8 * addr_size_bytes
@ -99,7 +103,8 @@ def windows_reg_key(comp_expr):
being compared. This enables case-insensitive comparisons between two being compared. This enables case-insensitive comparisons between two
patterns, for those values. This side-effects the given AST. patterns, for those values. This side-effects the given AST.
:param comp_expr: A _ComparisonExpression object whose type is Args:
comp_expr: A _ComparisonExpression object whose type is
windows-registry-key windows-registry-key
""" """
if _path_is(comp_expr.lhs, ("key",)) \ if _path_is(comp_expr.lhs, ("key",)) \
@ -119,7 +124,8 @@ def ipv4_addr(comp_expr):
This side-effects the given AST. This side-effects the given AST.
:param comp_expr: A _ComparisonExpression object whose type is ipv4-addr. Args:
comp_expr: A _ComparisonExpression object whose type is ipv4-addr.
""" """
if _path_is(comp_expr.lhs, ("value",)): if _path_is(comp_expr.lhs, ("value",)):
value = comp_expr.rhs.value value = comp_expr.rhs.value
@ -179,7 +185,8 @@ def ipv6_addr(comp_expr):
This side-effects the given AST. This side-effects the given AST.
:param comp_expr: A _ComparisonExpression object whose type is ipv6-addr. Args:
comp_expr: A _ComparisonExpression object whose type is ipv6-addr.
""" """
if _path_is(comp_expr.lhs, ("value",)): if _path_is(comp_expr.lhs, ("value",)):
value = comp_expr.rhs.value value = comp_expr.rhs.value