/**
* @namespace Sk
*
*/
// this is stored into sys specially, rather than created by sys
Sk.sysmodules = new Sk.builtin.dict([]);
Sk.realsyspath = undefined;
/**
* @param {string} name to look for
* @param {string} ext extension to use (.py or .js)
* @param {Object=} searchPath an iterable set of path strings
*/
Sk.importSearchPathForName = function (name, ext, searchPath) {
var fn;
var j;
var fns = [];
var nameAsPath = name.replace(/\./g, "/");
var it, i;
var tryPathAndBreakOnSuccess = function(filename, packagePath) {
return Sk.misceval.chain(
Sk.misceval.tryCatch(function() {
return Sk.read(filename);
}, function(e) { /* Exceptions signal "not found" */ }),
function(code) {
if (code !== undefined) {
// This will cause the iterFor() to return the specified value
return new Sk.misceval.Break({filename: filename, code: code, packagePath: packagePath});
}
}
);
};
if (searchPath === undefined) {
searchPath = Sk.realsyspath;
}
return Sk.misceval.iterFor(searchPath.tp$iter(), function(pathStr) {
// For each element of path, try loading the module, and if that
// doesn't work, try the corresponding package.
return Sk.misceval.chain(
tryPathAndBreakOnSuccess(pathStr.v + "/" + nameAsPath + ext, false), // module
function(r) {
return r ? r : tryPathAndBreakOnSuccess(pathStr.v + "/" + nameAsPath + "/__init__" + ext,
pathStr.v + "/" + nameAsPath); // package
}
);
});
};
/**
* Complete any initialization of Python classes which relies on internal
* dependencies.
*
* This includes making Python classes subclassable and ensuring that the
* {@link Sk.builtin.object} magic methods are wrapped inside Python functions.
*
* @return {undefined}
*/
Sk.doOneTimeInitialization = function (canSuspend) {
var proto, name, i, x, func, typesWithFunctionsToWrap, builtin_type, j;
// can't fill these out when making the type because tuple/dict aren't
// defined yet.
Sk.builtin.type.basesStr_ = new Sk.builtin.str("__bases__");
Sk.builtin.type.mroStr_ = new Sk.builtin.str("__mro__");
// Register a Python class with an internal dictionary, which allows it to
// be subclassed
var setUpClass = function (child) {
var parent = child.tp$base;
var bases = [];
var base;
for (base = parent; base !== undefined; base = base.tp$base) {
bases.push(base);
}
child.tp$mro = new Sk.builtin.tuple([child]);
if (!child.tp$base){
child.tp$base = bases[0];
}
child["$d"] = new Sk.builtin.dict([]);
child["$d"].mp$ass_subscript(Sk.builtin.type.basesStr_, new Sk.builtin.tuple(bases));
child["$d"].mp$ass_subscript(Sk.builtin.type.mroStr_, child.tp$mro);
};
for (x in Sk.builtin) {
func = Sk.builtin[x];
if ((func.prototype instanceof Sk.builtin.object ||
func === Sk.builtin.object) && !func.sk$abstract) {
setUpClass(func);
}
}
// Wrap the inner Javascript code of Sk.builtin.object's Python methods inside
// Sk.builtin.func, as that class was undefined when these functions were declared
typesWithFunctionsToWrap = [Sk.builtin.object, Sk.builtin.type, Sk.builtin.func, Sk.builtin.method];
for (i = 0; i < typesWithFunctionsToWrap.length; i++) {
builtin_type = typesWithFunctionsToWrap[i];
proto = builtin_type.prototype;
for (j = 0; j < builtin_type.pythonFunctions.length; j++) {
name = builtin_type.pythonFunctions[j];
if (proto[name] instanceof Sk.builtin.func) {
// If functions have already been initialized, do not wrap again.
break;
}
proto[name].co_kwargs = null;
proto[name] = new Sk.builtin.func(proto[name]);
}
}
// compile internal python files and add them to the __builtin__ module
for (var file in Sk.internalPy.files) {
var fileWithoutExtension = file.split(".")[0].split("/")[1];
var mod = Sk.importBuiltinWithBody(fileWithoutExtension, false, Sk.internalPy.files[file], true);
mod = Sk.misceval.retryOptionalSuspensionOrThrow(mod);
Sk.asserts.assert(mod["$d"][fileWithoutExtension] !== undefined, "Should have imported name " + fileWithoutExtension);
Sk.builtins[fileWithoutExtension] = mod["$d"][fileWithoutExtension];
}
};
/**
* currently only pull once from Sk.syspath. User might want to change
* from js or from py.
*/
Sk.importSetUpPath = function (canSuspend) {
var i;
var paths;
if (!Sk.realsyspath) {
paths = [
new Sk.builtin.str("src/builtin"),
new Sk.builtin.str("src/lib"),
new Sk.builtin.str(".")
];
for (i = 0; i < Sk.syspath.length; ++i) {
paths.push(new Sk.builtin.str(Sk.syspath[i]));
}
Sk.realsyspath = new Sk.builtin.list(paths);
Sk.doOneTimeInitialization(canSuspend);
}
};
/**
* @param {string} name name of module to import
* @param {boolean=} dumpJS whether to output the generated js code
* @param {string=} modname what to call the module after it's imported if
* it's to be renamed (i.e. __main__)
* @param {string=} suppliedPyBody use as the body of the text for the module
* rather than Sk.read'ing it.
* @param {Object=} relativeToPackage perform import relative to this package
* @param {boolean=} returnUndefinedOnTopLevelNotFound return 'undefined' rather than throwing ImportError if the *first* load failed
* @param {boolean=} canSuspend whether we may return a Suspension object
*/
Sk.importModuleInternal_ = function (name, dumpJS, modname, suppliedPyBody, relativeToPackage, returnUndefinedOnTopLevelNotFound, canSuspend) {
//dumpJS = true;
var filename;
var prev;
var parentModName;
var parentModule;
var modNameSplit;
var ret;
var module;
var topLevelModuleToReturn = null;
var relativePackageName = relativeToPackage !== undefined ? relativeToPackage.tp$getattr(Sk.builtin.str.$name) : undefined;
var absolutePackagePrefix = relativePackageName !== undefined ? relativePackageName.v + "." : "";
var searchPath = relativeToPackage !== undefined ? relativeToPackage.tp$getattr(Sk.builtin.str.$path) : undefined;
Sk.importSetUpPath(canSuspend);
if (relativeToPackage && !relativePackageName) {
if (returnUndefinedOnTopLevelNotFound) {
return undefined;
} else {
throw new Sk.builtin.ValueError("Attempted to import relative to invalid package (no name)");
}
}
// if no module name override, supplied, use default name
if (modname === undefined) {
modname = absolutePackagePrefix + name;
}
modNameSplit = name.split(".");
// if leaf is already in sys.modules, early out
try {
prev = Sk.sysmodules.mp$subscript(modname);
// if we're a dotted module, return the top level, otherwise ourselves
if (modNameSplit.length > 1) {
return Sk.sysmodules.mp$subscript(absolutePackagePrefix + modNameSplit[0]);
} else {
return prev;
}
} catch (x) {
// not in sys.modules, continue
}
if (modNameSplit.length > 1) {
// if we're a module inside a package (i.e. a.b.c), then we'll need to return the
// top-level package ('a'). recurse upwards on our parent, importing
// all parent packages. so, here we're importing 'a.b', which will in
// turn import 'a', and then return 'a' eventually.
parentModName = modNameSplit.slice(0, modNameSplit.length - 1).join(".");
topLevelModuleToReturn = Sk.importModuleInternal_(parentModName, dumpJS, undefined, undefined, relativeToPackage, returnUndefinedOnTopLevelNotFound, canSuspend);
}
ret = Sk.misceval.chain(topLevelModuleToReturn, function(topLevelModuleToReturn_) {
var codeAndPath, co, googClosure;
var searchFileName = name;
var result;
topLevelModuleToReturn = topLevelModuleToReturn_;
// If we're inside a package, look search using its __path__
if (modNameSplit.length > 1) {
if (!topLevelModuleToReturn) {
return undefined;
}
parentModule = Sk.sysmodules.mp$subscript(absolutePackagePrefix + parentModName);
searchFileName = modNameSplit[modNameSplit.length-1];
searchPath = parentModule.tp$getattr(Sk.builtin.str.$path);
}
// otherwise:
// - create module object
// - add module object to sys.modules
// - compile source to (function(){...});
// - run module and set the module locals returned to the module __dict__
module = new Sk.builtin.module();
if (suppliedPyBody) {
filename = name + ".py";
co = Sk.compile(suppliedPyBody, filename, "exec", canSuspend);
} else {
co = Sk.misceval.chain(undefined, function() {
// If an onBeforeImport method is supplied, call it and if
// the result is false or a string, prevent the import.
// This allows for a user to conditionally prevent the usage
// of certain libraries.
if (Sk.onBeforeImport && typeof Sk.onBeforeImport === "function") {
return Sk.onBeforeImport(name);
}
return;
}, function(result) {
if (result === false) {
throw new Sk.builtin.ImportError("Importing " + name + " is not allowed");
} else if (typeof result === "string") {
throw new Sk.builtin.ImportError(result);
}
// Try loading as a builtin (i.e. already in JS) module, then try .py files
return Sk.importSearchPathForName(searchFileName, ".js", searchPath);
}, function(codeAndPath) {
if (codeAndPath) {
return {
funcname: "$builtinmodule", code: codeAndPath.code,
filename: codeAndPath.filename, packagePath: codeAndPath.packagePath
};
} else {
return Sk.misceval.chain(Sk.importSearchPathForName(searchFileName, ".py", searchPath), function(codeAndPath_) {
codeAndPath = codeAndPath_; // We'll want it in a moment
if (codeAndPath) {
return Sk.compile(codeAndPath.code, codeAndPath.filename, "exec", canSuspend);
}
}, function(co) {
if (co) {
co.packagePath = codeAndPath.packagePath;
return co;
}
});
}
});
}
return co;
}, function(co) {
var finalcode;
var withLineNumbers;
var modscope;
if (!co) {
return undefined;
}
// Now we know this module exists, we can add it to the cache
Sk.sysmodules.mp$ass_subscript(modname, module);
module.$js = co.code; // todo; only in DEBUG?
finalcode = co.code;
if (filename == null) {
filename = co.filename;
}
if (Sk.dateSet == null || !Sk.dateSet) {
finalcode = "Sk.execStart = Sk.lastYield = new Date();\n" + co.code;
Sk.dateSet = true;
}
// if (!COMPILED)
// {
if (dumpJS) {
withLineNumbers = function (code) {
var j;
var pad;
var width;
var i;
var beaut = Sk.js_beautify(code);
var lines = beaut.split("\n");
for (i = 1; i <= lines.length; ++i) {
width = ("" + i).length;
pad = "";
for (j = width; j < 5; ++j) {
pad += " ";
}
lines[i - 1] = "/* " + pad + i + " */ " + lines[i - 1];
}
return lines.join("\n");
};
finalcode = withLineNumbers(finalcode);
Sk.debugout(finalcode);
}
// }
finalcode += "\n" + co.funcname + ";";
modscope = Sk.global["eval"](finalcode);
module["$d"] = {
"__name__": new Sk.builtin.str(modname),
"__doc__": Sk.builtin.none.none$,
"__package__": co.packagePath ? new Sk.builtin.str(modname) :
parentModName ? new Sk.builtin.str(absolutePackagePrefix + parentModName) :
relativePackageName ? relativePackageName : Sk.builtin.none.none$
};
if (co.packagePath) {
module["$d"]["__path__"] = new Sk.builtin.tuple([new Sk.builtin.str(co.packagePath)]);
}
return modscope(module["$d"]);
}, function (modlocs) {
var i;
if (modlocs === undefined) {
if (returnUndefinedOnTopLevelNotFound && !topLevelModuleToReturn) {
return undefined;
} else {
throw new Sk.builtin.ImportError("No module named " + name);
}
}
// Some builtin modules replace their globals entirely.
// For their benefit, we copy over any of the standard
// dunder-values they didn't supply.
if (modlocs !== module["$d"]) {
for (i in module["$d"]) {
if (!modlocs[i]) {
modlocs[i] = module["$d"][i];
}
}
module["$d"] = modlocs;
}
// If an onAfterImport method is defined on the global Sk
// then call it now after a library has been successfully imported
// and compiled.
if (Sk.onAfterImport && typeof Sk.onAfterImport === "function") {
try {
Sk.onAfterImport(name);
} catch (e) {
}
}
if (topLevelModuleToReturn) {
// if we were a dotted name, then we want to return the top-most
// package. we store ourselves into our parent as an attribute
parentModule.tp$setattr(new Sk.builtin.str(modNameSplit[modNameSplit.length - 1]), module);
//print("import returning parent module, modname", modname, "__name__", toReturn.tp$getattr("__name__").v);
return topLevelModuleToReturn;
}
if (relativeToPackage) {
relativeToPackage.tp$setattr(new Sk.builtin.str(name), module);
}
//print("name", name, "modname", modname, "returning leaf");
// otherwise we return the actual module that we just imported
return module;
});
return canSuspend ? ret : Sk.misceval.retryOptionalSuspensionOrThrow(ret);
};
/**
* @param {string} name the module name
* @param {boolean=} dumpJS print out the js code after compilation for debugging
* @param {boolean=} canSuspend can this function suspend and return a Suspension object?
*/
Sk.importModule = function (name, dumpJS, canSuspend) {
return Sk.importModuleInternal_(name, dumpJS, undefined, undefined, undefined, false, canSuspend);
};
Sk.importMain = function (name, dumpJS, canSuspend) {
Sk.dateSet = false;
Sk.filesLoaded = false;
// Added to reset imports
Sk.sysmodules = new Sk.builtin.dict([]);
Sk.realsyspath = undefined;
Sk.resetCompiler();
return Sk.importModuleInternal_(name, dumpJS, "__main__", undefined, undefined, false, canSuspend);
};
/**
* **Run Python Code in Skulpt**
*
* When you want to hand Skulpt a string corresponding to a Python program this is the function.
*
* @param name {string} File name to use for messages related to this run
* @param dumpJS {boolean} print out the compiled javascript
* @param body {string} Python Code
* @param canSuspend {boolean} Use Suspensions for async execution
*
*/
Sk.importMainWithBody = function (name, dumpJS, body, canSuspend) {
Sk.dateSet = false;
Sk.filesLoaded = false;
// Added to reset imports
Sk.sysmodules = new Sk.builtin.dict([]);
Sk.realsyspath = undefined;
Sk.resetCompiler();
return Sk.importModuleInternal_(name, dumpJS, "__main__", body, undefined, false, canSuspend);
};
/**
* Imports internal python files into the `__builtin__` module. Used during startup
* to compile and import all *.py files from the src/ directory.
*
* @param name {string} File name to use for messages related to this run
* @param dumpJS {boolean} print out the compiled javascript
* @param body {string} Python Code
* @param canSuspend {boolean} Use Suspensions for async execution
*
*/
Sk.importBuiltinWithBody = function (name, dumpJS, body, canSuspend) {
return Sk.importModuleInternal_(name, dumpJS, "__builtin__."+name, body, undefined, false, canSuspend);
};
Sk.builtin.__import__ = function (name, globals, locals, fromlist, level) {
//print("Importing: ", JSON.stringify(name), JSON.stringify(fromlist), level);
//if (name == "") { debugger; }
// Save the Sk.globals variable importModuleInternal_ may replace it when it compiles
// a Python language module.
var saveSk = Sk.globals;
// This might be a relative import, so first we get hold of the module object
// representing this module's package (so we can search its __path__).
// module.__package__ contains its name, so we use that to look it up in sys.modules.
var relativeToPackage;
var relativeToPackageName;
var relativeToPackageNames;
if (level === undefined) {
level = Sk.__future__.absolute_import ? 0 : -1;
}
if (level !== 0 && globals["__package__"] && globals["__package__"] !== Sk.builtin.none.none$) {
relativeToPackageName = globals["__package__"].v;
if (relativeToPackageName && level > 0) {
// Trim <level> packages off the end
relativeToPackageNames = relativeToPackageName.split(".");
if (level-1 >= relativeToPackageNames.length) {
throw new Sk.builtin.ValueError("Attempted relative import beyond toplevel package");
}
relativeToPackageNames.length -= level-1;
relativeToPackageName = relativeToPackageNames.join(".");
}
try {
relativeToPackage = Sk.sysmodules.mp$subscript(relativeToPackageName);
} catch(e) {
relativeToPackageName = undefined;
}
}
if (level > 0 && relativeToPackage === undefined) {
throw new Sk.builtin.ValueError("Attempted relative import in non-package");
}
var dottedName = name.split(".");
var firstDottedName = dottedName[0];
return Sk.misceval.chain(undefined, function() {
// Attempt local load first (and just fall through to global
// case if level == -1 and we fail to load the top-level package)
if (level !== 0 && relativeToPackage !== undefined) {
if (name === "") {
// "from .. import ..."
return relativeToPackage;
} else {
return Sk.importModuleInternal_(name, undefined, relativeToPackageName + "." + name, undefined, relativeToPackage, level==-1, true);
}
}
}, function(ret) {
if (ret === undefined) {
// Either it was always a global import, or it was an
// either-way import that just fell through.
relativeToPackage = undefined;
relativeToPackageName = undefined;
return Sk.importModuleInternal_(name, undefined, undefined, undefined, undefined, false, true);
} else {
return ret;
}
}, function(ret) {
// We might also have to load modules named by the fromlist.
// If there is no fromlist, we have reached the end of the lookup, return
if (!fromlist || fromlist.length === 0) {
return ret;
} else {
// try to load from-names as modules from the file system
// if they are not present on the module itself
var i;
var fromName;
var leafModule;
var importChain;
leafModule = Sk.sysmodules.mp$subscript(
(relativeToPackageName || "") +
((relativeToPackageName && name) ? "." : "") +
name);
for (i = 0; i < fromlist.length; i++) {
fromName = fromlist[i];
// "ret" is the module we're importing from
// Only import from file system if we have not found the fromName in the current module
if (fromName != "*" && leafModule.tp$getattr(new Sk.builtin.str(fromName)) === undefined) {
importChain = Sk.misceval.chain(importChain,
Sk.importModuleInternal_.bind(null, fromName, undefined, undefined, undefined, leafModule, true, true)
);
}
}
return Sk.misceval.chain(importChain, function() {
// if there's a fromlist we want to return the leaf module
// (ret), not the toplevel namespace
Sk.asserts.assert(leafModule);
return leafModule;
});
}
}, function(ret) {
if (saveSk !== Sk.globals) {
Sk.globals = saveSk;
}
return ret;
});
};
Sk.importStar = function (module, loc, global) {
var i;
var props = Object["getOwnPropertyNames"](module["$d"]);
for (i in props) {
if (props[i].charAt(0) != "_") {
loc[props[i]] = module["$d"][props[i]];
}
}
};
Sk.exportSymbol("Sk.importMain", Sk.importMain);
Sk.exportSymbol("Sk.importMainWithBody", Sk.importMainWithBody);
Sk.exportSymbol("Sk.importBuiltinWithBody", Sk.importBuiltinWithBody);
Sk.exportSymbol("Sk.builtin.__import__", Sk.builtin.__import__);
Sk.exportSymbol("Sk.importStar", Sk.importStar);