Skip to content

Commit

Permalink
Merge 1481d1b into c0366e8
Browse files Browse the repository at this point in the history
  • Loading branch information
np5 committed Jun 26, 2024
2 parents c0366e8 + 1481d1b commit 4d4ca4d
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 0 deletions.
102 changes: 102 additions & 0 deletions server/base/management/commands/dump_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import pprint
from django.conf import settings
from django.core.management.base import BaseCommand
from django.urls import URLPattern, URLResolver
import xlsxwriter


DECORATORS = [
"csrf_protect",
"csrf_exempt",
"requires_csrf_token",
]


class Command(BaseCommand):
help = "Dump all the configured Django views."
csv_headers = [
("pattern", "Pattern"),
("module", "Module"),
("name", "View"),
("accounts_view", "Accounts view?"),
("admin_view", "Admin view?"),
("api_view", "API view?"),
("metrics_view", "Metrics view?"),
("public_view", "Public view?"),
("parents", "Parent view(s)"),
]

def add_arguments(self, parser):
parser.add_argument("--xlsx")

def handle(self, *args, **options):
urlconf = __import__(settings.ROOT_URLCONF, {}, {}, [''])
workbook = worksheet = None
row_idx = col_idx = 0
outfile = options.get("xlsx")
if outfile:
workbook = xlsxwriter.Workbook(outfile)
worksheet = workbook.add_worksheet("Zentral Django views")
for _, name in self.csv_headers:
worksheet.write(row_idx, col_idx, name)
col_idx += 1
for view_info in self.iter_view_info(urlconf.urlpatterns):
row_idx += 1
col_idx = 0
if worksheet:
view_info["parents"] = "\n".join(f"{m}.{n}" for m, n in view_info.pop("parents"))
for key, _ in self.csv_headers:
worksheet.write(row_idx, col_idx, view_info[key])
col_idx += 1
else:
self.stdout.write(pprint.pformat(view_info))
if workbook:
workbook.close()

def iter_views(self, urlpatterns, base='', namespace=None):
for p in urlpatterns:
pattern_desc = base + str(p.pattern)
if isinstance(p, URLPattern):
name = p.name
if namespace:
name = f'{namespace}:{name}'
yield p.callback, pattern_desc, name
elif isinstance(p, URLResolver):
if namespace and p.namespace:
_namespace = f'{namespace}:{p.namespace}'
else:
_namespace = p.namespace or namespace
yield from self.iter_views(p.url_patterns, pattern_desc, namespace=_namespace)
elif hasattr(p, '_get_callback'):
yield p._get_callback(), pattern_desc, p.name
elif hasattr(p, 'url_patterns') or hasattr(p, '_get_url_patterns'):
yield from self.iter_views(p.url_patterns, pattern_desc, namespace=namespace)

def prepare_view_info(self, func, pattern, url_name):
api_view = pattern.startswith("api/")
public_view = pattern.startswith("public/")
metrics_view = pattern.startswith("metrics/")
accounts_view = pattern.startswith("accounts/")
admin_view = not any([api_view, public_view, metrics_view, accounts_view])
view_class = getattr(func, "view_class", None)
parents = []
if view_class:
parents = [(cls.__module__, cls.__name__) for cls in view_class.__mro__ if cls not in (view_class, object)]
view_obj = view_class or func
view_module = view_obj.__module__
view_name = view_obj.__name__
return {
"api_view": api_view,
"public_view": public_view,
"metrics_view": metrics_view,
"accounts_view": accounts_view,
"admin_view": admin_view,
"module": view_module,
"name": view_name,
"parents": parents,
"pattern": pattern
}

def iter_view_info(self, urlpatterns):
for func, pattern, url_name in self.iter_views(urlpatterns):
yield self.prepare_view_info(func, pattern, url_name)
21 changes: 21 additions & 0 deletions tests/server_base/test_management_command_dump_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from io import StringIO
import os.path
import tempfile
from django.core.management import call_command
from django.test import TestCase


class DumpViewsBaseManagementCommandsTest(TestCase):
def test_dump_views_defaults(self):
out = StringIO()
call_command('dump_views', stdout=out)
self.assertIn("'name': 'IndexView'", out.getvalue())

def test_dump_views_xlsx(self):
with tempfile.TemporaryDirectory() as tmpdirname:
dest_file = os.path.join(tmpdirname, "yolo.xsls")
self.assertFalse(os.path.exists(dest_file))
call_command('dump_views', '--xlsx', os.path.join(tmpdirname, "yolo.xsls"))
self.assertTrue(os.path.exists(dest_file))
with open(dest_file, "rb") as f:
self.assertEqual(f.read(4), b"PK\x03\x04")

0 comments on commit 4d4ca4d

Please sign in to comment.