Search code examples
pythonpippackagingsetup.pypypi

Python ImportError (most likely due to a circular import) for pip install but not local setup.py


I have a simple Python package for plotting scientific data called pliffy. The code is hosted on Github in this repo. I have published it on PyPi here.

I received a Github issue from a colleague trying to use the package. Basically, doing pip install pliffy installs the package, but when you start a Python interpreter and try to import the package you get the follow error message:

ImportError: cannot import name 'figure' from partially initialized module 'pliffy' (most likely due to a circular import) ([...]/testing/pliffy/venv/lib/python3.8/site-packages/pliffy/__init__.py)

I have been able to reproduce the issue on my own machine after creating a fresh Python environment and pip-intalling my package (yes, I now know the importance of testing your own packages after you push them to Pypi; won't make that mistake again!)

However, if I do the following -- clone and local install -- I don't get the error message:

git clone https://github.com/MartinHeroux/pliffy.git
cd pliffy/
python3 -m venv venv
source venv/bin/activate
python setup.py build
python setup.py install
python
>>> import pliffy
>>> pliffy.demo.demo()

I have run into trouble with circular imports when using type-hinting my own classes/objects, but I thought I solved everything given that I was able to install and use my package locally.

I did try changing the import statements in my plot.py module to import only pliffy rather than from pliffy import estimate, figure, parse, but that did not solve the problem. And because the problem only seems to appear after I have created the Python wheel and pushed it to PyPi, I have to bump and push a version in order to figure out it is not working (i.e. it works when I install the package locally).

In case it would be useful, here is how I create my wheel and push my package to PyPi:

pip install twine
python setup.py sdist bdist_wheel
twine upload --repository-url https://test.pypi.org/legacy/ dist/* # as a test 
twine upload dist/*

Any help with this issue would be greatly appreciated.


Update: Additional info

Dear Justin, thank you for taking the time to read through my question and asking for more information.

In response to your question, I create a local environment, locally installed my package (i.e. pliffy), and started up a Python interpreter not in the package folder. I gott an error message when I tried to import my package, but a different error this time:

>>> import pliffy
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<frozen zipimport>", line 259, in load_module
  File "/home/martin/Desktop/venv/lib/python3.8/site-packages/pliffy-0.1.2-py3.8.egg/pliffy/__init__.py", line 4, in <module>
ImportError: cannot import name 'figure' from 'pliffy' (/home/martin/Desktop/venv/lib/python3.8/site-packages/pliffy-0.1.2-py3.8.egg/pliffy/__init__.py)

This tells me that previously I was not getting an error because I was starting the Python interpreter when I was in the package directory. Why I get an error (and a different one at that) when I start the Python interpreter not in the package folder is not clear to me.

Dustin, you also asked about the import structure. I am not too sure how much (little) info, but I decided to provide eveything:

pliffy
├── __init__.py             
├── demo.py
├── estimate.py
├── parser.py
├── plot.py
├── utils.py
└── figure
    ├── diff_axis.py
    ├── figure_ab.py
    ├── figure_diff.py
    ├── figure.py
    └── __init__.py

init.py [Only bottom two import are needed for API, but other imports were needed to be able to get my test suite to work (this may not be needed, but when I coded this, I could not tests these other modules unless I included explicite imports here).]

from . import estimate
from . import plot
from . import utils
from . import figure
from . import parser
from . import demo
from pliffy.plot import plot_abd
from pliffy.utils import PliffyInfoABD, ABD

demo.py

from pliffy.utils import PliffyInfoABD, ABD
from pliffy.plot import plot_abd

estimate.py

from pliffy.utils import ABD

parser.py

from pliffy import estimate
from pliffy import utils

plot.py

import pliffy

utils.py

from pliffy import estimate

figure/init.py

from .figure import Figure
from .figure_ab import FigureAB
from .figure_diff import FigureDiff
from .diff_axis import DiffAxCreator

figure/diff_axis.py

from pliffy import utils, parser

figure/figure.py

from pliffy.parser import Xticks, Raw, Mean, CI, Paired

figure/figure_ab.py

from pliffy.figure import Figure
from pliffy import parser

figure/figure_diff.py

from pliffy.figure import Figure
from pliffy import parser

Let me know if more information is needed.


Solution

  • I looked into your published wheel and indeed it does not contain your figure sub-package.

    In order to understand why, lets check your setup.py

    you declared your packages as packages=["pliffy"] but you did not declared pliffy.figure sub-package. Becasue of this, the wheel packager just did not take it.

    A better and standard way is to use setuptools find_packages() function that do the packages discovery for you.

    packages=find_packages()