Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Self-documenting environment variables #96

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion config/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,24 @@
"""Holds the setings and entrypoints."""
"""Define the configuration scheme using environ-config."""

import logging

import environ

logger = logging.getLogger(__name__)


@environ.config(prefix="SCRAM")
class AppConfig:
"""Top level configuration (i.e. SCRAM_)."""

debugger = environ.var(
default="", help='Will launch the appropriate debugger if set to either "pycharm-pydevd" or "debugpy".'
)

@debugger.validator
def _warn_on_unknown_debugger(self, var, debugger):
samoehlert marked this conversation as resolved.
Show resolved Hide resolved
if debugger and debugger not in {"pycharm-pydevd", "debugpy"}:
logger.warning("Unknown debugger value: %s", debugger)


cfg = environ.to_config(AppConfig)
26 changes: 3 additions & 23 deletions config/asgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,10 @@
# TODO: from channels.security.websocket import AllowedHostsOriginValidator
from django.core.asgi import get_asgi_application

logger = logging.getLogger(__name__)

# Here we setup a debugger if this is desired. This obviously should not be run in production.
debug = os.environ.get("DEBUG")
if debug:
logger.info("Django is set to use a debugger. Provided debug mode: %s", debug)
if debug == "pycharm-pydevd":
logger.info("Entering debug mode for pycharm, make sure the debug server is running in PyCharm!")

import pydevd_pycharm

pydevd_pycharm.settrace("host.docker.internal", port=56783, stdoutToServer=True, stderrToServer=True)
from scram.utils import debug

logger.info("Debugger started.")
elif debug == "debugpy":
logger.info("Entering debug mode for debugpy (VSCode)")

import debugpy

debugpy.listen(("0.0.0.0", 56780)) # noqa S104 (doesn't like binding to all interfaces)

logger.info("Debugger listening on port 56780.")
else:
logger.warning("Invalid debug mode given: %s. Debugger not started", debug)
logger = logging.getLogger(__name__)
debug.setup(base_port=56730)

# This allows easy placement of apps within the interior
# scram directory.
Expand Down
28 changes: 28 additions & 0 deletions docs/document_env_vars.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""Converts environ-config's documentation to Markdown and writes it to the docs folder."""

import sys
from pathlib import Path

sys.path.append(".")

from config import cfg


def formatter(options):
"""Formats the help text to Markdown.

Returns:
str: A simple Markdown table with the env vars
"""
result = "| Name | Description | Required | Default |\n"
result += "|-|-|-|-|\n"
for o in options:
result += f"|{o['var_name']}|{o['help_str']}|{o['required']}|{o['default']!r}|\n"

return result


def on_pre_build(config):
"""Handler from mkdocs hook."""
with Path("docs/environment_variables.md").open("w", encoding="utf-8") as f:
f.write(cfg.generate_help(formatter=formatter))
4 changes: 2 additions & 2 deletions docs/reference/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

The SCRAM ecosystem consists of two parts:

A Django app, [route_manager](/reference/django)
A Django app, [route_manager](django.md)

A translator service, [translator](/reference/translator)
A translator service, [translator](translator.md)
3 changes: 3 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ plugins:
show_submodules: true
- search
- section-index

hooks:
- docs/document_env_vars.py
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ data_file = "coverage.coverage"

[tool.coverage.report]
exclude_also = [
"if cfg.debugger:",
"if debug:",
"if self.debug:",
"if settings.DEBUG",
Expand Down
1 change: 1 addition & 0 deletions requirements/base.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
argon2-cffi==21.3.0 # https://github.com/hynek/argon2_cffi
django-celery-beat # https://github.com/celery/django-celery-beat
django-netfields # https://pypi.org/project/django-netfields/
environ-config # https://pypi.org/project/environ-config/
flower==1.0.0 # https://github.com/mher/flower
python-slugify==6.1.2 # https://github.com/un33k/python-slugify
uvicorn[standard]==0.17.6 # https://github.com/encode/uvicorn
Expand Down
6 changes: 0 additions & 6 deletions requirements/local.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,3 @@ django-debug-toolbar==3.4.0 # https://github.com/jazzband/django-debug-toolbar
django-extensions==3.1.5 # https://github.com/django-extensions/django-extensions
django-coverage-plugin==3.1.0 # https://github.com/nedbat/django_coverage_plugin
pytest-django==4.5.2 # https://github.com/pytest-dev/pytest-django

# Debugging
# ------------------------------------------------------------------------------
debugpy
# Pycharm might force you to be on the same version IDE as library, use caution.
pydevd-pycharm
52 changes: 52 additions & 0 deletions scram/utils/debug.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""Enable either the PyCharm or debugpy debugger."""

import logging
import subprocess # noqa: S404
import sys

from config import cfg

logger = logging.getLogger(__name__)


def setup(base_port=56780):
"""Setup a debugger if this is desired. This obviously should not be run in production.

If using PyCharm, will start it on base_port + 1.
If using debugpy, will start it on base_port.

"""
if cfg.debugger:
logger.info("Django is set to use a debugger. Provided debug mode: %s", cfg.debugger)
if cfg.debugger == "pycharm-pydevd":
logger.info("Entering debug mode for pycharm, make sure the debug server is running in PyCharm!")

try:
import pydevd_pycharm # noqa: PLC0415
except ImportError:
logger.info("Installing pydevd_pycharm...")
subprocess.check_call([sys.executable, "-m", "pip", "install", "pydevd-pycharm"]) # noqa: S603 TODO: add this to the container build
import pydevd_pycharm # noqa: PLC0415

logger.info("Done installing pydevd_pycharm")

pydevd_pycharm.settrace(
"host.docker.internal", port=base_port + 1, stdoutToServer=True, stderrToServer=True
)

logger.info("pycharm-pydevd debugger started on host=host.docker.internal port=%d.", base_port + 1)
elif cfg.debugger == "debugpy":
logger.info("Entering debug mode for debugpy (VSCode)")

try:
import debugpy # noqa: PLC0415
except ImportError:
logger.info("Installing debugpy...")
subprocess.check_call([sys.executable, "-m", "pip", "install", "debugpy"]) # noqa: S603 TODO: add this to the container build
import debugpy # noqa: PLC0415

logger.info("Done installing debugpy")

debugpy.listen(("0.0.0.0", base_port)) # noqa S104 (doesn't like binding to all interfaces)

logger.info("VScode debugpy debugger started on host=0.0.0.0 port=%d.", base_port)
50 changes: 3 additions & 47 deletions translator/translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@
import websockets
from gobgp import GoBGP

from scram.utils import debug

logger = logging.getLogger(__name__)
debug.setup(base_port=56732)

KNOWN_MESSAGES = {
"translator_add",
Expand All @@ -20,53 +23,6 @@
"translator_check",
}

# Here we setup a debugger if this is desired. This obviously should not be run in production.
debug_mode = os.environ.get("DEBUG")
if debug_mode:

def install_deps():
"""Install necessary dependencies for debuggers.

Because of how we build translator currently, we don't have a great way to selectively
install things at build, so we just do it here! Right now this also includes base.txt,
which is unecessary, but in the future when we build a little better, it'll already be
setup.
"""
logger.info("Installing dependencies for debuggers")

import subprocess # noqa: S404, PLC0415
import sys # noqa: PLC0415

subprocess.check_call([sys.executable, "-m", "pip", "install", "-r", "/requirements/local.txt"]) # noqa: S603 TODO: add this to the container build

logger.info("Done installing dependencies for debuggers")

logger.info("Translator is set to use a debugger. Provided debug mode: %s", debug_mode)
# We have to setup the debugger appropriately for various IDEs. It'd be nice if they all used the same thing but
# sadly, we live in a fallen world.
if debug_mode == "pycharm-pydevd":
logger.info("Entering debug mode for pycharm, make sure the debug server is running in PyCharm!")

install_deps()

import pydevd_pycharm

pydevd_pycharm.settrace("host.docker.internal", port=56782, stdoutToServer=True, stderrToServer=True)

logger.info("Debugger started.")
elif debug_mode == "debugpy":
logger.info("Entering debug mode for debugpy (VSCode)")

install_deps()

import debugpy

debugpy.listen(("0.0.0.0", 56781)) # noqa S104 (doesn't like binding to all interfaces)

logger.info("Debugger listening on port 56781.")
else:
logger.warning("Invalid debug mode given: %s. Debugger not started", debug_mode)

# Must match the URL in asgi.py, and needs a trailing slash
hostname = os.environ.get("SCRAM_HOSTNAME", "scram_hostname_not_set")
url = os.environ.get("SCRAM_EVENTS_URL", "ws://django:8000/ws/route_manager/translator_block/")
Expand Down
Loading