Update app and tooling

This commit is contained in:
Lawrence Chen 2026-01-29 17:36:26 -08:00
parent 3046531bdd
commit e620ec7349
4950 changed files with 2975120 additions and 10 deletions

View file

@ -0,0 +1,72 @@
import sys
import ast
def contains_app_or_handler(file_path: str) -> bool:
"""
Check if a Python file contains or exports:
- A top-level 'app' callable (e.g., Flask, FastAPI, Sanic apps)
- A top-level 'handler' class (e.g., BaseHTTPRequestHandler subclass)
"""
with open(file_path, "r") as file:
code = file.read()
try:
tree = ast.parse(code)
except SyntaxError:
return False
for node in ast.iter_child_nodes(tree):
# Check for top-level assignment to 'app'
# e.g., app = Sanic() or app = Flask(__name__) or app = create_app()
if isinstance(node, ast.Assign):
for target in node.targets:
if isinstance(target, ast.Name) and target.id == "app":
return True
# Check for annotated assignment to 'app'
# e.g., app: Sanic = Sanic()
if isinstance(node, ast.AnnAssign):
if isinstance(node.target, ast.Name) and node.target.id == "app":
return True
# Check for function named 'app'
# e.g., def app(environ, start_response): ...
if isinstance(node, ast.FunctionDef) and node.name == "app":
return True
# Check for async function named 'app'
# e.g., async def app(scope, receive, send): ...
if isinstance(node, ast.AsyncFunctionDef) and node.name == "app":
return True
# Check for import of 'app'
# e.g., from server import app
# e.g., from server import application as app
if isinstance(node, ast.ImportFrom):
for alias in node.names:
# alias.asname is the 'as' name, alias.name is the original name
# If aliased, check asname; otherwise check the original name
imported_as = alias.asname if alias.asname else alias.name
if imported_as == "app":
return True
# Check for top-level class named 'handler'
# e.g., class handler(BaseHTTPRequestHandler):
if isinstance(node, ast.ClassDef) and node.name.lower() == "handler":
return True
return False
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python ast_parser.py <file_path>")
sys.exit(1)
file_path = sys.argv[1]
result = contains_app_or_handler(file_path)
# Exit with 0 if found, 1 if not found
sys.exit(0 if result else 1)

View file

@ -0,0 +1,72 @@
import unittest
import tempfile
import os
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent))
from ast_parser import contains_app_or_handler
class TestContainsAppOrHandler(unittest.TestCase):
def _check(self, code: str) -> bool:
"""Helper to test code snippets without needing fixture files."""
with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f:
f.write(code)
f.flush()
try:
return contains_app_or_handler(f.name)
finally:
os.unlink(f.name)
def test_flask_app(self):
self.assertTrue(self._check("from flask import Flask\napp = Flask(__name__)"))
def test_fastapi_app(self):
self.assertTrue(self._check("from fastapi import FastAPI\napp = FastAPI()"))
def test_sanic_app(self):
self.assertTrue(self._check("from sanic import Sanic\napp = Sanic('app')"))
def test_annotated_app(self):
self.assertTrue(self._check("from fastapi import FastAPI\napp: FastAPI = FastAPI()"))
def test_wsgi_function(self):
self.assertTrue(self._check("def app(environ, start_response):\n pass"))
def test_asgi_function(self):
self.assertTrue(self._check("async def app(scope, receive, send):\n pass"))
def test_imported_app(self):
self.assertTrue(self._check("from server import app"))
def test_imported_app_aliased(self):
self.assertTrue(self._check("from server import application as app"))
def test_handler_class(self):
self.assertTrue(self._check("class Handler:\n pass"))
def test_handler_class_lowercase(self):
self.assertTrue(self._check("class handler:\n pass"))
def test_no_app_or_handler(self):
self.assertFalse(self._check("def hello():\n return 'world'"))
def test_app_in_function_not_toplevel(self):
# app defined inside a function should NOT match
self.assertFalse(self._check("def create():\n app = Flask(__name__)\n return app"))
def test_syntax_error(self):
self.assertFalse(self._check("def broken("))
def test_empty_file(self):
self.assertFalse(self._check(""))
def test_only_comments(self):
self.assertFalse(self._check("# just a comment\n# another comment"))
if __name__ == "__main__":
unittest.main()