Conditional import in a module - python

I have created a module modA which I am importing in my main program. Depending on what happens in my main program (it has an interactive mode and a batch script mode), I want modA itself to import matplotlib with either the TkAgg backend or the ps backend. Is there a way for my main program to communicate information to modA to tell it how it should import matplotlib?
To clarify the situation:
The main program:
#if we are in interactive mode
#import modA which imports matplotlib using TkAgg backend
#else
#import modA which imports matplotlib using the ps backend
Module modA:
#import matplotlib
#matplotlib.use('ps') or matplotlib.use('TkAgg') (how can I do this?)

Have a function in your module which will determine this.
import matplotlib
def setEnv(env):
matplotlib.use(env)
Then in your program you can have modA.setEnv('ps') or something else based on if-else statement condition.
You do not need a conditional import here (since you are using only one external module), but it is possible to do it:
if condition:
import matplotlib as mlib
else:
import modifiedmatplotlib as mlib
For more information about importing modules within function see these:
Python: how to make global imports from a function
Is it possible to import to the global scope from inside a function (Python)?

You can probably detect the way your session is started by evaluating the arguments passed to the command line:
import sys
import matplotlib
if '-i' in sys.argv:
# program started with an interactive session
matplotlib.use('TkAdd')
else:
# batch session
matplotlib.use('ps')
If not, you can use os.environ to communicate between modules:
In main:
import os
if interactive:
os.environ['MATPLOTLIB_USE'] = 'TkAdd'
else:
os.environ['MATPLOTLIB_USE'] = 'ps'
In modA:
import os
import matplotlib
matplotlib.use(os.environ['MATPLOTLIB_USE'])

Related

Python - Importing packages by running a script

I have a script which is importing lots of packages, including import numpy as np.
I have lots of scripts which need to import all of these packages (including some of my own). To make my life easier, I have a file called mysetup.py in my path to import all the packages. It includes the statement in a function called "import numpy as np".
I run "main.py". It runs the following
from mysetup import *
import_my_stuff()
np.pi()
"mysetup.py"
def import_my_stuff():
import numpy as np
return
However, I am unable to use numpy in "main.py" - this code will fail. Any suggestions as to why?
The problem you are facing is a consequence of a very important features of Python: namespaces.
https://docs.python.org/3/tutorial/classes.html#python-scopes-and-namespaces
https://realpython.com/python-namespaces-scope/
Basically, in your case, when you do that (numpy) import inside the (import_my_stuff) function, you are defining the code object numpy/np inside the function namespace. (scope, if you prefer).
To solve your issue (the way you are doing; not the only way), you should simply import everything at the module top level (without a function encapsulating the imports):
mysetup.py:
import numpy as np
# other modules...
main.py:
from mysetup import *
np.pi()
Imports in functions are not the best idea.
But you can just define whatever imports you need in top level code of mysetup.py
import numpy as np
and then it will be available when you import * from mysetup
from mysetup import *
print(np.pi)

how to only import module if necessary and only once

I have a class which can be plotted using matplotlib, but it can (and will) also be used without plotting it.
I would like to only import matplotlib if necessary, ie. if the plot method is called on an instance of the class, but at the same time I would like to only import matplotlib once if at all.
Currently what I do is:
class Cheese:
def plot(self):
from matplotlib import pyplot as plt
# *plot some cheese*
..but I suppose that this may lead to importing multiple times.
I can think of lots of ways to accomplish only importing once, but they are not pretty.
What is a pretty and "pythonic" way of doing this?
I don't mean for this to be "opinion based", so let me clarify what I mean by "pretty":
using the fewest lines of code.
most readable
most efficient
least error-prone
etc.
If a module is already loaded then it won't be loaded again. you will just get a reference to it. If you don't plan to use this class locally and just want to satisfy the typehinter then you can do the following
#imports
#import whatever you need localy
from typing import TYPE_CHECKING
if TYPE_CHECKING: # False at runtime
from matplotlib import pyplot as plt
Optional import in Python:
try:
import something
import_something = True
except ImportError:
import something_else
import_something_else = True
Conditional import in Python:
if condition:
import something
# something library related code
elif condition:
# code without library
import related to one function:
def foo():
import some_library_to_use_only_inside_foo
TLDR; Python does so for you already, for free.
Python import machinery imports module only once, even if it was imported multiple times. Even from different files (docs).
The most pythonic way to import something is to do so at the beginning of file. Unless you have special needs, like import different modules depending on some condition, eg. platform (windows, linux).

pythonic way to do checks before imports

I have to develop python code for an inhouse framework which can either run in the system's standard python environment or sometimes requires a custom environment to be active. For example, to be able to load certain modules.
Because an ImportError might not be too obvious for any user, I would like to give the user a proper error message, explaining the issue.
Some sample code might look like this:
# standard imports...
import sys
import numpy as np
# import which requires special environment
import myspecialmodule
# [...]
One method would be to check for ImportErrors like this:
# standard imports...
import sys
import numpy as np
# import which requires special environment
try:
import myspecialmodule
except ImportError:
print('not in the env', file=sys.stderr)
sys.exit(1)
# [...]
However, that is quite tedious to do, especially if there are many such scripts or if there are many imports. The question is then, which import has failed, if you do not want to repeat the try/except several times.
Now, I wrote a function guard() which checks for the existence of the environment in another way:
import sys
import os
def guard():
# assume the environment sets this special variable
if 'MYSPECIALENV' in os.environ:
# do more checks if the environment is correctly loaded
# if it is, simply:
return
print("The environment is not loaded correctly. "
"Run this script only in the special environment", file=sys.stderr)
sys.exit(1)
I altered the imports on the script:
# standard imports...
import sys
import numpy as np
# import which requires special environment
guard()
import myspecialmodule
# [...]
The advantage over the try/except method is, that an ImportError is still raised even if the environment is loaded.
But the issue is, that code linters like isort do not like function calls before imports.
Now, one could add configuration to isort to skip this section...
Furthermore, for a reader of the code, it might not be too obvious what is going on.
Of course, I could add some comments explaining it...
Another method I thought of is to write a module which does the job of guard, i.e.:
# file: guard/__init__.py
import sys
import os
if 'MYSPECIALENV' not in os.environ:
print("The environment is not loaded correctly. "
"Run this script only in the special environment", file=sys.stderr)
sys.exit(1)
# standard imports...
import sys
import numpy as np
# import which requires special environment
import guard
import myspecialmodule
# [...]
but this might be even less obvious, especially as imports might be sorted in a different way (again thinking about isort).
Is there a better, more pythonic way to do such things before importing a module? Especially one that is obvious for a future developer as well.

Name re is not defined although re is imported in module and in main code

I'm working on a Jupyter Notebook for my master's thesis and I'd like to keep it clean. I use a lot of functions to assign categories to groups of data.
Therefore, I've decided to put all those functions in a functions.py module which I import at the start of my notebook. My notebook has the following imports:
import sys
sys.path.append('../src/') # ugly hack to be able to import the functions module
import re
import numpy as np
import pandas as pd
import seaborn as sns
import functions as fn
One of my functions uses the "re" module for matching strings with regex. When I called the said function I get NameError: ("name 're' is not defined", 'occurred at index 0') so I figured I had to import re at the beginning of my functions.py file. This didn't change anything. So I even tried to put import re in the function body, but it wouldn't work either.
I have absolutely no idea why re doesn't work despite trying to import it everywhere.
Note: my functions worked correctly when I was defining and using them from the notebook so I know for certain it's not a bug in my function.
Solved my own issue, the answer is stupidly simple: Jupyter doesn't take into account any edits to an imported module even if you reimport it. If you make any changes to a module you have to shut down the kernel and restart it, import again and the edits will work.
In my particular case I had added import re to my functions.py but Jupyter didn't take it into account until I restarted the kernel.
In a notebook, you can use the importlib library and call importlib.reload(module) instead of restarting the kernel

Using imported modules within an imported function

I have a script which runs as a standalone program, however I'd like to be able to use it as a callable function as well. Currently when i try and run it from another script, i get errors saying that certain modules are not defined/imported. For example:
NameError: global name 'exp' is not defined
Here's an example of my code that produces the error:
from PostREC3 import * ##import the required functions from the module
from numpy import array, shape, math, loadtxt, log10, vstack, arange
from scipy.integrate import quad
from pylab import all
from numpy import pi as pi
from assimulo.solvers.sundials import IDA
from assimulo.problem import Implicit_Problem
from math import exp, log10, fabs, atan, log
import pickle
import sys
results = PostREC(2,100,90,1.0,1, 1,"0",2 ) #run an imported function
output:
NameError: global name 'exp' is not defined
I've tried importing exp from within the function itself, however that doesn't change anything. As far as I'm aware, as long as I've imported them before using the function then they should be available for any other functions to use. So, is there something wrong with what I'm doing, or does this point to another error within the code itself?
O/S: Ubuntu 12.10
Python 2.7 64 bit
Import exp and any other module/function you need at the top of your PostREC3 module, not whithin a particular function.
Imports are not "global", each module needs to import everything it needs to run, even if another module already did so.

Categories