Search code examples
pythonpython-3.xwith-statementshelve

Shelve gives AttributeError in Python 3.3 for hello world example using the "with shelve.open" syntax, but not without it


I'm trying to use shelve with Python 3.3. It is recommended to use the with shelve.open('spam.db') as db:... syntax to ensure we close the "connection". However, when I try it I get the following error AttributeError: __exit__. What gives? Any thoughts? Many similar questions here, although couldn't find a satisfying solution. The following shows what I have attempted thus far:

The following fails:

import shelve
with shelve.open('spam.db') as db:
    db['key'] = 'value'
    print(db['key'])

Error message:

Traceback (most recent call last):
  File "D:\arbitrary_path_to_script\nf_shelve_test.py", line 3, in <module>
    with shelve.open('spam.db') as db:
AttributeError: __exit__
[Finished in 0.1s with exit code 1]

The following works:

import shelve
db = shelve.open('spam.db')
db['key'] = 'value'
print(db['key'])
db.close()

And outputs the expected:

value
[Finished in 0.1s]

Printing the shelve module path

import shelve
print(shelve)

Location:

<module 'shelve' from 'C:\\Python33\\lib\\shelve.py'>
[Finished in 0.1s]

Solution

  • In Python 3.3 shelve.open() is not a context manager and cannot be used in a with statement. The with statement expects there to be __enter__ and __exit__ methods; the error you see is because there are no such methods.

    You can use contextlib.closing() to wrap the shelve.open() result in a context manager here:

    from contextlib import closing
    
    with closing(shelve.open('spam.db')) as db:
    

    Alternatively, upgrade to Python 3.4, where the required context manager methods were added to the return value of shelve.open(). From the shelve.Shelve documentation:

    Changed in version 3.4: Added context manager support.