diff --git a/config/settings.py b/config/settings.py index 4fa4e23b..07b9767e 100755 --- a/config/settings.py +++ b/config/settings.py @@ -22,6 +22,7 @@ # Whether or not we're in local development mode LOCAL_DEVELOPMENT = env.bool("LOCAL_DEVELOPMENT", default=False) +DEBUG_TOOLBAR = env.bool("DEBUG_TOOLBAR", default=False) CI = env.bool("CI", default=False) if DEBUG: @@ -567,3 +568,12 @@ SLACK_BOT_TOKEN = env("SLACK_BOT_TOKEN", default="") ACCOUNT_DELETION_GRACE_PERIOD_DAYS = 10 + +if DEBUG_TOOLBAR: + INSTALLED_APPS += ["debug_toolbar"] + INTERNAL_IPS = ["127.0.0.1", "localhost"] + DEBUG_TOOLBAR_CONFIG = { + "SHOW_TOOLBAR_CALLBACK": lambda x: True, + "ROOT_TAG_EXTRA_ATTRS": "hx-preserve", + } + MIDDLEWARE.append("debug_toolbar.middleware.DebugToolbarMiddleware") diff --git a/config/test_settings.py b/config/test_settings.py index 82b986e3..3ad22f33 100644 --- a/config/test_settings.py +++ b/config/test_settings.py @@ -18,6 +18,12 @@ def __getitem__(self, item): DEBUG = False +OAUTH2_PROVIDER_APPLICATION_MODEL = "oauth2_provider.Application" +OAUTH2_PROVIDER_ACCESS_TOKEN_MODEL = "oauth2_provider.AccessToken" +OAUTH2_PROVIDER_ID_TOKEN_MODEL = "oauth2_provider.IDToken" +OAUTH2_PROVIDER_GRANT_MODEL = "oauth2_provider.Grant" +OAUTH2_PROVIDER_REFRESH_TOKEN_MODEL = "oauth2_provider.RefreshToken" + EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend" MIGRATION_MODULES = DisableMigrations() diff --git a/config/urls.py b/config/urls.py index fee92c8d..9a474828 100755 --- a/config/urls.py +++ b/config/urls.py @@ -1,3 +1,5 @@ +import logging + from django.conf import settings from django.conf.urls.static import static from django.contrib import admin @@ -13,6 +15,7 @@ NotFoundView, OKView, ) +from config.settings import DEBUG_TOOLBAR from core.views import ( BSLView, CalendarView, @@ -78,6 +81,17 @@ VersionDetail, ) +djdt_urls = [] +try: + if DEBUG_TOOLBAR: + from debug_toolbar.toolbar import debug_toolbar_urls + + djdt_urls = debug_toolbar_urls() +except ModuleNotFoundError: + logging.error( + "DEBUG_TOOLBAR enabled but Django Debug Toolbar not installed. Run `just build`" + ) + register_converter(BoostVersionSlugConverter, "boostversionslug") router = routers.SimpleRouter() @@ -358,11 +372,12 @@ ), # Static content re_path( - r"^(?P.+)/?", + r"^(?!__debug__)(?P.+)/?", StaticContentTemplateView.as_view(), name="static-content-page", ), ] + + djdt_urls ) handler404 = "ak.views.custom_404_view" diff --git a/docker-compose.yml b/docker-compose.yml index 9e3c8263..f584e159 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,6 +25,8 @@ services: build: context: . dockerfile: docker/Dockerfile + args: + LOCAL_DEVELOPMENT: "true" command: [ "/bin/bash", "/code/docker/compose-start.sh" ] depends_on: - db @@ -96,6 +98,8 @@ services: /code/docker/wait-for-it.sh -h web -p 8000 -t 20 -- celery -A config worker --concurrency=10 -P gevent --loglevel=debug networks: - backend + environment: + DEBUG_TOOLBAR: "false" env_file: - .env depends_on: @@ -109,6 +113,8 @@ services: context: . dockerfile: docker/Dockerfile command: [ "celery", "-A", "config", "beat", "--loglevel=debug" ] + environment: + DEBUG_TOOLBAR: "false" env_file: - .env depends_on: diff --git a/docker/Dockerfile b/docker/Dockerfile index 3ec1fd8c..f1c6c4ce 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -2,6 +2,8 @@ FROM python:3.11-slim AS builder-py +ARG LOCAL_DEVELOPMENT + RUN apt update && apt install -y build-essential gcc python-dev-is-python3 libpq-dev postgresql-client ruby ruby-dev && rm -rf /var/lib/apt/lists/* # Install ruby's asciidoctor. @@ -13,6 +15,8 @@ RUN pip install --upgrade pip # Boostrap uv. RUN pip install 'uv>=0.2.27,<0.3' COPY ./requirements.txt ./code/requirements.txt +COPY ./requirements-dev.txt ./code/requirements-dev.txt + # Create the virtualenv. RUN uv venv venv @@ -22,6 +26,11 @@ RUN --mount=type=cache,target=/root/.cache \ . /venv/bin/activate && \ uv pip install -r /code/requirements.txt +RUN --mount=type=cache,target=/root/.cache if [ "${LOCAL_DEVELOPMENT}" = "true" ]; then \ + . /venv/bin/activate && \ + uv pip install -r /code/requirements-dev.txt; \ + fi + # Builder step for JS. FROM node:22-slim AS builder-js diff --git a/docs/development_setup_notes.md b/docs/development_setup_notes.md index 60efa3d4..ab66cf66 100644 --- a/docs/development_setup_notes.md +++ b/docs/development_setup_notes.md @@ -340,3 +340,19 @@ Setup should be complete and you should be able to see an option to "Use Google" #### Additional Notes: **Working locally**: If you need to run through the login flows multiple times, create a superuser so you can log into the admin. Then, log into the admin and delete your "Social Account" from the admin. This will test a fresh connection to GitHub for your logged-in GitHub user. + +### Debugging +For local development there is Django Debug Toolbar, and the option to set a debugger. + +#### Common Options +In your env: +- Django Debug Toolbar, enabled by default, can be disabled by setting DEBUG_TOOLBAR=False +- IDE Debugging, disabled by default, can be enabled by uncommenting `PYTHONBREAKPOINT` in your .env file. + + +#### Set Up Pycharm +You can set up your IDE with a new "Python Debug Server" configuration as: +The GitHub screen that registers a new OAuth app + +#### Common Usage +To use the debugger add `breakpoint()` somewhere before you want to start debugging and then add breakpoints by clicking on the gutter. The debugger will stop at these point, you can then step/inspect the variables. diff --git a/docs/images/pycharm_debugger_settings.png b/docs/images/pycharm_debugger_settings.png new file mode 100644 index 00000000..0dbe8675 Binary files /dev/null and b/docs/images/pycharm_debugger_settings.png differ diff --git a/env.template b/env.template index b9e668c2..90565258 100644 --- a/env.template +++ b/env.template @@ -55,3 +55,8 @@ GOOGLE_OAUTH_CLIENT_ID= GOOGLE_OAUTH_CLIENT_SECRET= SLACK_BOT_TOKEN=changeme +DEBUG_TOOLBAR=True +# uncomment whichever is appropriate for your editor +# currently only pycharm is supported, vscode kept for example of alternative options +# PYTHONBREAKPOINT=pycharm_debugger.set_trace +# PYTHONBREAKPOINT=vscode_debugger.set_trace diff --git a/justfile b/justfile index d0ee10b2..24afaa18 100644 --- a/justfile +++ b/justfile @@ -51,10 +51,10 @@ alias shell := console docker compose --file docker-compose.yml run --rm web python manage.py migrate --noinput @test_pytest: ## runs pytest - -docker compose run --rm web pytest -s --create-db + -docker compose run --rm -e DEBUG_TOOLBAR="False" web pytest -s --create-db @test_pytest_asciidoctor: ## runs asciidoctor tests - -docker compose run --rm web pytest -m asciidoctor -s + -docker compose run --rm -e DEBUG_TOOLBAR="False" web pytest -m asciidoctor -s --create-db @test_interrogate: ## runs interrogate tests docker compose run --rm web interrogate -vv --fail-under 100 --whitelist-regex "test_.*" . @@ -122,6 +122,7 @@ alias shell := console # Dependency management @pip-compile ARGS='': ## rebuilds our pip requirements docker compose run --rm web uv pip compile {{ ARGS }} ./requirements.in --no-strip-extras --output-file ./requirements.txt + docker compose run --rm web uv pip compile {{ ARGS }} ./requirements-dev.in --no-strip-extras --output-file ./requirements-dev.txt @pip-compile-upgrade: ## Upgrade existing Python dependencies to their latest versions just pip-compile --upgrade diff --git a/pycharm_debugger.py b/pycharm_debugger.py new file mode 100644 index 00000000..c8165d98 --- /dev/null +++ b/pycharm_debugger.py @@ -0,0 +1,13 @@ +def set_trace(): + import pydevd_pycharm + + # this ip address is for the gateway IP, equivalent to host.docker.internal which + # isn't available on all platforms + gateway_ip = "172.17.0.1" + pydevd_pycharm.settrace( + host=gateway_ip, + port=12345, # Use the same port number configured in PyCharm + stdoutToServer=True, + stderrToServer=True, + suspend=False, + ) diff --git a/requirements-dev.in b/requirements-dev.in new file mode 100644 index 00000000..d853217b --- /dev/null +++ b/requirements-dev.in @@ -0,0 +1,3 @@ +-c requirements.txt +django-debug-toolbar +pydevd-pycharm==242.23726.102 # pinned to appropriate version for current pycharm diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 00000000..f831d396 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,19 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile ./requirements-dev.in --no-strip-extras --output-file ./requirements-dev.txt +asgiref==3.8.1 + # via + # -c ./requirements.txt + # django +django==4.2.16 + # via + # -c ./requirements.txt + # django-debug-toolbar +django-debug-toolbar==4.4.6 + # via -r ./requirements-dev.in +pydevd-pycharm==242.23726.102 + # via -r ./requirements-dev.in +sqlparse==0.5.1 + # via + # -c ./requirements.txt + # django + # django-debug-toolbar