Package import creates a module, submodules still importable - python

I've been working on a python package and now I would like to turn it into a small RPM distribution. Package includes a few modules, one of which is executable. I can create the RPM-package with python setup.py bdist_rpm and install it on a fedora box with rpm.
At this point have the desired command myscript and it works like a charm. But when i try to import the package in ipython, I run into something strange. I can do the following
from myscript import sdf
import myscript.mol2
Both work flawlessly, but
import myscript
myscript.sdf
throws
AttributeError: 'module' object has no attribute 'sdf'
I've been working with this for a while now to no avail. There's plenty of questions of import problems, but I haven't found an answer for this one yet.
What I should change to make it work?
The current folder structure is:
myscript/ #project root
setup.py
src/
myscript/
__init__.py
functions.py
sdf.py
mol2.py
runner.py
bin/
myscript #symbolic link to src/myscript/runner.py
setup.py is:
from distutils.core import setup
setup(name = 'myscript',
version = '0.75',
author ='me',
requires = ['numpy'],
packages = ['myscript'],
package_dir = {'myscript':'src/myscript'},
scripts = ['bin/myscript']
)
and __init__.py is:
__all__ = ['functions','sdf','mol2','runner']

This is normal behavior. If you want submodules to be imported then you must import them in the module.
# myscript/__init__.py
from . import sdf

Related

Why do I get an import error when a child file is trying to access a parent file

My directory is structured like this
>project
>tests
>test_to_json.py
>app.py
>x.db
in my test_to_json.py I want to access a class from app.py
How would I import it? I've tried from ..app import myClass but that gives me ImportError: attempted relative import with no known parent package. Is there something I'm missing?
You cannot use .. relative pathing in python. That specific type of relative python is simply not allowed. . is allowed, though. The resolution for this problem is usually done by converting your project into a python package.
Extensive tutorials for doing so can be found here, but I will give an example of how to convert your project into a package.
Step 1
The new file structure should look like this:
>project
>tests
>__init__.py #Note this file
>test_to_json.py
>__init__.py #Note this file
>setup.py #Note this file
>app.py
>x.db
Step 2
Write your setup.py.
Here is an generic setup.py that should work for your project:
from setuptools import setup, find_packages
setup(
name='project_package', #the name of your desired import
version='0.0.1',
author='An Awesome Coder',
packages=find_packages(),
description='An awesome package that does something',
install_requires=[], # a list of python dependencies for your package
)
find_packages() looks for all the __init__.py files in your package to identify submodules.
Step 3
Install your package. In the folder with your new setup.py, run pip install -e . This will install your package on your computer, basically adding the files to your python system path.
Step 4
From any python terminal on your computer you should now be able to import your package using the package_name you specified.
import project_package
from project_package.app import myClass
myClass()
.
.
.

python setup tools - install a sub package from within a project

I have two projects (trysetup1 and trysetup2) with the following structure:
I want to pip install package1 and use module1 from project trysetup2
my setup.py that under package1 looks like this:
import setuptools
setuptools.setup(
name="common",
version="1.0.2",
packages=setuptools.find_packages(),
)
the way I want to use module1 is like this from package1.module1 import ClassOne because I still need to use it from package2
when trying to import from module2 it works just fine
but when trying to use it from module3 (in the different project after pip installing it) i'm having "Unresolved reference 'package1'" problem
I know I'm able to use module1 by putting it inside another package under package1 but I need this exact stracture in order to use it from the rest of the project 'trysetup1'
Thanks!
My answer was found here:
https://docs.python.org/3/distutils/examples.html
actually, all I needed to do was to change my setup.py file to look like this:
setuptools.setup(
name="common",
version="1.0.2",
package_dir={'package1': ''},
packages=['package1'],
)
by adding package_dir param, setup function tells all files under my root directory (package1) to be under package1 directory and by adding packages param it distributes package1 package and then if you go to:
/..../venv/lib/python3.8/site-packages/common-1.0.2-py3.8.egg-info/top_level.txt
you'll see the following content:

Installed Python script cannot import package modules

I have created a Python package with the following directory structure:
/
LICENSE
MANIFEST.IN
README.rst
VERSION
docs/
multitool/
__init__.py
core/
__init__.py
classes.py
utils.py
libs/
multitool.py
tests/
tools/
__init__.py
hashtool.py
webtool.py
setup.py
The goal is to create a command line application (multitool.py) that 3rd parties can add to by adding their own files to the tools directory. This is accomplished by having them subclass a class that I've created. For example, these are the first few lines of hashtool.py:
import multitool
class HashTool(multitool.core.classes.CLITool):
All of this works as long as I run it from the project directory itself:
$ ./multitool.py -h <---works
$ ./multitool/multitool.py -h <---works
The problem comes when I try to create and install it as a package. The install runs and installs the script. However, when you run the script, it cannot find any of the modules in the package:
$ multitool.py
import core
ImportError: No module named core
I've tried changing the import to multitool, multitool.core, .multitool, ..multitool, and others with the same result.
However, I am able to do imports from the Python interpreter:
Type "help", "copyright", "credits" or "license" for more information.
>>> import multitool
>>> import multitool.core
>>> import multitool.core.classes
>>> from multitool import core
>>>
Here is the relevant portion of my setup.py
setup(
name = 'multitool',
version = __version__,
license = 'GPLv2',
packages = find_packages(exclude=['test/']),
scripts = ['multitool/multitool.py'],
include_package_data = True,
....
)
What am I doing wrong? How can I import my own code and the files from the tools directory in the script that I install with the package?
Updated
MrAlias's edited comment below worked. The confusion was that the script was the same name as the package itself and was not in a separate directory. Moving the script to its own bin/ directory solved the problem.
First off, when you install the package you are importing core without identifying it is being apart of the multitool package. So:
import core
should be,
from multitool import core
That way the interpreter knows the module to import core from.
[Edit]
As for the directory structure of the installed package, scripts need to go into a separate directory from the module itself. The way the shown directory structure is Distutils will install the script you named into both a place your system looks for executables as well as in the package itself, which is likely where all the confusion is coming from.
import multitool
class HashTool(multitool.core.classes.CLITool):
Importing a package does not import its subpackages and submodules. Try this:
import multitool.core.classes
class HashTool(multitool.core.classes.CLITool):

How to import your package/modules from a script in bin folder in python

When organising python project, this structure seems to be a standard way of doing it:
myproject\
bin\
myscript
mypackage\
__init__.py
core.py
tests\
__init__.py
mypackage_tests.py
setup.py
My question is, how do I import my core.py so I can use it in myscript?
both __init__.py files are empty.
Content of myscript:
#!/usr/bin/env python
from mypackage import core
if __name__ == '__main__':
core.main()
Content of core.py
def main():
print 'hello'
When I run myscript from inside myproject directory, I get the following error:
Traceback (most recent call last):
File "bin/myscript", line 2, in <module>
from mypackage import core
ImportError: No module named mypackage
What am I missing?
Usually, setup.py should install the package in a place where the Python interpreter can find it, so after installation import mypackage will work. To facilitate running the scripts in bin right from the development tree, I'd usually simply add a simlink to ../mypackage/ to the bin directory. Of course, this requires a filesystem supporting symlinks…
I'm not sure if there is a "best choice", but the following is my normal practice:
Put whatever script I wanna run in /bin
do "python -m bin.script" in the dir myproject
When importing in script.py, consider the dir in which script.py is sitting as root. So
from ..mypackage import core
If the system supports symlink, it's a better choice.
I usually add my bin path into $PYTHONPATH, that will enable python to look for asked module in bin directory too.
export PYTHONPATH=/home/username/bin:$PYTHONPATH
$ python
import module_from_bin
I solved the issue following setuptools specifications.
In setup.py you can specify the modules as an argument for the function setup():
packages = find_packages()
This finds all modules.
p.s. you have to import this function: from setuptools import setup, find_packages

ImportError on subpackage when running setup.py test

I'm trying to create an install package for a Python project with included unit tests. My project layout is as follows:
setup.py
src/
disttest/
__init__.py
core.py
tests/
disttest/
__init__.py
testcore.py
My setup.py looks like this:
from distutils.core import setup
import setuptools
setup(name='disttest',
version='0.1',
package_dir={'': 'src'},
packages=setuptools.find_packages('src'),
test_suite='nose.collector',
tests_require=['Nose'],
)
The file tests/disttest/testcore.py contains the line from disttest.core import DistTestCore.
Running setup.py test now gives an ImportError: No module named core.
After a setup.py install, python -c "from disttest.core import DistTestCore" works fine. It also works if I put import core into src/disttest/__init__.py, but I don't really want to maintain that and it only seems necessary for the tests.
Why is that? And what is the correct way to fix it?
You may want to double-check this, but it looks like your tests are importing the disttest package in the tests/ directory, instead of the package-under-test from the src/ directory.
Why do you need to use a package with the same name as the package-under-test? I'd simply move the testcore module up to the tests directory, or rename the tests/disttest package and avoid the potential naming conflict altogether.
In any case, you want to insert a import pdb; pdb.set_trace() line just before the failing import and play around with different import statements to see what is being imported from where (import sys; sys.modules['modulename'].__file__ is your friend) so you get a better insight into what is going wrong.

Categories