petermr / dictionary

Collection of Wikidata-based dictionaries for scientific annotation and searching
Apache License 2.0
7 stars 4 forks source link

Relative filenames in Python `import` statements fail with "ImportError: attempted relative import with no known parent package" #18

Closed petermr closed 3 years ago

petermr commented 3 years ago

The pyamidict/pyamidict directory is intended to be a Python project with nested packages. It is closely modelled on https://docs.python.org/3/reference/import.html#package-relative-imports

5.7. Package Relative Imports

Relative imports use leading dots. A single leading dot indicates a relative import, starting with the current package. Two or more leading dots indicate a relative import to the parent(s) of the current package, one level per dot after the first. For example, given the following package layout:

package/
    __init__.py
    subpackage1/
        __init__.py
        moduleX.py
        moduleY.py
    subpackage2/
        __init__.py
        moduleZ.py
    moduleA.py

In either subpackage1/moduleX.py or subpackage1/init.py, the following are valid relative imports:

from .moduleY import spam
from .moduleY import spam as ham
from . import moduleY
from ..subpackage1 import moduleY
from ..subpackage2.moduleZ import eggs
from ..moduleA import foo

The directory pyamidict/pyamidict/ contains this example (example_package`)

pyamidict/
├── __init__.py
├── editor
│   ├── __init__.py
│   ├── dict.py
│   └── schematron.py
├── example_package
│   ├── __init__.py
│   ├── moduleA.py
│   ├── subpackage1
│   │   ├── __init__.py
│   │   ├── moduleX.py
│   │   └── moduleY.py
│   └── subpackage2
│       ├── __init__.py
│       └── moduleZ.py
├── resources
│   ├── openVirus.schematron.xml
│   ├── openVirus_schema.xsd
│   ├── schematron_test.py
│   └── simple.xml
└── tests
    ├── __init__.py
    └── test_editor.py

and can be run with

 python subpackage1/moduleX.py

which fails with

Traceback (most recent call last):
  File "subpackage1/moduleX.py", line 16, in <module>
    from .moduleY import yy
ImportError: attempted relative import with no known parent package

Similar failures occur in both PyCharm and interpreter with

m286macbook:pyamidict pm286$ python tests/test_editor.py 
Traceback (most recent call last):
  File "tests/test_editor.py", line 4, in <module>
    from ..editor.dict import Dictionary
ImportError: attempted relative import with no known parent package

In PyCharm the imports work with:

from pyamidict.example_package.subpackage1.moduleY import yy
from pyamidict.example_package.subpackage1.moduleY import yy as yyy
from pyamidict.example_package.subpackage1 import moduleY
from pyamidict.example_package.subpackage1 import moduleY
from pyamidict.example_package.subpackage2.moduleZ import zz
from pyamidict.example_package.moduleA import aa

but these fail with the interpreter (e.g. in test_editor.py):

python test_editor.py 
Traceback (most recent call last):
  File "test_editor.py", line 3, in <module>
    from pyamidict.editor.dict import Dictionary
ModuleNotFoundError: No module named 'pyamidict'
petermr commented 3 years ago

This appears to be a known problem, e.g.: https://www.google.com/search?q=attempted+relative+import+with+no+known+parent+package&oq=attempted+relative+import+with+no+known+parent+package&aqs=chrome.0.69i59j0l4j69i60l3.6112j0j4&sourceid=chrome&ie=UTF-8

I have not yet found a "solution" that works for me.

PLEASE SEE IF YOU CAN REPRODUCE THE PROBLEM OR PROVIDE A SOLUTION

ayush4921 commented 3 years ago

Hello sir, I think I have the solution.

├───.idea
│   └───inspectionProfiles
└───pyamidict
    ├───editor
    │   └───__pycache__
    ├───resources
    │   └───.ipynb_checkpoints
    ├───tests
    │   └───__pycache__
    └───__pycache__

When we cd in pyamidict and then try to run test_editor.py which is present in tests, the same problem should occur

This is the import being used --from pyamidict.editor.dict import Dictionary , but what we have to do is we have to run this from the terminal as a module. So, I cd to pyamidict which has tests folder inside it and then I do python -m pyamidict.tests.test_editor instead of python pyamidict/tests/test_editor Then even this import works -- from ..editor.dict import Dictionary So the thing is to run the code using python -m pyamidict.tests.test_editor all the imports should work fine. But if i run it directly it cant find the modules because python doesnt know itself what directories we have if not stated expicitly and that is what this command this. It tells python to look for the project structure.

ayush4921 commented 3 years ago

In short just change python subpackage1/moduleX.py to python -m pyamidict.subpackage1.moduleX and make sure to run this command while being in the pyamidict directory which has all the subpackages.

petermr commented 3 years ago

deleted and reformatted in new comment

petermr commented 3 years ago

Reformatting the last issue...

I changed

dictionary/pyamidict/pyamidict

to

dictionary/pythoncode/pyamidict

to avoid ambiguity. and recommitted.

I now issue the command that Pycharm generates:


(base) pm286macbook:pythoncode pm286$ python -m unittest
pyamidict.tests.test_editor

dict.py

start test_editor

test dictionary

EsE

======================================================================

ERROR: test_create_dictionary (pyamidict.tests.test_editor.TestEditor)
----------------------------------------------------------------------

Traceback (most recent call last):

  File "/Users/pm286/dictionary/pythoncode/pyamidict/tests/test_editor.py",
line 24, in setUp

    self.root_element =
Dictionary.read_dictionary_element(self.simple_xml_file)

  File "/Users/pm286/dictionary/pythoncode/pyamidict/editor/dict.py", line
32, in read_dictionary_element

    dictionary_text = Dictionary.read_dictionary_as_text(dictionary_file)

  File "/Users/pm286/dictionary/pythoncode/pyamidict/editor/dict.py", line
26, in read_dictionary_as_text

    with open(dictionary_file, "r") as f:

FileNotFoundError: [Errno 2] No such file or directory:
'../resources/simple.xml'

======================================================================

ERROR: test_read_dictionary (pyamidict.tests.test_editor.TestEditor)
----------------------------------------------------------------------

Traceback (most recent call last):

  File "/Users/pm286/dictionary/pythoncode/pyamidict/tests/test_editor.py",
line 24, in setUp

    self.root_element =
Dictionary.read_dictionary_element(self.simple_xml_file)

  File "/Users/pm286/dictionary/pythoncode/pyamidict/editor/dict.py", line
32, in read_dictionary_element

    dictionary_text = Dictionary.read_dictionary_as_text(dictionary_file)

  File "/Users/pm286/dictionary/pythoncode/pyamidict/editor/dict.py", line
26, in read_dictionary_as_text

    with open(dictionary_file, "r") as f:

FileNotFoundError: [Errno 2] No such file or directory:
'../resources/simple.xml'
----------------------------------------------------------------------

Ran 3 tests in 0.001s

FAILED (errors=2, skipped=1)

which seems to run the code but gets the relative file structures wrong.

On Tue, Dec 29, 2020 at 1:52 AM Ayush Garg @.***> wrote:

In short just change

python subpackage1/moduleX.py

to

python -m  pyamidict.subpackage1.moduleX

and make sure to run this command while being in the pyamidict directory which has all the subpackages.

I tried this and got:

pwd

/Users/pm286/dictionary/pythoncode/pyamidict

(base) pm286macbook:pyamidict pm286$ python -m pyamidict.subpackage1.moduleX

/opt/anaconda3/bin/python: Error while finding module specification for
'pyamidict.subpackage1.moduleX' (ModuleNotFoundError: No module named
'pyamidict')

Can you please checkout the latest versions and see if you can run it.

ayush4921 commented 3 years ago

The issue was coming because of the way some code IDEs modify python import statements. The problem has been fixed.