Search code examples
pythonopencvimportpython-importgenetic-programming

Python import dependencies


I am dynamically creating some python code that I want to run inside a wrapper. Here is an overly simplified example.

[wrapper.py]

import cv2
img = cv2.imread('pic.png',0)

__import__("fragment")

cv2.imshow('pic',img)

[fragment.py]

img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)

I want the wrapper to set up any imports and variables, then import the fragment which will do stuff (i.e. make the image grayscale) and then do some standardized stuff afterwards (i.e. display image).

The fragments will be changing (genetic algorithm) so I would prefer to keep them separate from the setup which will be constant and will just get make manipulating the fragments more complicated.

When I run the program I get dependency errors on the fragment because cv2 and img are not defined (scope errors). Is there a way to achieve this either with a correction to the method I have used above or with another method?

I expect I might be able to also create the composite of the files in ram and then exec it or write over the fragment with a version of itself that contains all of the needed wrapping, but I wanted to see if there was something cleaner first.

Sincerely, Paul.


Solution

  • The fragments will be changing (genetic algorithm) so I would prefer to keep them separate from the setup which will be constant and will just get make manipulating the fragments more complicated.

    Whatever the complexity of the genetic algorithms you implemented in fragment.py is, I do not see how importing cv2 (and eventually more modules) will impact it in a way or an other.

    However, I agree with the first part of your statement in that you want to respect the principle of separation of concerns and make your code cleaner.

    The solution I see for your problem is to set a configuration file config.py in which you set all your imports. But importing config.py into other files is useless unless you succeed to make modules such as cv2 available elsewhere once for all. You can achieve that by dynamically importing them within config.py file:

    cv2=__import__('cv2')
    

    in your main program, fragment.py file or whatever module, you can make use of cv2 by simply running this:

    import config
    config.cv2.imread('pic.png')
    

    import config ↔ you do not need anymore to run: import cv2. This is because this trick renders cv2 as a global variable available across multiple modules.

    The same idea is valid for your other variables such as img that you need to declare in your config.py file too.

    Given these facts, here is my solution for your problem. Note that I am not using classes and functions: I prefer to address your problem straightforwardly and keep things too simple and clear instead.

    Organization of the code:

    The config.py file corresponds to your wrapper.py:

    solution/
    ├── application.py
    ├── cfg
    │   ├── config.py
    │   └── __init__.pyc
    ├── gallery
    │   └── pic.png
    └── genalgos
        ├── fragment.py
        └── __init__.py
    

    config.py:

    # This will make cv2 global and thus you won't need to import it in ./genalgos/fragment.py
    # You can use the same idea for all your other imports
    cv2=__import__('cv2')
    imgc=cv2.imread('./gallery/pic.png') # imgc is global
    

    fragment.py:

    # The only import you can not avoid is this one
    import cfg.config
    
    # imgs is global
    # By importing cfg.config you do not need to import cv2 here
    imgf=cfg.config.cv2.cvtColor(cfg.config.imgc,cfg.config.cv2.COLOR_BGR2GRAY) 
    

    application.py:

    import cfg.config
    import genalgos.fragment
    if __name__=="__main__":
    
       """
        Display the image 'imgc' as it is in 'cfg/config' file
       """
       cfg.config.cv2.imshow('Pic in BGR',cfg.config.imgc)
       cfg.config.cv2.waitKey(0)
       cfg.config.cv2.destroyAllWindows()
    
       """
        Display the grascaled image 'imgf' as it is in 'genalgos/fragment' file which
        itself is obtained after transforming imgc of 'cfg/config' file.
       """
       cfg.config.cv2.imshow('PIC Grayscaled',genalgos.fragment.imgf)
       cfg.config.cv2.waitKey(0) # Press any key to exit
       cfg.config.cv2.destroyAllWindows() # Unpaint windows and leave