1

Possibly because of my noobness, I can't get pylint and django management commands to agree about how to import files in my project.

Setup

# venv
cd $(mktemp -d)
virtualenv venv
venv/bin/pip install django pylint pylint-django
# django
venv/bin/django-admin startproject foo
touch foo/__init__.py
touch foo/foo/models.py
# management command
mkdir -p foo/foo/management/commands
touch foo/foo/management/__init__.py
touch foo/foo/management/commands/__init__.py
echo -e "import foo.models\nclass Command:\n  def run_from_argv(self, options):\n    pass" > foo/foo/management/commands/pa.py
# install
perl -pe 's/(INSTALLED_APPS = \[)$/\1 "foo",\n/' -i foo/foo/settings.py
# testing
venv/bin/python foo/manage.py pa
venv/bin/pylint --load-plugins pylint_django --django-settings-module=foo.foo.settings --errors-only foo

Result

You'll note that manage.py is happy with import foo.models, but pylint isn't:

************* Module foo.foo.management.commands.pa
foo/foo/management/commands/pa.py:1:0: E0401: Unable to import 'foo.models' (import-error)
foo/foo/management/commands/pa.py:1:0: E0611: No name 'models' in module 'foo' (no-name-in-module)

If I change it to import foo.foo.models, pylint passes but manage.py breaks:

...
  File "<frozen importlib._bootstrap_external>", line 883, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/tmp/tmp.YnQCNTrkbX/foo/foo/management/commands/pa.py", line 1, in <module>
    import foo.foo.models
ModuleNotFoundError: No module named 'foo.foo'

What am I missing?

Nitz
  • 320
  • 2
  • 9
  • I'm upvoting just for the repro script, it's very easy to understand and follow. This is a duplicate, add a `.pylintrc` as described in linked dupe. – STerliakov Dec 29 '22 at 16:01
  • Does this answer your question? [PyLint "Unable to import" error - how to set PYTHONPATH?](https://stackoverflow.com/questions/1899436/pylint-unable-to-import-error-how-to-set-pythonpath) – STerliakov Dec 29 '22 at 16:01
  • @SUTerliakov I'm happy to mark it as a dup but I couldn't get the suggested solution to work. – Nitz Dec 29 '22 at 16:27
  • Hm, interesting, really doesn't work for me on your repro. You can just add `__init__.py` on the topmost level (as a sibling of `venv` and `foo` folders), it resolves the issue. Though there should be some better way. – STerliakov Dec 29 '22 at 16:36
  • @SUTerliakov works. I'm happy to accept that as an answer if you want to submit it – Nitz Dec 29 '22 at 16:49
  • Actually, it doesn't. Weird. – Nitz Dec 29 '22 at 17:05
  • is renaming a way to go for you? It looks like the simplest solution here. – STerliakov Dec 29 '22 at 17:06

2 Answers2

1

Hm, okay, one suggested way was to add __init__.py to the topmost folder (though I really dislike this solution, your project folder is not a module). Another working solution is to rename outer foo to bar - so the trouble source is the name collision. With the help of .pylintrc I managed to make sys.path equal for both python foo/manage.py ca and pylint --errors-only foo (just with debug prints everywhere). So, it means that pylint does some weird lookup not completely equivalent to the lookup of python itself, giving precedence to current working directory. pylint resolves foo to the outer foo directory, while python - for inner. For some reason it's changed when foo is a part of another module, which doesn't make sense for me.

STerliakov
  • 4,983
  • 3
  • 15
  • 37
1

I found a solution today, after leaving it for a while.
While it is useless to try and scan the entire project directory, each app inside the directory scans just fine.

My makefile line looks like this:

DJANGO_SETTINGS_MODULE=djang.settings.dev venv/bin/pylint djang/*/

This includes all app directories inside the project, including the "main" one containing settings.py, url.py and co.

Nitz
  • 320
  • 2
  • 9