From a976e54c196fe5ae5d8c3a9326c9c94ca89f2792 Mon Sep 17 00:00:00 2001 From: Jacob Beck Date: Thu, 16 Jul 2020 16:39:26 -0600 Subject: [PATCH] Parse selectors This doesn't use hologram, as it needs more permissive schemas than what hologram provides. Added some unit tests --- core/dbt/contracts/common.py | 11 - core/dbt/contracts/graph/unparsed.py | 34 +-- core/dbt/contracts/selection.py | 21 ++ core/dbt/contracts/util.py | 32 +++ core/dbt/graph/cli.py | 155 +++++++++++- core/dbt/graph/selector.py | 10 +- core/dbt/graph/selector_methods.py | 27 +- core/dbt/graph/selector_spec.py | 59 ++--- test/unit/test_graph_selection.py | 14 +- test/unit/test_graph_selector_parsing.py | 301 +++++++++++++++++++++++ test/unit/test_graph_selector_spec.py | 70 +++--- 11 files changed, 615 insertions(+), 119 deletions(-) delete mode 100644 core/dbt/contracts/common.py create mode 100644 core/dbt/contracts/selection.py create mode 100644 test/unit/test_graph_selector_parsing.py diff --git a/core/dbt/contracts/common.py b/core/dbt/contracts/common.py deleted file mode 100644 index b42f6306be8..00000000000 --- a/core/dbt/contracts/common.py +++ /dev/null @@ -1,11 +0,0 @@ - - -def named_property(name, doc=None): - def get_prop(self): - return self._contents.get(name) - - def set_prop(self, value): - self._contents[name] = value - self.validate() - - return property(get_prop, set_prop, doc=doc) diff --git a/core/dbt/contracts/graph/unparsed.py b/core/dbt/contracts/graph/unparsed.py index e354a2a3454..8810bf04b86 100644 --- a/core/dbt/contracts/graph/unparsed.py +++ b/core/dbt/contracts/graph/unparsed.py @@ -1,5 +1,9 @@ from dbt.node_types import NodeType -from dbt.contracts.util import Replaceable, Mergeable +from dbt.contracts.util import ( + AdditionalPropertiesMixin, + Mergeable, + Replaceable, +) # trigger the PathEncoder import dbt.helper_types # noqa:F401 from dbt.exceptions import CompilationException @@ -177,32 +181,12 @@ def __bool__(self): @dataclass -class AdditionalPropertiesAllowed(ExtensibleJsonSchemaMixin): +class AdditionalPropertiesAllowed( + AdditionalPropertiesMixin, + ExtensibleJsonSchemaMixin +): _extra: Dict[str, Any] = field(default_factory=dict) - @property - def extra(self): - return self._extra - - @classmethod - def from_dict(cls, data, validate=True): - self = super().from_dict(data=data, validate=validate) - keys = self.to_dict(validate=False, omit_none=False) - for key, value in data.items(): - if key not in keys: - self._extra[key] = value - return self - - def to_dict(self, omit_none=True, validate=False): - data = super().to_dict(omit_none=omit_none, validate=validate) - data.update(self._extra) - return data - - def replace(self, **kwargs): - dct = self.to_dict(omit_none=False, validate=False) - dct.update(kwargs) - return self.from_dict(dct) - @dataclass class ExternalPartition(AdditionalPropertiesAllowed, Replaceable): diff --git a/core/dbt/contracts/selection.py b/core/dbt/contracts/selection.py new file mode 100644 index 00000000000..298279622f2 --- /dev/null +++ b/core/dbt/contracts/selection.py @@ -0,0 +1,21 @@ +from dataclasses import dataclass, field +from hologram import JsonSchemaMixin + +from typing import List, Dict, Any, Union + + +@dataclass +class SelectorDefinition(JsonSchemaMixin): + name: str + definition: Union[str, Dict[str, Any]] + + +@dataclass +class SelectorFile(JsonSchemaMixin): + selectors: List[SelectorDefinition] + version: int = 2 + + +@dataclass +class SelectorCollection: + packages: Dict[str, List[SelectorFile]] = field(default_factory=dict) diff --git a/core/dbt/contracts/util.py b/core/dbt/contracts/util.py index e90694fedaf..e2f2c257c2a 100644 --- a/core/dbt/contracts/util.py +++ b/core/dbt/contracts/util.py @@ -44,3 +44,35 @@ def merged(self, *args): class Writable: def write(self, path: str, omit_none: bool = False): write_json(path, self.to_dict(omit_none=omit_none)) # type: ignore + + +class AdditionalPropertiesMixin: + """Make this class an extensible property. + + The underlying class definition must include a type definition for a field + named '_extra' that is of type `Dict[str, Any]`. + """ + ADDITIONAL_PROPERTIES = True + + @classmethod + def from_dict(cls, data, validate=True): + self = super().from_dict(data=data, validate=validate) + keys = self.to_dict(validate=False, omit_none=False) + for key, value in data.items(): + if key not in keys: + self.extra[key] = value + return self + + def to_dict(self, omit_none=True, validate=False): + data = super().to_dict(omit_none=omit_none, validate=validate) + data.update(self.extra) + return data + + def replace(self, **kwargs): + dct = self.to_dict(omit_none=False, validate=False) + dct.update(kwargs) + return self.from_dict(dct) + + @property + def extra(self): + return self._extra diff --git a/core/dbt/graph/cli.py b/core/dbt/graph/cli.py index 3b0d946e3e8..2158e58d986 100644 --- a/core/dbt/graph/cli.py +++ b/core/dbt/graph/cli.py @@ -2,9 +2,12 @@ import itertools from typing import ( - List, Optional + Dict, List, Optional, Tuple, Any, Union ) +from dbt.contracts.selection import SelectorDefinition +from dbt.exceptions import InternalException, ValidationException + from .selector_spec import ( SelectionUnion, SelectionSpec, @@ -97,3 +100,153 @@ def parse_test_selectors( return SelectionIntersection( components=[base, intersect_with], expect_exists=True ) + + +def _get_list_dicts( + dct: Dict[str, Any], key: str +) -> List[Union[str, Dict[str, Any]]]: + result: List[Dict[str, Any]] = [] + if key not in dct: + raise InternalException( + f'Expected to find key {key} in dict, only found {list(dct)}' + ) + values = dct[key] + if not isinstance(values, list): + raise ValidationException( + f'Invalid value type {type(values)} in key "{key}" ' + f'(value "{values}")' + ) + for value in values: + if isinstance(value, dict): + for value_key in value: + if not isinstance(value_key, str): + raise ValidationException( + f'Expected all keys to "{key}" dict to be strings, ' + f'but "{value_key}" is a "{type(value_key)}"' + ) + result.append(value) + elif isinstance(value, str): + result.append(value) + else: + raise ValidationException( + f'Invalid value type {type(value)} in key "{key}", expected dict ' + f'or str (value: {value}).' + ) + + return result + + +def _parse_include_exclude_subdefs( + definitions: List[Dict[str, Any]] +) -> Tuple[List[SelectionSpec], Optional[SelectionSpec]]: + include_parts: List[SelectionSpec] = [] + exclusions: Optional[List[Dict[str, Any]]] = None + + for definition in definitions: + if 'exclude' in definition: + # do not allow multiple exclude: defs at the same level + if exclusions is not None: + raise ValidationException( + f'Got multiple exclusion definitions in definition list ' + f'{definitions}' + ) + exclusions = _get_list_dicts(definition, 'exclude') + else: + include_parts.append(parse_from_definition(definition)) + + diff_arg: Optional[SelectionSpec] = None + if exclusions: + parsed_exclusions = [ + parse_from_definition(excl) for excl in exclusions + ] + if len(exclusions) == 1: + diff_arg = parsed_exclusions[0] + else: + diff_arg = SelectionUnion( + components=parsed_exclusions, + raw=exclusions + ) + return (include_parts, diff_arg) + + +def parse_union_definition(definition: Dict[str, Any]) -> SelectionSpec: + union_def_parts = _get_list_dicts(definition, 'union') + include, exclude = _parse_include_exclude_subdefs(union_def_parts) + + union = SelectionUnion(components=include) + + if exclude is None: + union.raw = definition + return union + else: + return SelectionDifference( + components=[union, exclude], + raw=definition + ) + + +def parse_intersection_definition( + definition: Dict[str, Any] +) -> SelectionSpec: + intersection_def_parts = _get_list_dicts(definition, 'intersection') + include, exclude = _parse_include_exclude_subdefs(intersection_def_parts) + intersection = SelectionIntersection(components=include) + if exclude is None: + intersection.raw = definition + return intersection + else: + return SelectionDifference( + components=[intersection, exclude], + raw=definition + ) + + +def parse_dict_definition(definition: Dict[str, Any]) -> SelectionSpec: + if len(definition) == 1: + key = list(definition)[0] + value = definition[key] + if not isinstance(key, str): + raise ValidationException( + f'Expected definition key to be a "str", got one of type ' + f'"{type(key)}" ({key})' + ) + dct = { + 'method': key, + 'value': value, + } + elif 'method' in definition and 'value' in definition: + dct = definition + else: + raise ValidationException( + f'Expected exactly 1 key in the selection definition or "method" ' + f'and "value" keys, but got {list(definition)}' + ) + + # if key isn't a valid method name, this will raise + return SelectionCriteria.from_dict(dct, dct) + + +def parse_from_definition(definition: Dict[str, Any]) -> SelectionSpec: + if 'union' in definition: + return parse_union_definition(definition) + elif 'intersection' in definition: + return parse_intersection_definition(definition) + elif isinstance(definition, dict): + return parse_dict_definition(definition) + elif isinstance(definition, str): + return SelectionCriteria.from_single_spec(definition) + else: + raise ValidationException( + f'Expected to find str or dict, instead found ' + f'{type(definition)}: {definition}' + ) + + +def parse_from_selectors_definition( + selectors: List[SelectorDefinition] +) -> Dict[str, SelectionSpec]: + result: Dict[str, SelectionSpec] = {} + selector: SelectorDefinition + for selector in selectors: + result[selector.name] = parse_from_definition(selector.definition) + return result diff --git a/core/dbt/graph/selector.py b/core/dbt/graph/selector.py index f47e1bc48c2..539340dd873 100644 --- a/core/dbt/graph/selector.py +++ b/core/dbt/graph/selector.py @@ -93,15 +93,15 @@ def collect_specified_neighbors( overlap with the selected set). """ additional: Set[UniqueId] = set() - if spec.select_childrens_parents: + if spec.childrens_parents: additional.update(self.graph.select_childrens_parents(selected)) - if spec.select_parents: - depth = spec.select_parents_max_depth + if spec.parents: + depth = spec.parents_depth additional.update(self.graph.select_parents(selected, depth)) - if spec.select_children: - depth = spec.select_children_max_depth + if spec.children: + depth = spec.children_depth additional.update(self.graph.select_children(selected, depth)) return additional diff --git a/core/dbt/graph/selector_methods.py b/core/dbt/graph/selector_methods.py index 1b029396028..afc968654a2 100644 --- a/core/dbt/graph/selector_methods.py +++ b/core/dbt/graph/selector_methods.py @@ -23,6 +23,7 @@ InternalException, RuntimeException, ) +from dbt.node_types import NodeType SELECTOR_GLOB = '*' @@ -38,6 +39,7 @@ class MethodName(StrEnum): Config = 'config' TestName = 'test_name' TestType = 'test_type' + ResourceType = 'resource_type' def is_selected_node(real_node, node_selector): @@ -259,7 +261,9 @@ def __eq__(self, other): class ConfigSelectorMethod(SelectorMethod): def search( - self, included_nodes: Set[UniqueId], selector: str + self, + included_nodes: Set[UniqueId], + selector: Any, ) -> Iterator[UniqueId]: parts = self.arguments # special case: if the user wanted to compare test severity, @@ -276,14 +280,25 @@ def search( except AttributeError: continue else: - # the selector can only be a str, so call str() on the value. - # of course, if one wished to render the selector in the jinja - # native env, this would no longer be true - - if selector == str(value): + if selector == value: yield node +class ResourceTypeSelectorMethod(SelectorMethod): + def search( + self, included_nodes: Set[UniqueId], selector: str + ) -> Iterator[UniqueId]: + try: + resource_type = NodeType(selector) + except ValueError as exc: + raise RuntimeException( + f'Invalid resource_type selector "{selector}"' + ) from exc + for node, real_node in self.parsed_nodes(included_nodes): + if real_node.resource_type == resource_type: + yield node + + class TestNameSelectorMethod(SelectorMethod): def search( self, included_nodes: Set[UniqueId], selector: str diff --git a/core/dbt/graph/selector_spec.py b/core/dbt/graph/selector_spec.py index ee86e091ca9..f8547c4d2c7 100644 --- a/core/dbt/graph/selector_spec.py +++ b/core/dbt/graph/selector_spec.py @@ -13,7 +13,7 @@ RAW_SELECTOR_PATTERN = re.compile( r'\A' - r'(?P(\@))?' + r'(?P(\@))?' r'(?P((?P(\d*))\+))?' r'((?P([\w.]+)):)?(?P(.*?))' r'(?P(\+(?P(\d*))))?' @@ -57,18 +57,18 @@ def _match_to_int(match: Dict[str, str], key: str) -> Optional[int]: @dataclass class SelectionCriteria: - raw: str + raw: Any method: MethodName method_arguments: List[str] - value: str - select_childrens_parents: bool - select_parents: bool - select_parents_max_depth: Optional[int] - select_children: bool - select_children_max_depth: Optional[int] + value: Any + childrens_parents: bool + parents: bool + parents_depth: Optional[int] + children: bool + children_depth: Optional[int] def __post_init__(self): - if self.select_children and self.select_childrens_parents: + if self.children and self.childrens_parents: raise RuntimeException( f'Invalid node spec {self.raw} - "@" prefix and "+" suffix ' 'are incompatible' @@ -83,7 +83,7 @@ def default_method(cls, value: str) -> MethodName: @classmethod def parse_method( - cls, raw: str, groupdict: Dict[str, Any] + cls, groupdict: Dict[str, Any] ) -> Tuple[MethodName, List[str]]: raw_method = groupdict.get('method') if raw_method is None: @@ -100,35 +100,36 @@ def parse_method( return method_name, method_arguments @classmethod - def from_single_spec(cls, raw: str) -> 'SelectionCriteria': - result = RAW_SELECTOR_PATTERN.match(raw) - if result is None: - # bad spec! - raise RuntimeException(f'Invalid selector spec "{raw}"') - result_dict = result.groupdict() - - if 'value' not in result_dict: + def from_dict(cls, raw: Any, dct: Dict[str, Any]) -> 'SelectionCriteria': + if 'value' not in dct: raise RuntimeException( f'Invalid node spec "{raw}" - no search value!' ) + method_name, method_arguments = cls.parse_method(dct) - method_name, method_arguments = cls.parse_method(raw, result_dict) - - parents_max_depth = _match_to_int(result_dict, 'parents_depth') - children_max_depth = _match_to_int(result_dict, 'children_depth') - + parents_depth = _match_to_int(dct, 'parents_depth') + children_depth = _match_to_int(dct, 'children_depth') return cls( raw=raw, method=method_name, method_arguments=method_arguments, - value=result_dict['value'], - select_childrens_parents=bool(result_dict.get('childs_parents')), - select_parents=bool(result_dict.get('parents')), - select_parents_max_depth=parents_max_depth, - select_children=bool(result_dict.get('children')), - select_children_max_depth=children_max_depth, + value=dct['value'], + childrens_parents=bool(dct.get('childrens_parents')), + parents=bool(dct.get('parents')), + parents_depth=parents_depth, + children=bool(dct.get('children')), + children_depth=children_depth, ) + @classmethod + def from_single_spec(cls, raw: str) -> 'SelectionCriteria': + result = RAW_SELECTOR_PATTERN.match(raw) + if result is None: + # bad spec! + raise RuntimeException(f'Invalid selector spec "{raw}"') + + return cls.from_dict(raw, result.groupdict()) + class BaseSelectionGroup(Iterable[SelectionSpec], metaclass=ABCMeta): def __init__( diff --git a/test/unit/test_graph_selection.py b/test/unit/test_graph_selection.py index a5623a95793..7180680bc24 100644 --- a/test/unit/test_graph_selection.py +++ b/test/unit/test_graph_selection.py @@ -167,19 +167,19 @@ def test_run_specs(include, exclude, expected): @pytest.mark.parametrize( - 'spec,parents,parents_max_depth,children,children_max_depth,filter_type,filter_value,childrens_parents', + 'spec,parents,parents_depth,children,children_depth,filter_type,filter_value,childrens_parents', param_specs, ids=id_macro ) -def test_parse_specs(spec, parents, parents_max_depth, children, children_max_depth, filter_type, filter_value, childrens_parents): +def test_parse_specs(spec, parents, parents_depth, children, children_depth, filter_type, filter_value, childrens_parents): parsed = graph_selector.SelectionCriteria.from_single_spec(spec) - assert parsed.select_parents == parents - assert parsed.select_parents_max_depth == parents_max_depth - assert parsed.select_children == children - assert parsed.select_children_max_depth == children_max_depth + assert parsed.parents == parents + assert parsed.parents_depth == parents_depth + assert parsed.children == children + assert parsed.children_depth == children_depth assert parsed.method == filter_type assert parsed.value == filter_value - assert parsed.select_childrens_parents == childrens_parents + assert parsed.childrens_parents == childrens_parents invalid_specs = [ diff --git a/test/unit/test_graph_selector_parsing.py b/test/unit/test_graph_selector_parsing.py new file mode 100644 index 00000000000..da6814ae80a --- /dev/null +++ b/test/unit/test_graph_selector_parsing.py @@ -0,0 +1,301 @@ +from dbt.graph import ( + cli, + SelectionUnion, + SelectionIntersection, + SelectionDifference, + SelectionCriteria, +) +from dbt.graph.selector_methods import MethodName +import textwrap +import yaml + +from dbt.contracts.selection import SelectorFile + + +def parse_file(txt: str) -> SelectorFile: + txt = textwrap.dedent(txt) + dct = yaml.safe_load(txt) + sf = SelectorFile.from_dict(dct) + return sf + + +class Union: + def __init__(self, *args): + self.components = args + + def __str__(self): + return f'Union(components={self.components})' + + def __repr__(self): + return f'Union(components={self.components!r})' + + def __eq__(self, other): + if not isinstance(other, SelectionUnion): + return False + + return all(mine == theirs for mine, theirs in zip(self.components, other.components)) + + +class Intersection: + def __init__(self, *args): + self.components = args + + def __str__(self): + return f'Intersection(components={self.components})' + + def __repr__(self): + return f'Intersection(components={self.components!r})' + + def __eq__(self, other): + if not isinstance(other, SelectionIntersection): + return False + + return all(mine == theirs for mine, theirs in zip(self.components, other.components)) + + +class Difference: + def __init__(self, *args): + self.components = args + + def __str__(self): + return f'Difference(components={self.components})' + + def __repr__(self): + return f'Difference(components={self.components!r})' + + def __eq__(self, other): + if not isinstance(other, SelectionDifference): + return False + + return all(mine == theirs for mine, theirs in zip(self.components, other.components)) + + +class Criteria: + def __init__(self, method, value, **kwargs): + self.method = method + self.value = value + self.kwargs = kwargs + + def __str__(self): + return f'Criteria(method={self.method}, value={self.value}, **{self.kwargs})' + + def __repr__(self): + return f'Criteria(method={self.method!r}, value={self.value!r}, **{self.kwargs!r})' + + def __eq__(self, other): + if not isinstance(other, SelectionCriteria): + return False + return ( + self.method == other.method and + self.value == other.value and + all(getattr(other, k) == v for k, v in self.kwargs.items()) + ) + + +def test_parse_simple(): + sf = parse_file('''\ + selectors: + - name: tagged_foo + definition: + tag: foo + ''') + + assert len(sf.selectors) == 1 + parsed = cli.parse_from_selectors_definition(sf.selectors) + assert len(parsed) == 1 + assert 'tagged_foo' in parsed + assert Criteria( + method=MethodName.Tag, + method_arguments=[], + value='foo', + children=False, + parents=False, + childrens_parents=False, + children_depth=None, + parents_depth=None, + ) == parsed['tagged_foo'] + + +def test_parse_simple_childrens_parents(): + sf = parse_file('''\ + selectors: + - name: tagged_foo + definition: + method: tag + value: foo + childrens_parents: True + ''') + + assert len(sf.selectors) == 1 + parsed = cli.parse_from_selectors_definition(sf.selectors) + assert len(parsed) == 1 + assert 'tagged_foo' in parsed + assert Criteria( + method=MethodName.Tag, + method_arguments=[], + value='foo', + children=False, + parents=False, + childrens_parents=True, + children_depth=None, + parents_depth=None, + ) == parsed['tagged_foo'] + + +def test_parse_simple_arguments_with_modifiers(): + sf = parse_file('''\ + selectors: + - name: configured_view + definition: + method: config.materialized + value: view + parents: True + children: True + children_depth: 2 + ''') + + assert len(sf.selectors) == 1 + parsed = cli.parse_from_selectors_definition(sf.selectors) + assert len(parsed) == 1 + assert 'configured_view' in parsed + assert Criteria( + method=MethodName.Config, + method_arguments=['materialized'], + value='view', + children=True, + parents=True, + childrens_parents=False, + children_depth=2, + parents_depth=None, + ) == parsed['configured_view'] + + +def test_parse_union(): + sf = parse_file('''\ + selectors: + - name: views-or-foos + definition: + union: + - method: config.materialized + value: view + - tag: foo + ''') + assert len(sf.selectors) == 1 + parsed = cli.parse_from_selectors_definition(sf.selectors) + assert 'views-or-foos' in parsed + assert Union( + Criteria(method=MethodName.Config, value='view', method_arguments=['materialized']), + Criteria(method=MethodName.Tag, value='foo', method_arguments=[]) + ) == parsed['views-or-foos'] + + +def test_parse_intersection(): + sf = parse_file('''\ + selectors: + - name: views-and-foos + definition: + intersection: + - method: config.materialized + value: view + - tag: foo + ''') + assert len(sf.selectors) == 1 + parsed = cli.parse_from_selectors_definition(sf.selectors) + + assert 'views-and-foos' in parsed + assert Intersection( + Criteria(method=MethodName.Config, value='view', method_arguments=['materialized']), + Criteria(method=MethodName.Tag, value='foo', method_arguments=[]), + ) == parsed['views-and-foos'] + + +def test_parse_union_excluding(): + sf = parse_file('''\ + selectors: + - name: views-or-foos-not-bars + definition: + union: + - method: config.materialized + value: view + - tag: foo + - exclude: + - tag: bar + ''') + assert len(sf.selectors) == 1 + parsed = cli.parse_from_selectors_definition(sf.selectors) + assert 'views-or-foos-not-bars' in parsed + assert Difference( + Union( + Criteria(method=MethodName.Config, value='view', method_arguments=['materialized']), + Criteria(method=MethodName.Tag, value='foo', method_arguments=[]) + ), + Criteria(method=MethodName.Tag, value='bar', method_arguments=[]), + ) == parsed['views-or-foos-not-bars'] + + +def test_parse_yaml(): + sf = parse_file('''\ + selectors: + - name: test_name + definition: + union: + - intersection: + - tag: foo + - tag: bar + - union: + - package: snowplow + - config.materialized: incremental + - union: + - path: "models/snowplow/marketing/custom_events.sql" + - fqn: "snowplow.marketing" + - intersection: + - resource_type: seed + - package: snowplow + - exclude: + - country_codes + - intersection: + - tag: baz + - config.materialized: ephemeral + - name: weeknights + definition: + union: + - tag: nightly + - tag:weeknights_only + ''') + + assert len(sf.selectors) == 2 + parsed = cli.parse_from_selectors_definition(sf.selectors) + assert 'test_name' in parsed + assert 'weeknights' in parsed + assert Union( + Criteria(method=MethodName.Tag, value='nightly'), + Criteria(method=MethodName.Tag, value='weeknights_only'), + ) == parsed['weeknights'] + + assert Union( + Intersection( + Criteria(method=MethodName.Tag, value='foo'), + Criteria(method=MethodName.Tag, value='bar'), + Union( + Criteria(method=MethodName.Package, value='snowplow'), + Criteria(method=MethodName.Config, value='incremental', method_arguments=['materialized']), + ), + ), + Union( + Criteria(method=MethodName.Path, value="models/snowplow/marketing/custom_events.sql"), + Criteria(method=MethodName.FQN, value='snowplow.marketing'), + ), + Difference( + Intersection( + Criteria(method=MethodName.ResourceType, value='seed'), + Criteria(method=MethodName.Package, value='snowplow'), + ), + Union( + Criteria(method=MethodName.FQN, value='country_codes'), + Intersection( + Criteria(method=MethodName.Tag, value='baz'), + Criteria(method=MethodName.Config, value='ephemeral', method_arguments=['materialized']), + ), + ), + ), + ) == parsed['test_name'] diff --git a/test/unit/test_graph_selector_spec.py b/test/unit/test_graph_selector_spec.py index fdbd43e917e..68c8611ccac 100644 --- a/test/unit/test_graph_selector_spec.py +++ b/test/unit/test_graph_selector_spec.py @@ -18,11 +18,11 @@ def test_raw_parse_simple(): assert result.method == MethodName.FQN assert result.method_arguments == [] assert result.value == raw - assert not result.select_childrens_parents - assert not result.select_children - assert not result.select_parents - assert result.select_parents_max_depth is None - assert result.select_children_max_depth is None + assert not result.childrens_parents + assert not result.children + assert not result.parents + assert result.parents_depth is None + assert result.children_depth is None def test_raw_parse_simple_infer_path(): @@ -32,11 +32,11 @@ def test_raw_parse_simple_infer_path(): assert result.method == MethodName.Path assert result.method_arguments == [] assert result.value == raw - assert not result.select_childrens_parents - assert not result.select_children - assert not result.select_parents - assert result.select_parents_max_depth is None - assert result.select_children_max_depth is None + assert not result.childrens_parents + assert not result.children + assert not result.parents + assert result.parents_depth is None + assert result.children_depth is None def test_raw_parse_simple_infer_path_modified(): @@ -46,11 +46,11 @@ def test_raw_parse_simple_infer_path_modified(): assert result.method == MethodName.Path assert result.method_arguments == [] assert result.value == raw[1:] - assert result.select_childrens_parents - assert not result.select_children - assert not result.select_parents - assert result.select_parents_max_depth is None - assert result.select_children_max_depth is None + assert result.childrens_parents + assert not result.children + assert not result.parents + assert result.parents_depth is None + assert result.children_depth is None def test_raw_parse_simple_infer_fqn_parents(): @@ -60,11 +60,11 @@ def test_raw_parse_simple_infer_fqn_parents(): assert result.method == MethodName.FQN assert result.method_arguments == [] assert result.value == 'asdf' - assert not result.select_childrens_parents - assert not result.select_children - assert result.select_parents - assert result.select_parents_max_depth is None - assert result.select_children_max_depth is None + assert not result.childrens_parents + assert not result.children + assert result.parents + assert result.parents_depth is None + assert result.children_depth is None def test_raw_parse_simple_infer_fqn_children(): @@ -74,11 +74,11 @@ def test_raw_parse_simple_infer_fqn_children(): assert result.method == MethodName.FQN assert result.method_arguments == [] assert result.value == 'asdf' - assert not result.select_childrens_parents - assert result.select_children - assert not result.select_parents - assert result.select_parents_max_depth is None - assert result.select_children_max_depth is None + assert not result.childrens_parents + assert result.children + assert not result.parents + assert result.parents_depth is None + assert result.children_depth is None def test_raw_parse_complex(): @@ -88,11 +88,11 @@ def test_raw_parse_complex(): assert result.method == MethodName.Config assert result.method_arguments == ['arg', 'secondarg'] assert result.value == 'argument_value' - assert not result.select_childrens_parents - assert result.select_children - assert result.select_parents - assert result.select_parents_max_depth == 2 - assert result.select_children_max_depth == 4 + assert not result.childrens_parents + assert result.children + assert result.parents + assert result.parents_depth == 2 + assert result.children_depth == 4 def test_raw_parse_weird(): @@ -103,11 +103,11 @@ def test_raw_parse_weird(): assert result.method == MethodName.FQN assert result.method_arguments == [] assert result.value == '' - assert not result.select_childrens_parents - assert not result.select_children - assert not result.select_parents - assert result.select_parents_max_depth is None - assert result.select_children_max_depth is None + assert not result.childrens_parents + assert not result.children + assert not result.parents + assert result.parents_depth is None + assert result.children_depth is None def test_raw_parse_invalid():