[4.2.x] Fixed #32813 -- Made runserver display port after binding.

Thanks Florian Apolloner for the review.

Backport of a18d20ca97 from main
This commit is contained in:
Dhanush 2023-02-04 01:43:36 +05:30 committed by Mariusz Felisiak
parent aaacf72c4c
commit a0623b117c
3 changed files with 45 additions and 36 deletions

View File

@ -127,14 +127,6 @@ class Command(BaseCommand):
threading = options["use_threading"] threading = options["use_threading"]
# 'shutdown_message' is a stealth option. # 'shutdown_message' is a stealth option.
shutdown_message = options.get("shutdown_message", "") shutdown_message = options.get("shutdown_message", "")
quit_command = "CTRL-BREAK" if sys.platform == "win32" else "CONTROL-C"
if self._raw_ipv6:
addr = f"[{self.addr}]"
elif self.addr == "0":
addr = "0.0.0.0"
else:
addr = self.addr
if not options["skip_checks"]: if not options["skip_checks"]:
self.stdout.write("Performing system checks...\n\n") self.stdout.write("Performing system checks...\n\n")
@ -142,23 +134,6 @@ class Command(BaseCommand):
# Need to check migrations here, so can't use the # Need to check migrations here, so can't use the
# requires_migrations_check attribute. # requires_migrations_check attribute.
self.check_migrations() self.check_migrations()
now = datetime.now().strftime("%B %d, %Y - %X")
self.stdout.write(now)
self.stdout.write(
(
"Django version %(version)s, using settings %(settings)r\n"
"Starting development server at %(protocol)s://%(addr)s:%(port)s/\n"
"Quit the server with %(quit_command)s."
)
% {
"version": self.get_version(),
"settings": settings.SETTINGS_MODULE,
"protocol": self.protocol,
"addr": addr,
"port": self.port,
"quit_command": quit_command,
}
)
try: try:
handler = self.get_handler(*args, **options) handler = self.get_handler(*args, **options)
@ -168,6 +143,7 @@ class Command(BaseCommand):
handler, handler,
ipv6=self.use_ipv6, ipv6=self.use_ipv6,
threading=threading, threading=threading,
on_bind=self.on_bind,
server_cls=self.server_cls, server_cls=self.server_cls,
) )
except OSError as e: except OSError as e:
@ -188,3 +164,23 @@ class Command(BaseCommand):
if shutdown_message: if shutdown_message:
self.stdout.write(shutdown_message) self.stdout.write(shutdown_message)
sys.exit(0) sys.exit(0)
def on_bind(self, server_port):
quit_command = "CTRL-BREAK" if sys.platform == "win32" else "CONTROL-C"
if self._raw_ipv6:
addr = f"[{self.addr}]"
elif self.addr == "0":
addr = "0.0.0.0"
else:
addr = self.addr
now = datetime.now().strftime("%B %d, %Y - %X")
version = self.get_version()
print(
f"{now}\n"
f"Django version {version}, using settings {settings.SETTINGS_MODULE!r}\n"
f"Starting development server at {self.protocol}://{addr}:{server_port}/\n"
f"Quit the server with {quit_command}.",
file=self.stdout,
)

View File

@ -252,13 +252,23 @@ class WSGIRequestHandler(simple_server.WSGIRequestHandler):
handler.run(self.server.get_app()) handler.run(self.server.get_app())
def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer): def run(
addr,
port,
wsgi_handler,
ipv6=False,
threading=False,
on_bind=None,
server_cls=WSGIServer,
):
server_address = (addr, port) server_address = (addr, port)
if threading: if threading:
httpd_cls = type("WSGIServer", (socketserver.ThreadingMixIn, server_cls), {}) httpd_cls = type("WSGIServer", (socketserver.ThreadingMixIn, server_cls), {})
else: else:
httpd_cls = server_cls httpd_cls = server_cls
httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6) httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
if on_bind is not None:
on_bind(getattr(httpd, "server_port", port))
if threading: if threading:
# ThreadingMixIn.daemon_threads indicates how threads will behave on an # ThreadingMixIn.daemon_threads indicates how threads will behave on an
# abrupt shutdown; like quitting the server by the user or restarting # abrupt shutdown; like quitting the server by the user or restarting

View File

@ -1587,21 +1587,24 @@ class ManageRunserver(SimpleTestCase):
call_command(self.cmd, addrport="7000") call_command(self.cmd, addrport="7000")
self.assertServerSettings("127.0.0.1", "7000") self.assertServerSettings("127.0.0.1", "7000")
@mock.patch("django.core.management.commands.runserver.run") def test_zero_ip_addr(self):
@mock.patch("django.core.management.base.BaseCommand.check_migrations") self.cmd.addr = "0"
def test_zero_ip_addr(self, *mocked_objects): self.cmd._raw_ipv6 = False
call_command( self.cmd.on_bind("8000")
"runserver",
addrport="0:8000",
use_reloader=False,
skip_checks=True,
stdout=self.output,
)
self.assertIn( self.assertIn(
"Starting development server at http://0.0.0.0:8000/", "Starting development server at http://0.0.0.0:8000/",
self.output.getvalue(), self.output.getvalue(),
) )
def test_on_bind(self):
self.cmd.addr = "127.0.0.1"
self.cmd._raw_ipv6 = False
self.cmd.on_bind("14437")
self.assertIn(
"Starting development server at http://127.0.0.1:14437/",
self.output.getvalue(),
)
@unittest.skipUnless(socket.has_ipv6, "platform doesn't support IPv6") @unittest.skipUnless(socket.has_ipv6, "platform doesn't support IPv6")
def test_runner_addrport_ipv6(self): def test_runner_addrport_ipv6(self):
call_command(self.cmd, addrport="", use_ipv6=True) call_command(self.cmd, addrport="", use_ipv6=True)