How can I keep imported modules from being accessible (i.e., clogging my code-completion options)?
For example:
# testmodule.py
import os
def o_stuff():
return
When I import testmodule, I don't want os to show up every time I type testmodule.; I only want the functions/classes declared within testmodule – in this case, just o_stuff.
Is there something similar to the asterisk (i.e., from testmodule import *) that will do this?
You can define a special variable __all__ containing a list of the names to be imported by from module import * - for example:
# testmodule.py
import os
__all__ = ['o_stuff', 'more_stuff']
def o_stuff():
pass
def more_stuff():
pass
IDEs with code-completion will typically also respect __all__ (though I'm unfamiliar with Visual Studio, so I don't know whether IntelliSense does so).
An alternative, included here for completeness although I would strongly recommend against it (on the grounds that it'll annoy anyone reading your code to distraction) is to import modules as an underscore-prefixed alias:
# ugly_as_sin.py
import os as _os
def o_stuff():
return _os.name
Again, both from module import * and, typically, code-completion will ignore underscore-prefixed names.
You can try to use the __all__ in your module to see if it helps.
import os
__all__ = ['o_stuff']
def o_stuff():
return
Not familiar with Intellisense but it sounds like it could also use a bit of fine-tuning.
Related
I am importing a module in python as this:
from myutils.user_data import *
How do I find out what are the list of methods that I have imported?
I know one workaround from here:
How to list all functions in a Python module?
being:
from inspect import getmembers, isfunction
import myutils.user_data as module_name
functions_list = getmembers(module_name, isfunction)
print(functions_list)
but this would oblige me to use the nomenclature:
module_name.mehtodA() whereas I would like to be able to use the methods as such methodA()
of course I can do:
from myutils.user_data import *
import myutils.user_data as module_name
but this is actually importing two times.
Any idea?
EDIT: Why do I need this? I am creating documentation for a module in a JupyterHub environment (in premises). I create this documentation using notebooks, i.e. anyone interested in finding out the use of a particular .py file (including utility methods) can open the notebook and play around AND the jupyter notebook can be rendered as a web site with voila. In that case I would like to print all the methods included in the particular .py file.
This is also a question that just made me curious. Someone commented you would never import with * a module. Well, why not if you know what you are importing being a few very small methods.
Generally you are rarely recommended to use the from ... import * style, because it could override local symbols or symbols imported first by other modules.
That beeing said, you could do
symbols_before = dir()
from myutils.user_data import *
symbols_after = dir()
imported_symbols = [s for s in symbols_after if not s in symbols_before]
which stores the freshly imported symbols in the imported_symbols list.
Or you could use the fact, that the module is still loaded into sys.modules and do
import sys
from inspect import getmembers, isfunction
from myutils.user_data import *
functions_list = getmembers(sys.modules['myutils.user_data'], isfunction)
print(functions_list)
Let's say I have a file where I'm importing some packages:
# myfile.py
import os
import re
import pathlib
def func(x, y):
print(x, y)
If I go into another file and enter
from myfile import *
Not only does it import func, but it also imports os, re, and pathlib,
but I DO NOT want those modules to be imported when I do import *.
Why is it importing the other packages I'm importing and how do you avoid this?
The reason
Because import imports every name in the namespace. If something has a name inside the module, then it's valid to be exported.
How to avoid
First of all, you should almost never be using import *. It's almost always clearer code to either import the specific methods/variables you're trying to use (from module import func), or to import the whole module and access methods/variables via dot notation (import module; ...; module.func()).
That said, if you must use import * from module, there are a few ways to prevent certain names from being exported from module:
Names starting with _ will not be imported by import * from .... They can still be imported directly (i.e. from module import _name), but not automatically. This means you can rename your imports so that they don't get exported, e.g. import os as _os. However, this also means that your entire code in that module has to refer to the _os instead of os, so you may have to modify lots of code.
If a module contains the name __all__: List[str], then import * will export only the names contained in that list. In your example, add the line __all__ = ['func'] to your myfile.py, and then import * will only import func. See also this answer.
from myfile import func
Here is the fix :)
When you import *, you import everything from. Which includes what yu imported in the file your source.
It has actually been discussed on Medium, but for simplification, I will answer it myself.
from <module/package> import * is a way to import all the names we can get in that specific module/package. Usually, everyone doesn't actually use import * for this reason, and rather sticked with import <module>.
Python's import essentially just runs the file you point it to import (it's not quite that but close enough). So if you import a module it will also import all the things the module imports. If you want to import only specific functions within the module, try:
from myfile import func
...which would import only myfile.func() instead of the other things as well.
in myModule.py I am importing environ from os , like
from os import environ since I am only using environ, but when I do dir(myModule) it shows environ as publicly visible , how ever should it be imported as protected assuming some other project may also have its own environ function ?
If you're doing from os import environ, then you'll reference it as environ.
If you do import os, it's os.environ.
So depending on your needs, the second option might be better. The first will look better and read easier, whereas the second avoids namespace pollution.
Expanding on #mgilson's comment - when you do dir(somemodule), everything you see is namespaced to that module. In other words, you have to use the . (name resolution operator) to "reach" those items.
So, in myModule.py you have the following lines:
from os import environ
a = 4
In some other module, or the Python prompt, you have the following statements:
import myModule
dir(myModule)
Now, in order to get to a or environ that is inside myModule, you'd have to explicitly define its scope:
print(a) # this won't work
print(myModule.a) # this will print 4
In Python as a general rule, there is no explicit hiding/protecting. Python expects its users to be consenting adults and "know what they are doing".
However, developers can control what happens when someone tries to import everything from a module (from myModule import *), but this isn't strictly enforced. You can still get to everything inside myModule by prefixing the module name.
I have written a small Python library, currently hosted at BitBucket. As you can see, the library is called pygpstools, and it's made from 5 files:
gpstime.py → A class
satellite.py → A class
geodesy.py → A module with some geodesy methods
almanacs.py → A module with some almanac methods
constants.py → Some constants
I want to use it as written at the README. For example:
from pygpstools import GPSTime
GPSTime(wn=1751, tow=314880)
or:
import pygpstools
pygpstools.GPSTime(wn=1751, tow=314880)
But after installing my library with command python setup.py install I'm getting ImportError when trying to access GPSTime class like this.
I guess the problem is at the __init__.py file. When I asked about this at the python IRC channel, I was told that leaving it empty does the trick. But I have researched and it looks like that only tells Python that it is a module, but it is not enough to allow this kind of importing I'm looking for, as at any other library out there.
So I have tried (not currently updated at bitbucket) to use this as __init__.py:
__title__ = 'pygpstools'
__version__ = '0.1.1'
__author__ = 'Roman Rodriguez'
__license__ = 'MIT'
__copyright__ = 'Copyright 2013 Roman Rodriguez'
import almanacs
import constants
import geodesy
import gpstime
import satellite
but still doesn't work: ImportError for GPSTime.
What am I missing?
GPSTime, for example, is in the module gpstime, so its actual (relative) name is gpstime.GPSTime. So when you import gpstime in your __init__ you are actually making available the name gpstime which holds a reference to your type as gpstime.GPSTime.
So you would have to use from pygpstools import gpstime and then gpstime.GPSTime as the type name.
Obviously this is not what you want, so instead, you want to “collect” all your types in the __init__ module. You can do that by just making them available directly:
from almanacs import *
from constants import *
from geodesy import *
from gpstime import GPSTime
from satellite import *
I have used * now to import anything because I didn’t take a closer look at what actual types there are in your files. You should specify it though. It is also recommended, to define an __all__ list in your __init__ so that you can control which names are imported when writing from pygpstools import *.
Is there a place when I can put default imports for all my modules?
If you want default imports when using the python shell you can also set the PYTHONSTARTUP environmental variable to point to a python file that will be executed whenever you start the shell. Put all your default imports in this file.
Yes, just create a separate module and import it into yours.
Example:
# my_imports.py
'''Here go all of my imports'''
import sys
import functools
from contextlib import contextmanager # This is a long name, no chance to confuse it.
....
# something1.py
'''One of my project files.'''
from my_imports import *
....
# something2.py
'''Another project file.'''
from my_imports import *
....
Note that according to standard guidelines, from module import * should be avoided. If you're managing a small project with several files that need common imports, I think you'll be fine with from module import *, but it still would be a better idea to refactor your code so that different files need different imports.
So do it like this:
# something1.py
'''One of my project files. Takes care of main cycle.'''
import sys
....
# something2.py
'''Another project file. Main program logic.'''
import functools
from contextlib import contextmanager # This is a long name, no chance to confuse it.
....