class

Detector::Python::HttpServer

Inherits Detector < Reference < Object

Constants

HANDLER_SUBCLASS_RE = /\bclass\s+\w+\s*\(\s*(?:[\w.]+\s*,\s*)*(?:[\w.]+\.)?(?:Base|Simple|CGI)HTTPRequestHandler\s*[,)]/

A handler subclass still counts on its own: a module that receives the base class through a re-export (from .compat import BaseHTTPRequestHandler) carries no http.server import of its own, and it is the file the analyzer needs. Anchored to a real class ...( header so a bare mention of the name in prose no longer qualifies. Earlier bases are allowed: class Handler(ThreadingMixIn, BaseHTTPRequestHandler) is the idiomatic way to write exactly the module this branch exists for.

IMPORT_RE = /(?:^|\n)[ \t\x{FEFF}]*(?:from[ \t]+http\.server[ \t]+import\b|import[ \t]+(?:[\w.]+[ \t]*,[ \t]*)*http\.server\b|from[ \t]+http[ \t]+import[ \t]+(?:[\w,][\w, \t]*[ \t,])?server\b)/

The stdlib module has to be imported before any of its handler or server classes can be named, so anchor on the import the way the other built-in-server detectors do (java_httpserver requires com.sun.net.httpserver, dart_http requires import 'dart:io').

This replaces four bare substring probes — "http.server", "HTTPServer", "BaseHTTPRequestHandler", "SimpleHTTPRequestHandler" — that matched anywhere in a file, including prose. Two real cases fell out of that:

  • a python -m http.server line in a comment or module docstring (the standard way to say "serve these fixtures locally") flagged the whole project as a stdlib-server app;
  • HTTPServer alone also matched Tornado's from tornado.httpserver import HTTPServer, so every Tornado project was additionally reported as python_http_server and paid for a second analyzer pass over the same tree.

Covers from http.server import ..., import [os, ]http.server[ as x] and from http import [cookies, ]server. \x{FEFF} after the line start keeps a UTF-8-BOM file's first line matchable — Noir::TextFile deliberately strips no BOM.

Instance methods

applicable?(filename : String) : Bool

Cheap filename-only filter the detector pass uses to skip detect on files the detector cannot possibly match. The default true preserves prior behavior (every detector runs on every file). Override with the same predicate the body of detect starts with — e.g., filename.ends_with?(".py") for a Python framework detector — so the detector loop avoids the detect dispatch on files outside the detector's language.

On large codebases (saleor's 4255 .py files) this lifts ~100 virtual detect calls per file out of the hot loop because most detectors' inner first-line is exactly this kind of cheap filename check.

Source
detect(filename : String, file_contents : String) : Bool
Source
name

The tech name; detector_for overrides it. Empty on the bare base.

Source