0

I'm working on a rather elaborate project and have run into some confusion regarding why I get a ModuleNotFoundError: No module named 'burrow.settings' (I called it myapp.settings in the title for better searchability) when calling __main__.py by running $ python -m burrow, but $ python burrow works perfectly well!

I have no relative imports anywhere in my code and haven't touched the boilerplate generated by Django, and have tried and searched all kinds of things and can't find out why this is behaving differently, so any insight would be greatly appreciated!

The repository structure may be a little confusing (suggestions for improvement welcome), but effectively consists of a single Project (meercat) consisting of two sub-packages (burrow and lookout) which represent a server and a client respectively. Within the server package (burrow), there is the regular Django boilerplate (burrow/burrow) as well as a Django REST Framework app (api).

meercat
    - data
    - docs
    - meercat
      - burrow
        - api     // newly created
        - burrow  // created with startapp, untouched
        - __init__.py
        - __main__.py
        - controller.py
        - manage.py
      - env
      - lookout
      - __init__.py
      - core.py
  README.md

Relevant code:

# __main__.py

import argparse as ap
import logging
import os
import sys

import django
from django.core.exceptions import AppRegistryNotReady
from django.core.management.color import supports_color

try:
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "burrow.settings")
    django.setup()
    import controller
except (AppRegistryNotReady, ModuleNotFoundError) as e:
    raise RuntimeError(f"Caught {e}: Ensure execution from correct location!")

# various logging and argparse setup

def main() -> None:
    """Create and run a Meercat Burrow."""
    vals: dict[str, Any] = vars(args)  # argparse values

    return controller.main(vals)


if __name__ == "__main__":
    # runs when package is called
    sys.exit(main())

Upon running /meercat/meercat$ python3 burrow, sys.path is

[
    '/home/memory_module/Code/meercat/meercat/burrow',
    '/usr/lib/python311.zip', '/usr/lib/python3.11', 
    '/usr/lib/python3.11/lib-dynload', 
    '/home/user/.local/lib/python3.11/site-packages', 
    '/usr/local/lib/python3.11/dist-packages', 
    '/usr/lib/python3/dist-packages'
]

and upon running /meercat/meercat$ python3 -m burrow, sys.path is

[
    '/home/memory_module/Code/meercat/meercat',
    '/usr/lib/python311.zip', '/usr/lib/python3.11', 
    '/usr/lib/python3.11/lib-dynload', 
    '/home/user/.local/lib/python3.11/site-packages', 
    '/usr/local/lib/python3.11/dist-packages', 
    '/usr/lib/python3/dist-packages'
]

but manually appending '/home/memory_module/Code/meercat/meercat/burrow' to the path doesn't help.

I should note that when I run controller.main() directly (either through meercat/meercat/burrow$ python3 controller.py or meercat/meercat/burrow$ python3 -m controller)

Why does __main__.py behave differently in this regard to controller.py, and what am I doing wrong?

TL;DR: Django doesn't like treating __main__.py the same as controller.py, and I can't figure out why.

Source: A total of ca. 6 hours trying to understand the intricacies of __main__ from the Python docs, trying to find people who have had related issues and a bunch of fruitless experimentation.

Full Traceback:

Traceback (most recent call last):
    File "/home/memory_module/Code/meercat/meercat/burrow/__main__.py", line 20, in <module>
        django.setup()
    File "/home/rjn/.local/lib/python3.11/site-packages/django/__init__.py", line 19, in setup
        configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)
                      ^^^^^^^^^^^^^^^^^^^^^^^
    File "/home/rjn/.local/lib/python3.11/site-packages/django/conf/__init__.py", line 92, in __getattr__
        self._setup(name)
    File "/home/rjn/.local/lib/python3.11/site-packages/django/conf/__init__.py", line 79, in _setup
        self._wrapped = Settings(settings_module)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/home/rjn/.local/lib/python3.11/site-packages/django/conf/__init__.py", line 190, in __init__
        mod = importlib.import_module(self.SETTINGS_MODULE)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/usr/lib/python3.11/importlib/__init__.py", line 126, in import_module
        return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "<frozen importlib._bootstrap>", line 1206, in _gcd_import
    File "<frozen importlib._bootstrap>", line 1178, in _find_and_load
    File "<frozen importlib._bootstrap>", line 1142, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'burrow.settings'
MattDMo
  • 100,794
  • 21
  • 241
  • 231
  • Have you considered using custom management commands? `manage.py` handles the setup of django and your path for you when you call a management command – Iain Shelvington Apr 05 '23 at 14:34
  • @IainShelvington Could you elaborate on that? I've never heard of management commands and don't quite see how that changes things. – Blinkenlights Apr 05 '23 at 16:23
  • I do not know what's controller.py. Anyways: Do I understand you correctly that you want to create "your own" script that runs your project called __main__.py? When you put the -m flag it runs and when you don't put the -m flag it does not run? How the path changes with that flag you can read [here](https://stackoverflow.com/a/69527909/18018869) – Tarquinius Apr 06 '23 at 07:21

0 Answers0