How to make statement `import datetime` bind the datetime type instead of the datetime module?
Question: After one too many times having accidentally typed `import datetime` when what
was really needed was `from datetime import datetime`, I wondered whether it
was possible to hack around and make the former do the latter.

That is, to recreate this behaviour (in a freshly opened interpreter session):

    
    
    $ python -ic ''
    >>> import datetime
    >>> datetime(2016, 5, 27)
    datetime.datetime(2016, 5, 27, 0, 0)
    

Came pretty close to faking a "callable module" below:

    
    
    >>> import dt
    >>> dt(2016, 5, 27)
    datetime.datetime(2016, 5, 27, 0, 0)
    

Which was implemented like this:

    
    
    # dt.py
    import sys
    import datetime
    
    class CallableModule(object):
        def __init__(self, thing):
            self.thing = thing
        def __call__(self, *args, **kwargs):
            return self.thing.__call__(*args, **kwargs)
    
    sys.modules['dt'] = CallableModule(datetime.datetime)
    

However it doesn't work if I try to use the filename `datetime.py` for the
module, and I could not yet find any hack to get at the built-in datetime
module when my own file was also called `datetime.py`.

How can we _temporarily unhide_ a built-in or site-packages module, from
within the shadowing module itself? Is there any indirect way to get at the
core `datetime` under this situation (perhaps similar to how we can still
access `sys.__stdout__` even when `sys.stdout` has been redirected)?

**Disclaimer** : In no way suggesting that this is a sane idea - just
interested if it's _possible_.


Answer: Here we go:

`datetime.py`:

    
    
    import sys
    import imp
    import os
    
    path = [p for p in sys.path if p != os.path.dirname(__file__)]
    f, pathname, desc = imp.find_module('datetime', path)
    std_datetime = imp.load_module('datetime', f, pathname, desc)
    # if this^ is renamed to datetime, everything breaks!
    f.close()
    
    class CallableModule(object):
    
        def __init__(self, module, fn):
            self.module = module
            self.fn = fn
    
        def __call__(self, *args, **kwargs):
            return self.fn(*args, **kwargs)
    
        def __getattr__(self, item):
            try:
                return getattr(self.fn, item)
            except AttributeError:
                return getattr(self.module, item)
    
    sys.modules['datetime'] = CallableModule(std_datetime, std_datetime.datetime)
    

`test.py` (lives next to `datetime.py`):

    
    
    import datetime
    
    print(datetime(1, 2, 3))
    print(datetime.timedelta(days=1))
    print(datetime.now())
    

Run `test.py`, output:

    
    
    0001-02-03 00:00:00
    1 day, 0:00:00
    2016-05-27 23:16:30.954270
    

It also works with `from datetime import datetime, timedelta` etc.

This is especially hacky and fragile and will depend on your distribution. For
example, apparently it doesn't work with IPython. You must import
`datetime.py` before the standard library module.

To understand just how weird things get with this, if the variable
`std_datetime` (the datetime module object) is renamed to `datetime`, then
`datetime.datetime` is no longer the class, but rather `datetime is
datetime.datetime is datetime.datetime.datetime ...`. If someone can explain
why this happens, I'd love to hear it.

(note that the first comment below is from before I got to the final version)

