Search code examples
pythonrecursionimportlinecache

Unnecessary import necessary for proper function


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__ = '[email protected]'

__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...


Solution

  • 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.