Ejemplo n.º 1
0
Branch* load_module(const char* module_name, Term* loadCall)
{
    Branch* existing = find_loaded_module(module_name);
    if (existing != NULL)
        return existing;
    
    Value filename;
    bool found = find_module_file(module_name, &filename);

    if (!found)
        return NULL;

    Term* import = load_module_from_file(module_name, as_cstring(&filename))->owningTerm;

    // If a loadCall is provided, possibly move the new import to be before the loadCall.
    if (loadCall != NULL) {
        Term* callersModule = find_parent_term_in_branch(loadCall, import->owningBranch);

        if (callersModule != NULL && (import->index > callersModule->index))
            move_before(import, callersModule);
    }

    // If the module has static errors, print them now.
    print_static_errors_formatted(nested_contents(import));

    return nested_contents(import);
}
/*
 * name will be the fully-qualified package name in question, but
 * we are the loader for a given directory (eg. package) so we should
 * only get this if we are already the correct path for a given module
 * We cache by fully-qualified name though, since that's what we need
 * everywhere else.
 */
PyObject* PyResMgrImportLoader::find_module( const std::string& name )
{
//	TRACE_MSG( "PyResMgrImportLoader(%s)::find_module: %s\n", path_.c_str(),
//		name.c_str() );

    std::string moduleName = name;
    std::string::size_type dotPos = name.rfind( "." );
    if ( dotPos != std::string::npos )
    {
        moduleName = name.substr( dotPos + 1 );
    }

    moduleCache::const_iterator moduleIt = modules_.find( name );
    // If we haven't already cached this module, do so now
    if ( moduleIt == modules_.end() )
    {
        modules_[ name ] = find_module_file( moduleName, pDirectory_ );
    }

    // Do we have a matching module?
    if ( modules_[ name ].first == NOT_FOUND )
    {
        Py_Return;
    }

    if ( modules_[ name ].first == C_EXTENSION )
    {
        //ERROR_MSG( "PyResMgrImportLoader(%s)::find_module: Can't load module %s "
        //	"as a C extension\n", path_.c_str(), name.c_str() );
        Py_Return;
    }
    Py_INCREF( this );
    return this;
}
/**
 * This static routine identifies a Python module for the given name in
 * the supplied DataSection, returning the relevant DataSectionPtr and
 * the type of the module.
 *
 *	@param	name 	The name of the python module to find
 *
 *	@param	pDirectory	The DataSection to locate the module within
 *
 *	@return	A pair of < pythonModuleType, DataSectionPtr > for the requested
 *  module file, or < NOT_FOUND, NULL > if one could not be found.
 */
PyResMgrImportLoader::moduleCacheEntry PyResMgrImportLoader::find_module_file(
    const std::string& name, DataSectionPtr pDirectory )
{
    moduleCacheEntry result;
    result.first = NOT_FOUND;

    DataSectionPtr package = pDirectory->findChild( name );
    if ( package )
    {
        // packageInit is basically a wasted load here. It'll be needed
        // soon enough.
        moduleCacheEntry packgeInit = find_module_file( "__init__", package );
        switch( packgeInit.first ) {
        case PY_SOURCE:
        case PY_OBJECT:
        case C_EXTENSION:
            return std::make_pair( PKG_DIRECTORY, package );
            break;
        case NOT_FOUND:
        case PKG_DIRECTORY:
            break;
        }
    }

    suffixLookupMap::const_iterator suffixIt;
    for ( suffixIt = s_suffixes_.begin(); suffixIt != s_suffixes_.end(); suffixIt++ )
    {
        DataSectionPtr pCandidate = pDirectory->openSection( name + "." + suffixIt->first );
        if ( !pCandidate )
            continue;

        // This shouldn't happen...
        MF_ASSERT( suffixIt->second != PKG_DIRECTORY );

        // We have a match, check if it's a better match than any known match
        if ( suffixIt->second > result.first )
        {
            result.first = suffixIt->second;
            result.second = pCandidate;
        }
    }

    return result;

}
/*
 * This routine needs to emulate load_package in import.c in
 * python, but from a DataSectionPtr
 */
PyObject* PyResMgrImportLoader::load_package( const std::string& name,
        DataSectionPtr package )
{
    // We don't erase ourselves from the modules_ list, since whatever
    // we call to process our __init__ script will do it for us.
    std::string moduleName = name;
    std::string::size_type dotPos = name.rfind( "." );
    if ( dotPos != std::string::npos )
    {
        moduleName = name.substr( dotPos + 1 );
    }

    PyObject *module = PyImport_AddModule( name.c_str() );
    if ( module == NULL )
    {
        // Propagate the PyErr up
        return NULL;
    }
    PyObject *moduleDict = PyModule_GetDict( module );
    PyObject *file = PyString_FromString( ( path_ + "/" + moduleName).c_str() );
    if ( file == NULL )
    {
        return NULL;
    }
    PyObject *path = Py_BuildValue( "[O]", file );
    if ( path == NULL )
    {
        Py_DECREF( file );
        return NULL;
    }
    int err = PyDict_SetItemString( moduleDict, "__file__", file );
    Py_DECREF( file );

    if ( err != 0 )
    {
        Py_DECREF( path );
        return NULL;
    }
    err = PyDict_SetItemString( moduleDict, "__path__", path );
    Py_DECREF( path );
    if ( err != 0 )
    {
        return NULL;
    }
    err = PyDict_SetItemString( moduleDict, "__loader__", this );
    if ( err != 0 )
    {
        return NULL;
    }

    // This call was tested in find_module_file earlier.
    moduleCacheEntry packageInit = find_module_file( "__init__", package );

//	TRACE_MSG( "PyResMgrImportLoader(%s)::load_package: processing %s\n",
//		path_.c_str(), name.c_str() );

    switch( packageInit.first )
    {
    case PY_OBJECT:
        return load_compiled_module( name,
                                     packageInit.second->asBinary() );
    case PY_SOURCE:
        return load_source_module( name,
                                   packageInit.second->asBinary(),
                                   package );
    case NOT_FOUND:
    case PKG_DIRECTORY:
    case C_EXTENSION:
        break;
    }
    Py_Return;
}