all: Support lazy imports of submodules
A getattr hook in the top-level "tornado" package now imports submodules automatically, eliminating the need to explicitly reference multiple submodules in imports
This commit is contained in:
parent
41e70ac920
commit
6c2aae090c
|
@ -21,8 +21,7 @@ Here is a simple "Hello, world" example web app for Tornado:
|
|||
.. code-block:: python
|
||||
|
||||
import asyncio
|
||||
|
||||
import tornado.web
|
||||
import tornado
|
||||
|
||||
class MainHandler(tornado.web.RequestHandler):
|
||||
def get(self):
|
||||
|
|
|
@ -21,12 +21,7 @@ import markdown
|
|||
import os.path
|
||||
import psycopg2
|
||||
import re
|
||||
import tornado.escape
|
||||
import tornado.httpserver
|
||||
import tornado.ioloop
|
||||
import tornado.locks
|
||||
import tornado.options
|
||||
import tornado.web
|
||||
import tornado
|
||||
import unicodedata
|
||||
|
||||
from tornado.options import define, options
|
||||
|
|
|
@ -15,9 +15,7 @@
|
|||
# under the License.
|
||||
|
||||
import asyncio
|
||||
import tornado.escape
|
||||
import tornado.locks
|
||||
import tornado.web
|
||||
import tornado
|
||||
import os.path
|
||||
import uuid
|
||||
|
||||
|
|
|
@ -16,11 +16,7 @@
|
|||
|
||||
import asyncio
|
||||
import os.path
|
||||
import tornado.auth
|
||||
import tornado.escape
|
||||
import tornado.httpserver
|
||||
import tornado.options
|
||||
import tornado.web
|
||||
import tornado
|
||||
|
||||
from tornado.options import define, options
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import asyncio
|
|||
import logging
|
||||
from urllib.parse import unquote
|
||||
|
||||
import tornado.web
|
||||
import tornado
|
||||
from tornado import options
|
||||
|
||||
|
||||
|
|
|
@ -15,9 +15,7 @@
|
|||
# under the License.
|
||||
|
||||
import asyncio
|
||||
import tornado.httpserver
|
||||
import tornado.options
|
||||
import tornado.web
|
||||
import tornado
|
||||
|
||||
from tornado.options import define, options
|
||||
|
||||
|
|
|
@ -20,10 +20,7 @@ Authentication, error handling, etc are left as an exercise for the reader :)
|
|||
|
||||
import asyncio
|
||||
import logging
|
||||
import tornado.escape
|
||||
import tornado.options
|
||||
import tornado.web
|
||||
import tornado.websocket
|
||||
import tornado
|
||||
import os.path
|
||||
import uuid
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
.. testsetup::
|
||||
|
||||
import tornado.auth, tornado.gen, tornado.web
|
||||
import tornado
|
||||
|
||||
.. automodule:: tornado.auth
|
||||
|
||||
|
|
|
@ -3,8 +3,7 @@ Authentication and security
|
|||
|
||||
.. testsetup::
|
||||
|
||||
import tornado.auth
|
||||
import tornado.web
|
||||
import tornado
|
||||
|
||||
Cookies and secure cookies
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
.. testsetup::
|
||||
|
||||
import tornado.web
|
||||
import tornado
|
||||
|
||||
Structure of a Tornado web application
|
||||
======================================
|
||||
|
@ -17,8 +17,7 @@ A minimal "hello world" example looks something like this:
|
|||
.. testcode::
|
||||
|
||||
import asyncio
|
||||
|
||||
import tornado.web
|
||||
import tornado
|
||||
|
||||
class MainHandler(tornado.web.RequestHandler):
|
||||
def get(self):
|
||||
|
|
|
@ -3,7 +3,7 @@ Templates and UI
|
|||
|
||||
.. testsetup::
|
||||
|
||||
import tornado.web
|
||||
import tornado
|
||||
|
||||
Tornado includes a simple, fast, and flexible templating language.
|
||||
This section describes that language as well as related issues
|
||||
|
|
|
@ -32,8 +32,7 @@ Hello, world
|
|||
Here is a simple "Hello, world" example web app for Tornado::
|
||||
|
||||
import asyncio
|
||||
|
||||
import tornado.web
|
||||
import tornado
|
||||
|
||||
class MainHandler(tornado.web.RequestHandler):
|
||||
def get(self):
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
.. testsetup::
|
||||
|
||||
import tornado.websocket
|
||||
import tornado
|
||||
|
||||
.. automodule:: tornado.websocket
|
||||
|
||||
|
|
|
@ -24,3 +24,44 @@
|
|||
# number has been incremented)
|
||||
version = "6.3.dev1"
|
||||
version_info = (6, 3, 0, -100)
|
||||
|
||||
import importlib
|
||||
import typing
|
||||
|
||||
__all__ = [
|
||||
"auth",
|
||||
"autoreload",
|
||||
"concurrent",
|
||||
"curl_httpclient",
|
||||
"escape",
|
||||
"gen",
|
||||
"http1connection",
|
||||
"httpclient",
|
||||
"httpserver",
|
||||
"httputil",
|
||||
"ioloop",
|
||||
"iostream",
|
||||
"locale",
|
||||
"locks",
|
||||
"log",
|
||||
"netutil",
|
||||
"options",
|
||||
"platform",
|
||||
"process",
|
||||
"queues",
|
||||
"routing",
|
||||
"simple_httpclient",
|
||||
"tcpclient",
|
||||
"tcpserver",
|
||||
"template",
|
||||
"testing",
|
||||
"util",
|
||||
"web",
|
||||
]
|
||||
|
||||
|
||||
# Copied from https://peps.python.org/pep-0562/
|
||||
def __getattr__(name: str) -> typing.Any:
|
||||
if name in __all__:
|
||||
return importlib.import_module("." + name, __name__)
|
||||
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
||||
|
|
|
@ -83,7 +83,7 @@ class IOLoop(Configurable):
|
|||
import functools
|
||||
import socket
|
||||
|
||||
import tornado.ioloop
|
||||
import tornado
|
||||
from tornado.iostream import IOStream
|
||||
|
||||
async def handle_connection(connection, address):
|
||||
|
|
|
@ -1069,9 +1069,8 @@ class IOStream(BaseIOStream):
|
|||
|
||||
.. testcode::
|
||||
|
||||
import tornado.ioloop
|
||||
import tornado.iostream
|
||||
import socket
|
||||
import tornado
|
||||
|
||||
async def main():
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
|
||||
|
|
|
@ -56,7 +56,7 @@ Your ``main()`` method can parse the command line or parse a config file with
|
|||
either `parse_command_line` or `parse_config_file`::
|
||||
|
||||
import myapp.db, myapp.server
|
||||
import tornado.options
|
||||
import tornado
|
||||
|
||||
if __name__ == '__main__':
|
||||
tornado.options.parse_command_line()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import unittest
|
||||
|
||||
import tornado.escape
|
||||
import tornado
|
||||
from tornado.escape import (
|
||||
utf8,
|
||||
xhtml_escape,
|
||||
|
|
|
@ -11,38 +11,31 @@ _import_everything = b"""
|
|||
import asyncio
|
||||
asyncio.set_event_loop(None)
|
||||
|
||||
import tornado.auth
|
||||
import tornado.autoreload
|
||||
import tornado.concurrent
|
||||
import tornado.escape
|
||||
import tornado.gen
|
||||
import tornado.http1connection
|
||||
import tornado.httpclient
|
||||
import tornado.httpserver
|
||||
import tornado.httputil
|
||||
import tornado.ioloop
|
||||
import tornado.iostream
|
||||
import tornado.locale
|
||||
import tornado.log
|
||||
import tornado.netutil
|
||||
import tornado.options
|
||||
import tornado.process
|
||||
import tornado.simple_httpclient
|
||||
import tornado.tcpserver
|
||||
import tornado.tcpclient
|
||||
import tornado.template
|
||||
import tornado.testing
|
||||
import tornado.util
|
||||
import tornado.web
|
||||
import tornado.websocket
|
||||
import tornado.wsgi
|
||||
import importlib
|
||||
import tornado
|
||||
|
||||
try:
|
||||
import pycurl
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
import tornado.curl_httpclient
|
||||
for mod in tornado.__all__:
|
||||
if mod == "curl_httpclient":
|
||||
# This module has extra dependencies; skip it if they're not installed.
|
||||
try:
|
||||
import pycurl
|
||||
except ImportError:
|
||||
continue
|
||||
importlib.import_module(f"tornado.{mod}")
|
||||
"""
|
||||
|
||||
_import_lazy = b"""
|
||||
import sys
|
||||
import tornado
|
||||
|
||||
if "tornado.web" in sys.modules:
|
||||
raise Exception("unexpected eager import")
|
||||
|
||||
# Trigger a lazy import by referring to something in a submodule.
|
||||
tornado.web.RequestHandler
|
||||
|
||||
if "tornado.web" not in sys.modules:
|
||||
raise Exception("lazy import did not update sys.modules")
|
||||
"""
|
||||
|
||||
|
||||
|
@ -56,6 +49,12 @@ class ImportTest(unittest.TestCase):
|
|||
proc.communicate(_import_everything)
|
||||
self.assertEqual(proc.returncode, 0)
|
||||
|
||||
def test_lazy_import(self):
|
||||
# Test that submodules can be referenced lazily after "import tornado"
|
||||
proc = subprocess.Popen([sys.executable], stdin=subprocess.PIPE)
|
||||
proc.communicate(_import_lazy)
|
||||
self.assertEqual(proc.returncode, 0)
|
||||
|
||||
def test_import_aliases(self):
|
||||
# Ensure we don't delete formerly-documented aliases accidentally.
|
||||
import tornado.ioloop
|
||||
|
|
|
@ -4,7 +4,7 @@ import sys
|
|||
import datetime
|
||||
import unittest
|
||||
|
||||
import tornado.escape
|
||||
import tornado
|
||||
from tornado.escape import utf8
|
||||
from tornado.util import (
|
||||
raise_exc_info,
|
||||
|
|
|
@ -23,7 +23,7 @@ Here is a simple "Hello, world" example app:
|
|||
.. testcode::
|
||||
|
||||
import asyncio
|
||||
import tornado.web
|
||||
import tornado
|
||||
|
||||
class MainHandler(tornado.web.RequestHandler):
|
||||
def get(self):
|
||||
|
|
|
@ -23,7 +23,6 @@ import hashlib
|
|||
import os
|
||||
import sys
|
||||
import struct
|
||||
import tornado.escape
|
||||
import tornado.web
|
||||
from urllib.parse import urlparse
|
||||
import zlib
|
||||
|
|
Loading…
Reference in New Issue