Confused about python imports - python

I reviewed the Python 2.7.5 documentation. I am having issues with my real project, but created a small test project here to concisely reproduce the issue. Imagine a package with the following layout stored at ~/Development/Test
Here is the structure:
Test/
__init__.py
foo.py
sub/
__init__.py
test_foo.py
And the code (__init__.py files are empy):
foo.py
def bar():
print("hello world")
test_foo.py
import Test.foo
# also tried from Test import foo
def main():
foo.bar()
if __name__ == "__main__":
main()
When trying to run test_foo.py from the terminal (i.e. python test_foo.py) I'm getting:
Traceback (most recent call last):
File "test_foo.py", line 1, in <module>
import Test.foo
ImportError: No module named Test.foo
I'm trying to import the main file in the package (foo.py) from the test file in the sub module (in my real project the sub module is the unit testing code). Oddly using Sublime text 2 editor and the plugin python test runner, I can run my individual tests just fine, but I cannot build the test file. It gives me the above error.

Module names are case-sensitive. Use:
import Test.foo as foo
(The as foo is so that you can call foo.bar in main.)
You must also have ~/Development listed in PYTHONPATH.
If using Unix and your login shell is bash, to add ~/Development to PYTHONPATH edit ~/.profile to include
export PYTHONPATH=$PYTHONPATH:$HOME/Development
Here are instructions for Windows.
Further suggestions for debugging:
Place
import sys
print(sys.path)
import Test
print(Test)
import Test.foo
at the top of test_foo.py. Please post the output.

Runnable scripts should always be put outside the module. So if you have a module and a script that runs some code from that module, the structure should look like:
foo/
__init__.py
bar.py
your_script.py
And the code in your_script.py should be something like:
from foo.bar import your_func
your_func()
In case of unittesting it is a good idea (this is opinionated and everyone has his way of doing things) to place the tests inside the module so the structure should look like:
foo/
__init__.py
bar.py
tests/
test_bar.py
But in that case you shouldn't run the script directly. You should either use one of the testing frameworks like nose and run:
nosetests foo
in the directory where you placed your foo module.
Or if you used the standard unittest library, create a TestSuite and what not, run it with:
python -m unittest foo.tests.test_bar
again in the directory where you placed your foo module.

Related

trying to make paths work - attempted relative import beyond top-level package

I can't make this work..
My structure is:
program_name/
__init__.py
setup.py
src/
__init__.py
Process/
__init__.py
thefile.py
tests/
__init__.py
thetest.py
thetest.py:
from ..src.Process.thefile.py import sth
Running: pytest ./tests/thetest.py from program_name gives :
ValueError: attempted relative import beyond top-level package
I tried also other approaches but i am receiving various errors.
But I would expect for the above to work.
ValueError: Attempted relative import in non-package
States that you're trying to use relative import in the module, which are to be used for packages i.e. to make it a package add __init__.py and call the thetest.py from some file outside the package.
Directly running thetest.py from interpreter won't work.
Relative imports require that the module which uses them is being
imported itself either as package module.
Suggestion 1:
The current tests directory has a __init__.py file but that doesn't allow you to run it as a module (via shell) - to make your current (relative) import work, you need to import it in an external (to package) file/module - let's create a main.py (can name it anything you like):
main.py
program_name/
__init__.py
setup.py
src/
__init__.py
Process/
__init__.py
thefile.py
tests/
__init__.py
thetest.py
src/Process/thefile.py:
s = 'Hello world'
tests/thetest.py:
from ..src.Process.thefile import s
print s
main.py:
from program_name.tests.thetest import s
Executing main.py:
[nahmed#localhost ~]$ python main.py
Hello world
Suggestion 2:
Execute the file just above root dir i.e. one level up the program_name/ , in the following fashion:
[nahmed#localhost ~]$ python -m program_name.tests.thetest
Hell World
P.S. relative imports are for packages, not modules.
Just solved a similar problem with a lot of googling.
Here's two solutions without changing the existing file structor:
1
The way to import module from parent folder from ..src.Process.thefile.py import sth is called "relative import".
It's only supported when launching as a package from the top-level package. In your case, that is launching command line from the directory which contains program_name/ and type (for win environment)
python -m program_name.tests.thetest
or simply (useful for many pytest files):
python -m pytest
2
Otherwise -- when trying to run a script alone or from a non top-level package --
you could manually add directory to the PYTHONPATH at run time.
import sys
from os import path
sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))
from src.Process.thefile import s
Try the first one first see if it's compatiable with the pytest framework. Otherwise the second one should always solve the problem.
Reference (How to fix "Attempted relative import in non-package" even with __init__.py)
When importing a file, Python only searches the current directory, the directory that the entry-point script is running from.
you can use sys.path to include different locations
import sys
sys.path.insert(0, '/path/to/application/app/folder')
import thefile

Where to place python unittests

I have a directory structure as follows:
DirA
__init__.py
MyClass.py
unittests <------------------directory
MyClassTest.py
MyClassTest.py is executable:
import unittest
from . import MyClass
class MyClassTestCase(unittest.TestCase):
""" Testcase """
...
.....
if __name__ == '__main__':
unittest.main()
I get an error "Parent module '' not loaded, cannot perform relative import" at the line:
from . import MyClass
I would like to place unittests in a 'unittests' directory beside the modules being tested. Is there a way to do this and have access to all the modules in the parent directory which I am testing?
Have you tried running the tests like so:
cd DirA
python -m unittest discover unittests "*Test.py"
This should find your modules correctly. See Test Discovery
Use whatever layout you want, depending on your own preferences and the way you want your module to be imported:
http://python-notes.curiousefficiency.org/en/latest/python_concepts/import_traps.html#the-double-import-trap
https://pytest.org/latest/goodpractises.html
To find your unittests folder, since the name is not the conventional one (unit test scripts by default look for a test folder), you can use the discover option of the unittest module to tell how to find your test scripts:
python -m unittest discover unittests
Note that the first unittest is the Python module, and the second unittests (with an s) is your directory where you have placed your testing scripts.
Another alternative is to use the nosetest module (or other new unit testing modules like pytest or tox) which should automatically find your testing script, wherever you place them:
nosetests -vv
And to fix your import error, you should use the full relative (or absolute) path:
from ..MyClass import MyClass # Relative path from the unittests folder
from MyClass import MyClass # Absolute path from the root folder, which will only work for some unit test modules or if you configure your unit test module to run the tests from the root
A suggested structure, would be to look at your structure like this:
my_app
my_pkg
__init__.py
module_foo.py
test
__init__.py
test_module_foo.py
main.py
Run everything from within my_app, this way you will use all the same module references between your test code and core code.

Python importing works from one folder but not another

I have a project directory that is set up in the following way:
>root
> modules
__init__.py
module1.py
> moduleClass
__init__.py
moduleClass1.py
moduleClass2.py
> scripts
runTests.py
> tests
__init__.py
test1.py
test2.py
run.sh
In runTests.py I have the following import statements:
import modules.module1
import modules.moduleClass.moduleClass2
import tests.test1
import tests.test2
The first two import statements work fine, but the second two give me the errors ImportError: No module named test1 and ImportError: No module named test2. I can't see what is different between the tests and modules directories.
I'd be happy to provide more information as needed.
When you run a script, Python adds the script's containing directory (here, scripts/) to sys.path. If your modules don't appear in sys.path any other way, that means Python may not be able to find them at all.
The usual solution is to put your scripts somewhere in your module hierarchy and "run" them with python -m path.to.module. But in this case, you could just use an existing test runner: Python comes with python -m unittest discover, or you might appreciate something fancier like py.test (pip install --user pytest).
The problem turned out to be that python didn't like the folder name tests. Changing the name to unit_tests solved the problem.

How do I correctly import packages with py.test?

I have the following layout:
/spamalot
/spam
__init__.py
spam.py
/spam_on_eggs
__init__.py
spam_on_eggs.py
/tests
test_spam.py
Spam just so happens to be a flask application.
Within spam.py I have
import spam_on_eggs.spam_on_eggs as eggs
# Other Flask setup & application code here.
And this works fine - from the spamalot directory I'm able to run python spam/spam.py
However, when I start to throw tests into the mix, it's not as awesome.
In my test_spam.py file I have:
import spam.spam
test_client = spam.spam.app.test_client()
def test_it_fails():
assert False
However, rather than failing where I would expect, it fails on the import line:
/spamalot/ $ py.test
# some output
E ImportError
I can fix this by putting __init__.py in my /tests folder, but then I get a different ImportError:
spam/spam.py:1: in <module>
> import spam_on_eggs.spam_on_eggs as eggs
E ImportError: No module named 'spam_on_eggs'
I can solve that one by changing the line to:
from spam.spam_on_eggs import spam_on_eggs
Which allows me to test but then I break my ability to run $ python spam/spam.py - because I get
ImportError: no module named 'spam'
Obviously I have a gap in my understanding of how module imports work and how py.test works with this system.
What am I missing?
Is it even possible to have the layout I've described - and be able to run both py.test and my server from the spamalot directory?
py.test will always use the shortest directory path with an __init__.py in it.
Put a __init__.py into spamalot and you can import spamalot.spam.spam.
Reference: choosing a test layout

Structuring Python OOP Code and Modules

packageName\
__init__.py
src\
__init__.py
someFile.py
classes\
__init__.py
engine1.py
engine2.py
engine.py
tests\
__init__.py
myTests.py
temp\
I'm working on OOP with Python, and I have a few questions.
I understand that __init__.py defines the folder as a module, but what I do not understand is how this benefits me.
How would I run myTests.py if it needs to import a class from the packageName/src/classes folder?
$ python packageName/tests/myTests.py
The above call is how I guess I'd intend to run my tests. If the structure is the case, how can I import the classes?
from ..src.classes.engine1 import *
As #Mike mentioned, The Hitchhiker's Guide to Packaging would be a great place to start.
Now, as far as your tests go: for various Reasons, you can't just run python packageName/tests/myTests.py (specifically, Python will get confused about the package layout — when you run a file with python foo.py, it's expected to be outside a package, so the from ..src … line will fail with Attempted relative import in non-package).
Instead, you need to start your tests from outside the package… Either using a test runner like nose or unittest2, or writing a simple script in the top level directory (ie, above packageName/):
$ ls
packageName/ run_tests
$ cat run_tests.py
from packageName.tests.myTests import main
main()
Then put a main() function in myTests().
However, using a test runner is much simpler. If you've written your tests correctly, you can run them with:
$ ls
packageName/
$ nosetests
..................................
----------------------------------------------------------------------
Ran 34 tests in 1.440s
OK

Categories

Resources