Code Introspection in Minecraft and Python

I recently got around to trying out the new-ish Python mode for coding within Minecraft: Education Edition, and whilst it is refreshing to be able to write code, the lack of a code library to be able to refer to made learning the Minecraft-specific commands somewhat difficult.

Enter code introspection, which is the ability to look inside classes and methods from within Python to list them and see what is available, or to show their docstring and discover their arguments.

Unfortunately, although the dir function works within Minecraft the same way as in regular Python, the help function does not seem to.

Text Output in Minecraft

Ordinarily, the interactive shell would be the place to do this, as in the screenshots above, however Minecraft doesn't have an interactive shell for Python. In places I have no shell (for example in Processing's Python mode) you could print the output of the the dir or help, but Minecraft doesn't show the output of the print function. However it does have a method for speaking text: the say function!

Combining say() and dir()

The naive way (because print in regular Python lets you) of showing available commands for an object like the agent would be to run code like this:

say(dir(agent))

However, this will fail to run, with the possibly unhelpful error message:

Error: _minecraft_builtins.MinecraftError: Syntax error: Unexpected "[": at "~ ~ ~ say >>[<<'__class__" (Code: 0x80000000)

which basically boils down to the output of dir being a list of strings, and the say function expecting just one string. The print function will happily give you a string representation of anything, but say is not so flexible.

The solution is to join the list into one string separated by something useful like a line break:

say("\n".join(dir(agent)))

This may look a bit arcane, so let's break it down:

  • "\n" is the string we would like to join together the individual list items with.
    This is a newline character, which creates a line break, so every item will be on its own line.
  • join is a string function we call on the newline character, and takes as an argument a list of strings.
  • dir(agent) gets us the name of every attribute and method which belongs to the agent object as a list of strings.
Partial output of the dir(agent) call.
Here is the last part of the output of this code, showing what we can do with the Agent.

This works nicely. The list is long, and so only shows part of it in the world chat view, but we can open up the chat window (by pressing t or Enter) to be able to scroll through the whole list:

  • attack
  • collect
  • destroy
  • drop
  • get_item
  • get_item_count
  • give
  • inspect
  • inspect_data
  • interact
  • move
  • place
  • position
  • rotation
  • say
  • teleport
  • till
  • transfer
  • turn

You will also see a number of listings with __ or _ prepended. These are internal methods and attributes, which you generally don't want to fiddle with.

We can also use a similar technique to look at the contents of the globals dictionary, which is the collection of variables currently defined in the global scope. This gives us an idea of what objects have been created which we can poke at using the dir function (not everything is an object though).

say("\n".join(globals()))

This gives us interesting things to look at like the player, world, and user, as well as globally defined functions like spawn, and summon.

Help

Unfortunately, although there is a help function available, it doesn't seem to work the same way as the standard Python one, so the way to figure out how many of the functions and methods work is through trial and error. Generally the Python editor within Minecraft will give you useful enough errors to know how many and what type of arguments something needs to run when you get it wrong, and that combined with liberal use of good old print debugging using the say function should get you where you need to go.

For example I spent a little while poking at the agent's inspect method trying to solve one of this year's Hour of Code problems in a manner that wasn't in the instructions (didn't work, but led to this post as inspect wasn't advertised anywhere in the instructions).

First I can just try the inspect method by itself (even though knowing what it does I should expect a direction):

agent.inspect()

This gives me an error when I run it and return to Code Builder:

An inspect error
An error indicating that I need to give inspect a single argument

Now I can add in a directional argument, save the return value of that method call to a variable, and say it to determine what information the agent is actually receiving.

d = agent.inspect("down")
say(d)
Output of the inspect command
"grass" is what is under my Agent!

With a bit of perseverance, you should be able to figure out most of the undocumented features through this method.