diff --git a/docs/_static/custom.css b/docs/_static/custom.css index f73ba5976..9c5e79971 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -267,3 +267,11 @@ dl.attribute > dd > p { .field-list p { margin-bottom: 1em; } + +div.body div.section > ul.simple > li > dl.simple > dd > ul { + margin: 0; +} + +div.body div.toctree-wrapper.compound > ul > li.toctree-l1 > ul { + margin-top: 0; +} diff --git a/docs/api/app.rst b/docs/api/app.rst index 0cb997f2b..a88c5a816 100644 --- a/docs/api/app.rst +++ b/docs/api/app.rst @@ -3,6 +3,10 @@ The App Class ============= +* `WSGI App`_ +* `ASGI App`_ +* `Options`_ + Falcon supports both the WSGI (:class:`falcon.App`) and ASGI (:class:`falcon.asgi.App`) protocols. This is done by instantiating the respective ``App`` class to create a @@ -21,12 +25,21 @@ you can host them with any standard-compliant server. wsgi_app = falcon.App() asgi_app = falcon.asgi.App() +WSGI App +-------- + .. autoclass:: falcon.App :members: +ASGI App +-------- + .. autoclass:: falcon.asgi.App :members: +Options +------- + .. autoclass:: falcon.RequestOptions :members: diff --git a/docs/api/cookies.rst b/docs/api/cookies.rst index 2edc4f235..b98c90926 100644 --- a/docs/api/cookies.rst +++ b/docs/api/cookies.rst @@ -3,6 +3,11 @@ Cookies ------- +* `Getting Cookies`_ +* `Setting Cookies`_ +* `The Secure Attribute`_ +* `The SameSite Attribute`_ + .. _getting-cookies: Getting Cookies diff --git a/docs/api/errors.rst b/docs/api/errors.rst index 448c45cca..3f31c1664 100644 --- a/docs/api/errors.rst +++ b/docs/api/errors.rst @@ -3,6 +3,10 @@ Error Handling ============== +* `Base Class`_ +* `Mixins`_ +* `Predefined Errors`_ + When it comes to error handling, you can always directly set the error status, appropriate response headers, and error body using the ``resp`` object. However, Falcon tries to make things a little easier by diff --git a/docs/api/hooks.rst b/docs/api/hooks.rst index 20cfa0071..a3adf4333 100644 --- a/docs/api/hooks.rst +++ b/docs/api/hooks.rst @@ -3,6 +3,9 @@ Hooks ===== +* `Before Hooks`_ +* `After Hooks`_ + Falcon supports *before* and *after* hooks. You install a hook simply by applying one of the decorators below, either to an individual responder or to an entire resource. @@ -90,6 +93,12 @@ requests. are intended to hold request and response data specific to your app as it passes through the framework. +Before Hooks +------------ + .. autofunction:: falcon.before +After Hooks +----------- + .. autofunction:: falcon.after diff --git a/docs/api/media.rst b/docs/api/media.rst index 97b6c4dfa..ff426faa7 100644 --- a/docs/api/media.rst +++ b/docs/api/media.rst @@ -3,6 +3,15 @@ Media ===== +* `Usage`_ +* `Validating Media`_ +* `Content-Type Negotiation`_ +* `Replacing the Default Handlers`_ +* `Supported Handler Types`_ +* `Custom Handler Type`_ +* `Handlers Mapping`_ +* `Media Type Constants`_ + Falcon allows for easy and customizable internet media type handling. By default Falcon only enables handlers for JSON and HTML (URL-encoded and multipart) forms. However, additional handlers can be configured through the @@ -141,8 +150,8 @@ provided by Falcon: :member-order: bysource -Handlers --------- +Handlers Mapping +---------------- .. autoclass:: falcon.media.Handlers :members: diff --git a/docs/api/middleware.rst b/docs/api/middleware.rst index dcd7eb2c1..f2670ab79 100644 --- a/docs/api/middleware.rst +++ b/docs/api/middleware.rst @@ -3,6 +3,9 @@ Middleware ========== +* `Short-Circuiting`_ +* `Exception Handling`_ + Middleware components provide a way to execute logic before the framework routes each request, after each request is routed but before the target responder is called, or just before the response is returned @@ -240,7 +243,7 @@ like this:: mob2.process_response mob1.process_response -Short-circuiting +Short-Circuiting ---------------- A *process_request* or *process_resource* middleware method may short-circuit diff --git a/docs/api/multipart.rst b/docs/api/multipart.rst index a435454b8..a39a999a8 100644 --- a/docs/api/multipart.rst +++ b/docs/api/multipart.rst @@ -3,6 +3,10 @@ Multipart Forms =============== +* `Body Part Type`_ +* `Parsing Options`_ +* `Parsing Errors`_ + Falcon features easy and efficient access to submitted multipart forms by using :class:`falcon.media.MultipartFormHandler` to handle the ``multipart/form-data`` :ref:`media ` type. This handler is enabled by diff --git a/docs/api/redirects.rst b/docs/api/redirects.rst index 06527fd2d..72ca9837b 100644 --- a/docs/api/redirects.rst +++ b/docs/api/redirects.rst @@ -7,10 +7,7 @@ Falcon defines a set of exceptions that can be raised within a middleware method, hook, or responder in order to trigger a 3xx (Redirection) response to the client. Raising one of these classes short-circuits request processing in a manner similar to -raising an instance or subclass of :py:class:`~.HTTPError` - -Redirects ---------- +raising an instance or subclass of :py:class:`~.HTTPError`. .. autoexception:: falcon.HTTPMovedPermanently diff --git a/docs/api/request_and_response_asgi.rst b/docs/api/request_and_response_asgi.rst index 529946fc3..b2cabb3c6 100644 --- a/docs/api/request_and_response_asgi.rst +++ b/docs/api/request_and_response_asgi.rst @@ -3,6 +3,9 @@ ASGI Requests & Responses ========================= +* `Request`_ +* `Response`_ + Instances of the :class:`falcon.asgi.Request` and :class:`falcon.asgi.Response` classes are passed into responders as the second and third arguments, respectively: @@ -44,5 +47,3 @@ Response .. autoclass:: falcon.asgi.SSEvent :members: - - diff --git a/docs/api/request_and_response_wsgi.rst b/docs/api/request_and_response_wsgi.rst index c35c14c17..4d1532286 100644 --- a/docs/api/request_and_response_wsgi.rst +++ b/docs/api/request_and_response_wsgi.rst @@ -3,6 +3,9 @@ WSGI Requests & Responses ========================= +* `Request`_ +* `Response`_ + Instances of the :class:`falcon.Request` and :class:`falcon.Response` classes are passed into WSGI app responders as the second and third arguments, respectively: @@ -40,6 +43,3 @@ Response .. autoclass:: falcon.Response :members: - - - diff --git a/docs/api/routing.rst b/docs/api/routing.rst index 789a7d506..ed56cbb8f 100644 --- a/docs/api/routing.rst +++ b/docs/api/routing.rst @@ -3,6 +3,15 @@ Routing ======= +* `Default Behavior`_ +* `Default Router`_ +* `Field Converters`_ +* `Built-in Converters`_ +* `Custom Converters`_ +* `Custom Routers`_ +* `Routing Utilities`_ +* `Custom HTTP Methods`_ + Falcon routes incoming requests to resources based on a set of URI templates. If the path requested by the client matches the template for a given route, the request is then passed on to the associated resource @@ -52,8 +61,8 @@ implement a responder for the requested HTTP method, the framework invokes a default responder that raises an instance of :class:`~.HTTPMethodNotAllowed`. -Default Router --------------- +Default Behavior +---------------- Falcon's default routing engine is based on a decision tree that is first compiled into Python code, and then evaluated by the runtime. @@ -99,6 +108,11 @@ Responders must always define at least two arguments to receive def on_post(self, req, resp): pass +For ASGI apps, the responder must be a coroutine function:: + + async def on_post(self, req, resp): + pass + The :class:`~.falcon.Request` object represents the incoming HTTP request. It exposes properties and methods for examining headers, query string parameters, and other metadata associated with @@ -348,4 +362,3 @@ You then can define request methods like any other HTTP method, such as:: def on_foo(self, req, resp): ... - diff --git a/docs/api/status.rst b/docs/api/status.rst index ec0c802d0..56ba3cc26 100644 --- a/docs/api/status.rst +++ b/docs/api/status.rst @@ -3,6 +3,13 @@ Status Codes ============ +* `HTTPStatus`_ +* `1xx Informational`_ +* `2xx Success`_ +* `3xx Redirection`_ +* `4xx Client Error`_ +* `5xx Server Error`_ + Falcon provides a list of constants for common `HTTP response status codes `_. diff --git a/docs/api/testing.rst b/docs/api/testing.rst index 3068cb9cc..b0de27e2a 100644 --- a/docs/api/testing.rst +++ b/docs/api/testing.rst @@ -1,15 +1,60 @@ .. _testing: -Testing -======= +Testing Helpers +=============== -Reference ---------- +* `General Helpers`_ +* `Simulating Requests`_ + * `Main Interface`_ + * `Low-Level Utils`_ .. automodule:: falcon.testing - :members: Result, Cookie, - simulate_request, simulate_get, simulate_head, simulate_post, - simulate_put, simulate_options, simulate_patch, simulate_delete, - TestClient, TestCase, SimpleTestResource, StartResponseMock, - capture_responder_args, rand_string, create_environ, create_req, - create_asgi_req, get_unused_port, redirected, closed_wsgi_iterable + :noindex: + +.. TODO: Add TOC here, and to other large RSTs? + +General Helpers +--------------- + +.. autoclass:: TestCase +.. autoclass:: SimpleTestResource + +.. autofunction:: invoke_coroutine_sync +.. autofunction:: rand_string +.. autofunction:: get_unused_port +.. autofunction:: redirected +.. autofunction:: get_encoding_from_headers + + +Simulating Requests +------------------- + +Main Interface +~~~~~~~~~~~~~~ + +.. autofunction:: simulate_get +.. autofunction:: simulate_head +.. autofunction:: simulate_post +.. autofunction:: simulate_put +.. autofunction:: simulate_options +.. autofunction:: simulate_patch +.. autofunction:: simulate_delete +.. autofunction:: simulate_request + +.. autoclass:: Result +.. autoclass:: Cookie +.. autoclass:: TestClient +.. autofunction:: capture_responder_args + +Low-Level Utils +~~~~~~~~~~~~~~~ + +.. autoclass:: StartResponseMock +.. autoclass:: ASGIRequestEventEmitter +.. autoclass:: ASGILifespanEventEmitter +.. autoclass:: ASGIResponseEventCollector +.. autofunction:: create_environ +.. autofunction:: create_scope +.. autofunction:: create_req +.. autofunction:: create_asgi_req +.. autofunction:: closed_wsgi_iterable diff --git a/docs/api/util.rst b/docs/api/util.rst index b652bcaf0..d754d188d 100644 --- a/docs/api/util.rst +++ b/docs/api/util.rst @@ -3,34 +3,42 @@ Utilities ========= -URI Functions -------------- +* `URI`_ +* `Date and Time`_ +* `HTTP Status`_ +* `Other`_ + +URI +--- .. automodule:: falcon.uri :members: encode, encode_value, decode, parse_host, parse_query_string, unquote_string -ASGI Helpers ------------- - -.. _asgi_helpers: +Date and Time +------------- .. automodule:: falcon :noindex: - :members: sync_to_async, wrap_sync_to_async, - wrap_sync_to_async_unsafe + :members: http_now, dt_to_http, http_date_to_dt +.. autoclass:: falcon.TimezoneGMT + :members: -Miscellaneous -------------- +HTTP Status +----------- .. automodule:: falcon - :members: deprecated, http_now, dt_to_http, http_date_to_dt, - to_query_str, get_http_status, http_status_to_code, code_to_http_status, - get_bound_method, secure_filename, is_python_func + :noindex: + :members: get_http_status, http_status_to_code, code_to_http_status -.. autoclass:: falcon.TimezoneGMT - :members: +Other +----- + +.. automodule:: falcon + :noindex: + :members: deprecated, to_query_str, + get_bound_method, secure_filename, is_python_func .. autoclass:: falcon.Context :members: diff --git a/docs/index.rst b/docs/index.rst index 5d4f971ce..f948a3604 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -113,7 +113,7 @@ Documentation ------------- .. toctree:: - :maxdepth: 2 + :maxdepth: 3 user/index deploy/index diff --git a/falcon/testing/helpers.py b/falcon/testing/helpers.py index e3a66d9cb..b3d84248a 100644 --- a/falcon/testing/helpers.py +++ b/falcon/testing/helpers.py @@ -48,6 +48,24 @@ class ASGILifespanEventEmitter: + """Emits ASGI lifespan events to an ASGI app. + + This class can be used to drive a standard ASGI app callable in order to + perform functional tests on the app in question. + + When simulating both lifespan and per-request events, each event stream + will require a separate invocation of the ASGI callable; one with a + lifespan event emitter, and one with a request event emitter. An + asyncio :class:`~asyncio.Condition` can be used to pause the + lifespan emitter until all of the desired request events have been + emitted. + + Keyword Args: + shutting_down (asyncio.Condition): An instance of + :class:`asyncio.Condition` that will be awaited before + emitting the final shutdown event (``'lifespan.shutdown``). + """ + def __init__(self, shutting_down): self._state = 0 self._shutting_down = shutting_down @@ -74,6 +92,17 @@ async def emit(self): class ASGIRequestEventEmitter: """Emits events on-demand to an ASGI app. + This class can be used to drive a standard ASGI app callable in order to + perform functional tests on the app in question. + + Note: + In order to ensure the app is able to handle subtle variations + in the ASGI events that are allowed by the specification, such + variations are applied to the emitted events at unspecified + intervals. This includes whether or not the `more_body` field + is explicitly set, or whether or not the request `body` chunk in + the event is occasionally empty, + Keyword Args: body (str): The body content to use when emitting http.request events. May be an empty string. If a byte string, it will @@ -177,7 +206,26 @@ def _toggle_branch(self, name): class ASGIResponseEventCollector: - """Collects and validates ASGI events returned by an app.""" + """Collects and validates ASGI events returned by an app. + + Attributes: + events (iterable): An iterable of events that were emitted by + the app, collected as-is from the app. + headers (iterable): An iterable of (str, str) tuples representing + the UTF-8 decoded headers emitted by the app in the body of + the ``'http.response.start'`` event. + status (int): HTTP status code emitted by the app in the body of + the ``'http.response.start'`` event. + body_chunks (iterable): An iterable of ``bytes`` objects emitted + by the app via ``'http.response.body'`` events. + more_body (bool): Whether or not the app expects to emit more + body chunks. Will be ``None`` if unknown (i.e., the app has + not yet emitted any ``'http.response.body'`` events.) + + Raises: + TypeError: An event field emitted by the app was of an unexpected type. + ValueError: Invalid event name or field value. + """ _LIFESPAN_EVENT_TYPES = frozenset([ 'lifespan.startup.complete',