How to allow excluding a module when importing my Python package? - python

I wrote a Python package pack that can perform a set of related tasks, taskA, taskB, ..., taskZ. Each of them has its own module file, e.g. taskN.py.
Now say in taskN.py I import a third party package evilpack. It Works On My Machine™, but a coworker of mine (a) can't install evilpack, but (b) does not even need that module taskN.
My goal is to structure my package so that we can choose at import time whether we want to load the module taskN or ignore it.
What's the most elegant way to solve this? I'm sensing it has something to do with the directories' __init__.py files.

A simple way to solve this problem:
Identify all of the modules that may have unfulfilled dependencies.
In the main module that does the importing, surround each such import with a try...except clause:
try:
import packN
except ImportError as details:
print ("Could not import packN because of this error:", details)
print ("Functionality xxxx will not be available")
packN = None
If your colleague's code doesn't call a function that relies on packN then all will be well.

I think I can only point you in the correct direction via setupscript because I do not have access to your data/package details.
To simply put, you will have to locate your taskN.py's setup.py script, and specifically remove the module from inside the script.

Related

Two different submodules with same name in different 3rd party modules

The problem
My Python-2.7 project needs to use two third-party modules, let's call them firstmodule and secondmodule.
There are two different submodules with the same name, say thesubmodule, one in firstmodule and one in secondmodule.
There is another third party module, let's call it mainmodule, which means to import firstmodule.thesubmodule.
But when it tries to import thesubmodule, it ends up importing it from secondmodule, and everything fails because these two submodules have the same name but they are completely different.
I think it would not be nice to modify the implementation of mainmodulejust to avoid this ambiguity, as it is a third party module and I should just use it without modifying it.
The code
In terms, of code, when I write the following in my project:
import mainmodule
then mainmodule tries to execute this:
import thesubmodule
but it ends up importing secondmodule.thesubmodule instead of firstmodule.thesubmodule, then it generates errors like this:
NameError: name 'blabla' is not defined
(where 'blabla' can only be found in firstmodule.thesubmodule).
The question
Is there a way to specify, when importing mainmodule, that any reference to thesubmodule refers to firstmodule.thesubmodule ?
Further observations
When I try to remove the path of secondmodule from PYTHONPATH then thesubmodule is correctly imported, but I need secondmodule in my project, so not importing it is not an option unfortunately.
If it was possible to set a specific value for PYTHONPATH just for that single import, and then restore its original value afterwards, then I guess it would work, but it does not seem an easy thing to do.
A "dirty" attempt?
Based on my last observation, would it be too dirty to temporarily change the value of PYTHONPATH with a shell command just before importing mainmodule? I mean something like:
...
import os
...
savePYTHONPATHvalue()
os.system('export PYTHONPATH=somevalue')
import mainmodule
restorePYTHONPATHvalue()
...

Defining and using a decorator function in __init__.py

EDIT: Solved! Solution on the bottom of this post. tl;dr: I should have been using relative imports, and launching python with the correct flag.
So I'm trying to get used to some python stuff (version 2.7.3—it's what's installed on the work PC), and I've got a little project to teach me some python stuff. I've got a module defined like so:
curses_graphics
| __init__.py
| graphicsobject.py
| go_test.py
(code to follow)
I've got a decorator defined in __init__, and I'm trying to use it on methods defined in a class in graphicsobject.py that I'm trying to attach the decorator to, and I'm testing its functionality in go_test.
When I run go_test (just being in the directory and calling "python go_test.py"), I get a no package found error. Same happens if I rename go_test to __main__.py and try to run the package from its parent directory. If I try to run the go_test without importing the package, it doesn't recognise my function.
How can I reference a function defined in __init__.py from within the same package? Is it wrong to try and import while within the package?
Thanks!
__init__.py:
import curses
import logging
#Define logging stuff
gLog = logging.getLogger("cg_log")
gLog.basicConfig(filename="log.log", level=logging.DEBUG)
# Logging decorators for this library
def debug_announce(module_func):
log=logging.getLogger("cg_log")
log.info("Curses Graphics Lib:Entering function:"+module_func.__name__)
module_func()
log.info("Curses Graphics Lib:Left function:"+module_func.__name__)
go_test.py
#debug_announce
def logTester():
print("A test method")
logTester()
logger.debug("Curses initialization")
screen=curses.initscr()
curses.start_color()
screen.keypad(True)
logger.debug("Initializing a green block filled with red '.'s")
block = GraphicsOBject.blankline(0, 0, 3, curses.COLOR_GREEN, curses.COLOR_RED, 20, '.')
logger.debug("Drawing the block.")
block.draw(screen)
logger.debug("Pausing execution with a getch")
screen.getch()
logger.debug("Cleaning up curses")
screen.keypad(False)
curses.endwin()
os.system('stty sane')
I can include graphicsobject.py, though I suspect that would be clutter here, as the issue occurs on the first line of go_test.py
Thanks, everyone!
EDIT:
I'm attaching a capture of the errors reported. In the first error, I've added "from curses_graphics import debug_announce" and in the second the code doesn't have that line.
Errors with and without debug_announce import
EDIT:
Some further searching led me to relative imports. For anyone who has my issue, you use those to import something defined in your own module. In my case, I appended "from . import debug_announce" to the head of my go_test.py file. I attempted to run it, and received the error “Attempted relative import in non-package”.
Some further searching led me to this question:
How to fix "Attempted relative import in non-package" even with __init__.py
Which told me that it wasn't attempting to run this program as a package. This meant the "__init__.py" was never running, as the package wouldn't be imported. Further, since I was inside the package, attempting to import the package (i.e. "import curses_graphics") would result in it searching inside curses_graphics... for curses_graphics.
To run this correctly, as the linked question implies, I need to go to the parent directory of curses_graphics and execute it with "python -m curses_graphics.go_test". This runs the package with its inits and such and run the script of go_test.
(And, FWIW, my code had other issues. Don't take this as an example of how to use curses or logging :P)

Backing up/copying an entire folder tree in batch or python?

I'm trying to copy an entire directory from one locations to another via python every 7 days to essentially make a backup...
The backup folder/tree folder may or may not exist so it needs to create the folder if it doesn't exist, that's why I assumed distutils is better suited over shutil
Note Is it better for me to use batch or some other language for the said job?
The following code:
import distutils
distutils.dir_util.copy_tree("C:\Users\A\Desktop\Test", "C:\Users\A\Desktop\test_new", preserve_mode=1, preserve_times=1, preserve_symlinks=0, update=1, verbose=0, dry_run=0)
Returns:
Traceback (most recent call last):
File "C:\Users\A\Desktop\test.py", line 2, in <module>
distutils.dir_util.copy_tree("C:\Users\A\Desktop\test", "C:\Users\A\Desktop\test2", preserve_mode=1, preserve_times=1, preserve_symlinks=0, update=1, verbose=0, dry_run=0)
AttributeError: 'module' object has no attribute 'dir_util'
What am I doing wrong?
Thanks in advance
- Hyflex
You need to import dir_util specifically to access it's functions:
from distutils import dir_util
If there are other modules in that package that you need, add them to the line, separated by commas. Only import the modules you need.
For Unix/Linux, I suggest 'rsync'.
For windows: xcopy
I've been attempting essentially the same thing to back up what I write on a plethora of virtual machines.
I ran into the same problem you did with distutils. From what I can tell, the Python community is using the distutils module to start standardizing how new modules interface with Python. I think they're still in the thick of it though as everything I've seen relating to it seems more complicated, not less complicated. Hopefully, I'm just seeing all the crazy that happens in the middle of a big change.
But I did figure out how to get it working. To use distutil.dir_util.copytree(),
>>> from distutils import dir_util
>>> dir_util.copy_tree("/home/user/backing_up/temp", "/home/user/backing_up/other")
['/home/user/backing_up/other/stuff.txt'] # Return value indicating success
If you feel like it's worthwhile, you can import distutils.core and make the longer call to distutils.dir_util.copy_tree().
>>> import distutils.core
>>> distutils.dir_util.copy_tree("/home/user/backing_up/temp", "/home/user/backing_up/other")
['/home/user/backing_up/other/stuff.txt'] # Return value indicating success
(I know, I know, there are subtle differences between "import module.submodule" and "from module import submodule" but that's not the intent of the question and so long as you're importing the correct stuff and calling the functions appropriately, it doesn't make a difference.)
Like you, I also explicitly stated that I wanted the default for preserve_mode and preserve_times, but I didn't touch the other variables. Everything worked as expected once I imported and called the function the way it wanted me to.
Now that my back up script works, I realize I should have written it in Bash since I plan on having it run whenever the machine goes to a specific runlevel. I'm using a wrapper instead now, even if I should just re-write it.

Python: Importing an "import file"

I am importing a lot of different scripts, so at the top of my file it gets cluttered with import statements, i.e.:
from somewhere.fileA import ...
from somewhere.fileB import ...
from somewhere.fileC import ...
...
Is there a way to move all of these somewhere else and then all I have to do is import that file instead so it's just one clean import?
I strongly advise against what you want to do. You are doing the global include file mistake again. Although only one module is importing all your modules (as opposed to all modules importing the global one), the remaining point is that if there's a valid reason for all those modules to be collected under a common name, fine. If there's no reason, then they should be kept as separate includes. The reason is documentation. If I open your file, and see only one import, I don't get any information about what is imported and where it comes from. If on the other hand, I have the list of imports, I know at a glance what is needed and what not.
Also, there's another important error I assume you are doing. When you say
from somewhere.fileA import ...
from somewhere.fileB import ...
from somewhere.fileC import ...
I assume you are importing, for example, a class, like this
from somewhere.fileA import MyClass
this is wrong. This alternative solution is much better
from somewhere import fileA
<later>
a=fileA.MyClass()
Why? two reasons: first, namespacing. If you have two modules having a class named MyClass, you would have a clash. Second, documentation. Suppose you use the first option, and I find in your code the following line
a=MyClass()
now I have no idea where this MyClass comes from, and I will have to grep around all your files in order to find it. Having it qualified with the module name allows me to immediately understand where it comes from, and immediately find, via a /search, where stuff coming from the fileA module is used in your program.
Final note: when you say "fileA" you are doing a mistake. There are modules (or packages), not files. Modules map to files, and packages map to directories, but they may also map to egg files, and you may even create a module having no file at all. This is naming of concepts, and it's a lateral issue.
Of course there is; just create a file called myimports.py in the same directory where your main file is and put your imports there. Then you can simply use from myimports import * in your main script.

python NameError: name '<anything>' is not defined (but it is!)

Note: Solved. It turned out that I was importing a previous version of the same module.
It is easy to find similar topics on StackOverflow, where someone ran into a NameError. But most of the questions deal with specific modules and the solution is often to update the module.
In my case, I am trying to import a function from a module that I wrote myself. The module is named InfraPy, and it is definitely on sys.path. One particular function (called listToText) in InfraPy returns a NameError, but only when I try to import it into another script. Inside InfraPy, under if __name__=='__main__':, the listToText function works just fine. From InfraPy I can import other functions with no problems. Including from InfraPy import * in my script does not return any errors until I try to use the listToText function.
How can this occur?
How can importing one particular function return a NameError, while importing all the other functions in the same module works fine?
Using python 2.6 on MacOSX 10.6, also encountered the same error running the script on Windows 7, using IronPython 2.6 for .NET 4.0
Thanks.
If there are other details you think would be helpful in solving this, I'd be happy to provide them.
As requested, here is the function definition inside of InfraPy:
def listToText(inputList, folder=None, outputName='list.txt'):
'''
Creates a text file from a list (with each list item on a separate line). May be placed in any given folder, but will otherwise be created in the working directory of the python interpreter.
'''
fname = outputName
if folder != None:
fname = folder+'/'+fname
f = open(fname, 'w')
for file in inputList:
f.write(file+'\n')
f.close()
This function is defined above and outside of if __name__=='__main__':
I've tried moving InfraPy around in relation to the script. The most baffling situation is that when InfraPy is in the same folder as the script, and I import using from InfraPy import listToText, I receive this error: NameError: name listToText is not defined. Again, the other functions import fine, they are all defined outside of if __name__=='__main__': in InfraPy.
This could happen if the module has __all__ defined
Alternatively there could be another version of the module in your path that is getting imported instead of the one you are expecting
Is the NameError about listToText or is it something inside the function causing the exception?
In addition the __all__ variable gnibbler mentioned you could also have a problem with a InfraPy.pyc file lying around somewhere.
I'd recommend putting a import pdb;pdb.set_trace() first in the InfraPy.py file to make sure you are in the right file, and step through the definition of InfraPy.py to see what is happening. If you don't get a breakpoint, you are importing another file than you think.
You can also dir(InfraPy) after importing it, and check which file you are actually importing with InfraPy.__file__.
Can't think of any more import debugging hints right now. ;-)

Categories

Resources