Hey, I am new to the pants ecosystem and I am tryi...
# general
h
Hey, I am new to the pants ecosystem and I am trying to build a monorepo for my django projects. Here is the dir structure that I have
Copy code
.
├── 3rdparty
│   └── python
│       └── default.lock
├── BUILD
├── pants
├── pants.toml
├── poetry.lock
├── projects
│   ├── proj1
│   │   ├── BUILD
│   │   ├── manage.py
│   │   └── proj1
│   │       ├── BUILD
│   │       ├── __init__.py
│   │       ├── asgi.py
│   │       ├── settings.py
│   │       ├── urls.py
│   │       └── wsgi.py
│   └── proj2
│       ├── ...
└── pyproject.toml
Here's my pants.toml:
Copy code
[GLOBAL]
pants_version = "2.12.0"
backend_packages.add = [
  'pants.backend.python',
]

[anonymous-telemetry]
enabled = false

[source]
root_patterns = ["/"]

[python]
enable_resolves = true
lockfile_generator = "pex"

[python-infer]
string_imports = true
Here's my projects/proj1/BUILD:
Copy code
pex_binary(
    name="manage",
    entry_point="manage.py",
)

python_sources()
Here's my projects/proj1/proj1/BUILD:
Copy code
python_sources()
I am trying to run the runserver command with pants:
Copy code
./pants run projects/proj1/:manage -- runserver
But I am getting an error with stack trace:
Copy code
Traceback (most recent call last):
  File "/Users/reksus/.cache/pants/named_caches/pex_root/installed_wheels/115baf5049d5cf4163e43492cdc7139c306ed6d451e7d3571fe9612903903713/Django-3.2.15-py3-none-any.whl/django/core/management/base.py", line 354, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/Users/reksus/.cache/pants/named_caches/pex_root/installed_wheels/115baf5049d5cf4163e43492cdc7139c306ed6d451e7d3571fe9612903903713/Django-3.2.15-py3-none-any.whl/django/core/management/commands/runserver.py", line 61, in execute
    super().execute(*args, **options)
  File "/Users/reksus/.cache/pants/named_caches/pex_root/installed_wheels/115baf5049d5cf4163e43492cdc7139c306ed6d451e7d3571fe9612903903713/Django-3.2.15-py3-none-any.whl/django/core/management/base.py", line 398, in execute
    output = self.handle(*args, **options)
  File "/Users/reksus/.cache/pants/named_caches/pex_root/installed_wheels/115baf5049d5cf4163e43492cdc7139c306ed6d451e7d3571fe9612903903713/Django-3.2.15-py3-none-any.whl/django/core/management/commands/runserver.py", line 68, in handle
    if not settings.DEBUG and not settings.ALLOWED_HOSTS:
  File "/Users/reksus/.cache/pants/named_caches/pex_root/installed_wheels/115baf5049d5cf4163e43492cdc7139c306ed6d451e7d3571fe9612903903713/Django-3.2.15-py3-none-any.whl/django/conf/__init__.py", line 82, in __getattr__
    self._setup(name)
  File "/Users/reksus/.cache/pants/named_caches/pex_root/installed_wheels/115baf5049d5cf4163e43492cdc7139c306ed6d451e7d3571fe9612903903713/Django-3.2.15-py3-none-any.whl/django/conf/__init__.py", line 69, in _setup
    self._wrapped = Settings(settings_module)
  File "/Users/reksus/.cache/pants/named_caches/pex_root/installed_wheels/115baf5049d5cf4163e43492cdc7139c306ed6d451e7d3571fe9612903903713/Django-3.2.15-py3-none-any.whl/django/conf/__init__.py", line 170, in __init__
    mod = importlib.import_module(self.SETTINGS_MODULE)
  File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 961, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 973, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'proj1'
I tried updating the projects/proj1/BUILD:
Copy code
pex_binary(
    name="manage",
    entry_point="manage.py",
    dependencies=[
        "projects/proj1/proj1:proj1",
    ]
)

python_sources()
But still the same error. What am I missing here?
r
What are the import statements you are using? I feel like it's imported as
from proj1 ..
If that's the case then your
root_patterns
should have
projects
h
Yeah you are right, since manage.py has this line
Copy code
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proj1.settings')
which require projects/proj1/ to be in pythonpath so I fixed by updating pants.toml
Copy code
[source]
root_patterns = ["/"]
marker_filenames = ["manage.py"]
But now the command
Copy code
./pants run projects/proj1:manage -- runserver
thrown this error:
Copy code
Traceback (most recent call last):
  File "path/to/projects/proj1/manage.py", line 11, in main
    from django.core.management import execute_from_command_line
ModuleNotFoundError: No module named 'django'
but this command is working
Copy code
./pants run projects/proj1:manage -- runserver --noreload
Why is this?
r
How do you define your 3rd party dependencies (basically packages like Django)? Do you use
requirements.txt
? I don't see anywhere the code you have pasted here. As mentioned in this doc you can see all the dependencies (1st and 2nd) using
dependencies
command and it can be transitive too. So I would debug using that https://www.pantsbuild.org/docs/python-third-party-dependencies
h
I am using poetry top level pyproject.toml
Copy code
[tool.poetry]
name = "monorepo"
version = "0.1.0"
description = ""
authors = ["Tarun Tyagi"]
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.9"
Django = "^3.2"


[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
top level BUILD:
Copy code
pex_binary(
    name="django-admin",
    dependencies=[
        ":poetry#Django",
    ],
    script="django-admin",
)


poetry_requirements(name="poetry")
r
Yeah so I would run
dependencies
command and see if
django
shows up or not. Are you able to run it outside pants with just python?
Ideally you wouldn’t need to provide explicit dependency as long as pants can infer it.
h
Copy code
> ./pants dependencies projects/proj1/manage.py 
//:poetry#Django
projects/proj1/manage.py
projects/proj1/proj1/__init__.py
projects/proj1/proj1/asgi.py
projects/proj1/proj1/settings.py
projects/proj1/proj1/urls.py
projects/proj1/proj1/wsgi.py
Maybe I didn't write my earlier message clearly: This command doesn't work and says no module named django
Copy code
./pants run projects/proj1:manage -- runserver
But the following is working. So I have this working now.
Copy code
./pants run projects/proj1:manage -- runserver --noreload
I am actually asking what difference does --noreload make as far as pants is concerned? And in the github example-django the --noreload flag is not required with runserver cmd, so how can that be made possible here?
r
Ah ok! Sorry I might have also missed your question. Yeah this I am not sure about. Seems something django specific.
h
No problem Shantanu, thanks though. Btw --noreload simple stops reloading server on live code changes, i.e. doens't update the code already loaded in memory. Many languages have this live reloading feature. Maybe this could help you in helping me find the fix.
h
Ah yes - if I remember correctly, the way the Django autoreloader works interacts badly with Pants’s hermetic sandboxes, and gives that error (the autoreloader has some very unusual syspath hacking).
The way around this is to set
restartable=True
on the
pex_binary
target. (https://www.pantsbuild.org/docs/reference-pex_binary#coderestartablecode)
Then you get Pants itself to autoreload for you, instead of the Django autoreloader.
Pants is already watching the filesystem for changes, and it knows about dependencies even Django doesn’t know about, so it can actually be more accurate than the Django autoreloader anyway.
For example, Pants will reload (and rebuild as necessary) when you change your pyproject.toml, and I don’t think Django will
With Pants you get autoreloading even if the underlying framework doesn’t have it