hello_there_andy hello_there_andy - 6 days ago 7
Python Question

Check if a built-in function/class/type/module has been over-written during the script?

Question

We are getting a strange error** and we suspect it is because our script.py*** assigned a variable that already has some built-in meaning. E.g.

str = 2


Is there a way we can check if this has happened?




So far

We're thinking it would involve:


  1. Assign a list at the beggining of the script, containing all built-in objects' names as strings:

    builtin_names = get_builtin_var_names() # hypothetical function

  2. Assign a list at the end of the script, containing all user-assigned objects' names as strings:

    user_names = get_user_var_names() # hypothetical function

  3. Find the intersection, and check if not empty:

    overwritten_names = list(set(user_names) & set(builtin_names))

    if overwritten_names:
    print("Whoops")






Related






**Silent error, for those interested in it, is silent, i.e. it finishes without an error code but the value it spits out differs between two implementations of the same code, call them A and B... both versions require the running of two modules (separate files) that we've made (changes.py and dnds.py), but whereas:


  • Version A: involves running changes.py -> pickle intermediate data (into a .p file) -> dnds.py,

  • Version B: involves running changes.py -> return the data (a dict) as arguments to dnds.py -> dnds.py.



And for some reason only version A is the one with the correct final value (benchmarked against MATLAB's dnds function).

***script.py, is actually dnds.py (who has imported changes.py). You can find all the code, but to test the two alternative versions I was talking about in ** you need to specifically look at dnds.py, the line with: CTRL+F:
"#@TODO:Urgent:debug:2016-11-28:"
. Once you find that line, you can read the rest of that comment line for instructions how to replicate version B, and its resulting silent error**. For some reason I HAVE to pickle the data to get it to work... when I just return the dicts directly I get the wrong dN/dS values.

Answer

You can get the names (and values) of builtins via the dict __builtins__. You can get the names (and values) of global variables with globals() and of locals with locals(). So you could do something like:

import __builtin__
name, val = None, None
for name, val in locals().iteritems():
    if hasattr(__builtin__, name) and getattr(__builtin__, name) != val:
        print("{} was overwritten!".format(name))

and then the same for globals(). This will check whether there is any object in the local namespace that has a different value in the builtins namespace. (Setting name and val to None is needed so that the variables exist before calling locals, or else you'll get a "dictionary changed sized during iteration" error because the names are added partway through the loop.)

You could also use a tool like pylint which checks for such errors among many others.