Pythia icon indicating copy to clipboard operation
Pythia copied to clipboard

Ability to include other files from adapter.py

Open overfl0 opened this issue 9 years ago • 3 comments

This enhancement may be blocked by #7.

Allow the storage of multiple .py files that could then be included by adapter.py so that all the code is not in one big file.

This won't impact performance as once a module is loaded to memory, import something has no effect so it will be loaded only once.

overfl0 avatar Jan 02 '17 12:01 overfl0

Import hooks should be able to solve this issue and also enable finer control on what is imported (and blocked) by the non-pythia scripts. They could even allow storing and loading python modules directly from pbo files!

This is definitely worth investigating.

https://www.python.org/dev/peps/pep-0302/

overfl0 avatar Apr 26 '17 12:04 overfl0

import sys
import importlib.abc
import importlib.machinery
import textwrap


class InterceptDummyWrapper(object):
    data = {
        'intercept_modules/__init__.py': textwrap.dedent('''\
            # This should be __init__py
            print('Executing intercept_modules.__init__.py')
    
            Foo = 43
        ''').encode('latin-1'),

        'intercept_modules/submodule.py': textwrap.dedent('''\
            print('Executing intercept_modules.submodule.py')
            
            print('Trying to import another module from within a submodule')
            import other_modules
        ''').encode('latin-1'),

        'other_modules/__init__.py': textwrap.dedent('''\
            print('Executing other_modules/__init__.py')
        ''').encode('latin-1'),

        'other_modules/raiser.py': textwrap.dedent('''\
            print('Executing other_modules/raiser.py')
            
            print('This will raise an exception. Notice the right file name in the calltrace!')
            1/0
        ''').encode('latin-1')
    }

    @staticmethod
    def get_filename(fullname):
        pathname = fullname.replace('.', '/')
        for suffix in ('/__init__.py', '.py'):
            if pathname + suffix in InterceptDummyWrapper.data:
                return pathname + suffix

        raise KeyError('{} not found'.format(fullname))

    @staticmethod
    def is_package(fullname):
        return InterceptDummyWrapper.get_filename(fullname).endswith('/__init__.py')


class PBOModuleFinder(importlib.abc.MetaPathFinder):

    def install(self):
        if self not in sys.meta_path:
            sys.meta_path.insert(0, self)

    def find_spec(self, name, path, target = None):
        print('Test_Finder: Trying to load: {}'.format(name))

        try:
            is_package = InterceptDummyWrapper.is_package(name)
            return importlib.machinery.ModuleSpec(name, PBOLoader(), is_package=is_package)

        except KeyError:
            return None


class PBOLoader(importlib.abc.SourceLoader):
    def get_filename(self, fullname):
        print('PBOLoader: Requesting filename for {}'.format(fullname))
        return InterceptDummyWrapper.get_filename(fullname)

    def get_data(self, filename):
        print('PBOLoader: Fetching {} from pbo file'.format(filename))
        return InterceptDummyWrapper.data[filename]


def test():
    # Install the finder
    finder = PBOModuleFinder()
    finder.install()

    # Check if the finder is installed (should be the first there)
    print('meta_path:', sys.meta_path)

    # Import the package
    import intercept_modules
    print('intercept_modules.Foo:', intercept_modules.Foo)


    # Import a submodule (which imports another provided package)
    import intercept_modules.submodule
    from intercept_modules import submodule


    # Try raising an exception when inside a virtual file
    try:
        import other_modules.raiser
    except:
        import traceback
        # traceback.print_exc()
        print(traceback.format_exc())
        print('Exception printed. All is good :)')


if __name__ == '__main__':
    test()

overfl0 avatar Jun 06 '17 08:06 overfl0

I think we may consider just using zipimport for storing those files inside the dll. The easiest (and cross-platform) way would be to just append the zip at the end of the file and read the dll as a zip (making it a dll-zip polyglot) but this may stop working as soon as the file is digitally signed.

So it may be possible to just append the zip in linux (if we ever get a linux version) and store the zip as a dll ressource on Windows. Now the question is whether it will be possible to automatically pack the files with Visual Studio, prior to building and then dynamically include it in the resources as part of the building process.

overfl0 avatar Nov 22 '17 10:11 overfl0