Supporting the "with open" syntax without using contextlib.closing()
Question: I really like the syntax "with open('in_file'') as f". I want to use that
syntax for my own resources which must be opened and closed.

However, I do not understand how to change my open() method to enable the
'with' syntax. I can (and do) use the contextlib.closing() approach but it
becomes a bit bulky after repeated use.

So, I will ask my question below in relation to shelve.open(). I am not
proposing a change to the shelve module but instead am using it because the
source code is readily available to all of you.

There is nothing special about shelve.open() vs. other standard library
resources that require closing: socket.socket(), sqlite3.connect(),
urllib2.urlopen(), etc.

    
    
    import contextlib, inspect, shelve, sys
    
    #print(inspect.getsource(open))  # can not see how it was done here :-(
    
    print('-' * 40)
    # Given that we can view the source for the shelve module:
    print(inspect.getsource(shelve))
    
    print('-' * 40)
    # Given that we can view the docs for the shelve module:
    print(shelve.__doc__)
    
    #print('-' * 40)
    # Given that the desired syntax is Pythonic but is not supported:
    #with shelve.open('test_shelve') as my_shelve:
    #    my_shelve['fact_number_1'] = "There's a dead fish on the landing."
    
    # Given that the required syntax is convoluted and
    #    takes programmer attention away from the task at hand:
    with contextlib.closing(shelve.open('test_shelve')) as my_shelve:
        my_shelve['fact_number_2'] = "There's another dead fish on the landing."
    
    # Q: What changes would need to made to shelve.open() to allow the
    #    'with shelve.open(x) as y' syntax?
    

I am not really interested in an extra wrapper with a different name. Using
contextlib.closing() is easier, safer, and more intuitive than that. What I am
really interested in is creating a single open() method that can be called
either with or without 'with'.

So, to successfully answer this question, you need to take the source code for
the shelve module and show what changes would need to be made to shelve.open()
to have a single method that can be used either with or without 'with' (like
the builtin open() or the Python3 urllib.urlopen()).


Answer: The biggest problem here is that if you do

    
    
    shelf = the_function_you_want()
    

the function you want has to return the shelf, but if you do

    
    
    with the_function_you_want() as shelf:
    

the function you want has to return a context manager. That means you need to
return a shelf that is also a context manager, which in turn means you either
need to make a shelf subclass or monkey-patch `Shelf`. It's probably better to
make a subclass:

    
    
    class ContextManagerShelf(shelve.DbfilenameShelf):
        def __enter__(self):
            return self
        def __exit__(self, *exc_info):
            self.close()
    

Then you can use `ContextManagerShelf` as a context manager or not. The
signature is the same as `shelve.open`. If you want, you can also make an
`open` function to go with it.

