|
6 | 6 | # See the LICENSE for more information. |
7 | 7 | # |
8 | 8 | # Vendored and modified for Plain. |
9 | | -import ast |
10 | 9 | import email.utils |
11 | 10 | import errno |
12 | 11 | import fcntl |
13 | 12 | import html |
14 | 13 | import importlib |
15 | 14 | import inspect |
16 | 15 | import io |
17 | | -import logging |
18 | 16 | import os |
19 | 17 | import random |
20 | 18 | import re |
|
28 | 26 | from collections.abc import Callable |
29 | 27 | from typing import Any |
30 | 28 |
|
31 | | -from .errors import AppImportError |
32 | 29 | from .workers import SUPPORTED_WORKERS |
33 | 30 |
|
34 | 31 | # Server and Date aren't technically hop-by-hop |
@@ -256,115 +253,6 @@ def write_error(sock: socket.socket, status_int: int, reason: str, mesg: str) -> |
256 | 253 | write_nonblock(sock, http.encode("latin1")) |
257 | 254 |
|
258 | 255 |
|
259 | | -def _called_with_wrong_args(f: Any) -> bool: |
260 | | - """Check whether calling a function raised a ``TypeError`` because |
261 | | - the call failed or because something in the function raised the |
262 | | - error. |
263 | | -
|
264 | | - :param f: The function that was called. |
265 | | - :return: ``True`` if the call failed. |
266 | | - """ |
267 | | - tb = sys.exc_info()[2] |
268 | | - |
269 | | - try: |
270 | | - while tb is not None: |
271 | | - if tb.tb_frame.f_code is f.__code__: |
272 | | - # In the function, it was called successfully. |
273 | | - return False |
274 | | - |
275 | | - tb = tb.tb_next |
276 | | - |
277 | | - # Didn't reach the function. |
278 | | - return True |
279 | | - finally: |
280 | | - # Delete tb to break a circular reference in Python 2. |
281 | | - # https://docs.python.org/2/library/sys.html#sys.exc_info |
282 | | - del tb |
283 | | - |
284 | | - |
285 | | -def import_app(module: str) -> Callable[..., Any]: |
286 | | - parts = module.split(":", 1) |
287 | | - if len(parts) == 1: |
288 | | - obj = "application" |
289 | | - else: |
290 | | - module, obj = parts[0], parts[1] |
291 | | - |
292 | | - try: |
293 | | - mod = importlib.import_module(module) |
294 | | - except ImportError: |
295 | | - if module.endswith(".py") and os.path.exists(module): |
296 | | - msg = "Failed to find application, did you mean '%s:%s'?" |
297 | | - raise ImportError(msg % (module.rsplit(".", 1)[0], obj)) |
298 | | - raise |
299 | | - |
300 | | - # Parse obj as a single expression to determine if it's a valid |
301 | | - # attribute name or function call. |
302 | | - try: |
303 | | - expression = ast.parse(obj, mode="eval").body |
304 | | - except SyntaxError: |
305 | | - raise AppImportError( |
306 | | - f"Failed to parse {obj!r} as an attribute name or function call." |
307 | | - ) |
308 | | - |
309 | | - if isinstance(expression, ast.Name): |
310 | | - name = expression.id |
311 | | - args = kwargs = None |
312 | | - elif isinstance(expression, ast.Call): |
313 | | - # Ensure the function name is an attribute name only. |
314 | | - if not isinstance(expression.func, ast.Name): |
315 | | - raise AppImportError(f"Function reference must be a simple name: {obj!r}") |
316 | | - |
317 | | - name = expression.func.id |
318 | | - |
319 | | - # Parse the positional and keyword arguments as literals. |
320 | | - try: |
321 | | - args = [ast.literal_eval(arg) for arg in expression.args] |
322 | | - kwargs = {kw.arg: ast.literal_eval(kw.value) for kw in expression.keywords} |
323 | | - except ValueError: |
324 | | - # literal_eval gives cryptic error messages, show a generic |
325 | | - # message with the full expression instead. |
326 | | - raise AppImportError( |
327 | | - f"Failed to parse arguments as literal values: {obj!r}" |
328 | | - ) |
329 | | - else: |
330 | | - raise AppImportError( |
331 | | - f"Failed to parse {obj!r} as an attribute name or function call." |
332 | | - ) |
333 | | - |
334 | | - is_debug = logging.root.level == logging.DEBUG |
335 | | - try: |
336 | | - app = getattr(mod, name) |
337 | | - except AttributeError: |
338 | | - if is_debug: |
339 | | - traceback.print_exception(*sys.exc_info()) |
340 | | - raise AppImportError(f"Failed to find attribute {name!r} in {module!r}.") |
341 | | - |
342 | | - # If the expression was a function call, call the retrieved object |
343 | | - # to get the real application. |
344 | | - if args is not None: |
345 | | - try: |
346 | | - app = app(*args, **kwargs) |
347 | | - except TypeError as e: |
348 | | - # If the TypeError was due to bad arguments to the factory |
349 | | - # function, show Python's nice error message without a |
350 | | - # traceback. |
351 | | - if _called_with_wrong_args(app): |
352 | | - raise AppImportError( |
353 | | - "".join(traceback.format_exception_only(TypeError, e)).strip() |
354 | | - ) |
355 | | - |
356 | | - # Otherwise it was raised from within the function, show the |
357 | | - # full traceback. |
358 | | - raise |
359 | | - |
360 | | - if app is None: |
361 | | - raise AppImportError(f"Failed to find application object: {obj!r}") |
362 | | - |
363 | | - if not callable(app): |
364 | | - raise AppImportError("Application object must be callable.") |
365 | | - return app |
366 | | - |
367 | | - |
368 | 256 | def getcwd() -> str: |
369 | 257 | # get current path, try to use PWD env first |
370 | 258 | try: |
|
0 commit comments