Skip to content

Instantly share code, notes, and snippets.

@ErikKalkoken
Created October 4, 2024 13:37
Show Gist options
  • Save ErikKalkoken/526e54215475bc794fe425d0a0dfcb85 to your computer and use it in GitHub Desktop.
Save ErikKalkoken/526e54215475bc794fe425d0a0dfcb85 to your computer and use it in GitHub Desktop.
Find_apps is a command line tool to identify Django apps in a Python package
"""Find_apps is a command line tool to identify all Django apps in a Python package.
The tools will look for and parse AppConfig definitions in apps.py files.
Django apps which do not have an apps.py file will not be recognized.
usage: find_apps.py [-h] [-path PATH] [-hide-name]
options:
-h, --help show this help message and exit
-path PATH, -p PATH starting path (default: .)
-hide-name do not show app names (default: False)
"""
import argparse
import re
from pathlib import Path
from typing import NamedTuple
class AppConfig(NamedTuple):
name: str
label: str
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument("-path", "-p", default=".", help="starting path")
parser.add_argument("-hide-name", action='store_true', help="do not show app names")
args = parser.parse_args()
start = Path(args.path).absolute()
print(f"Looking for Django apps at: {start}")
apps = find_apps(start)
if args.hide_name:
for a in apps:
print(a.label)
else:
label_width = max_label_width(apps)
for a in apps:
print(f"{a.label:{label_width}} {a.name}")
def find_apps(start: Path) -> list[AppConfig]:
apps = []
for p in start.rglob("apps.py"):
text = p.read_text()
if "AppConfig" not in text:
continue
ac = extract_config(text)
if ac == "":
print(f"ERROR: failed to determine label for {p}")
apps.append(ac)
apps.sort(key=lambda x:x.label)
return apps
def extract_config(text: str) -> AppConfig:
m = re.search(r"name\s*=\s*[\"']([\w.]+)[\"']", text)
if m is None:
return ""
name = m.group(1)
parts = name.split(".")
label = parts.pop()
m = re.search(r"label\s*=\s*[\"'](\w+)[\"']", text)
if m is not None:
label = m.group(1) # label defined
return AppConfig(name=name, label=label)
def max_label_width(apps):
w = 0
for a in apps:
w = max(w, len(a.label))
return w
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment