# Pytest Can't find executable in aiida\_local\_code\_factory

**URL:** <https://aiida.discourse.group/t/pytest-cant-find-executable-in-aiida-local-code-factory/97>\
**Category:** New to AiiDA\
**Tags:** question\
**Created:** [September 11, 2023, 7:24pm UTC](https://aiida.discourse.group/t/pytest-cant-find-executable-in-aiida-local-code-factory/97 "2023-09-11T19:24:17Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![kmlefran](https://yyz2.discourse-cdn.com/free1/user_avatar/aiida.discourse.group/kmlefran/32/48_2.png) [@kmlefran](https://aiida.discourse.group/u/kmlefran)\
**Post date:** [September 11, 2023, 7:24pm UTC](https://aiida.discourse.group/t/pytest-cant-find-executable-in-aiida-local-code-factory/97/1 "2023-09-11T19:24:17Z")

</div>

I’m developing a plugin for software installed on my local machine (so far works great) but I’m trying to get tests implemented. My starting point is the test file setup created when using the cookiecutter tool.

Namely:

- conftest.py
- /tests
  - \_\_init\_\_.py
  - test\_calculations.py
  - /input\_files
    - {input file}

I’m getting an error when loading the code for my software using aiida\_local\_code\_factory in conftest.py

```auto
@pytest.fixture(scope="function")
def aimall_code(aiida_local_code_factory):
    """Get an aimall code."""
    return aiida_local_code_factory(
        executable="/Applications/AIMAll/AIMQB.app/Contents/MacOS/aimqb",
        entry_point="aimall",
        label="aimall2",
    )

```

When this is called, I’m getting an error “ValueError: The executable “/Applications/AIMAll/AIMQB.app/Contents/MacOS/aimqb” was not found in the $PATH.”

Looking at the aiida\_local\_code\_factory definition, I see it tries to find the executable with:

```auto
import shutil
executable_path = shutil.which(executable)
if not executable_path:
   raise ValueError(f'The executable "{executable}" was not found in the $PATH.')

```

I don’t know why this wouldn’t be working for this case. When I run python3 in a terminal and run the same code, I get the path as expected.

```auto
>>> import shutil
>>> shutil.which("/Applications/AIMAll/AIMQB.app/Contents/MacOS/aimqb")
'/Applications/AIMAll/AIMQB.app/Contents/MacOS/aimqb'

```

I’ve tried just passing ‘aimqb’ as the executable, with ‘/Applications/AIMAll/AIMQB.app/Contents/MacOS’ in my system path. I’ve also tried adding the below before the call to aiida\_local\_code\_factory in contest.py

```auto
import sys

def aimall_code(...):
    sys.path.insert('/Applications/AIMAll/AIMQB.app/Contents/MacOS',0)
    return .....

```

Can anyone help me find what might be going wrong here?

Thanks in advance

---

<div class="post-metadata">

**Author:** ![sphuber](https://yyz2.discourse-cdn.com/free1/user_avatar/aiida.discourse.group/sphuber/32/6_2.png) [@sphuber](https://aiida.discourse.group/u/sphuber)\
**Post date:** [September 11, 2023, 7:45pm UTC](https://aiida.discourse.group/t/pytest-cant-find-executable-in-aiida-local-code-factory/97/2 "2023-09-11T19:45:42Z")

</div>

Hi @kmlefran , before we try and solve this problem, do you expect your unit tests to actually run the `aimqb` executable? As in to run complete integration tests? Or are you planning to write more unit-style tests where the executable is not actually invoked? Because in the latter case, you could take any old executable as a placeholder.

---

<div class="post-metadata">

**Author:** ![kmlefran](https://yyz2.discourse-cdn.com/free1/user_avatar/aiida.discourse.group/kmlefran/32/48_2.png) [@kmlefran](https://aiida.discourse.group/u/kmlefran)\
**Post date:** [September 11, 2023, 7:54pm UTC](https://aiida.discourse.group/t/pytest-cant-find-executable-in-aiida-local-code-factory/97/3 "2023-09-11T19:54:56Z")

</div>

I suppose a complete integration test? I was hoping the program would be run. Pretty new to Python development and these are some of the first tests I’m writing. Maybe I can just load the code by label in the test rather than whatever the contest.py is supposed to do? Here’s the test. Build inputs, run calculation, check output type

```auto
file = SinglefileData(
        file=os.path.join(TEST_DIR, "input_files", "water_wb97xd_augccpvtz_qtaim.wfx")
    )

    # set up calculation
    inputs = {
        "code": aimall_code,
        "parameters": parameters,
        "file": file,
    }

    result = run(CalculationFactory("aimall"), **inputs)
    computed_atomic_props = result["atomic_properties"].get_dict()
    computed_bcp_props = result["bcp_properties"].get_dict()

    assert computed_atomic_props is Dict
    assert computed_bcp_props is Dict

```

---

<div class="post-metadata">

**Author:** ![sphuber](https://yyz2.discourse-cdn.com/free1/user_avatar/aiida.discourse.group/sphuber/32/6_2.png) [@sphuber](https://aiida.discourse.group/u/sphuber)\
**Post date:** [September 11, 2023, 8:25pm UTC](https://aiida.discourse.group/t/pytest-cant-find-executable-in-aiida-local-code-factory/97/4 "2023-09-11T20:25:33Z")

</div>

I see, then it is indeed important that the executable exists. The behavior is really weird, I am not sure why `shutil.which` would complain in the context of `pytest` compared to when you run it in a normal shell. I have to admit that I don’t have an idea of where the problem could be. As a temporary workaround, you can simply copy the implementation of the `aiida_local_code_factory` fixture and remove the check. I only added that check to prevent accidental typos in the executable path to cause weird failures.

On another note, since you are working on a plugin for a new code, I wondered if you are aware of [`aiida-shell`](https://aiida-shell.readthedocs.io/en/latest/howto.html). This is a plugin I wrote to make starting to using new codes with AiiDA very easy. You don’t need to write any plugins and can start prototyping quickly.

I am not familiar with aimqb, but looking at your test invocation and a quick google, I think you could run the calculation with `aiida-shell`. Just run `pip install aiida-shell` and then run the following:

```python
from aiida_shell import launch_shell_job
results, node = launch_shell_job(
    'aimqb',
    arguments='-nogui -bim=proaim {wfx}',
    nodes={
        'wfx': 'water_wb97xd_augccpvtz_qtaim.wfx'
    }
)
print(results['stdout'].get_content())

```

As you can see, you can pass any command line arguments that aimqb understands in the `arguments` input.  
This is a very simple example, but the `aiida-shell` interface has quite a bit of flexibility, just have a look at the docs.  
Would be interested to know if this would be helpful for your use case.

---

<div class="post-metadata">

**Author:** ![kmlefran](https://yyz2.discourse-cdn.com/free1/user_avatar/aiida.discourse.group/kmlefran/32/48_2.png) [@kmlefran](https://aiida.discourse.group/u/kmlefran)\
**Post date:** [September 12, 2023, 1:32pm UTC](https://aiida.discourse.group/t/pytest-cant-find-executable-in-aiida-local-code-factory/97/5 "2023-09-12T13:32:27Z")

</div>

Thanks, I’ll try that! aiida\_shell definitely looks like it should work for my case, but the plugin is already written. I would have probably used it if I’d known at the start of creating this. But it’s all written and implemented in a few WorkChains I’m using

---

<div class="post-metadata">

**Author:** ![kmlefran](https://yyz2.discourse-cdn.com/free1/user_avatar/aiida.discourse.group/kmlefran/32/48_2.png) [@kmlefran](https://aiida.discourse.group/u/kmlefran)\
**Post date:** [September 12, 2023, 2:29pm UTC](https://aiida.discourse.group/t/pytest-cant-find-executable-in-aiida-local-code-factory/97/6 "2023-09-12T14:29:42Z")

</div>

This worked for this issue for me. For anyone who may run into something similar, my conftest.py now looks like the below. Note that since the pytest fixture is being used in the same file as it’s defined, provide `name='my_aim_code'` to the fixture and use that name in the code to use the fixture.

```auto
import pytest

from aiida.common import exceptions
from aiida.orm import Computer, InstalledCode, QueryBuilder

pytest_plugins = ["aiida.manage.tests.pytest_fixtures"]

#removed the three lines relating to executable file path, 
#and changed filepath_executable in code dictionary to be assigned executable.
#Therefore in this usage, the executable should probably be the whole file 
#path to the executable

@pytest.fixture(name="my_aim_code")
def aiida_local_code_factory2(aiida_localhost):
"""Get an AiiDA code on localhost. 
Modified from https://aiida.readthedocs.io/projects/aiida-core/en/latest/_modules/aiida/manage/tests/pytest_fixtures.html

    Searches in the PATH for a given executable and creates an AiiDA code with provided entry point.

    Usage::

      def test_1(aiida_local_code_factory):
          code = aiida_local_code_factory('quantumespresso.pw', '/usr/bin/pw.x')
          # use code for testing ...

    :return: A function get_code(entry_point, executable) that returns the `Code` node.
    :rtype: object
    """

    def get_code(
        entry_point, executable, computer=aiida_localhost, label=None, **kwargs
    ):
        """Get local code.

        Sets up code for given entry point on given computer.

        :param entry_point: Entry point of calculation plugin
        :param executable: name of executable; will be searched for in local system PATH.
        :param computer: (local) AiiDA computer
        :param label: Define the label of the code. By default the ``executable`` is taken. This can be useful if
            multiple codes need to be created in a test which require unique labels.
        :param kwargs: Additional keyword arguments that are passed to the code's constructor.
        :return: the `Code` either retrieved from the database or created if it did not yet exist.
        :rtype: :py:class:`~aiida.orm.Code`
        """

        if label is None:
            label = executable

        builder = QueryBuilder().append(
            Computer, filters={"uuid": computer.uuid}, tag="computer"
        )
        builder.append(
            InstalledCode,
            filters={"label": label, "attributes.input_plugin": entry_point},
            with_computer="computer",
        )

        try:
            code = builder.one()[0]
        except (exceptions.MultipleObjectsError, exceptions.NotExistent):
            code = None
        else:
            return code

        code = InstalledCode(
            label=label,
            description=label,
            default_calc_job_plugin=entry_point,
            computer=computer,
            filepath_executable=executable,
            **kwargs,
        )

        return code.store()

    return get_code

@pytest.fixture(scope="function", autouse=True)
def clear_database_auto(clear_database): # pylint: disable=unused-argument
    """Automatically clear database in between tests."""

@pytest.fixture(scope="function")
def aimall_code(my_aim_code):
    """Get a aimall code."""
    return my_aim_code(
        executable="/Applications/AIMAll/AIMQB.app/Contents/MacOS/aimqb",
        entry_point="aimall",
        label="aimall",
    )

```
