def test_invalid_graph_missing_states():
    missing_states = textwrap.dedent("""\
    name: example
    import: [stdlib]
    body:
    - component:
        name: fill_valve
        edges:
          edge1:
            nodes: [0, 1]
        states:
          open:
            edge1: 6
          closed:
            edge1: closed
    - graph:
        name: main
        nodes:
          A:
            fixed_pressure: 500
            components:
              - [fill_valve, 0]

          B:
            components:
              - [fill_valve, 1]
    """)
    missing_states_file = top.File(missing_states, 's')
    with pytest.raises(exceptions.BadInputError) as err:
        top.Package([missing_states_file])
    assert "missing component" in str(err)
def test_bad_entry():
    nonexistent = 'parameter'

    bad_entry = textwrap.dedent(f"""\
    name: example
    import: [stdlib]
    body:
    - {nonexistent}:
        name: a

    - graph:
        name: main
        nodes:
          A:
            fixed_pressure: 500

          B:
            components:
              - [fill_valve, 1]

        states:
          fill_valve: closed
          vent_valve: open
          three_way_valve: left
        """)

    with pytest.raises(exceptions.BadInputError) as err:
        _ = top.File(bad_entry, 's')

    assert "invalid input type" in str(err)
def test_invalid_undefined_component_param():
    undefined_component_param = textwrap.dedent("""\
    name: example
    import: [stdlib]
    body:
    - typedef:
        params: [edge1, open_teq, closed_teq]
        name: valve
        edges:
          edge1:
            nodes: [0, 1]
        states:
          open:
            edge1: open_teq
          closed:
            edge1: closed_teq
    - component:
        name: vent_valve
        type: valve
        params:
          edge1: fav_edge
          open_teq: 1
          closed_teq: closed
          extra_param: 100
    """)
    with pytest.raises(exceptions.BadInputError):
        _ = top.File(undefined_component_param, input_type='s')
def test_invalid_param():
    not_param = 'nonexistent'

    invalid_param = textwrap.dedent(f"""\
    name: example
    import: [stdlib]
    body:
    - typedef:
        params: [edge1, open_teq, closed_teq]
        name: valve
        edges:
          edge1:
            nodes: [0, 1]
        states:
          open:
            edge1: open_teq
          closed:
            edge1: closed_teq

    - component:
        name: vent_valve
        type: valve
        params:
          edge1: fav_edge
          open_teq: 1
          {not_param}: closed
    """)

    with pytest.raises(exceptions.BadInputError) as err:
        _ = top.File(invalid_param, 's')

    assert "not found" in str(err)
def test_default_arg_inserted():
    default_arg_inserted = textwrap.dedent("""\
    name: example
    import: [stdlib]
    body:
    - typedef:
        params: [edge1=default, open_teq, closed_teq]
        name: valve
        edges:
          edge1:
            nodes: [0, 1]
        states:
          open:
            edge1: open_teq
          closed:
            edge1: closed_teq
    - component:
        name: vent_valve
        type: valve
        params:
          open_teq: 1
          closed_teq: closed
    """)

    pack = top.Package([top.File(default_arg_inserted, 's')])
    assert 'default' in pack.component_dict['example'][0]['edges']
def test_invalid_no_hoisting():
    no_hoisting = textwrap.dedent("""\
    name: example
    import: [stdlib]
    body:
    - component:
        name: vent_valve
        type: valve
        params:
          edge1: fav_edge
          open_teq: 1
          closed_teq: closed
    - typedef:
        params: [edge1, open_teq, closed_teq]
        name: valve
        edges:
          edge1:
            nodes: [0, 1]
        states:
          open:
            edge1: open_teq
          closed:
            edge1: closed_teq
    """)
    with pytest.raises(exceptions.BadInputError):
        _ = top.File(no_hoisting, input_type='s')
def test_files_unchanged():
    file = top.File(utils.example_path)

    top.Package([file])

    assert len(file.typedefs) == 2
    assert len(file.components) == 6
    assert len(file.graphs) == 2
def test_valid_pdl():
    file = top.File(utils.example_path)

    assert file.namespace == 'example'
    assert file.imports == ['stdlib']

    assert len(file.typedefs) == 2
    assert len(file.components) == 6
    assert len(file.graphs) == 2
def test_package_shortcuts():
    file = top.File(utils.example_path)
    namespace = file.namespace

    pack = top.Package([file])
    for component in pack.component_dict[namespace]:
        assert 'states' in component
        for edges in component['states'].values():
            for teq in edges.values():
                assert 'fwd' in teq and 'back' in teq
def test_invalid_no_state_no_teq():

    no_state_no_teq = textwrap.dedent("""\
    name: example
    import: [stdlib]
    body:
    - component:
        name: vent_plug
        edges:
          edge1:
            nodes: [0, 1]
    """)
    with pytest.raises(exceptions.BadInputError):
        _ = top.File(no_state_no_teq, input_type='s')
def test_duplicate_names():
    file_1 = textwrap.dedent("""\
    name: name1
    body:
    - component:
        name: fill_valve
        edges:
          edge1:
            nodes: [0, 1]
        states:
          open:
            edge1: 6
          closed:
            edge1: closed
    """)

    file_2 = textwrap.dedent("""\
    name: name2
    body:
    - component:
        name: fill_valve
        edges:
          edge1:
            nodes: [0, 1]
        states:
          open:
            edge1: 6
          closed:
            edge1: closed
    """)
    duplicate_pack = top.Package(
        [top.File(file_1, 's'), top.File(file_2, 's')])
    assert duplicate_pack.component_dict["name1"][0][
        'name'] == "name1.fill_valve"
    assert duplicate_pack.component_dict["name2"][0][
        'name'] == "name2.fill_valve"
def test_invalid_nested_import():
    nested_import = textwrap.dedent("""\
    name: example
    import: [stdlib]
    body:
    - component:
        name: vent_valve
        type: stdlib.NEST.hole
        params:
          edge_name: fav_edge
          open_teq: 5
    """)
    nested_import_file = top.File(nested_import, input_type='s')
    with pytest.raises(NotImplementedError) as err:
        top.Package([nested_import_file])
    assert "nested imports" in str(err)
def test_invalid_no_component_name():
    no_name = textwrap.dedent("""\
    name: example
    import: [stdlib]
    body:
    - component:
        edges:
          edge1:
            nodes: [0, 1]
        states:
          open:
            edge1: 1
          closed:
            edge1: closed
    """)
    with pytest.raises(exceptions.BadInputError):
        _ = top.File(no_name, input_type='s')
def test_package_storage():
    file = top.File(utils.example_path)

    pack = top.Package([file])

    namespace = file.namespace
    assert len(pack.typedefs) == 2
    assert 'example' in pack.typedefs and 'stdlib' in pack.typedefs

    assert len(pack.component_dict[namespace]) == 6
    assert len(pack.component_dict['stdlib']) == 0
    assert len(pack.components()) == 6

    assert len(pack.typedefs[namespace]) == 2
    assert len(pack.typedefs['stdlib']) == 1

    assert len(pack.graph_dict[namespace]) == 2
    assert len(pack.graph_dict['stdlib']) == 0
    assert len(pack.graphs()) == 2
def test_invalid_typedef():
    no_params = textwrap.dedent("""\
    name: example
    import: [stdlib]
    body:
    - typedef:
        params:
        name: valve
        edges:
          edge1:
            nodes: [0, 1]
        states:
          open:
            edge1: open_teq
          closed:
            edge1: closed_teq
    """)

    with pytest.raises(exceptions.BadInputError):
        _ = top.File(no_params, input_type='s')
예제 #16
0
    def __init__(self, files, input_type='f', import_paths=None):
        """
        Initialize a parser from one or more PDL files.

        A Parser contains a Package; most of its functionality lies in restructuring the data
        contained in its Package into output suitable for loading a plumbing engine.

        Parameters
        ----------

        files: iterable
            files is the iterable (usually a list) of one or more paths of the PDL files we
            want parsed. Alternatively, it can also be a list of strings that are each a valid
            PDL file. Alternatively, a single string or file path is also acceptable.

        input_type: char
            input_type indicates whether the argument provided to "files" is
            a list of file paths (f) or a list of strings (s).

        """
        self.import_paths = copy.deepcopy(import_paths)
        if import_paths is None:
            self.import_paths = utils.default_paths

        file_list = []

        # if a single element, put into list for processing
        if isinstance(files, str):
            files = [files]

        for file in files:
            file_list.append(top.File(file, input_type))
        self.package = top.Package(file_list, self.import_paths)

        self.components = {}
        self.mapping = {}
        self.initial_pressures = {}
        self.initial_states = {}

        self.parse_components()
        self.parse_graphs()
def test_invalid_bad_import_type():
    # typedef not found errors having to do with imported files will only be caught at the package
    # level, not at the file one. We can look at changing this if we change the implementation of
    # how importable files are stored.
    bad_type = "NONEXISTENT_TYPE"
    bad_imported_type = textwrap.dedent(f"""\
    name: example
    import: [stdlib]
    body:
    - component:
        name: vent_valve
        type: stdlib.{bad_type}
        params:
          edge_name: fav_edge
          open_teq: 5
          closed_teq: closed
    """)
    bad_imported_type_file = top.File(bad_imported_type, input_type='s')
    with pytest.raises(exceptions.BadInputError) as err:
        top.Package([bad_imported_type_file])
    assert "invalid component" in str(err)
def test_invalid_import():
    bad_import = "NONEXISTENT"
    invalid_import = textwrap.dedent(f"""\
    name: example
    import: [stdlib, {bad_import}]
    body:
    - typedef:
        params: [edge1, open_teq, closed_teq]
        name: valve
        edges:
          edge1:
            nodes: [0, 1]
        states:
          open:
            edge1: open_teq
          closed:
            edge1: closed_teq
    """)
    invalid_import_file = top.File(invalid_import, input_type='s')
    with pytest.raises(exceptions.BadInputError) as err:
        top.Package([invalid_import_file])
    assert "invalid import" in str(err)
def test_no_import():
    no_import = textwrap.dedent("""\
    name: example
    body:
    - typedef:
        params: [edge_name, open_teq, closed_teq]
        name: valve
        edges:
          edge1:
            nodes: [0, 1]
        states:
          open:
            edge1: open_teq
          closed:
            edge1: closed_teq
    """)
    file = top.File(no_import, 's')

    assert file.namespace == 'example'
    assert file.imports == []

    assert len(file.typedefs) == 1
def test_invalid_incomplete_node():
    # A is missing its components
    incomplete_nodes = textwrap.dedent("""\
    name: example
    import: [stdlib]
    body:
    - graph:
        name: main
        nodes:
          A:
            fixed_pressure: 500

          B:
            components:
              - [fill_valve, 1]

        states:
          fill_valve: closed
          vent_valve: open
          three_way_valve: left
    """)

    with pytest.raises(exceptions.BadInputError):
        _ = top.File(incomplete_nodes, 's')
def test_package_typedefs():
    file = top.File(utils.example_path)
    namespace = file.namespace

    pack = top.Package([file])

    var_open = 'open_teq'
    var_closed = 'closed_teq'
    var_name = 'edge_name'

    for component in pack.component_dict[namespace]:
        # ensure typedef fulfillment occurred
        assert 'type' not in component and 'params' not in component
        assert 'edges' in component

        # ensure variables were replaced
        if component['name'] == 'vent_valve':
            assert var_name not in list(component['edges'].keys())
            assert var_open not in component['states']['open']
            assert var_closed not in component['states']['closed']

        if component['name'] == 'hole':
            assert var_name not in list(component['edges'].keys())
            assert var_open not in component['states']['open']
예제 #22
0
    def __init__(self, files, import_paths=None):
        """
        Initialize a Package from one or more Files.

        A Package should have all the components of a complete plumbing engine system; from
        here no additional information will make it into the PlumbingEngine. Once instantiated,
        a Package's PDL is cleaned and ready to use.

        Parameters
        ----------

        files: iterable
            files is an iterable (usually a list) of one or more Files whose contents should go
            into the Package.
        """
        self.import_paths = copy.deepcopy(import_paths)
        if import_paths is None:
            self.import_paths = utils.default_paths
        self.importable_files = dict()

        imports_folder = []

        for import_path in self.import_paths:
            try:
                filenames = os.listdir(import_path)
                filenames = [
                    os.path.join(import_path, fname) for fname in filenames
                ]
                imports_folder.extend(filenames)

            except FileNotFoundError:
                imports_folder = []
                warnings.warn(
                    f"import directory {import_path} could not be found")

        for path in imports_folder:
            try:
                name = yaml.safe_load(open(path, 'r'))['name']

                if name in self.importable_files:
                    self.importable_files[name].add(path)
                else:
                    self.importable_files[name] = {path}
            except KeyError:
                warnings.warn(path + " does not describe a pdl file")

        if len(list(files)) < 1:
            raise exceptions.BadInputError(
                "cannot instantiate a Package with no Files")
        self.imports = []

        # dicts of {namespace: [entries]}, where entry is a PDL object. Organized like this to
        # reduce dict nesting; since this is a one time process it should be easy to keep
        # them synced.
        self.typedefs = {}
        self.component_dict = {}
        self.graph_dict = {}

        for file in files:
            # TODO(wendi): unused import detection
            self.imports.extend(copy.deepcopy(file.imports))

        for imp in set(self.imports):
            if imp not in self.importable_files:
                raise exceptions.BadInputError(f"invalid import: {imp}")
            for path in self.importable_files[imp]:
                files.append(top.File(path))

        # consolidate entry information from files
        for file in files:
            name = file.namespace
            if name not in self.typedefs:
                self.typedefs[name] = {}
                self.component_dict[name] = []
                self.graph_dict[name] = []
            self.typedefs[name].update(copy.deepcopy(file.typedefs))
            self.component_dict[name].extend(copy.deepcopy(file.components))
            self.graph_dict[name].extend(copy.deepcopy(file.graphs))

        self.clean()
def test_bad_input_type():
    bad_format = 'p'
    with pytest.raises(exceptions.BadInputError) as err:
        _ = top.File("", bad_format)

    assert "invalid input type" in str(err)
def test_import_modification():
    file = top.File(utils.example_path)

    pack = top.Package([file])

    assert len(pack.importable_files) != 0