0

In a project, I want to dynamically import the right module based on a version-number. For this I'm using importlib, and works find as long as the package is part of the source.

AdminApi = import_module(f"{self.version}", "AdminApi").AdminApi

The folder-structure looks like:

Admin-Package / 
    - __init__.py  # Contains dynamic class loader
    - admin64/
        - __init__.py  # contains AdminApi v6.4
        - ...
    - admin65/...
        - __init__.py  # contains AdminApi v6.5
        - ...

However, now I find myself needing to decouple the code into its own package to re-use in another project. So I've packaged this part of the source. This however seems to cause path-related issues. This seems to mean that importlib cannot help me.

So far, thanks to: https://stackoverflow.com/a/54138717/5731101 I've come to this point:

import importlib
from pathlib import Path

path = Path(__file__).resolve().parent
script_path = os.path.join(path, version, '__init__.py')

spec = importlib.util.spec_from_file_location(f"AdminApi", script_path)
AdminApi = importlib.util.module_from_spec(spec)
spec.loader.exec_module(AdminApi)

Unfortunately the spec.loader.excec_module fails with error: ModuleNotFoundError: No module named 'AdminApi' Even thought the class is clearly available in the file supplied via the path.

I would be grateful if anyone can help me out on this.

S.D.
  • 2,486
  • 1
  • 16
  • 23
  • Just a q: what's wrong with `if version == 64: import AdminApi64`, etc? If you only have a few versions your want to handle I would find that more readable, and it would avoid messing with anything like importlib. Ofc if this dynamic importing is a feature, it might not be a good solution – 2e0byo Nov 25 '21 at 16:27
  • That's a fair remark, perhaps I'm overcomplicating. It would however be a great feature going forward depending on the amount af variations we end up with. It seems the AdminApi we talk to seems to have some minor changes on every update - which is every month. – S.D. Nov 25 '21 at 17:06
  • 1
    Fair enough. If you only ever need to talk to *one* AdminApi I would just call it Admin and replace it every time. But I take it in your use case you need multiple access.. In any case you've got a solution which works fine :) (the other option btw might be using `admin = __import__(f"Admin{self.version}")` (equivalent to `import f"Admin{self.version}" as admin` if import allowed that. I don't know, but I suspect that avoiding importlib and going higher level might fix it. – 2e0byo Nov 25 '21 at 18:12

1 Answers1

0

I decided to try another tool in the toolbox of importlib Based on this answer: https://stackoverflow.com/a/67692/5731101

from importlib.machinery import SourceFileLoader

foo = SourceFileLoader("AdminAPI", "/path/to/file.py").load_module()
foo.AdminAPI()

This approach had no problems detecting the class and simply imported everything correctly.

S.D.
  • 2,486
  • 1
  • 16
  • 23