laike9m
laike9m

Reputation: 19388

Inspecting Python object in Pyodide

Pyodide is quite new, but I would be interested to know if there's a way to let users inspect Python objects like they can do with Js objects. For example, right now if you print a dict in pyodide, the output is a string:

image

But if you console.log a JavaScript object, it outputs something that the brower understands, and you can click to expand and see it's attributes.

image

For debugging, I think this kind of utility is necessary, almost all IDEs have it. With pyodide creates a full Python environment, I wouldn't expect this to be too hard.

Upvotes: 2

Views: 570

Answers (1)

Sebastiaan van der Tol
Sebastiaan van der Tol

Reputation: 131

You can send python objects to the console. On the python side you can do

pyodide.runPython(`
   myvar = {"msg": "Hello from python"}
   from js import console
   console.log(myvar)
`);

and on the javascript side you can

console.log(pyodide.globals.myvar);

Basic python types are converted to their javascript equivalent and can be inspected directly. Other types are wrapped in Proxy object. The information shown in chrome devTools console window is not very helpful for these types.

However chrome devTools can be extended with a custom formatter like this

(function() {
  var formatter = {
    header: function(x, config) {
      if (config && config.PyProxyFormatter) {
        return ["div", {"width": "100px"}, config.key + ": " + String(x)];
      }
      if (typeof x === 'function' &&
            pyodide._module.PyProxy.isPyProxy(x)) {
        return ["div", {}, String(x)];
      }
      return null;
    },
    hasBody: function(x) {
      return true;
    },
    body: function(x, config) {
      var level = config !== undefined ? config.level : 0;
      if (typeof x === 'function' &&
            pyodide._module.PyProxy.isPyProxy(x)) {
        var keys = pyodide.globals.dir(x);
        var elements = keys.map(function(key) {
          var childObj = x[key];
          var child;
          if (typeof childObj === 'object' ||
              (typeof childObj === 'function' &&
               pyodide._module.PyProxy.isPyProxy(childObj))) {
            child = ["object", { 
               object: childObj, 
               config: {PyProxyFormatter: true, key: key, level: level + 1}}];
          } else {
            child = key + ": " + String(childObj);
          }
          return ["div", {style: "margin-left: " + level*20 + "px"}, child];
        });
        return ["div", {}].concat(elements);
      } else {
        return ["div", {}, ["object", { object: x}]];
      }
    }
  };
  window.devtoolsFormatters = [formatter];
}
)();

Upvotes: 4

Related Questions