stachyra
stachyra

Reputation: 4593

How do I import a function into a Python package without also importing the file that contains it?

I am working in Python 3.4.2 on Mac OSX and I have a simple version-controlled Python project whose directory/file structure looks like this:

vcs_projectname/
    foo/
        __init__.py
        simplefunc.py
    docs/
    other_related_stuff/

The __init__.py file looks like this:

from .simplefunc import helloworld
__all__ = ['helloworld'] # Not sure whether I really need this line...?

and the simplefunc.py file looks like this:

def helloworld():
    print('Hello world!')

I test my code by changing to a directory outside of the project hierarchy, setting my PYTHONPATH environment variable (in bash) to point at the vcs_projectname base directory, and launching ipython:

> cd ~
> export PYTHONPATH=~/vcs_projectname
> ipython

Within ipython, I import the package foo and then view its directory structure, with the following result:

In [1]: import foo

In [2]: dir(foo)
Out[2]: 
['__all__',
 '__builtins__',
 '__cached__',
 '__doc__',
 '__file__',
 '__loader__',
 '__name__',
 '__package__',
 '__path__',
 '__spec__',
 'helloworld',
 'simplefunc']

My question: how do I get rid of the reference to the simplefunc file module in the package directory structure? This is desirable to do because in the best case it is just useless clutter (we don't need it there since the thing that we actually want, the helloworld() function, has already been made available at the package level by the __init__.py file), and in the worst case it's essentially a reference to an irrelevant implementation detail (the underlying file structure of the project) that could change later, and which I therefore don't want my users to come to expect and rely upon in future versions.

Upvotes: 2

Views: 184

Answers (2)

ronakg
ronakg

Reputation: 4212

What you're trying to do is not possible elegantly. As @Lukas mentioned, there are hacks that can accomplish this.

Instead what I've been following is, create a sub-package named _private and put all such modules in there. That way when user imports the package, all the exposed APIs are available and private APIs are tucked away inside _private.

Example:

foo/
    __init__.py
    _private/
        __init__.py
        test1.py
        test2.py

foo/__init__.py:

from _private import bar, baz

foo/_private/__init__.py:

from test1 import bar
from test2 import baz

foo/_private/test1.py:

def bar():
    print "bar"

foo/_private/test2.py:

def baz():
    print "baz"

Importing foo:

>>> import foo
>>> dir(foo)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', '_private', 'bar', 'baz']

Upvotes: 3

Robᵩ
Robᵩ

Reputation: 168626

how do I get rid of the reference to the simplefunc file module in the package directory structure?

You can accomplish your stated goal by adding del simplefunc to your foo/__init__.py, like so:

from  .simplefunc import helloworld
del simplefunc
__all__ = ['helloworld'] # Not sure whether I really need this line...?

Upvotes: 2

Related Questions