If I code a mistake and I do something like this:
__builtins__ = 'abcd'
and before I didn't code import builtins
is there a way to restore __builtins__
to its default value?
If I code a mistake and I do something like this:
__builtins__ = 'abcd'
and before I didn't code import builtins
is there a way to restore __builtins__
to its default value?
Let's assume even a worse case than the described situation: you completely ruin, nuke, destroy, annihilate and wipe out __builtins__
:
__builtins__.__dict__.clear()
@Matrtijn's method will fail since every module will have the very same builtins
instance.
First, we will have to restore the basic types:
__builtins__.object = "".__class__.__mro__[-1]
__builtins__.type = object.__class__
According to python docs, __mro__
attribute: is a tuple of classes that are considered when looking for base classes during method resolution. Since every python modern class extends object
, it allows us to gain instance of the object
type.
Second, We will implement a class lookup. Given a class name we will return the class' type. For that we will use type.__subclasses__()
recursively (See this question for more information about that):
def all_subclasses_of(cls):
return type.__subclasses__(cls) + [g for s in type.__subclasses__(cls) for g in all_subclasses_of(s)]
def lookup(s):
for cls in all_subclasses_of(object):
if cls.__name__ == s:
return cls
Third, We'll extract the already loaded modules using BuiltinImporter
:
bi = lookup('BuiltinImporter')
modules = bi.load_module.__globals__['sys'].modules
We take advantage of the fact that BuiltinImporter
imports sys
module and then we use sys.modules
: a dictionary that maps module names to modules which have already been loaded.
Then, We will patch __builtins__
with the required methods and classes for the next step:
__builtins__.hasattr = lambda obj, key: key in obj.__dict__
__builtins__.KeyError = lookup('KeyError')
And now, for the magic to happen!
bi.load_module('builtins')
__builtins__ = bi.load_module.__globals__['module_from_spec'](modules['builtins'].__spec__)
We generate the __spec__
to the builtins
module using builtinImporter.load_module
. Then, we load the module from the generated spec. AND IT WORKS! (I don't really know why, but it indeed works)
However, the freshly generated builtins
module misses the method open
and all of the exceptions. We will have to add them manually to get import
working again:
__builtins__.BaseException = lookup('BaseException')
__builtins__.open = lambda name, mode: modules['io'].FileIO(name, mode)
for error in all_subclasses_of(BaseException):
__builtins__.__dict__[error.__name__] = error
Congratulations, you managed to muck up your namespace good and proper! There is no easy escape from this mess, no.
You can grab the name from any Python module you perhaps have imported, or from an imported Python function:
__builtins__ = some_python_module.__builtins__
or
__builtins__ = some_python_function.__globals__['__builtins__']
The function has to be one you imported from elsewhere, so that the __globals__
reference points to a different namespace that still has a reference to the __builtins__
mapping.
One name that I found will almost always work is the __loader__
reference in modules; it is an object with methods that will still give you access a module globals object:
__builtins__ = __loader__.find_spec.__func__.__globals__['__builtins__']
Otherwise, restart your Python session, and start again.