I am trying to write an Event Driven Ansible plugin that uses module_utils from the same collection. I cannot get the imports working properly, so I was wondering if anyone had any idea on how to do this or what to try.
This looks like a very nested relative import which might not be a good idea in terms of readability.
The error “ImportError: attempted relative import with no known parent package”
means the parent package is not actually a package, probably it is lacking __init__.py files. ANy package needs this file to be recognized as package by python.
To avoid relative imports, you should be able to access the package by its full absolute package. You mentioned that ansible_collections.servicenow.itsm.plugins.module_utils didn’t work, but ansible-collections does not seem to be a package, just a github namespace.
I think from servicenow.itsm.plugins.module_utils.instance_config import get_combined_instance_config should work.
The problem that I see is that servicenow.itsm is interpreted as [pyproject]/itsm.
I think the dot in the package name is problematic, if it does not work, you will might need to load the module explicitly with importlib
Another thing that I see is that you are placing a new instance_config module in plugins/module_utils that is out of the scope of extensions/eda/plugins.
/plugins/module_utils is intended for ansible-core while /extensions/eda/plugins is intended for ansible-rulebook.
Since this module is to be used by the source plugin, I suggest to locate in extensions/eda/plugins/utils, then you can use a relative import like ..utils and that should work and probably would be a more readable code. (don’t forget to add an empty __init__.py file so python can recognize it as package)
Unfortunately that creates a lot of duplicated code in our repository. The intent of using stuff from module_utils is to use code that already exists for the modules or other plugins. The instance_config module specifically is code that is already in the inventory plugin but can be used by the EDA plugins. So I am moving it to a shared location, and then will update the inventory plugin to use that instead of local methods
Ok, I just saw a new instance_config module in the PR and I thought that would be just for the eda plugin. For more reusability as you mention, my last comment is not a good idea, the explicit import with importlib to use on demand whatever you want for the rest of the collection seems to make more sense.
I tried using importlib without success. However, their docs suggest using sys.path instead, which is what I tried as a hack/stopgap so I will likely go with that.
But kept getting ImportError: attempted relative import with no known parent package
The working approach with sys.path is
import sys
import os
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../..'))
if project_root not in sys.path:
sys.path.insert(0, project_root)
from plugins.module_utils.instance_config import get_combined_instance_config
from plugins.module_utils import client, table