2

I'm implementing macros in Python (inspired by MacroPy). My project (when 'tests.py' is executed) works very well, but it doesn't work when I comment (or remove) the line import linecache from file 'import_hook.py' (all files are here). The script falls into recursion and the Python then uses another FileFinder and Loader.

This is the code of 'import_hook.py':

import sys

import ast
import _ast

import linecache  # Required because your mother is a kangaroo which sews cocoa.

import pymac.utils

import importlib.machinery
from types import ModuleType

from pymac.utils import *
from pymac.macro import *


__author__ = 'Jan Růžička'
__email__ = 'jan.ruzicka01@gmail.com'

__version__ = '0.1'


class FileWithMacrosLoader:
    def __init__(self, module_name, module):
        self.module = module

        sys.modules[module_name] = module

    def load_module(self, fullname):
        return self.module


class FileWithMacros:
    def __init__(self):
        self.bindings = None
        self.module_name = None

    def new_module(self, module_name, file_path):
        self.module_name = module_name

        module = ModuleType(module_name)

        module.__package__ = module_name.rpartition('.')[0]
        module.__file__ = file_path
        module.__loader__ = FileWithMacrosLoader(module_name, module)

        return module

    def expand_macros(self, source_code, file_path):
        tree = ast.parse(source_code)

        tree = ast.fix_missing_locations(expand_macros(tree))

        return compile(tree, file_path, 'exec'), tree

    def load_source(self, module_name, package_path):
        loader = importlib.machinery.PathFinder.find_module(module_name, package_path)

        source_code = loader.get_source(module_name)
        file_path = loader.path

        return source_code, file_path

    def find_module(self, module_name, package_path=None):
        try:
            source_code, file_path = self.load_source(module_name, package_path)

        except:
            return

        code, tree = self.expand_macros(source_code, file_path)

        module = self.new_module(module_name, file_path)

        namespace = dict_con(_ast.__dict__, pymac.utils.__dict__, module.__dict__)

        exec(code, namespace)

        return module.__loader__

It might be an ugly code, but I'm pretty new to Python import system and I'd be glad for an answer!

EDIT: I've ran it in PyCharm without the import linecache and it didn't work, but when I ran it with parameters -m pdb (Python debugger) it works as intended. The question might be more about PyCharm than Python I think...

R.O.S.S
  • 605
  • 5
  • 18
  • I like your comments – Mr. E Jan 28 '16 at 18:57
  • 1
    @Mr.E Thanks, but I was really angry about that :) – R.O.S.S Jan 28 '16 at 19:03
  • Just guessing but maybe ``linecache`` may be used by some other library you are using if loaded. If that is the case try an earlier import of ``linecache`` before the app entry point. – Fabio Menegazzo Jan 28 '16 at 19:12
  • It works with the linecache import, but not without it. And if some library wants to use `linecache`, why doesn't it import it itself? – R.O.S.S Jan 28 '16 at 19:16
  • What is the error you get when linecache is not imported? – Brendan Abel Jan 28 '16 at 19:38
  • 1
    Just a tip, you should probably try to avoid using `*` imports so heavily in your code. Makes it much harder to debug. – Brendan Abel Jan 28 '16 at 19:53
  • It take about 2 seconds and then a huge error message appears. At the top, it says that my Finder class hasn't a find_spec function, then some other errors and then it uses other loader for my (macro containing) file -> syntax/attribute errors. I'll post the error. – R.O.S.S Jan 28 '16 at 19:53
  • @BrendanAbel None of the `*` imported file uses the `linecache`. – R.O.S.S Jan 28 '16 at 19:56
  • How did you know that you had to import linecache? Was there some error related to it not being available? – Brendan Abel Jan 28 '16 at 19:57
  • @BrendanAbel I have sometimes in ancient ages imported `traceback` but I didn't use it at all, so I deleted its `import`. Then this exactly happened. So the first thing I did was that I searched `import`s inside the `traceback` module. There was a `import linecache`, so I imported it and it worked. However, I didn't realized why I need to do this. End of the tale. – R.O.S.S Jan 28 '16 at 20:02

1 Answers1

0

So I have figured out: My custom loader can't load the file linecache, so if I import it in my file, it doesn't need to be imported in other file that I import (I thinks it's the _ast) using my loader. However, if I don't import it, it needs to be imported later - using my loader, which is not capable of doing so.

R.O.S.S
  • 605
  • 5
  • 18