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.