I wanted to use the following code from here:
How can I save all the variables in the current python session?
import shelve
T='Hiya'
val=[1,2,3]
filename='/tmp/shelve.out'
my_shelf = shelve.open(filename,'n') # 'n' for new
for key in dir():
try:
my_shelf[key] = globals()[key]
except TypeError:
#
# __builtins__, my_shelf, and imported modules can not be shelved.
#
print('ERROR shelving: {0}'.format(key))
my_shelf.close()
But it gives the following error:
Traceback (most recent call last):
File "./bingo.py", line 204, in <module>
menu()
File "./bingo.py", line 67, in menu
my_shelf[key] = globals()[key]
KeyError: 'filename'
Can you help me please?
Thanks!
From your traceback, it appears you are trying to run that code from inside a function.
But dir looks up names in the current local scope. So if filename is defined inside the function, it will be in locals() rather than globals().
You probably want something more like this:
import shelve
T = 'Hiya'
val = [1, 2, 3]
def save_variables(globals_=None):
if globals_ is None:
globals_ = globals()
filename = '/tmp/shelve.out'
my_shelf = shelve.open(filename, 'n')
for key, value in globals_.items():
if not key.startswith('__'):
try:
my_shelf[key] = value
except Exception:
print('ERROR shelving: "%s"' % key)
else:
print('shelved: "%s"' % key)
my_shelf.close()
save_variables()
Note that when globals() is called from within the function, it returns the variables from the module where the function is defined, not from where it's called.
So if the save_variables function is imported, and you want the variables from the current module, then do:
save_variables(globals())
Related
I created a class and function. the function is creating a new object and executing other operations and returns the object.
class DoublyLinkedList:
def __init__(self, element):
self.item = element
self.before = None
self.after = None
def __str__(self):
if self.before is None:
return f'Previous node : {None}, item : {self.item}, Next node : {self.after.item};'
elif self.after is None:
return f'Previous node : {self.before.item}, item : {self.item}, Next node : {None};'
else:
return f'Previous node : {self.before.item}, item : {self.item}, Next node : {self.after.item};'
def addToHeadDLL(element, head):
try:
name = DoublyLinkedList(element)
except NameError:
print('Please enter correct parameters')
else:
head.before = name
name.after = head
print('List added to Head')
return name
a = DoublyLinkedList(1)
b = DoublyLinkedList(2)
a.after = b
b.before = a
c = addToHeadDLL(3, a) #Works
d = addToHeadDLL(4, e) #Produces NameError
When NameError occurs it has to print "Please enter correct parameters". But the output is like this,
List added to Head
Traceback (most recent call last):
File "c:/Users/JBallipalli/Desktop/Codes/dll.py", line 43, in <module>
d = addToHeadDLL(4, e)
NameError: name 'e' is not defined
Please help me solve this...
EDIT:
It's not that try-except- else not run in function. Check the following code. it does run.
import os
def openfolder(dir):
"""Opens folder in file explorer
Args:
dir (str): path of the folder
"""
os.startfile(dir)
def access(dir):
"""Checking access to the given directory
Args:
dir (str): directory path
Returns:
bool, list: status, list of files & folders in the directory path
"""
try:
filesList = os.listdir(dir)
except PermissionError:
print(f'No permission to access {os.path.basename(dir)}')
print(f'Please delete the file in {os.path.basename(dir)} manually')
folder = input('Do you wanna open folder in file explorer? type y/n : ')
if folder[0].lower() == 'y':
openfolder(dir)
return False, None
else:
return True, filesList
path = r'C:\Users\JBallipalli\Recent' # raises PermissionError
permission, files = access(path)
and check the output:
No permission to access Recent
Please delete the file in Recent manually
Do you wanna open folder in file explorer? type y/n :
The only difference between these two functions is above (DoublyLinkedList) code calls class inside a function and other doesn't. I want to know why its behaviour like that?
my Python version : 3.7.6
NameError is returned when you're calling function, as python doesn't know what to pass as e.
It never gets to the exception handling part in addToHeadDLL.
Do not use try and except in function,
If You want NameError then call function addToHeadDLL in try block.
Like that
try:
d = addToHeadDLL(4, e) #Produces NameError
except:
print("Name error")
To add to what everyone have said, you could modify you code like the sample below to fit your use case...
This time, you handle the error at function level...
def addToHeadDLL(element, head):
name = DoublyLinkedList(element)
if not isinstance(head, type(name)):
raise NameError('Please enter correct parameters')
head.before = name
name.after = head
print('List added to Head')
return name
a = DoublyLinkedList(1)
b = DoublyLinkedList(2)
a.after = b
b.before = a
try:
addToHeadDLL(4, e)
except NameError as e:
print(e)
suppose I have the following function:
def test():
...
if x['error']:
raise
This would raise an exception regardless if x['error'] is defined or not.
Instead if I try this, it doesn't throw any exception:
def test():
...
try:
if x['error']:
raise
except:
return
How can I test for a specific value and return an exception if it is defined, and to return successfully if it is not defined?
If you want to return error as string:
>>> def test():
try:
if x['error']:raise
except Exception as err:
return err
>>> test()
NameError("name 'x' is not defined",)
If you want to an error to occur:
>>> def test():
try:
if x['error']:raise
except:
raise
>>> test()
Traceback (most recent call last):
File "<pyshell#20>", line 1, in <module>
test()
File "<pyshell#19>", line 3, in test
if x['error']:raise
NameError: name 'x' is not defined
def test():
...
if x.get(‘error’):
raise
You can avoid unintentionally raising an error using the dictionary's built in get function. Get will return None if the value at the specified key does not exist instead of throwing an exception.
try this one
def check_not_exist(d,k):
#if keys exists in dict,raise it
if k in d:
raise
else:
return True
I have a function which load data into a dictionnary.
But, How can I load the dictionnary into Globals() inside a function.
Inside a function is important since we can do it easily outside on a script side.
def load237(filename):
filename = osp.abspath(filename)
old_cwd = os.getcwdu()
os.chdir(osp.dirname(filename))
error_message = None
try:
tar = tarfile.open(filename, "r")
tar.extractall()
pickle_filename = osp.splitext(filename)[0]+'.pickle'
data = cPickle.load(file(pickle_filename))
saved_arrays = {}
if load_array is not None:
try:
saved_arrays = data.pop('__saved_arrays__')
for (name, index), fname in saved_arrays.iteritems():
arr = np.load( osp.join(osp.dirname(filename), fname) )
if index is None:
data[name] = arr
elif isinstance(data[name], dict):
data[name][index] = arr
else:
data[name].insert(index, arr)
except KeyError:
pass
for fname in [pickle_filename]+[fn for fn in saved_arrays.itervalues()]:
os.remove(fname)
except (EOFError, ValueError), error:
error_message = unicode(error)
os.chdir(old_cwd)
return data, error_message
This one does not work (globals is local to the module/function...)
def load_inmemory(fpath):
globals().update(load237(fpath)[0])
You should really be storing those names on an object stored in a global and not as global variables. But you asked how to do it and so here is how:
Using Getting corresponding module from function with a for loop and setattr as modules do not support dictionary operations and it is possible to write the function as:
import sys
def load_inmemory():
module = sys.modules[load_inmemory.__module__]
for k, v in load237(fpath)[0].items():
setattr(module, k, v)
load_inmemory()
print x
I tested the following:
import sys
def func():
module = sys.modules[func.__module__]
for k,v in {'x':4}.items():
setattr(module, k, v)
func()
print x
Prints 4. Tested in Python 2.7.3.
I'm trying to mimic the matlab load and save functions. I'm following this thread: Shelve Code gives KeyError
It is smart. However, if I write that code in a separate module, and try to import that module and invoke that function, then it can't access the global variables.
Specifically, I write a happy.py and have the functions inside:
def save(filename='tmp', globals_=None):
if globals_ is None:
globals_ = globals()
globals()
import shelve
my_shelf = shelve.open(filename, 'n')
for key, value in globals_.items():
if not key.startswith('__'):
try:
my_shelf[key] = value
except Exception:
print('ERROR shelving: "%s"' % key)
else:
print('shelved: "%s"' % key)
my_shelf.close()
def load(filename='tmp', globals_=None):
import shelve
my_shelf = shelve.open(filename)
for key in my_shelf:
globals()[key] = my_shelf[key]
my_shelf.close()
and when I try
a = 1
b = 2
happy.save()
It would not give save a and b.
Is this because global() would not give the objects outside the module? How can I do what I want to do then?
The following will work as a separate module:
import shelve
import sys
import types
EXCLUDED_TYPES = (types.ModuleType,) # Everything can't be shelved.
def save(filename='tmp', globals_=None):
if globals_ is None:
globals_ = sys._getframe(1).f_globals # Caller's globals.
with shelve.open(filename, 'n') as my_shelf:
for key, value in globals_.items():
if not (key.startswith('__') or isinstance(value, EXCLUDED_TYPES)):
try:
my_shelf[key] = value
except Exception as e:
print('ERROR shelving: "%s"' % key, 'Exception:', e)
else:
print('shelved: "%s"' % key)
def load(filename='tmp', globals_=None):
if globals_ is None:
globals_ = sys._getframe(1).f_globals # Caller's globals.
with shelve.open(filename) as my_shelf:
for key in my_shelf:
globals_[key]=my_shelf[key]
print('unshelved: "%s"' % key)
Generally speaking, I don't think it's a good idea for a function to create global variables like this. Also note that load() might silently change existing values in the caller's namespace.
You can't easily save all global namespaces, since there's one associated with every module loaded, in addition to __main__'s. If you really want to do that, it might be possible to do so by iterating through the contents of sys.modules.
You can use inspect to look at the stack. This silly (poorly named function) that I've defined seems to do an OK job of picking up the global variables from the calling namespace although I haven't tested it extensively. I am also unsure about whether it will work with different python implementations. (I mention this because the inspect.currentframe function is definitely implementation dependent). It seems to work OK with Cpython for what it's worth.
import inspect
def save(globals=None):
if globals is None:
frames = inspect.stack()
caller_frame = frames[-1][0]
globals = dict((k,v) for (k,v) in caller_frame.f_globals.items() if not k.startswith('__'))
return globals
if __name__ == "__main__":
a = 1
b = 2
print save()
I don't have a problem with this code when it is pasted into an console:
>>> def save(filename='tmp',globals_=None):
... import shelve
... globals_ = globals_ or globals()
... my_shelf= shelve.open(filename, 'n')
... for key, value in globals_.items():
... if not key.startswith('__'):
... try:
... my_shelf[key] = value
... except Exception:
... print('ERROR shelving: "%s"' % key)
... else:
... print('shelved: "%s"' % key)
... my_shelf.close()
...
>>> def load(filename='tmp',globals_=None):
... import shelve
... my_shelf = shelve.open(filename)
... for key in my_shelf:
... globals()[key]=my_shelf[key]
... my_shelf.close()
...
>>> a, b = 1, 2
>>> save()
shelved: "load"
shelved: "a"
shelved: "b"
shelved: "save"
And then:
>>> def save(filename='tmp',globals_=None):
... import shelve
... globals_ = globals_ or globals()
... my_shelf= shelve.open(filename, 'n')
... for key, value in globals_.items():
... if not key.startswith('__'):
... try:
... my_shelf[key] = value
... except Exception:
... print('ERROR shelving: "%s"' % key)
... else:
... print('shelved: "%s"' % key)
... my_shelf.close()
...
>>> def load(filename='tmp',globals_=None):
... import shelve
... my_shelf = shelve.open(filename)
... for key in my_shelf:
... globals()[key]=my_shelf[key]
... my_shelf.close()
...
>>> load()
>>> a, b
(1, 2)
But it is a bit odd when you use it as a module:
>>> from happy import *
>>> a, b
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> load()
>>> a, b
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> happy.a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'happy' is not defined
>>> from happy import *
>>> a, b
(1, 2)
Is there enough here for you to have a work-around?
I'm working on a mail-sending library, and I want to be able to catch exceptions produced by the senders (SMTP, Google AppEngine, etc.) and wrap them in easily catchable exceptions specific to my library (ConnectionError, MessageSendError, etc.), with the original traceback intact so it can be debugged. What is the best way to do this in Python 2?
The simplest way would be to reraise with the old trace object. The following example shows this:
import sys
def a():
def b():
raise AssertionError("1")
b()
try:
a()
except AssertionError: # some specific exception you want to wrap
trace = sys.exc_info()[2]
raise Exception("error description"), None, trace
Check the documentation of the raise statement for details of the three parameters. My example would print:
Traceback (most recent call last):
File "C:\...\test.py", line 9, in <module>
a()
File "C:\...\test.py", line 6, in a
b()
File "C:\...\test.py", line 5, in b
raise AssertionError("1")
Exception: error description
For completeness, in Python 3 you'd use the raise MyException(...) from e syntax.
This answer is probably a little bit late, but you can wrap the function in a python decorator.
Here is a simple cheatsheet on how different decorators.
Here is some sample code of how to do this. Just change the decorator to catch different errors in the different ways that you need.
def decorator(wrapped_function):
def _wrapper(*args, **kwargs):
try:
# do something before the function call
result = wrapped_function(*args, **kwargs)
# do something after the function call
except TypeError:
print("TypeError")
except IndexError:
print("IndexError")
# return result
return _wrapper
#decorator
def type_error():
return 1 / 'a'
#decorator
def index_error():
return ['foo', 'bar'][5]
type_error()
index_error()
Use raise_from from the future.utils package.
Relevant example copied below:
from future.utils import raise_from
class FileDatabase:
def __init__(self, filename):
try:
self.file = open(filename)
except IOError as exc:
raise_from(DatabaseError('failed to open'), exc)
Within that package, raise_from is implemented as follows:
def raise_from(exc, cause):
"""
Equivalent to:
raise EXCEPTION from CAUSE
on Python 3. (See PEP 3134).
"""
# Is either arg an exception class (e.g. IndexError) rather than
# instance (e.g. IndexError('my message here')? If so, pass the
# name of the class undisturbed through to "raise ... from ...".
if isinstance(exc, type) and issubclass(exc, Exception):
e = exc()
# exc = exc.__name__
# execstr = "e = " + _repr_strip(exc) + "()"
# myglobals, mylocals = _get_caller_globals_and_locals()
# exec(execstr, myglobals, mylocals)
else:
e = exc
e.__suppress_context__ = False
if isinstance(cause, type) and issubclass(cause, Exception):
e.__cause__ = cause()
e.__suppress_context__ = True
elif cause is None:
e.__cause__ = None
e.__suppress_context__ = True
elif isinstance(cause, BaseException):
e.__cause__ = cause
e.__suppress_context__ = True
else:
raise TypeError("exception causes must derive from BaseException")
e.__context__ = sys.exc_info()[1]
raise e